2 Compiles swf code (.sc) files into .swf files.
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/drawer.h"
32 #include "../lib/log.h"
33 #include "../lib/args.h"
35 #include "../lib/mp3.h"
36 #include "../lib/wav.h"
38 #include "../lib/png.h"
39 #include "swfc-feedback.h"
40 #include "swfc-interpolation.h"
41 #include "swfc-history.h"
44 static char * outputname = "output.swf";
45 static int verbose = 2;
46 static int optimize = 0;
47 static int override_outputname = 0;
48 static int do_cgi = 0;
49 static int change_sets_all = 0;
51 static struct options_t options[] = {
60 int args_callback_option(char*name,char*val)
62 if(!strcmp(name, "V")) {
63 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
66 else if(!strcmp(name, "o")) {
68 override_outputname = 1;
71 else if(!strcmp(name, "O")) {
75 else if(!strcmp(name, "C")) {
79 else if(!strcmp(name, "v")) {
84 printf("Unknown option: -%s\n", name);
89 int args_callback_longoption(char*name,char*val)
91 return args_long2shortoption(options, name, val);
93 void args_callback_usage(char *name)
96 printf("Usage: %s [-o file.swf] file.sc\n", name);
98 printf("-h , --help Print short help message and exit\n");
99 printf("-V , --version Print version info and exit\n");
100 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
101 printf("-v , --verbose Increase verbosity. \n");
102 printf("-o , --output <filename> Set output file to <filename>.\n");
105 int args_callback_command(char*name,char*val)
108 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
115 static struct token_t* file;
122 static void readToken()
124 type = file[pos].type;
126 syntaxerror("unexpected end of file");
128 text = file[pos].text;
129 textlen = strlen(text);
130 line = file[pos].line;
131 column = file[pos].column;
133 //printf("---> %d(%s) %s\n", type, type_names[type], text);
136 static void pushBack()
139 if(!pos) syntaxerror("internal error 3");
144 textlen = strlen(text);
147 column = file[p].column;
150 static int noMoreTokens()
152 if(file[pos].type == END)
170 // ------------------------------ swf routines ----------------------------
174 int type; //0=swf, 1=sprite, 2=clip, 3=button
180 /* for sprites (1): */
186 dictionary_t oldinstances;
191 static int stackpos = 0;
193 static dictionary_t characters;
194 static dictionary_t images;
195 static dictionary_t textures;
196 static dictionary_t outlines;
197 static dictionary_t gradients;
198 static dictionary_t filters;
199 static dictionary_t interpolations;
200 static char idmap[65536];
201 static TAG*tag = 0; //current tag
203 static int id; //current character id
204 static int currentframe; //current frame in current level
205 static SRECT currentrect; //current bounding box in current level
206 static U16 currentdepth;
207 static dictionary_t instances;
208 static dictionary_t fonts;
209 static dictionary_t sounds;
210 static dictionary_t fontUsage;
212 typedef struct _parameters {
214 float scalex, scaley;
220 U8 blendmode; //not interpolated
222 U16 set; // bits indicating wether a parameter was set in the c_placement function
223 U16 flags; // bits to toggle anything you may care to implement as a toggle
226 typedef struct _character {
232 typedef struct _instance {
233 character_t*character;
235 parameters_t parameters;
239 typedef struct _outline {
244 typedef struct _gradient {
250 typedef struct _filter {
254 typedef struct _texture {
258 char* interpolationFunctions[] = {"linear", \
259 "quadIn", "quadOut", "quadInOut", \
260 "cubicIn", "cubicOut", "cubicInOut", \
261 "quartIn", "quartOut", "quartInOut", \
262 "quintIn", "quintOut", "quintInOut", \
263 "circleIn", "circleOut", "circleInOut", \
264 "exponentialIn", "exponentialOut", "exponentialInOut", \
265 "sineIn", "sineOut", "sineInOut", \
266 "elasticIn", "elasticOut", "elasticInOut", \
267 "backIn", "backOut", "backInOut", \
268 "bounceIn", "bounceOut", "bounceInOut", \
269 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
271 static void character_init(character_t*c)
273 memset(c, 0, sizeof(character_t));
276 static character_t* character_new()
279 c = (character_t*)malloc(sizeof(character_t));
284 static void instance_init(instance_t*i)
286 memset(i, 0, sizeof(instance_t));
287 i->history = history_new();
290 static void instance_free(instance_t* i)
292 history_free(i->history);
296 static instance_t* instance_new()
299 c = (instance_t*)malloc(sizeof(instance_t));
304 static void free_instance(void* i)
306 instance_free((instance_t*)i);
309 static void free_font(void* f)
311 swf_FontFree((SWFFONT*)f);
314 static void gradient_free(GRADIENT* grad)
321 static void free_gradient(void* grad)
323 gradient_free((GRADIENT*) grad);
326 static void outline_free(outline_t* o)
328 free(o->shape->data);
333 static void free_outline(void* o)
335 outline_free((outline_t*)o);
338 static void freeDictionaries()
340 dictionary_free_all(&instances, free_instance);
341 dictionary_free_all(&characters, free);
342 dictionary_free_all(&images, free);
343 dictionary_free_all(&textures, free);
344 dictionary_free_all(&outlines, free_outline);
345 dictionary_free_all(&gradients, free_gradient);
346 dictionary_free_all(&filters, free);
347 dictionary_free_all(&fonts, free_font);
348 dictionary_free_all(&sounds, free);
349 dictionary_free_all(&interpolations, free);
352 static void freeFontDictionary()
354 dictionary_free_all(&fonts, free_font);
357 static void incrementid()
361 syntaxerror("Out of character ids.");
366 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
368 if(dictionary_lookup(&characters, name))
369 syntaxerror("character %s defined twice", name);
370 character_t* c = character_new();
372 c->definingTag = ctag;
375 dictionary_put2(&characters, name, c);
377 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
379 swf_SetString(tag, name);
380 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
383 swf_SetString(tag, name);
385 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
387 if(dictionary_lookup(&images, name))
388 syntaxerror("image %s defined twice", name);
390 character_t* c = character_new();
391 c->definingTag = ctag;
394 dictionary_put2(&images, name, c);
396 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
398 if(dictionary_lookup(&instances, name))
399 syntaxerror("object %s defined twice", name);
400 instance_t* i = instance_new();
403 //swf_GetMatrix(0, &i->matrix);
404 dictionary_put2(&instances, name, i);
408 static void parameters_clear(parameters_t*p)
411 p->scalex = 1.0; p->scaley = 1.0;
414 p->pivot.x = 0; p->pivot.y = 0;
419 swf_GetCXForm(0, &p->cxform, 1);
422 static void makeMatrix(MATRIX*m, parameters_t*p)
431 sx = p->scalex*cos(p->rotate/360*2*M_PI);
432 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
433 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
434 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
436 m->sx = (int)(sx*65536+0.5);
437 m->r1 = (int)(r1*65536+0.5);
438 m->r0 = (int)(r0*65536+0.5);
439 m->sy = (int)(sy*65536+0.5);
443 h = swf_TurnPoint(p->pin, m);
448 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
453 r = swf_TurnRect(rect, &m);
454 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
455 currentrect.xmax == 0 && currentrect.ymax == 0)
458 swf_ExpandRect2(¤trect, &r);
464 interpolation_t* new;
465 new = (interpolation_t*)malloc(sizeof(interpolation_t));
466 new->function = IF_LINEAR;
467 dictionary_put2(&interpolations, "linear", new);
469 new = (interpolation_t*)malloc(sizeof(interpolation_t));
470 new->function = IF_QUAD_IN;
472 dictionary_put2(&interpolations, "quadIn", new);
473 new = (interpolation_t*)malloc(sizeof(interpolation_t));
474 new->function = IF_QUAD_OUT;
476 dictionary_put2(&interpolations, "quadOut", new);
477 new = (interpolation_t*)malloc(sizeof(interpolation_t));
478 new->function = IF_QUAD_IN_OUT;
480 dictionary_put2(&interpolations, "quadInOut", new);
482 new = (interpolation_t*)malloc(sizeof(interpolation_t));
483 new->function = IF_CUBIC_IN;
485 dictionary_put2(&interpolations, "cubicIn", new);
486 new = (interpolation_t*)malloc(sizeof(interpolation_t));
487 new->function = IF_CUBIC_OUT;
489 dictionary_put2(&interpolations, "cubicOut", new);
490 new = (interpolation_t*)malloc(sizeof(interpolation_t));
491 new->function = IF_CUBIC_IN_OUT;
493 dictionary_put2(&interpolations, "cubicInOut", new);
495 new = (interpolation_t*)malloc(sizeof(interpolation_t));
496 new->function = IF_QUART_IN;
498 dictionary_put2(&interpolations, "quartIn", new);
499 new = (interpolation_t*)malloc(sizeof(interpolation_t));
500 new->function = IF_QUART_OUT;
502 dictionary_put2(&interpolations, "quartOut", new);
503 new = (interpolation_t*)malloc(sizeof(interpolation_t));
504 new->function = IF_QUART_IN_OUT;
506 dictionary_put2(&interpolations, "quartInOut", new);
508 new = (interpolation_t*)malloc(sizeof(interpolation_t));
509 new->function = IF_QUINT_IN;
511 dictionary_put2(&interpolations, "quintIn", new);
512 new = (interpolation_t*)malloc(sizeof(interpolation_t));
513 new->function = IF_QUINT_OUT;
515 dictionary_put2(&interpolations, "quintOut", new);
516 new = (interpolation_t*)malloc(sizeof(interpolation_t));
517 new->function = IF_QUINT_IN_OUT;
519 dictionary_put2(&interpolations, "quintInOut", new);
521 new = (interpolation_t*)malloc(sizeof(interpolation_t));
522 new->function = IF_CIRCLE_IN;
523 dictionary_put2(&interpolations, "circleIn", new);
524 new = (interpolation_t*)malloc(sizeof(interpolation_t));
525 new->function = IF_CIRCLE_OUT;
526 dictionary_put2(&interpolations, "circleOut", new);
527 new = (interpolation_t*)malloc(sizeof(interpolation_t));
528 new->function = IF_CIRCLE_IN_OUT;
529 dictionary_put2(&interpolations, "circleInOut", new);
531 new = (interpolation_t*)malloc(sizeof(interpolation_t));
532 new->function = IF_EXPONENTIAL_IN;
533 dictionary_put2(&interpolations, "exponentialIn", new);
534 new = (interpolation_t*)malloc(sizeof(interpolation_t));
535 new->function = IF_EXPONENTIAL_OUT;
536 dictionary_put2(&interpolations, "exponentialOut", new);
537 new = (interpolation_t*)malloc(sizeof(interpolation_t));
538 new->function = IF_EXPONENTIAL_IN_OUT;
539 dictionary_put2(&interpolations, "exponentialInOut", new);
541 new = (interpolation_t*)malloc(sizeof(interpolation_t));
542 new->function = IF_SINE_IN;
543 dictionary_put2(&interpolations, "sineIn", new);
544 new = (interpolation_t*)malloc(sizeof(interpolation_t));
545 new->function = IF_SINE_OUT;
546 dictionary_put2(&interpolations, "sineOut", new);
547 new = (interpolation_t*)malloc(sizeof(interpolation_t));
548 new->function = IF_SINE_IN_OUT;
549 dictionary_put2(&interpolations, "sineInOut", new);
552 memset(&c, 0, sizeof(RGBA));
553 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
554 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
555 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
556 noGradient->gradient.num = 2;
557 noGradient->gradient.rgba[0] = c;
558 noGradient->gradient.ratios[0] = 0;
559 noGradient->gradient.rgba[1] = c;
560 noGradient->gradient.ratios[1] = 255;
561 noGradient->radial = 0;
562 noGradient->rotate = 0;
563 dictionary_put2(&gradients, "no_gradient", noGradient);
566 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
567 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
568 FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
569 dictionary_put2(&filters, "no_filters", dummy);
570 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
572 dictionary_put2(&filters, "no_blur", noBlur);
573 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
575 noBevel->composite = 1;
576 dictionary_put2(&filters, "no_bevel", noBevel);
577 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
578 noDropshadow->passes = 1;
579 noDropshadow->composite = 1;
580 dictionary_put2(&filters, "no_dropshadow", noDropshadow);
581 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
582 noGradientGlow->passes = 1;
583 noGradientGlow->composite = 1;
584 noGradientGlow->gradient = &noGradient->gradient;
585 dictionary_put2(&filters, "no_gradientglow", noGradientGlow);
588 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
591 syntaxerror(".swf blocks can't be nested");
592 if(stackpos==sizeof(stack)/sizeof(stack[0]))
593 syntaxerror("too many levels of recursion");
595 SWF*swf = (SWF*)malloc(sizeof(SWF));
597 memset(swf, 0, sizeof(swf));
598 swf->fileVersion = version;
600 swf->frameRate = fps;
601 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
602 swf->compressed = compress;
603 swf_SetRGB(tag,&background);
605 dictionary_init(&characters);
606 dictionary_init(&images);
607 dictionary_init(&textures);
608 dictionary_init(&outlines);
609 dictionary_init(&gradients);
610 dictionary_init(&filters);
611 dictionary_init(&instances);
612 dictionary_init(&sounds);
613 dictionary_init(&interpolations);
615 cleanUp = &freeDictionaries;
617 memset(&stack[stackpos], 0, sizeof(stack[0]));
618 stack[stackpos].type = 0;
619 stack[stackpos].filename = strdup(name);
620 stack[stackpos].swf = swf;
621 stack[stackpos].oldframe = -1;
625 memset(¤trect, 0, sizeof(currentrect));
628 memset(idmap, 0, sizeof(idmap));
632 void s_sprite(char*name)
634 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
635 swf_SetU16(tag, id); //id
636 swf_SetU16(tag, 0); //frames
638 memset(&stack[stackpos], 0, sizeof(stack[0]));
639 stack[stackpos].type = 1;
640 stack[stackpos].oldframe = currentframe;
641 stack[stackpos].olddepth = currentdepth;
642 stack[stackpos].oldrect = currentrect;
643 stack[stackpos].oldinstances = instances;
644 stack[stackpos].tag = tag;
645 stack[stackpos].id = id;
646 stack[stackpos].name = strdup(name);
648 /* FIXME: those four fields should be bundled together */
649 dictionary_init(&instances);
652 memset(¤trect, 0, sizeof(currentrect));
658 typedef struct _buttonrecord
666 typedef struct _button
670 buttonrecord_t records[4];
673 static button_t mybutton;
675 void s_button(char*name)
677 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
678 swf_SetU16(tag, id); //id
679 swf_ButtonSetFlags(tag, 0); //menu=no
681 memset(&mybutton, 0, sizeof(mybutton));
683 memset(&stack[stackpos], 0, sizeof(stack[0]));
684 stack[stackpos].type = 3;
685 stack[stackpos].tag = tag;
686 stack[stackpos].id = id;
687 stack[stackpos].name = strdup(name);
688 stack[stackpos].oldrect = currentrect;
689 memset(¤trect, 0, sizeof(currentrect));
694 void s_buttonput(char*character, char*as, parameters_t p)
696 character_t* c = dictionary_lookup(&characters, character);
701 if(!stackpos || (stack[stackpos-1].type != 3)) {
702 syntaxerror(".show may only appear in .button");
705 syntaxerror("character %s not known (in .shape %s)", character, character);
707 if(mybutton.endofshapes) {
708 syntaxerror("a .do may not precede a .show", character, character);
711 m = s_instancepos(c->size, &p);
719 if(*s==',' || *s==0) {
720 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
721 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
722 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
723 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
724 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
725 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
732 static void setbuttonrecords(TAG*tag)
734 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
735 if(!mybutton.endofshapes) {
738 if(!mybutton.records[3].set) {
739 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
743 if(mybutton.records[t].set) {
744 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
747 swf_SetU8(tag,0); // end of button records
748 mybutton.endofshapes = 1;
752 void s_buttonaction(int flags, char*action)
758 setbuttonrecords(stack[stackpos-1].tag);
760 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
762 syntaxerror("Couldn't compile ActionScript");
765 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
766 swf_ActionSet(stack[stackpos-1].tag, a);
767 mybutton.nr_actions++;
772 static void setactionend(TAG*tag)
774 if(!mybutton.nr_actions) {
775 /* no actions means we didn't have an actionoffset,
776 which means we can't signal the end of the
777 buttonaction records, so, *sigh*, we have
778 to insert a dummy record */
779 swf_SetU16(tag, 0); //offset
780 swf_SetU16(tag, 0); //condition
781 swf_SetU8(tag, 0); //action
785 static void s_endButton()
788 setbuttonrecords(stack[stackpos-1].tag);
789 setactionend(stack[stackpos-1].tag);
792 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
796 tag = stack[stackpos].tag;
797 currentrect = stack[stackpos].oldrect;
799 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
800 free(stack[stackpos].name);
803 TAG* removeFromTo(TAG*from, TAG*to)
805 TAG*save = from->prev;
807 TAG*next = from->next;
815 static int parametersChange(history_t* history, int frame)
819 willChange = willChange || history_change(history, frame, "x");
820 willChange = willChange || history_change(history, frame, "y");
821 willChange = willChange || history_change(history, frame, "scalex");
822 willChange = willChange || history_change(history, frame, "scaley");
823 willChange = willChange || history_change(history, frame, "cxform.r0");
824 willChange = willChange || history_change(history, frame, "cxform.g0");
825 willChange = willChange || history_change(history, frame, "cxform.b0");
826 willChange = willChange || history_change(history, frame, "cxform.a0");
827 willChange = willChange || history_change(history, frame, "cxform.r1");
828 willChange = willChange || history_change(history, frame, "cxform.g1");
829 willChange = willChange || history_change(history, frame, "cxform.b1");
830 willChange = willChange || history_change(history, frame, "cxform.a1");
831 willChange = willChange || history_change(history, frame, "rotate");
832 willChange = willChange || history_change(history, frame, "shear");
833 willChange = willChange || history_change(history, frame, "pivot.x");
834 willChange = willChange || history_change(history, frame, "pivot.y");
835 willChange = willChange || history_change(history, frame, "pin.x");
836 willChange = willChange || history_change(history, frame, "pin.y");
837 willChange = willChange || history_change(history, frame, "blendmode");
838 willChange = willChange || history_changeFilter(history, frame);
843 static void free_filterlist(FILTERLIST* f_list)
846 for (i = 0; i < f_list->num; i++)
848 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
849 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
850 free(f_list->filter[i]);
855 static void readParameters(history_t* history, parameters_t* p, int frame)
857 p->x = history_value(history, frame, "x");
858 p->y = history_value(history, frame, "y");
859 p->scalex = history_value(history, frame, "scalex");
860 p->scaley = history_value(history, frame, "scaley");
861 p->cxform.r0 = history_value(history, frame, "cxform.r0");
862 p->cxform.g0 = history_value(history, frame, "cxform.g0");
863 p->cxform.b0 = history_value(history, frame, "cxform.b0");
864 p->cxform.a0 = history_value(history, frame, "cxform.a0");
865 p->cxform.r1 = history_value(history, frame, "cxform.r1");
866 p->cxform.g1 = history_value(history, frame, "cxform.g1");
867 p->cxform.b1 = history_value(history, frame, "cxform.b1");
868 p->cxform.a1 = history_value(history, frame, "cxform.a1");
869 p->rotate = history_rotateValue(history, frame);
870 p->shear = history_value(history, frame, "shear");
871 p->pivot.x = history_value(history, frame, "pivot.x");
872 p->pivot.y = history_value(history, frame, "pivot.y");
873 p->pin.x = history_value(history, frame, "pin.x");
874 p->pin.y = history_value(history, frame, "pin.y");
875 p->blendmode = history_value(history, frame, "blendmode");
876 p->filters = history_filterValue(history, frame);
879 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
883 swf_GetPlaceObject(NULL, &po);
887 po.cxform = p->cxform;
893 po.blendmode = p->blendmode;
896 po.filters = p->filters;
897 swf_SetPlaceObject(tag, &po);
900 static void writeInstance(instance_t* i)
904 int frame = i->history->firstFrame;
905 TAG* tag = i->history->firstTag;
906 history_processFlags(i->history);
907 while (frame < currentframe)
910 while (tag->id != ST_SHOWFRAME)
912 if (parametersChange(i->history, frame))
914 readParameters(i->history, &p, frame);
915 m = s_instancepos(i->character->size, &p);
917 if(p.blendmode || p.filters)
918 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
920 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
921 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
923 free_filterlist(p.filters);
930 void dumpSWF(SWF*swf)
932 TAG* tag = swf->firstTag;
933 printf("vvvvvvvvvvvvvvvvvvvvv\n");
935 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
938 printf("^^^^^^^^^^^^^^^^^^^^^\n");
941 static void s_endSprite()
943 SRECT r = currentrect;
945 if(stack[stackpos].cut)
946 tag = removeFromTo(stack[stackpos].cut, tag);
950 stringarray_t* index =dictionary_index(&instances);
952 for (num = 0; num < dictionary_count(&instances); num++)
954 char* name = stringarray_at(index, num);
957 i = dictionary_lookup(&instances, name);
964 tag = swf_InsertTag(tag, ST_SHOWFRAME);
965 tag = swf_InsertTag(tag, ST_END);
967 tag = stack[stackpos].tag;
970 syntaxerror("internal error(7)");
971 /* TODO: before clearing, prepend "<spritename>." to names and
972 copy into old instances dict */
973 dictionary_free_all(&instances, free_instance);
975 currentframe = stack[stackpos].oldframe;
976 currentrect = stack[stackpos].oldrect;
977 currentdepth = stack[stackpos].olddepth;
978 instances = stack[stackpos].oldinstances;
980 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
981 free(stack[stackpos].name);
984 static void s_endSWF()
991 stringarray_t* index = dictionary_index(&instances);
993 for (num = 0; num < dictionary_count(&instances); num++)
995 char* name = stringarray_at(index, num);
998 i = dictionary_lookup(&instances, name);
1003 if(stack[stackpos].cut)
1004 tag = removeFromTo(stack[stackpos].cut, tag);
1008 swf = stack[stackpos].swf;
1009 filename = stack[stackpos].filename;
1011 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1012 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1013 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1015 tag = swf_InsertTag(tag, ST_END);
1017 swf_OptimizeTagOrder(swf);
1023 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1024 swf->movieSize = currentrect; /* "autocrop" */
1027 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1028 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1029 swf->movieSize.ymax += 20;
1030 warning("Empty bounding box for movie");
1033 if(do_cgi || !strcmp(filename, "-"))
1034 fi = fileno(stdout);
1036 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1038 syntaxerror("couldn't create output file %s", filename);
1041 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1042 else if(swf->compressed)
1043 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
1045 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1059 if(stack[stackpos-1].type == 0)
1060 syntaxerror("End of file encountered in .flash block");
1061 if(stack[stackpos-1].type == 1)
1062 syntaxerror("End of file encountered in .sprite block");
1063 if(stack[stackpos-1].type == 2)
1064 syntaxerror("End of file encountered in .clip block");
1070 return currentframe+1;
1073 void s_frame(int nr, int cut, char*name, char anchor)
1079 syntaxerror("Illegal frame number");
1080 nr--; // internally, frame 1 is frame 0
1082 for(t=currentframe;t<nr;t++) {
1083 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1084 if(t==nr-1 && name && *name) {
1085 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1086 swf_SetString(tag, name);
1088 swf_SetU8(tag, 1); //make this an anchor
1091 if(nr == 0 && currentframe == 0 && name && *name) {
1092 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1093 swf_SetString(tag, name);
1095 swf_SetU8(tag, 1); //make this an anchor
1100 syntaxerror("Can't cut, frame empty");
1102 stack[stackpos].cut = tag;
1108 int parseColor2(char*str, RGBA*color);
1110 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1114 gradient_t*gradient;
1116 if(name[0] == '#') {
1117 parseColor2(name, &color);
1118 return swf_ShapeAddSolidFillStyle(s, &color);
1119 } else if ((texture = dictionary_lookup(&textures, name))) {
1120 return swf_ShapeAddFillStyle2(s, &texture->fs);
1121 } else if((image = dictionary_lookup(&images, name))) {
1123 swf_GetMatrix(0, &m);
1124 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1125 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1128 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1129 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1133 swf_GetMatrix(0, &rot);
1134 ccos = cos(-gradient->rotate*2*M_PI/360);
1135 csin = sin(-gradient->rotate*2*M_PI/360);
1136 rot.sx = ccos*65536;
1137 rot.r1 = -csin*65536;
1138 rot.r0 = csin*65536;
1139 rot.sy = ccos*65536;
1140 r2 = swf_TurnRect(*r, &rot);
1141 swf_GetMatrix(0, &m);
1142 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1143 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1144 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1145 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1146 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1147 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1148 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1149 } else if (parseColor2(name, &color)) {
1150 return swf_ShapeAddSolidFillStyle(s, &color);
1152 syntaxerror("not a color/fillstyle: %s", name);
1157 RGBA black={r:0,g:0,b:0,a:0};
1158 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1167 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1170 linewidth = linewidth>=20?linewidth-20:0;
1171 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1174 fs1 = addFillStyle(s, &r2, texture);
1177 r.xmin = r2.xmin-linewidth/2;
1178 r.ymin = r2.ymin-linewidth/2;
1179 r.xmax = r2.xmax+linewidth/2;
1180 r.ymax = r2.ymax+linewidth/2;
1181 swf_SetRect(tag,&r);
1182 swf_SetShapeHeader(tag,s);
1183 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1184 swf_ShapeSetLine(tag,s,width,0);
1185 swf_ShapeSetLine(tag,s,0,height);
1186 swf_ShapeSetLine(tag,s,-width,0);
1187 swf_ShapeSetLine(tag,s,0,-height);
1188 swf_ShapeSetEnd(tag);
1191 s_addcharacter(name, id, tag, r);
1195 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1201 outline = dictionary_lookup(&outlines, outlinename);
1203 syntaxerror("outline %s not defined", outlinename);
1207 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1210 linewidth = linewidth>=20?linewidth-20:0;
1211 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1214 fs1 = addFillStyle(s, &r2, texture);
1217 rect.xmin = r2.xmin-linewidth/2;
1218 rect.ymin = r2.ymin-linewidth/2;
1219 rect.xmax = r2.xmax+linewidth/2;
1220 rect.ymax = r2.ymax+linewidth/2;
1222 swf_SetRect(tag,&rect);
1223 swf_SetShapeStyles(tag, s);
1224 swf_ShapeCountBits(s,0,0);
1225 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1226 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1227 swf_SetShapeBits(tag, s);
1228 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1231 s_addcharacter(name, id, tag, rect);
1235 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1240 r2.xmin = r2.ymin = 0;
1244 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1247 linewidth = linewidth>=20?linewidth-20:0;
1248 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1251 fs1 = addFillStyle(s, &r2, texture);
1253 rect.xmin = r2.xmin-linewidth/2;
1254 rect.ymin = r2.ymin-linewidth/2;
1255 rect.xmax = r2.xmax+linewidth/2;
1256 rect.ymax = r2.ymax+linewidth/2;
1258 swf_SetRect(tag,&rect);
1259 swf_SetShapeHeader(tag,s);
1260 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1261 swf_ShapeSetCircle(tag, s, r,r,r,r);
1262 swf_ShapeSetEnd(tag);
1265 s_addcharacter(name, id, tag, rect);
1269 void s_textshape(char*name, char*fontname, float size, char*_text)
1272 U8*text = (U8*)_text;
1276 font = dictionary_lookup(&fonts, fontname);
1278 syntaxerror("font \"%s\" not known!", fontname);
1280 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1281 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1282 s_box(name, 0, 0, black, 20, 0);
1285 g = font->ascii2glyph[text[0]];
1287 outline = malloc(sizeof(outline_t));
1288 memset(outline, 0, sizeof(outline_t));
1289 outline->shape = font->glyph[g].shape;
1290 outline->bbox = font->layout->bounds[g];
1294 swf_Shape11DrawerInit(&draw, 0);
1295 swf_DrawText(&draw, font, (int)(size*100), _text);
1297 outline->shape = swf_ShapeDrawerToShape(&draw);
1298 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1299 draw.dealloc(&draw);
1302 if(dictionary_lookup(&outlines, name))
1303 syntaxerror("outline %s defined twice", name);
1304 dictionary_put2(&outlines, name, outline);
1307 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1312 font = dictionary_lookup(&fonts, fontname);
1314 syntaxerror("font \"%s\" not known!", fontname);
1316 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1317 swf_SetU16(tag, id);
1318 if(!font->numchars) {
1319 s_box(name, 0, 0, black, 20, 0);
1322 r = swf_SetDefineText(tag, font, &color, text, size);
1324 if(stack[0].swf->fileVersion >= 8) {
1325 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1326 swf_SetU16(tag, id);
1327 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1328 swf_SetU32(tag, 0);//thickness
1329 swf_SetU32(tag, 0);//sharpness
1330 swf_SetU8(tag, 0);//reserved
1333 s_addcharacter(name, id, tag, r);
1337 void s_quicktime(char*name, char*url)
1342 memset(&r, 0, sizeof(r));
1344 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1345 swf_SetU16(tag, id);
1346 swf_SetString(tag, url);
1348 s_addcharacter(name, id, tag, r);
1352 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags, int align)
1355 EditTextLayout layout;
1358 if(fontname && *fontname) {
1359 flags |= ET_USEOUTLINES;
1360 font = dictionary_lookup(&fonts, fontname);
1362 syntaxerror("font \"%s\" not known!", fontname);
1364 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1365 swf_SetU16(tag, id);
1366 layout.align = align;
1367 layout.leftmargin = 0;
1368 layout.rightmargin = 0;
1376 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1378 s_addcharacter(name, id, tag, r);
1382 /* type: either "jpeg" or "png"
1384 void s_image(char*name, char*type, char*filename, int quality)
1386 /* an image is actually two folded: 1st bitmap, 2nd character.
1387 Both of them can be used separately */
1389 /* step 1: the bitmap */
1393 if(!strcmp(type,"jpeg")) {
1394 #ifndef HAVE_JPEGLIB
1395 warning("no jpeg support compiled in");
1396 s_box(name, 0, 0, black, 20, 0);
1399 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1400 swf_SetU16(tag, imageID);
1402 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1403 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1406 swf_GetJPEGSize(filename, &width, &height);
1413 s_addimage(name, id, tag, r);
1416 } else if(!strcmp(type,"png")) {
1418 swf_SetU16(tag, imageID);
1420 getPNG(filename, &width, &height, (unsigned char**)&data);
1423 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1426 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1427 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1428 swf_SetU16(tag, imageID);
1429 swf_SetLosslessImage(tag, data, width, height);
1436 s_addimage(name, id, tag, r);
1439 warning("image type \"%s\" not supported yet!", type);
1440 s_box(name, 0, 0, black, 20, 0);
1444 /* step 2: the character */
1445 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1446 swf_SetU16(tag, id);
1447 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1449 s_addcharacter(name, id, tag, r);
1453 void s_getBitmapSize(char*name, int*width, int*height)
1455 character_t* image = dictionary_lookup(&images, name);
1456 gradient_t* gradient = dictionary_lookup(&gradients,name);
1458 *width = image->size.xmax;
1459 *height = image->size.ymax;
1463 /* internal SWF gradient size */
1464 if(gradient->radial) {
1473 syntaxerror("No such bitmap/gradient: %s", name);
1476 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1478 if(dictionary_lookup(&textures, name))
1479 syntaxerror("texture %s defined twice", name);
1480 gradient_t* gradient = dictionary_lookup(&gradients, object);
1481 character_t* bitmap = dictionary_lookup(&images, object);
1482 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1484 FILLSTYLE*fs = &texture->fs;
1486 memset(&p, 0, sizeof(parameters_t));
1489 fs->type = FILL_TILED;
1490 fs->id_bitmap = bitmap->id;
1491 } else if(gradient) {
1492 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1493 fs->gradient = gradient->gradient;
1495 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1496 makeMatrix(&fs->m, &p);
1497 if(gradient && !gradient->radial) {
1504 p2 = swf_TurnPoint(p1, &m);
1513 dictionary_put2(&textures, name, texture);
1516 void s_font(char*name, char*filename)
1519 font = dictionary_lookup(&fonts, name);
1522 /* fix the layout. Only needed for old fonts */
1524 for(t=0;t<font->numchars;t++) {
1525 font->glyph[t].advance = 0;
1528 swf_FontCreateLayout(font);
1531 swf_FontReduce_swfc(font);
1532 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1533 swf_FontSetDefine2(tag, font);
1534 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1536 swf_SetU16(tag, id);
1537 swf_SetString(tag, name);
1544 typedef struct _sound_t
1550 void s_sound(char*name, char*filename)
1552 struct WAV wav, wav2;
1556 unsigned numsamples = 1;
1557 unsigned blocksize = 1152;
1560 if(dictionary_lookup(&sounds, name))
1561 syntaxerror("sound %s defined twice", name);
1563 if(wav_read(&wav, filename))
1566 wav_convert2mono(&wav, &wav2, 44100);
1567 samples = (U16*)wav2.data;
1568 numsamples = wav2.size/2;
1570 #ifdef WORDS_BIGENDIAN
1572 for(t=0;t<numsamples;t++)
1573 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1577 if(mp3_read(&mp3, filename))
1579 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1585 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1590 if(numsamples%blocksize != 0)
1592 // apply padding, so that block is a multiple of blocksize
1593 int numblocks = (numsamples+blocksize-1)/blocksize;
1596 numsamples2 = numblocks * blocksize;
1597 samples2 = malloc(sizeof(U16)*numsamples2);
1598 memcpy(samples2, samples, numsamples*sizeof(U16));
1599 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1600 numsamples = numsamples2;
1605 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1606 swf_SetU16(tag, id); //id
1609 swf_SetSoundDefineMP3(
1610 tag, mp3.data, mp3.size,
1617 swf_SetSoundDefine(tag, samples, numsamples);
1619 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1620 swf_SetU16(tag, id);
1621 swf_SetString(tag, name);
1622 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1624 swf_SetU16(tag, id);
1625 swf_SetString(tag, name);
1627 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1631 dictionary_put2(&sounds, name, sound);
1639 static char* gradient_getToken(const char**p)
1643 while(**p && strchr(" \t\n\r", **p)) {
1647 while(**p && !strchr(" \t\n\r", **p)) {
1650 result = malloc((*p)-start+1);
1651 memcpy(result,start,(*p)-start+1);
1652 result[(*p)-start] = 0;
1656 float parsePercent(char*str);
1657 RGBA parseColor(char*str);
1659 GRADIENT parseGradient(const char*str)
1663 const char* p = str;
1664 memset(&gradient, 0, sizeof(GRADIENT));
1665 gradient.ratios = rfx_calloc(16*sizeof(U8));
1666 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1670 char*posstr,*colorstr;
1673 posstr = gradient_getToken(&p);
1679 pos = (int)(parsePercent(posstr)*255.0);
1684 rfx_free(gradient.ratios);
1685 rfx_free(gradient.rgba);
1687 syntaxerror("Error in shape data: Color expected after %s", posstr);
1689 colorstr = gradient_getToken(&p);
1690 color = parseColor(colorstr);
1691 if(gradient.num == 16)
1693 warning("gradient record too big- max size is 16, rest ignored");
1696 gradient.ratios[gradient.num] = pos;
1697 gradient.rgba[gradient.num] = color;
1706 FILTERLIST* parseFilters(char* list)
1708 if (!strcmp(list, "no_filters"))
1711 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1713 char* f_start = list;
1717 f_end = strchr(f_start, ',');
1720 f = dictionary_lookup(&filters, f_start);
1724 syntaxerror("unknown filter %s", f_start);
1726 if (f_list->num == 8)
1728 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1731 f_list->filter[f_list->num] = f;
1736 f_start = f_end + 1;
1744 void s_gradient(char*name, const char*text, int radial, int rotate)
1746 gradient_t* gradient;
1747 gradient = malloc(sizeof(gradient_t));
1748 memset(gradient, 0, sizeof(gradient_t));
1749 gradient->gradient = parseGradient(text);
1750 gradient->radial = radial;
1751 gradient->rotate = rotate;
1753 dictionary_put2(&gradients, name, gradient);
1756 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1757 float angle, float distance, float strength, char innershadow,
1758 char knockout, char composite, char ontop, int passes)
1760 if(dictionary_lookup(&filters, name))
1761 syntaxerror("filter %s defined twice", name);
1763 gradient_t* g = dictionary_lookup(&gradients, gradient);
1765 syntaxerror("unknown gradient %s", gradient);
1769 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1770 filter->type = FILTERTYPE_GRADIENTGLOW;
1771 filter->gradient = &g->gradient;
1772 filter->blurx = blurx;
1773 filter->blury = blury;
1774 filter->strength = strength;
1775 filter->angle = angle;
1776 filter->distance = distance;
1777 filter->innershadow = innershadow;
1778 filter->knockout = knockout;
1779 filter->composite = composite;
1780 filter->ontop = ontop;
1781 filter->passes = passes;
1783 dictionary_put2(&filters, name, filter);
1786 void s_dropshadow(char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
1788 if(dictionary_lookup(&filters, name))
1789 syntaxerror("filter %s defined twice", name);
1792 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1793 filter->type = FILTERTYPE_DROPSHADOW;
1794 filter->color= color;
1795 filter->blurx = blurx;
1796 filter->blury = blury;
1797 filter->strength = strength;
1798 filter->angle = angle;
1799 filter->distance = distance;
1800 filter->innershadow = innershadow;
1801 filter->knockout = knockout;
1802 filter->composite = composite;
1803 filter->passes = passes;
1805 dictionary_put2(&filters, name, filter);
1808 void s_bevel(char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes)
1810 if(dictionary_lookup(&filters, name))
1811 syntaxerror("filter %s defined twice", name);
1814 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1815 filter->type = FILTERTYPE_BEVEL;
1816 filter->shadow = shadow;
1817 filter->highlight = highlight;
1818 filter->blurx = blurx;
1819 filter->blury = blury;
1820 filter->strength = strength;
1821 filter->angle = angle;
1822 filter->distance = distance;
1823 filter->innershadow = innershadow;
1824 filter->knockout = knockout;
1825 filter->composite = composite;
1826 filter->ontop = ontop;
1827 filter->passes = passes;
1829 dictionary_put2(&filters, name, filter);
1832 void s_blur(char*name, double blurx, double blury, int passes)
1834 if(dictionary_lookup(&filters, name))
1835 syntaxerror("filter %s defined twice", name);
1837 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1838 filter->type = FILTERTYPE_BLUR;
1839 filter->blurx = blurx;
1840 filter->blury = blury;
1841 filter->passes = passes;
1843 dictionary_put2(&filters, name, filter);
1846 void s_action(const char*text)
1849 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1853 syntaxerror("Couldn't compile ActionScript");
1856 tag = swf_InsertTag(tag, ST_DOACTION);
1858 swf_ActionSet(tag, a);
1863 void s_initaction(const char*character, const char*text)
1867 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1871 syntaxerror("Couldn't compile ActionScript");
1874 c = (character_t*)dictionary_lookup(&characters, character);
1876 tag = swf_InsertTag(tag, ST_DOINITACTION);
1877 swf_SetU16(tag, c->id);
1878 swf_ActionSet(tag, a);
1883 int s_swf3action(char*name, char*action)
1886 instance_t* object = 0;
1888 object = (instance_t*)dictionary_lookup(&instances, name);
1889 if(!object && name && *name) {
1890 /* we have a name, but couldn't find it. Abort. */
1893 a = action_SetTarget(0, name);
1894 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1895 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1896 else if(!strcmp(action, "stop")) a = action_Stop(a);
1897 else if(!strcmp(action, "play")) a = action_Play(a);
1898 a = action_SetTarget(a, "");
1901 tag = swf_InsertTag(tag, ST_DOACTION);
1902 swf_ActionSet(tag, a);
1907 void s_outline(char*name, char*format, char*source)
1909 if(dictionary_lookup(&outlines, name))
1910 syntaxerror("outline %s defined twice", name);
1919 //swf_Shape10DrawerInit(&draw, 0);
1920 swf_Shape11DrawerInit(&draw, 0);
1922 draw_string(&draw, source);
1924 shape = swf_ShapeDrawerToShape(&draw);
1925 bounds = swf_ShapeDrawerGetBBox(&draw);
1926 draw.dealloc(&draw);
1928 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1929 outline->shape = shape;
1930 outline->bbox = bounds;
1932 dictionary_put2(&outlines, name, outline);
1935 int s_playsound(char*name, int loops, int nomultiple, int stop)
1941 sound = dictionary_lookup(&sounds, name);
1945 tag = swf_InsertTag(tag, ST_STARTSOUND);
1946 swf_SetU16(tag, sound->id); //id
1947 memset(&info, 0, sizeof(info));
1950 info.nomultiple = nomultiple;
1951 swf_SetSoundInfo(tag, &info);
1955 void s_includeswf(char*name, char*filename)
1963 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1964 f = open(filename,O_RDONLY|O_BINARY);
1966 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1967 s_box(name, 0, 0, black, 20, 0);
1970 if (swf_ReadSWF(f,&swf)<0) {
1971 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1972 s_box(name, 0, 0, black, 20, 0);
1977 /* FIXME: The following sets the bounding Box for the character.
1978 It is wrong for two reasons:
1979 a) It may be too small (in case objects in the movie clip at the borders)
1980 b) it may be too big (because the poor movie never got autocropped)
1984 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1985 swf_SetU16(tag, id);
1986 swf_SetU16(tag, swf.frameCount);
1988 swf_Relocate(&swf, idmap);
1990 ftag = swf.firstTag;
1994 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1995 if(cutout[t] == ftag->id) {
1999 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2001 if(ftag->id == ST_END)
2006 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2007 /* We simply dump all tags right after the sprite
2008 header, relying on the fact that swf_OptimizeTagOrder() will
2009 sort things out for us later.
2010 We also rely on the fact that the imported SWF is well-formed.
2012 tag = swf_InsertTag(tag, ftag->id);
2013 swf_SetBlock(tag, ftag->data, ftag->len);
2019 syntaxerror("Included file %s contains errors", filename);
2020 tag = swf_InsertTag(tag, ST_END);
2024 s_addcharacter(name, id, tag, r);
2027 SRECT s_getCharBBox(char*name)
2029 character_t* c = dictionary_lookup(&characters, name);
2030 if(!c) syntaxerror("character '%s' unknown(2)", name);
2033 SRECT s_getInstanceBBox(char*name)
2035 instance_t * i = dictionary_lookup(&instances, name);
2037 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2039 if(!c) syntaxerror("internal error(5)");
2042 void s_getParameters(char*name, parameters_t* p)
2044 instance_t * i = dictionary_lookup(&instances, name);
2046 syntaxerror("instance '%s' unknown(10)", name);
2047 if (change_sets_all)
2048 readParameters(i->history, p, currentframe);
2052 void s_startclip(char*instance, char*character, parameters_t p)
2054 character_t* c = dictionary_lookup(&characters, character);
2058 syntaxerror("character %s not known", character);
2060 i = s_addinstance(instance, c, currentdepth);
2062 m = s_instancepos(i->character->size, &p);
2064 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2065 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2066 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2068 stack[stackpos].tag = tag;
2069 stack[stackpos].type = 2;
2078 swf_SetTagPos(stack[stackpos].tag, 0);
2079 swf_GetPlaceObject(stack[stackpos].tag, &p);
2080 p.clipdepth = currentdepth;
2082 swf_ClearTag(stack[stackpos].tag);
2083 swf_SetPlaceObject(stack[stackpos].tag, &p);
2087 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2089 history_begin(i->history, "x", currentframe, tag, p->x);
2090 history_begin(i->history, "y", currentframe, tag, p->y);
2091 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2092 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2093 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2094 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2095 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2096 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2097 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2098 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2099 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2100 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2101 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2102 history_begin(i->history, "shear", currentframe, tag, p->shear);
2103 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2104 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2105 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2106 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2107 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2108 history_beginFilter(i->history, currentframe, tag, p->filters);
2109 history_begin(i->history, "flags", currentframe, tag, 0);
2112 void s_put(char*instance, char*character, parameters_t p)
2114 character_t* c = dictionary_lookup(&characters, character);
2118 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2120 i = s_addinstance(instance, c, currentdepth);
2122 m = s_instancepos(i->character->size, &p);
2124 if(p.blendmode || p.filters)
2126 if(stack[0].swf->fileVersion < 8)
2129 warning("blendmodes only supported for flash version>=8");
2131 warning("filters only supported for flash version>=8");
2133 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2136 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2137 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2138 setStartparameters(i, &p, tag);
2142 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2145 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2147 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2148 if (p.set & SF_SCALEX)
2149 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2150 if (p.set & SF_SCALEY)
2151 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2152 if (p.set & SF_CX_R)
2154 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2155 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2157 if (p.set & SF_CX_G)
2159 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2160 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2162 if (p.set & SF_CX_B)
2164 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2165 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2167 if (p.set & SF_CX_A)
2169 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2170 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2172 if (p.set & SF_ROTATE)
2173 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2174 if (p.set & SF_SHEAR)
2175 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2176 if (p.set & SF_PIVOT)
2178 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2179 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2183 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2184 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2186 if (p.set & SF_BLEND)
2187 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2188 if (p.set & SF_FILTER)
2189 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2192 void s_jump(char* instance, parameters_t p)
2194 instance_t* i = dictionary_lookup(&instances, instance);
2196 syntaxerror("instance %s not known", instance);
2197 recordChanges(i->history, p, CF_JUMP, 0);
2200 void s_change(char*instance, parameters_t p, interpolation_t* inter)
2202 instance_t* i = dictionary_lookup(&instances, instance);
2204 syntaxerror("instance %s not known", instance);
2205 recordChanges(i->history, p, CF_CHANGE, inter);
2208 void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2210 instance_t* i = dictionary_lookup(&instances, instance);
2212 syntaxerror("instance %s not known", instance);
2213 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2216 void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
2218 instance_t* i = dictionary_lookup(&instances, instance);
2220 syntaxerror("instance %s not known", instance);
2221 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2224 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2227 void s_delinstance(char*instance)
2229 instance_t* i = dictionary_lookup(&instances, instance);
2231 syntaxerror("instance %s not known", instance);
2233 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2234 swf_SetU16(tag, i->depth);
2235 dictionary_del(&instances, instance);
2238 void s_schange(char*instance, parameters_t p, interpolation_t* inter)
2240 instance_t* i = dictionary_lookup(&instances, instance);
2242 syntaxerror("instance %s not known", instance);
2243 recordChanges(i->history, p, CF_SCHANGE, inter);
2249 syntaxerror(".end unexpected");
2250 switch (stack[stackpos-1].type)
2265 syntaxerror("internal error 1");
2269 // ------------------------------------------------------------------------
2271 typedef int command_func_t(map_t*args);
2273 SRECT parseBox(char*str)
2275 SRECT r = {0,0,0,0};
2276 float xmin, xmax, ymin, ymax;
2277 char*x = strchr(str, 'x');
2279 if(!strcmp(str, "autocrop")) {
2280 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2284 d1 = strchr(x+1, ':');
2286 d2 = strchr(d1+1, ':');
2288 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2292 else if(d1 && !d2) {
2293 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2299 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2304 r.xmin = (SCOORD)(xmin*20);
2305 r.ymin = (SCOORD)(ymin*20);
2306 r.xmax = (SCOORD)(xmax*20);
2307 r.ymax = (SCOORD)(ymax*20);
2310 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2313 float parseFloat(char*str)
2317 int parseInt(char*str)
2322 if(str[0]=='+' || str[0]=='-')
2326 if(str[t]<'0' || str[t]>'9')
2327 syntaxerror("Not an Integer: \"%s\"", str);
2330 int parseTwip(char*str)
2334 if(str[0]=='+' || str[0]=='-') {
2339 dot = strchr(str, '.');
2343 return sign*parseInt(str)*20;
2345 char* old = strdup(str);
2346 int l=strlen(dot+1);
2349 for(s=str;s<dot-1;s++)
2350 if(*s<'0' || *s>'9')
2353 syntaxerror("Not a coordinate: \"%s\"", str);
2356 if(*s<'0' || *s>'9')
2359 syntaxerror("Not a coordinate: \"%s\"", str);
2361 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2362 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2365 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2369 return sign*atoi(str)*20;
2371 return sign*atoi(str)*20+atoi(dot)*2;
2373 return sign*atoi(str)*20+atoi(dot)/5;
2378 int parseArc(char* str)
2380 if (!strcmp(str, "short"))
2382 if (!strcmp(str, "long"))
2384 syntaxerror("invalid value for the arc parameter: %s", str);
2388 int parseDir(char* str)
2390 if (!strcmp(str, "clockwise"))
2392 if (!strcmp(str, "counterclockwise"))
2394 syntaxerror("invalid value for the dir parameter: %s", str);
2398 int isPoint(char*str)
2400 if(strchr(str, '('))
2406 SPOINT parsePoint(char*str)
2410 int l = strlen(str);
2411 char*comma = strchr(str, ',');
2412 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2413 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2414 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2415 p.x = parseTwip(tmp);
2416 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2417 p.y = parseTwip(tmp);
2421 int parseColor2(char*str, RGBA*color)
2423 int l = strlen(str);
2427 struct {unsigned char r,g,b;char*name;} colors[] =
2428 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2429 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2430 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2431 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2432 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2433 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2434 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2435 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2436 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2437 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2438 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2439 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2443 if(str[0]=='#' && (l==7 || l==9)) {
2444 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2446 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2448 color->r = r; color->g = g; color->b = b; color->a = a;
2451 int len=strlen(str);
2453 if(strchr(str, '/')) {
2454 len = strchr(str, '/')-str;
2455 sscanf(str+len+1,"%02x", &alpha);
2457 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2458 if(!strncmp(str, colors[t].name, len)) {
2463 color->r = r; color->g = g; color->b = b; color->a = a;
2469 RGBA parseColor(char*str)
2472 if(!parseColor2(str, &c))
2473 syntaxerror("Expression '%s' is not a color", str);
2477 typedef struct _muladd {
2482 MULADD parseMulAdd(char*str)
2485 char* str2 = (char*)malloc(strlen(str)+5);
2492 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2493 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2494 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2495 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2496 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2497 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2498 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2499 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2500 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2501 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2503 syntaxerror("'%s' is not a valid color transform expression", str);
2505 m.add = (int)(add*256);
2506 m.mul = (int)(mul*256);
2511 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2513 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2514 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2516 if(a<-32768) a=-32768;
2517 if(a>32767) a=32767;
2518 if(m<-32768) m=-32768;
2519 if(m>32767) m=32767;
2525 float parsePxOrPercent(char*fontname, char*str)
2527 int l = strlen(str);
2528 if(strchr(str, '%'))
2529 return parsePercent(str);
2530 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2531 float p = atof(str);
2532 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2534 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2538 float parsePercent(char*str)
2540 int l = strlen(str);
2544 return atoi(str)/100.0;
2546 syntaxerror("Expression '%s' is not a percentage", str);
2549 int isPercent(char*str)
2551 return str[strlen(str)-1]=='%';
2553 int parseNewSize(char*str, int size)
2556 return parsePercent(str)*size;
2558 return (int)(atof(str)*20);
2561 int isColor(char*str)
2564 return parseColor2(str, &c);
2567 static char* lu(map_t* args, char*name)
2569 char* value = map_lookup(args, name);
2571 map_dump(args, stdout, "");
2572 syntaxerror("internal error 2: value %s should be set", name);
2577 static int c_flash(map_t*args)
2579 char* filename = map_lookup(args, "filename");
2580 char* compressstr = lu(args, "compress");
2581 char* change_modestr = lu(args, "change-sets-all");
2582 SRECT bbox = parseBox(lu(args, "bbox"));
2583 int version = parseInt(lu(args, "version"));
2584 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2585 RGBA color = parseColor(lu(args, "background"));
2588 if(!filename || !*filename) {
2589 /* for compatibility */
2590 filename = map_lookup(args, "name");
2591 if(!filename || !*filename) {
2594 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2595 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2599 if(!filename || override_outputname)
2600 filename = outputname;
2602 if(!strcmp(compressstr, "default"))
2603 compress = version>=6;
2604 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2606 else if(!strcmp(compressstr, "no"))
2608 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2610 if(!strcmp(change_modestr, "yes"))
2611 change_sets_all = 1;
2613 if(strcmp(change_modestr, "no"))
2614 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2616 s_swf(filename, bbox, version, fps, compress, color);
2619 int isRelative(char*str)
2621 return !strncmp(str, "<plus>", 6) ||
2622 !strncmp(str, "<minus>", 7);
2624 char* getOffset(char*str)
2626 if(!strncmp(str, "<plus>", 6))
2628 if(!strncmp(str, "<minus>", 7))
2630 syntaxerror("internal error (347)");
2633 int getSign(char*str)
2635 if(!strncmp(str, "<plus>", 6))
2637 if(!strncmp(str, "<minus>", 7))
2639 syntaxerror("internal error (348)");
2642 static dictionary_t points;
2643 static mem_t mpoints;
2644 int points_initialized = 0;
2646 static int c_interpolation(map_t *args)
2649 char* name = lu(args, "name");
2650 if (dictionary_lookup(&interpolations, name))
2651 syntaxerror("interpolation %s defined twice", name);
2653 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2654 char* functionstr = lu(args, "function");
2655 inter->function = 0;
2656 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2657 if (!strcmp(functionstr,interpolationFunctions[i]))
2659 inter->function = i + 1;
2662 if (!inter->function)
2663 syntaxerror("unkown interpolation function %s", functionstr);
2664 inter->speed = parseFloat(lu(args, "speed"));
2665 inter->amplitude = parseTwip(lu(args, "amplitude"));
2666 inter->growth = parseFloat(lu(args, "growth"));
2667 inter->bounces = parseInt(lu(args, "bounces"));
2668 inter->damping = parseFloat(lu(args, "damping"));
2669 inter->slope = parseFloat(lu(args, "slope"));
2671 dictionary_put2(&interpolations, name, inter);
2675 SPOINT getPoint(SRECT r, char*name)
2678 if(!strcmp(name, "center")) {
2680 p.x = (r.xmin + r.xmax)/2;
2681 p.y = (r.ymin + r.ymax)/2;
2684 if (!strcmp(name, "bottom-center"))
2687 p.x = (r.xmin + r.xmax)/2;
2693 if(points_initialized)
2694 l = (int)dictionary_lookup(&points, name);
2696 syntaxerror("Invalid point: \"%s\".", name);
2699 return *(SPOINT*)&mpoints.buffer[l];
2702 static int texture2(char*name, char*object, map_t*args, int errors)
2705 char*xstr = map_lookup(args, "x");
2706 char*ystr = map_lookup(args, "y");
2707 char*widthstr = map_lookup(args, "width");
2708 char*heightstr = map_lookup(args, "height");
2709 char*scalestr = map_lookup(args, "scale");
2710 char*scalexstr = map_lookup(args, "scalex");
2711 char*scaleystr = map_lookup(args, "scaley");
2712 char*rotatestr = map_lookup(args, "rotate");
2713 char* shearstr = map_lookup(args, "shear");
2714 char* radiusstr = map_lookup(args, "r");
2716 float scalex = 1.0, scaley = 1.0;
2717 float rotate=0, shear=0;
2719 if(!*xstr && !*ystr) {
2721 syntaxerror("x and y must be set");
2724 if(*scalestr && (*scalexstr || *scaleystr)) {
2725 syntaxerror("scale and scalex/scaley can't both be set");
2728 if((*widthstr || *heightstr) && *radiusstr) {
2729 syntaxerror("width/height and radius can't both be set");
2732 widthstr = radiusstr;
2733 heightstr = radiusstr;
2735 if(!*xstr) xstr="0";
2736 if(!*ystr) ystr="0";
2737 if(!*rotatestr) rotatestr="0";
2738 if(!*shearstr) shearstr="0";
2741 scalex = scaley = parsePercent(scalestr);
2742 } else if(*scalexstr || *scaleystr) {
2743 if(scalexstr) scalex = parsePercent(scalexstr);
2744 if(scaleystr) scaley = parsePercent(scaleystr);
2745 } else if(*widthstr || *heightstr) {
2748 s_getBitmapSize(object, &width, &height);
2750 scalex = (float)parseTwip(widthstr)/(float)width;
2752 scaley = (float)parseTwip(heightstr)/(float)height;
2754 x = parseTwip(xstr);
2755 y = parseTwip(ystr);
2756 rotate = parseFloat(rotatestr);
2757 shear = parseFloat(shearstr);
2759 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2764 static int c_texture(map_t*args)
2766 char*name = lu(args, "instance");
2767 char*object = lu(args, "character");
2768 return texture2(name, object, args, 1);
2771 static int c_gradient(map_t*args)
2773 char*name = lu(args, "name");
2774 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2775 int rotate = parseInt(lu(args, "rotate"));
2779 syntaxerror("colon (:) expected");
2781 if(dictionary_lookup(&gradients, name))
2782 syntaxerror("gradient %s defined twice", name);
2784 s_gradient(name, text, radial, rotate);
2786 /* check whether we also have placement information,
2787 which would make this a positioned gradient.
2788 If there is placement information, texture2() will
2789 add a texture, which has priority over the gradient.
2791 texture2(name, name, args, 0);
2795 static char* checkFiltername(map_t* args)
2797 char* name = lu(args, "name");
2798 if (strchr(name, ','))
2799 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
2803 static int c_blur(map_t*args)
2805 char*name = checkFiltername(args);
2806 char*blurstr = lu(args, "blur");
2807 char*blurxstr = lu(args, "blurx");
2808 char*blurystr = lu(args, "blury");
2809 float blurx=1.0, blury=1.0;
2811 blurx = parseFloat(blurstr);
2812 blury = parseFloat(blurstr);
2815 blurx = parseFloat(blurxstr);
2817 blury = parseFloat(blurystr);
2818 int passes = parseInt(lu(args, "passes"));
2819 s_blur(name, blurx, blury, passes);
2823 static int c_gradientglow(map_t*args)
2825 char*name = checkFiltername(args);
2826 char*gradient = lu(args, "gradient");
2827 char*blurstr = lu(args, "blur");
2828 char*blurxstr = lu(args, "blurx");
2829 char*blurystr = lu(args, "blury");
2830 float blurx=1.0, blury=1.0;
2832 blurx = parseFloat(blurstr);
2833 blury = parseFloat(blurstr);
2836 blurx = parseFloat(blurxstr);
2838 blury = parseFloat(blurystr);
2840 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2841 float distance = parseFloat(lu(args, "distance"));
2842 float strength = parseFloat(lu(args, "strength"));
2843 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2844 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2845 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2846 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2847 int passes = parseInt(lu(args, "passes"));
2849 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2853 static int c_dropshadow(map_t*args)
2855 char*name = checkFiltername(args);
2856 RGBA color = parseColor(lu(args, "color"));
2857 char*blurstr = lu(args, "blur");
2858 char*blurxstr = lu(args, "blurx");
2859 char*blurystr = lu(args, "blury");
2860 float blurx=1.0, blury=1.0;
2862 blurx = parseFloat(blurstr);
2863 blury = parseFloat(blurstr);
2866 blurx = parseFloat(blurxstr);
2868 blury = parseFloat(blurystr);
2870 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2871 float distance = parseFloat(lu(args, "distance"));
2872 float strength = parseFloat(lu(args, "strength"));
2873 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2874 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2875 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2876 int passes = parseInt(lu(args, "passes"));
2878 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2882 static int c_bevel(map_t*args)
2884 char*name = checkFiltername(args);
2885 RGBA shadow = parseColor(lu(args, "shadow"));
2886 RGBA highlight = parseColor(lu(args, "highlight"));
2887 char*blurstr = lu(args, "blur");
2888 char*blurxstr = lu(args, "blurx");
2889 char*blurystr = lu(args, "blury");
2890 float blurx=1.0, blury=1.0;
2892 blurx = parseFloat(blurstr);
2893 blury = parseFloat(blurstr);
2896 blurx = parseFloat(blurxstr);
2898 blury = parseFloat(blurystr);
2900 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2901 float distance = parseFloat(lu(args, "distance"));
2902 float strength = parseFloat(lu(args, "strength"));
2903 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2904 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2905 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2906 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2907 int passes = parseInt(lu(args, "passes"));
2909 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2913 static int c_point(map_t*args)
2915 char*name = lu(args, "name");
2919 if(!points_initialized) {
2920 dictionary_init(&points);
2922 points_initialized = 1;
2924 p.x = parseTwip(lu(args, "x"));
2925 p.y = parseTwip(lu(args, "y"));
2926 pos = mem_put(&mpoints, &p, sizeof(p));
2927 string_set(&s1, name);
2929 dictionary_put(&points, s1, (void*)pos);
2932 static int c_play(map_t*args)
2934 char*name = lu(args, "name");
2935 char*loop = lu(args, "loop");
2936 char*nomultiple = lu(args, "nomultiple");
2938 if(!strcmp(nomultiple, "nomultiple"))
2941 nm = parseInt(nomultiple);
2943 if(s_playsound(name, parseInt(loop), nm, 0)) {
2945 } else if(s_swf3action(name, "play")) {
2951 static int c_stop(map_t*args)
2953 char*name = map_lookup(args, "name");
2955 if(s_playsound(name, 0,0,1))
2957 else if(s_swf3action(name, "stop"))
2959 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2963 static int c_nextframe(map_t*args)
2965 char*name = lu(args, "name");
2967 if(s_swf3action(name, "nextframe")) {
2970 syntaxerror("I don't know anything about movie \"%s\"", name);
2974 static int c_previousframe(map_t*args)
2976 char*name = lu(args, "name");
2978 if(s_swf3action(name, "previousframe")) {
2981 syntaxerror("I don't know anything about movie \"%s\"", name);
2985 static int c_movement(map_t*args, int type)
2987 char*instance = lu(args, "name");
2995 xstr = lu(args, "x");
2996 ystr = lu(args, "y");
2998 s_getParameters(instance, &p);
3003 if(isRelative(xstr))
3005 if(type == PT_PUT || type == PT_STARTCLIP)
3006 syntaxerror("relative x values not allowed for initial put or startclip");
3007 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3011 p.x = parseTwip(xstr);
3017 if(isRelative(ystr))
3019 if(type == PT_PUT || type == PT_STARTCLIP)
3020 syntaxerror("relative y values not allowed for initial put or startclip");
3021 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3025 p.y = parseTwip(ystr);
3030 if (change_sets_all)
3038 char* interstr = lu(args, "interpolation");
3039 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3041 syntaxerror("unkown interpolation %s", interstr);
3042 s_change(instance, p, inter);
3047 char* interstr = lu(args, "interpolation");
3048 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3050 syntaxerror("unkown interpolation %s", interstr);
3051 s_schange(instance, p, inter);
3056 char* rstr = lu(args, "r");
3057 int radius = parseTwip(rstr);
3059 syntaxerror("sweep not possible: radius must be greater than 0.");
3060 char* dirstr = lu(args, "dir");
3061 int clockwise = parseDir(dirstr);
3062 char* arcstr = lu(args, "arc");
3063 int short_arc = parseArc(arcstr);
3064 char* interstr = lu(args, "interpolation");
3065 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3067 syntaxerror("unkown interpolation %s", interstr);
3068 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3075 static int c_placement(map_t*args, int type)
3077 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3080 char* luminancestr = lu(args, "luminance");
3081 char* scalestr = lu(args, "scale");
3082 char* scalexstr = lu(args, "scalex");
3083 char* scaleystr = lu(args, "scaley");
3084 char* rotatestr = lu(args, "rotate");
3085 char* shearstr = lu(args, "shear");
3086 char* xstr="", *pivotstr="";
3087 char* ystr="", *anglestr="";
3088 char*above = lu(args, "above"); /*FIXME*/
3089 char*below = lu(args, "below");
3090 char* rstr = lu(args, "red");
3091 char* gstr = lu(args, "green");
3092 char* bstr = lu(args, "blue");
3093 char* astr = lu(args, "alpha");
3094 char* pinstr = lu(args, "pin");
3095 char* as = map_lookup(args, "as");
3096 char* blendmode = lu(args, "blend");
3097 char* filterstr = lu(args, "filter");
3108 { // (?) .rotate or .arcchange
3109 pivotstr = lu(args, "pivot");
3110 anglestr = lu(args, "angle");
3114 xstr = lu(args, "x");
3115 ystr = lu(args, "y");
3119 luminance = parseMulAdd(luminancestr);
3123 luminance.mul = 256;
3128 if(scalexstr[0]||scaleystr[0])
3129 syntaxerror("scalex/scaley and scale cannot both be set");
3130 scalexstr = scaleystr = scalestr;
3133 if(type == PT_PUT || type == PT_STARTCLIP) {
3135 character = lu(args, "character");
3136 parameters_clear(&p);
3137 } else if (type == PT_BUTTON) {
3138 character = lu(args, "name");
3139 parameters_clear(&p);
3142 s_getParameters(instance, &p);
3148 if(isRelative(xstr))
3150 if(type == PT_PUT || type == PT_STARTCLIP)
3151 syntaxerror("relative x values not allowed for initial put or startclip");
3152 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3156 p.x = parseTwip(xstr);
3162 if(isRelative(ystr))
3164 if(type == PT_PUT || type == PT_STARTCLIP)
3165 syntaxerror("relative y values not allowed for initial put or startclip");
3166 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3170 p.y = parseTwip(ystr);
3175 /* scale, scalex, scaley */
3177 oldbbox = s_getCharBBox(character);
3179 oldbbox = s_getInstanceBBox(instance);
3180 oldwidth = oldbbox.xmax - oldbbox.xmin;
3181 oldheight = oldbbox.ymax - oldbbox.ymin;
3188 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3189 set = set | SF_SCALEX;
3197 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3198 set = set | SF_SCALEY;
3204 if(isRelative(rotatestr))
3205 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3207 p.rotate = parseFloat(rotatestr);
3208 set = set | SF_ROTATE;
3214 if(isRelative(shearstr))
3215 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3217 p.shear = parseFloat(shearstr);
3218 set = set | SF_SHEAR;
3223 if(isPoint(pivotstr))
3224 p.pivot = parsePoint(pivotstr);
3226 p.pivot = getPoint(oldbbox, pivotstr);
3227 set = set | SF_PIVOT;
3233 p.pin = parsePoint(pinstr);
3235 p.pin = getPoint(oldbbox, pinstr);
3239 /* color transform */
3241 if(rstr[0] || luminancestr[0])
3245 r = parseMulAdd(rstr);
3248 r.add = p.cxform.r0;
3249 r.mul = p.cxform.r1;
3251 r = mergeMulAdd(r, luminance);
3252 p.cxform.r0 = r.mul;
3253 p.cxform.r1 = r.add;
3254 set = set | SF_CX_R;
3256 if(gstr[0] || luminancestr[0])
3260 g = parseMulAdd(gstr);
3263 g.add = p.cxform.g0;
3264 g.mul = p.cxform.g1;
3266 g = mergeMulAdd(g, luminance);
3267 p.cxform.g0 = g.mul;
3268 p.cxform.g1 = g.add;
3269 set = set | SF_CX_G;
3271 if(bstr[0] || luminancestr[0])
3275 b = parseMulAdd(bstr);
3278 b.add = p.cxform.b0;
3279 b.mul = p.cxform.b1;
3281 b = mergeMulAdd(b, luminance);
3282 p.cxform.b0 = b.mul;
3283 p.cxform.b1 = b.add;
3284 set = set | SF_CX_B;
3288 MULADD a = parseMulAdd(astr);
3289 p.cxform.a0 = a.mul;
3290 p.cxform.a1 = a.add;
3291 set = set | SF_CX_A;
3298 for(t = 0; blendModeNames[t]; t++)
3300 if(!strcmp(blendModeNames[t], blendmode))
3308 syntaxerror("unknown blend mode: '%s'", blendmode);
3310 p.blendmode = blend;
3311 set = set | SF_BLEND;
3316 p.filters = parseFilters(filterstr);
3317 set = set | SF_FILTER;
3320 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3321 warning("As of version 0.8.2 using the .change command to modify an \
3322 object's position on the stage is considered deprecated. Future \
3323 versions may consider x and y parameters for the .change command \
3324 to be illegal; please use the .move command.");
3326 if (change_sets_all)
3333 s_put(instance, character, p);
3337 char* interstr = lu(args, "interpolation");
3338 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3340 syntaxerror("unkown interpolation %s", interstr);
3341 s_change(instance, p, inter);
3346 char* interstr = lu(args, "interpolation");
3347 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3349 syntaxerror("unkown interpolation %s", interstr);
3350 s_schange(instance, p, inter);
3354 s_jump(instance, p);
3357 s_startclip(instance, character, p);
3361 s_buttonput(character, as, p);
3363 s_buttonput(character, "shape", p);
3369 static int c_put(map_t*args)
3371 c_placement(args, PT_PUT);
3374 static int c_change(map_t*args)
3376 if (currentframe == 0)
3377 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3378 c_placement(args, PT_CHANGE);
3381 static int c_schange(map_t*args)
3383 c_placement(args, PT_SCHANGE);
3386 static int c_move(map_t* args)
3388 c_movement(args, PT_MOVE);
3391 static int c_smove(map_t* args)
3393 c_movement(args, PT_SMOVE);
3396 static int c_sweep(map_t* args)
3398 c_movement(args, PT_SWEEP);
3401 static int c_arcchange(map_t*args)
3403 c_placement(args, 0);
3406 static int c_jump(map_t*args)
3408 c_placement(args, PT_JUMP);
3411 static int c_startclip(map_t*args)
3413 c_placement(args, PT_STARTCLIP);
3416 static int c_show(map_t*args)
3418 c_placement(args, PT_BUTTON);
3421 static int c_toggle(map_t* args)
3423 char*instance = lu(args, "name");
3424 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3425 char* alignstr = lu(args, "fixed_alignment");
3426 if (!strcmp(alignstr, "on"))
3427 flagsOn += IF_FIXED_ALIGNMENT;
3429 if (!strcmp(alignstr, "off"))
3430 flagsOff -= IF_FIXED_ALIGNMENT;
3432 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3433 s_toggle(instance, flagsOn, flagsOff);
3436 static int c_del(map_t*args)
3438 char*instance = lu(args, "name");
3439 s_delinstance(instance);
3442 static int c_end(map_t*args)
3447 static int c_sprite(map_t*args)
3449 char* name = lu(args, "name");
3453 static int c_frame(map_t*args)
3455 char*framestr = lu(args, "n");
3456 char*cutstr = lu(args, "cut");
3458 char*name = lu(args, "name");
3459 char*anchor = lu(args, "anchor");
3462 if(!strcmp(anchor, "anchor") && !*name)
3467 if(strcmp(cutstr, "no"))
3469 if(isRelative(framestr)) {
3470 frame = s_getframe();
3471 if(getSign(framestr)<0)
3472 syntaxerror("relative frame expressions must be positive");
3473 frame += parseInt(getOffset(framestr));
3476 frame = parseInt(framestr);
3477 if(s_getframe() >= frame
3478 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3479 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3481 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3484 static int c_primitive(map_t*args)
3486 char*name = lu(args, "name");
3487 char*command = lu(args, "commandname");
3488 int width=0, height=0, r=0;
3489 int linewidth = parseTwip(lu(args, "line"));
3490 char*colorstr = lu(args, "color");
3491 RGBA color = parseColor(colorstr);
3492 char*fillstr = lu(args, "fill");
3499 if(!strcmp(command, "circle"))
3501 else if(!strcmp(command, "filled"))
3505 width = parseTwip(lu(args, "width"));
3506 height = parseTwip(lu(args, "height"));
3507 } else if (type==1) {
3508 r = parseTwip(lu(args, "r"));
3509 } else if (type==2) {
3510 outline = lu(args, "outline");
3513 if(!strcmp(fillstr, "fill"))
3515 if(!strcmp(fillstr, "none"))
3517 if(width<0 || height<0 || linewidth<0 || r<0)
3518 syntaxerror("values width, height, line, r must be positive");
3520 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3521 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3522 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3526 static int c_textshape(map_t*args)
3528 char*name = lu(args, "name");
3529 char*text = lu(args, "text");
3530 char*font = lu(args, "font");
3531 float size = parsePxOrPercent(font, lu(args, "size"));
3533 s_textshape(name, font, size, text);
3537 static int c_swf(map_t*args)
3539 char*name = lu(args, "name");
3540 char*filename = lu(args, "filename");
3541 char*command = lu(args, "commandname");
3542 if(!strcmp(command, "shape"))
3543 warning("Please use .swf instead of .shape");
3544 s_includeswf(name, filename);
3548 static int c_font(map_t*args)
3550 char*name = lu(args, "name");
3551 char*filename = lu(args, "filename");
3552 s_font(name, filename);
3556 static int c_sound(map_t*args)
3558 char*name = lu(args, "name");
3559 char*filename = lu(args, "filename");
3560 s_sound(name, filename);
3564 static int c_text(map_t*args)
3566 char*name = lu(args, "name");
3567 char*text = lu(args, "text");
3568 char*font = lu(args, "font");
3569 float size = parsePxOrPercent(font, lu(args, "size"));
3570 RGBA color = parseColor(lu(args, "color"));
3571 s_text(name, font, text, (int)(size*100), color);
3575 static int c_soundtrack(map_t*args)
3580 static int c_quicktime(map_t*args)
3582 char*name = lu(args, "name");
3583 char*url = lu(args, "url");
3584 s_quicktime(name, url);
3588 static int c_image(map_t*args)
3590 char*command = lu(args, "commandname");
3591 char*name = lu(args, "name");
3592 char*filename = lu(args, "filename");
3593 if(!strcmp(command,"jpeg")) {
3594 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3595 s_image(name, "jpeg", filename, quality);
3597 s_image(name, "png", filename, 0);
3602 static int c_outline(map_t*args)
3604 char*name = lu(args, "name");
3605 char*format = lu(args, "format");
3609 syntaxerror("colon (:) expected");
3611 s_outline(name, format, text);
3615 int fakechar(map_t*args)
3617 char*name = lu(args, "name");
3618 s_box(name, 0, 0, black, 20, 0);
3622 static int c_egon(map_t*args) {return fakechar(args);}
3623 static int c_button(map_t*args) {
3624 char*name = lu(args, "name");
3628 static int current_button_flags = 0;
3629 static int c_on_press(map_t*args)
3631 char*position = lu(args, "position");
3633 if(!strcmp(position, "inside")) {
3634 current_button_flags |= BC_OVERUP_OVERDOWN;
3635 } else if(!strcmp(position, "outside")) {
3636 //current_button_flags |= BC_IDLE_OUTDOWN;
3637 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3638 } else if(!strcmp(position, "anywhere")) {
3639 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3642 if(type == RAWDATA) {
3644 s_buttonaction(current_button_flags, action);
3645 current_button_flags = 0;
3651 static int c_on_release(map_t*args)
3653 char*position = lu(args, "position");
3655 if(!strcmp(position, "inside")) {
3656 current_button_flags |= BC_OVERDOWN_OVERUP;
3657 } else if(!strcmp(position, "outside")) {
3658 current_button_flags |= BC_OUTDOWN_IDLE;
3659 } else if(!strcmp(position, "anywhere")) {
3660 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3663 if(type == RAWDATA) {
3665 s_buttonaction(current_button_flags, action);
3666 current_button_flags = 0;
3672 static int c_on_move_in(map_t*args)
3674 char*position = lu(args, "state");
3676 if(!strcmp(position, "pressed")) {
3677 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3678 } else if(!strcmp(position, "not_pressed")) {
3679 current_button_flags |= BC_IDLE_OVERUP;
3680 } else if(!strcmp(position, "any")) {
3681 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3684 if(type == RAWDATA) {
3686 s_buttonaction(current_button_flags, action);
3687 current_button_flags = 0;
3693 static int c_on_move_out(map_t*args)
3695 char*position = lu(args, "state");
3697 if(!strcmp(position, "pressed")) {
3698 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3699 } else if(!strcmp(position, "not_pressed")) {
3700 current_button_flags |= BC_OVERUP_IDLE;
3701 } else if(!strcmp(position, "any")) {
3702 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3705 if(type == RAWDATA) {
3707 s_buttonaction(current_button_flags, action);
3708 current_button_flags = 0;
3714 static int c_on_key(map_t*args)
3716 char*key = lu(args, "key");
3718 if(strlen(key)==1) {
3721 current_button_flags |= 0x4000 + (key[0]*0x200);
3723 syntaxerror("invalid character: %c"+key[0]);
3728 <ctrl-x> = 0x200*(x-'a')
3732 syntaxerror("invalid key: %s",key);
3735 if(type == RAWDATA) {
3737 s_buttonaction(current_button_flags, action);
3738 current_button_flags = 0;
3745 static int c_edittext(map_t*args)
3747 //"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"},
3748 char*name = lu(args, "name");
3749 char*font = lu(args, "font");
3750 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3751 int width = parseTwip(lu(args, "width"));
3752 int height = parseTwip(lu(args, "height"));
3753 char*text = lu(args, "text");
3754 RGBA color = parseColor(lu(args, "color"));
3755 int maxlength = parseInt(lu(args, "maxlength"));
3756 char*variable = lu(args, "variable");
3757 char*passwordstr = lu(args, "password");
3758 char*wordwrapstr = lu(args, "wordwrap");
3759 char*multilinestr = lu(args, "multiline");
3760 char*htmlstr = lu(args, "html");
3761 char*noselectstr = lu(args, "noselect");
3762 char*readonlystr = lu(args, "readonly");
3763 char*borderstr = lu(args, "border");
3764 char*autosizestr = lu(args, "autosize");
3765 char*alignstr = lu(args, "align");
3769 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3770 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3771 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3772 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3773 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3774 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3775 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3776 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3777 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3778 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3779 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3780 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3781 else syntaxerror("Unknown alignment: %s", alignstr);
3783 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3787 static int c_morphshape(map_t*args) {return fakechar(args);}
3788 static int c_movie(map_t*args) {return fakechar(args);}
3790 static char* readfile(const char*filename)
3792 FILE*fi = fopen(filename, "rb");
3796 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3797 fseek(fi, 0, SEEK_END);
3799 fseek(fi, 0, SEEK_SET);
3800 text = rfx_alloc(l+1);
3801 fread(text, l, 1, fi);
3807 static int c_action(map_t*args)
3809 char* filename = map_lookup(args, "filename");
3810 if(!filename ||!*filename) {
3812 if(type != RAWDATA) {
3813 syntaxerror("colon (:) expected");
3817 s_action(readfile(filename));
3823 static int c_initaction(map_t*args)
3825 char* character = lu(args, "name");
3826 char* filename = map_lookup(args, "filename");
3827 if(!filename ||!*filename) {
3829 if(type != RAWDATA) {
3830 syntaxerror("colon (:) expected");
3832 s_initaction(character, text);
3834 s_initaction(character, readfile(filename));
3842 command_func_t* func;
3845 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no"},
3846 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3847 // "import" type stuff
3848 {"swf", c_swf, "name filename"},
3849 {"shape", c_swf, "name filename"},
3850 {"jpeg", c_image, "name filename quality=80%"},
3851 {"png", c_image, "name filename"},
3852 {"movie", c_movie, "name filename"},
3853 {"sound", c_sound, "name filename"},
3854 {"font", c_font, "name filename glyphs="},
3855 {"soundtrack", c_soundtrack, "filename"},
3856 {"quicktime", c_quicktime, "url"},
3858 // generators of primitives
3860 {"point", c_point, "name x=0 y=0"},
3861 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3862 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
3863 {"outline", c_outline, "name format=simple"},
3864 {"textshape", c_textshape, "name font size=100% text"},
3867 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3868 {"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"},
3869 {"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"},
3870 {"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"},
3872 // character generators
3873 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3874 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3875 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3877 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3878 {"text", c_text, "name text font size=100% color=white"},
3879 {"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="},
3880 {"morphshape", c_morphshape, "name start end"},
3881 {"button", c_button, "name"},
3882 {"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="},
3883 {"on_press", c_on_press, "position=inside"},
3884 {"on_release", c_on_release, "position=anywhere"},
3885 {"on_move_in", c_on_move_in, "state=not_pressed"},
3886 {"on_move_out", c_on_move_out, "state=not_pressed"},
3887 {"on_key", c_on_key, "key=any"},
3890 {"play", c_play, "name loop=0 @nomultiple=0"},
3891 {"stop", c_stop, "name= "},
3892 {"nextframe", c_nextframe, "name"},
3893 {"previousframe", c_previousframe, "name"},
3895 // object placement tags
3896 {"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="},
3897 {"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="},
3898 {"move", c_move, "name x= y= interpolation=linear"},
3899 {"smove", c_smove, "name x= y= interpolation=linear"},
3900 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
3901 {"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"},
3902 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3903 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
3904 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3905 {"del", c_del, "name"},
3906 // virtual object placement
3907 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3909 {"toggle", c_toggle, "name fixed_alignment="},
3911 // commands which start a block
3912 //startclip (see above)
3913 {"sprite", c_sprite, "name"},
3914 {"action", c_action, "filename="},
3915 {"initaction", c_initaction, "name filename="},
3921 static map_t parseArguments(char*command, char*pattern)
3937 string_set(&t1, "commandname");
3938 string_set(&t2, command);
3939 map_put(&result, t1, t2);
3941 if(!pattern || !*pattern)
3948 if(!strncmp("<i> ", x, 3)) {
3950 if(type == COMMAND || type == RAWDATA) {
3952 syntaxerror("character name expected");
3954 name[pos].str = "instance";
3956 value[pos].str = text;
3957 value[pos].len = strlen(text);
3961 if(type == ASSIGNMENT)
3964 name[pos].str = "character";
3966 value[pos].str = text;
3967 value[pos].len = strlen(text);
3975 isboolean[pos] = (x[0] =='@');
3988 name[pos].len = d-x;
3993 name[pos].len = e-x;
3994 value[pos].str = e+1;
3995 value[pos].len = d-e-1;
4003 /* for(t=0;t<len;t++) {
4004 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4005 isboolean[t]?"(boolean)":"");
4010 if(type == RAWDATA || type == COMMAND) {
4015 // first, search for boolean arguments
4016 for(pos=0;pos<len;pos++)
4018 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4020 if(type == ASSIGNMENT)
4022 value[pos].str = text;
4023 value[pos].len = strlen(text);
4024 /*printf("setting boolean parameter %s (to %s)\n",
4025 strdup_n(name[pos], namelen[pos]),
4026 strdup_n(value[pos], valuelen[pos]));*/
4031 // second, search for normal arguments
4033 for(pos=0;pos<len;pos++)
4035 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4036 (type != ASSIGNMENT && !set[pos])) {
4038 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4040 if(type == ASSIGNMENT)
4043 value[pos].str = text;
4044 value[pos].len = strlen(text);
4046 printf("setting parameter %s (to %s)\n",
4047 strdup_n(name[pos].str, name[pos].len),
4048 strdup_n(value[pos].str, value[pos].len));
4054 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4058 for(t=0;t<len;t++) {
4059 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4062 for(t=0;t<len;t++) {
4063 if(value[t].str && value[t].str[0] == '*') {
4064 //relative default- take value from some other parameter
4066 for(s=0;s<len;s++) {
4067 if(value[s].len == value[t].len-1 &&
4068 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4069 value[t].str = value[s].str;
4072 if(value[t].str == 0) {
4074 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4078 /* ok, now construct the dictionary from the parameters */
4082 map_put(&result, name[t], value[t]);
4086 static void parseArgumentsForCommand(char*command)
4091 msg("<verbose> parse Command: %s (line %d)", command, line);
4093 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4094 if(!strcmp(arguments[t].command, command)) {
4096 /* ugly hack- will be removed soon (once documentation and .sc generating
4097 utilities have been changed) */
4098 if(!strcmp(command, "swf") && !stackpos) {
4099 warning("Please use .flash instead of .swf- this will be mandatory soon");
4104 args = parseArguments(command, arguments[t].arguments);
4110 syntaxerror("command %s not known", command);
4112 // catch missing .flash directives at the beginning of a file
4113 if(strcmp(command, "flash") && !stackpos)
4115 syntaxerror("No movie defined- use .flash first");
4119 printf(".%s\n", command);fflush(stdout);
4120 map_dump(&args, stdout, "\t");fflush(stdout);
4123 (*arguments[nr].func)(&args);
4125 /*if(!strcmp(command, "button") ||
4126 !strcmp(command, "action")) {
4129 if(type == COMMAND) {
4130 if(!strcmp(text, "end"))
4145 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4146 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4147 * No syntax checking is done */
4148 static void analyseArgumentsForCommand(char*command)
4154 msg("<verbose> analyse Command: %s (line %d)", command, line);
4156 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4158 if(!strcmp(arguments[t].command, command))
4160 args = parseArguments(command, arguments[t].arguments);
4166 printf(".%s\n", command);fflush(stdout);
4167 map_dump(&args, stdout, "\t");fflush(stdout);
4169 char* name = lu(&args, "name");
4170 if (!strcmp(command, "font"))
4172 if(dictionary_lookup(&fonts, name))
4173 syntaxerror("font %s defined twice", name);
4176 fontfile = lu(&args, "filename");
4177 font = swf_LoadFont(fontfile);
4179 warning("Couldn't open font file \"%s\"", fontfile);
4180 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4181 memset(font, 0, sizeof(SWFFONT));
4183 swf_FontUseUTF8(font, lu(&args, "glyphs"));
4184 swf_FontPrepareForEditText(font);
4185 dictionary_put2(&fonts, name, font);
4189 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
4191 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4193 if (!strcmp(command, "edittext"))
4194 swf_FontUseAll(font);
4196 swf_FontUseUTF8(font, lu(&args, "text"));
4202 void skipParameters()
4206 while (type != COMMAND);
4210 void findFontUsage()
4212 char* fontRelated = "font;text;textshape;edittext;";
4213 while(!noMoreTokens())
4217 syntaxerror("command expected");
4218 if (strstr(fontRelated, text))
4219 analyseArgumentsForCommand(text);
4221 if(strcmp(text, "end"))
4230 dictionary_init(&fonts);
4231 cleanUp = &freeFontDictionary;
4235 int main (int argc,char ** argv)
4238 processargs(argc, argv);
4239 initLog(0,-1,0,0,-1,verbose);
4242 args_callback_usage(argv[0]);
4246 file = generateTokens(filename);
4248 fprintf(stderr, "parser returned error.\n");
4255 while(!noMoreTokens()) {
4258 syntaxerror("command expected");
4259 parseArgumentsForCommand(text);