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;
50 static int do_exports = 0;
52 static struct options_t options[] = {
61 int args_callback_option(char*name,char*val)
63 if(!strcmp(name, "V")) {
64 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
67 else if(!strcmp(name, "o")) {
69 override_outputname = 1;
72 else if(!strcmp(name, "O")) {
76 else if(!strcmp(name, "C")) {
80 else if(!strcmp(name, "v")) {
85 printf("Unknown option: -%s\n", name);
90 int args_callback_longoption(char*name,char*val)
92 return args_long2shortoption(options, name, val);
94 void args_callback_usage(char *name)
97 printf("Usage: %s [-o file.swf] file.sc\n", name);
99 printf("-h , --help Print short help message and exit\n");
100 printf("-V , --version Print version info and exit\n");
101 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
102 printf("-v , --verbose Increase verbosity. \n");
103 printf("-o , --output <filename> Set output file to <filename>.\n");
106 int args_callback_command(char*name,char*val)
109 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
116 static struct token_t* file;
123 static void readToken()
125 type = file[pos].type;
127 syntaxerror("unexpected end of file");
129 text = file[pos].text;
130 textlen = strlen(text);
131 line = file[pos].line;
132 column = file[pos].column;
134 //printf("---> %d(%s) %s\n", type, type_names[type], text);
137 static void pushBack()
140 if(!pos) syntaxerror("internal error 3");
145 textlen = strlen(text);
148 column = file[p].column;
151 static int noMoreTokens()
153 if(file[pos].type == END)
171 // ------------------------------ swf routines ----------------------------
175 int type; //0=swf, 1=sprite, 2=clip, 3=button
181 /* for sprites (1): */
187 dictionary_t oldinstances;
194 static int stackpos = 0;
196 static dictionary_t characters;
197 static dictionary_t images;
198 static dictionary_t textures;
199 static dictionary_t outlines;
200 static dictionary_t gradients;
201 static dictionary_t filters;
202 static dictionary_t interpolations;
203 static char idmap[65536];
204 static TAG*tag = 0; //current tag
206 static int id; //current character id
207 static int currentframe; //current frame in current level
208 static SRECT currentrect; //current bounding box in current level
209 static U16 currentdepth;
210 static dictionary_t instances;
211 static dictionary_t fonts;
212 static dictionary_t sounds;
213 static dictionary_t fontUsage;
215 typedef struct _parameters {
217 float scalex, scaley;
223 U8 blendmode; //not interpolated
225 U16 set; // bits indicating wether a parameter was set in the c_placement function
226 U16 flags; // bits to toggle anything you may care to implement as a toggle
229 typedef struct _character {
235 typedef struct _instance {
236 character_t*character;
238 parameters_t parameters;
242 typedef struct _outline {
247 typedef struct _gradient {
253 typedef struct _filter {
257 typedef struct _texture {
261 char* interpolationFunctions[] = {"linear", \
262 "quadIn", "quadOut", "quadInOut", \
263 "cubicIn", "cubicOut", "cubicInOut", \
264 "quartIn", "quartOut", "quartInOut", \
265 "quintIn", "quintOut", "quintInOut", \
266 "circleIn", "circleOut", "circleInOut", \
267 "exponentialIn", "exponentialOut", "exponentialInOut", \
268 "sineIn", "sineOut", "sineInOut", \
269 "elasticIn", "elasticOut", "elasticInOut", \
270 "backIn", "backOut", "backInOut", \
271 "bounceIn", "bounceOut", "bounceInOut", \
272 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
274 static void character_init(character_t*c)
276 memset(c, 0, sizeof(character_t));
279 static character_t* character_new()
282 c = (character_t*)malloc(sizeof(character_t));
287 static void instance_init(instance_t*i)
289 memset(i, 0, sizeof(instance_t));
290 i->history = history_new();
293 static void instance_free(instance_t* i)
295 history_free(i->history);
299 static instance_t* instance_new()
302 c = (instance_t*)malloc(sizeof(instance_t));
307 static void free_instance(void* i)
309 instance_free((instance_t*)i);
312 static void free_font(void* f)
314 swf_FontFree((SWFFONT*)f);
317 static void gradient_free(GRADIENT* grad)
324 static void free_gradient(void* grad)
326 gradient_free((GRADIENT*) grad);
329 static void outline_free(outline_t* o)
331 free(o->shape->data);
336 static void free_outline(void* o)
338 outline_free((outline_t*)o);
341 static void freeDictionaries()
343 dictionary_free_all(&instances, free_instance);
344 dictionary_free_all(&characters, free);
345 dictionary_free_all(&images, free);
346 dictionary_free_all(&textures, free);
347 dictionary_free_all(&outlines, free_outline);
348 dictionary_free_all(&gradients, free_gradient);
349 dictionary_free_all(&filters, free);
350 dictionary_free_all(&fonts, free_font);
351 dictionary_free_all(&sounds, free);
352 dictionary_free_all(&interpolations, free);
356 static void freeFontDictionary()
358 dictionary_free_all(&fonts, free_font);
361 static void incrementid()
365 syntaxerror("Out of character ids.");
370 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
372 if(dictionary_lookup(&characters, name))
373 syntaxerror("character %s defined twice", name);
374 character_t* c = character_new();
376 c->definingTag = ctag;
379 dictionary_put2(&characters, name, c);
382 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
384 swf_SetString(tag, name);
385 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
388 swf_SetString(tag, name);
391 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
393 if(dictionary_lookup(&images, name))
394 syntaxerror("image %s defined twice", name);
396 character_t* c = character_new();
397 c->definingTag = ctag;
400 dictionary_put2(&images, name, c);
402 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
404 if(dictionary_lookup(&instances, name))
405 syntaxerror("object %s defined twice", name);
406 instance_t* i = instance_new();
409 //swf_GetMatrix(0, &i->matrix);
410 dictionary_put2(&instances, name, i);
414 static void parameters_clear(parameters_t*p)
417 p->scalex = 1.0; p->scaley = 1.0;
420 p->pivot.x = 0; p->pivot.y = 0;
425 swf_GetCXForm(0, &p->cxform, 1);
428 static void makeMatrix(MATRIX*m, parameters_t*p)
437 sx = p->scalex*cos(p->rotate/360*2*M_PI);
438 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
439 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
440 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
442 m->sx = (int)(sx*65536+0.5);
443 m->r1 = (int)(r1*65536+0.5);
444 m->r0 = (int)(r0*65536+0.5);
445 m->sy = (int)(sy*65536+0.5);
449 h = swf_TurnPoint(p->pin, m);
454 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
459 r = swf_TurnRect(rect, &m);
460 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
461 currentrect.xmax == 0 && currentrect.ymax == 0)
464 swf_ExpandRect2(¤trect, &r);
470 interpolation_t* new;
471 new = (interpolation_t*)malloc(sizeof(interpolation_t));
472 new->function = IF_LINEAR;
473 dictionary_put2(&interpolations, "linear", new);
475 new = (interpolation_t*)malloc(sizeof(interpolation_t));
476 new->function = IF_QUAD_IN;
478 dictionary_put2(&interpolations, "quadIn", new);
479 new = (interpolation_t*)malloc(sizeof(interpolation_t));
480 new->function = IF_QUAD_OUT;
482 dictionary_put2(&interpolations, "quadOut", new);
483 new = (interpolation_t*)malloc(sizeof(interpolation_t));
484 new->function = IF_QUAD_IN_OUT;
486 dictionary_put2(&interpolations, "quadInOut", new);
488 new = (interpolation_t*)malloc(sizeof(interpolation_t));
489 new->function = IF_CUBIC_IN;
491 dictionary_put2(&interpolations, "cubicIn", new);
492 new = (interpolation_t*)malloc(sizeof(interpolation_t));
493 new->function = IF_CUBIC_OUT;
495 dictionary_put2(&interpolations, "cubicOut", new);
496 new = (interpolation_t*)malloc(sizeof(interpolation_t));
497 new->function = IF_CUBIC_IN_OUT;
499 dictionary_put2(&interpolations, "cubicInOut", new);
501 new = (interpolation_t*)malloc(sizeof(interpolation_t));
502 new->function = IF_QUART_IN;
504 dictionary_put2(&interpolations, "quartIn", new);
505 new = (interpolation_t*)malloc(sizeof(interpolation_t));
506 new->function = IF_QUART_OUT;
508 dictionary_put2(&interpolations, "quartOut", new);
509 new = (interpolation_t*)malloc(sizeof(interpolation_t));
510 new->function = IF_QUART_IN_OUT;
512 dictionary_put2(&interpolations, "quartInOut", new);
514 new = (interpolation_t*)malloc(sizeof(interpolation_t));
515 new->function = IF_QUINT_IN;
517 dictionary_put2(&interpolations, "quintIn", new);
518 new = (interpolation_t*)malloc(sizeof(interpolation_t));
519 new->function = IF_QUINT_OUT;
521 dictionary_put2(&interpolations, "quintOut", new);
522 new = (interpolation_t*)malloc(sizeof(interpolation_t));
523 new->function = IF_QUINT_IN_OUT;
525 dictionary_put2(&interpolations, "quintInOut", new);
527 new = (interpolation_t*)malloc(sizeof(interpolation_t));
528 new->function = IF_CIRCLE_IN;
529 dictionary_put2(&interpolations, "circleIn", new);
530 new = (interpolation_t*)malloc(sizeof(interpolation_t));
531 new->function = IF_CIRCLE_OUT;
532 dictionary_put2(&interpolations, "circleOut", new);
533 new = (interpolation_t*)malloc(sizeof(interpolation_t));
534 new->function = IF_CIRCLE_IN_OUT;
535 dictionary_put2(&interpolations, "circleInOut", new);
537 new = (interpolation_t*)malloc(sizeof(interpolation_t));
538 new->function = IF_EXPONENTIAL_IN;
539 dictionary_put2(&interpolations, "exponentialIn", new);
540 new = (interpolation_t*)malloc(sizeof(interpolation_t));
541 new->function = IF_EXPONENTIAL_OUT;
542 dictionary_put2(&interpolations, "exponentialOut", new);
543 new = (interpolation_t*)malloc(sizeof(interpolation_t));
544 new->function = IF_EXPONENTIAL_IN_OUT;
545 dictionary_put2(&interpolations, "exponentialInOut", new);
547 new = (interpolation_t*)malloc(sizeof(interpolation_t));
548 new->function = IF_SINE_IN;
549 dictionary_put2(&interpolations, "sineIn", new);
550 new = (interpolation_t*)malloc(sizeof(interpolation_t));
551 new->function = IF_SINE_OUT;
552 dictionary_put2(&interpolations, "sineOut", new);
553 new = (interpolation_t*)malloc(sizeof(interpolation_t));
554 new->function = IF_SINE_IN_OUT;
555 dictionary_put2(&interpolations, "sineInOut", new);
558 memset(&c, 0, sizeof(RGBA));
559 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
560 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
561 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
562 noGradient->gradient.num = 2;
563 noGradient->gradient.rgba[0] = c;
564 noGradient->gradient.ratios[0] = 0;
565 noGradient->gradient.rgba[1] = c;
566 noGradient->gradient.ratios[1] = 255;
567 noGradient->radial = 0;
568 noGradient->rotate = 0;
569 dictionary_put2(&gradients, "no_gradient", noGradient);
572 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
573 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
574 FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
575 dictionary_put2(&filters, "no_filters", dummy);
576 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
578 dictionary_put2(&filters, "no_blur", noBlur);
579 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
581 noBevel->composite = 1;
582 dictionary_put2(&filters, "no_bevel", noBevel);
583 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
584 noDropshadow->passes = 1;
585 noDropshadow->composite = 1;
586 dictionary_put2(&filters, "no_dropshadow", noDropshadow);
587 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
588 noGradientGlow->passes = 1;
589 noGradientGlow->composite = 1;
590 noGradientGlow->gradient = &noGradient->gradient;
591 dictionary_put2(&filters, "no_gradientglow", noGradientGlow);
594 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
597 syntaxerror(".swf blocks can't be nested");
598 if(stackpos==sizeof(stack)/sizeof(stack[0]))
599 syntaxerror("too many levels of recursion");
601 SWF*swf = (SWF*)malloc(sizeof(SWF));
603 memset(swf, 0, sizeof(swf));
604 swf->fileVersion = version;
606 swf->frameRate = fps;
607 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
608 swf->compressed = compress;
609 swf_SetRGB(tag,&background);
611 dictionary_init(&characters);
612 dictionary_init(&images);
613 dictionary_init(&textures);
614 dictionary_init(&outlines);
615 dictionary_init(&gradients);
616 dictionary_init(&filters);
617 dictionary_init(&instances);
618 dictionary_init(&sounds);
619 dictionary_init(&interpolations);
621 cleanUp = &freeDictionaries;
623 memset(&stack[stackpos], 0, sizeof(stack[0]));
624 stack[stackpos].type = 0;
625 stack[stackpos].filename = strdup(name);
626 stack[stackpos].swf = swf;
627 stack[stackpos].oldframe = -1;
631 memset(¤trect, 0, sizeof(currentrect));
634 memset(idmap, 0, sizeof(idmap));
638 void s_sprite(char*name, SRECT*scalegrid)
640 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
641 swf_SetU16(tag, id); //id
642 swf_SetU16(tag, 0); //frames
644 memset(&stack[stackpos], 0, sizeof(stack[0]));
645 stack[stackpos].type = 1;
646 stack[stackpos].oldframe = currentframe;
647 stack[stackpos].olddepth = currentdepth;
648 stack[stackpos].oldrect = currentrect;
649 stack[stackpos].oldinstances = instances;
650 stack[stackpos].tag = tag;
651 stack[stackpos].id = id;
652 stack[stackpos].name = strdup(name);
654 stack[stackpos].scalegrid = *scalegrid;
656 memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
659 /* FIXME: those four fields should be bundled together */
660 dictionary_init(&instances);
663 memset(¤trect, 0, sizeof(currentrect));
669 typedef struct _buttonrecord
677 typedef struct _button
681 buttonrecord_t records[4];
684 static button_t mybutton;
686 void s_button(char*name)
688 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
689 swf_SetU16(tag, id); //id
690 swf_ButtonSetFlags(tag, 0); //menu=no
692 memset(&mybutton, 0, sizeof(mybutton));
694 memset(&stack[stackpos], 0, sizeof(stack[0]));
695 stack[stackpos].type = 3;
696 stack[stackpos].tag = tag;
697 stack[stackpos].id = id;
698 stack[stackpos].name = strdup(name);
699 stack[stackpos].oldrect = currentrect;
700 memset(¤trect, 0, sizeof(currentrect));
705 void s_buttonput(char*character, char*as, parameters_t p)
707 character_t* c = dictionary_lookup(&characters, character);
712 if(!stackpos || (stack[stackpos-1].type != 3)) {
713 syntaxerror(".show may only appear in .button");
716 syntaxerror("character %s not known (in .shape %s)", character, character);
718 if(mybutton.endofshapes) {
719 syntaxerror("a .do may not precede a .show", character, character);
722 m = s_instancepos(c->size, &p);
730 if(*s==',' || *s==0) {
731 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
732 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
733 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
734 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
735 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
736 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
743 static void setbuttonrecords(TAG*tag)
745 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
746 if(!mybutton.endofshapes) {
749 if(!mybutton.records[3].set) {
750 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
754 if(mybutton.records[t].set) {
755 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
758 swf_SetU8(tag,0); // end of button records
759 mybutton.endofshapes = 1;
763 void s_buttonaction(int flags, char*action)
769 setbuttonrecords(stack[stackpos-1].tag);
771 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
773 syntaxerror("Couldn't compile ActionScript");
776 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
777 swf_ActionSet(stack[stackpos-1].tag, a);
778 mybutton.nr_actions++;
783 static void setactionend(TAG*tag)
785 if(!mybutton.nr_actions) {
786 /* no actions means we didn't have an actionoffset,
787 which means we can't signal the end of the
788 buttonaction records, so, *sigh*, we have
789 to insert a dummy record */
790 swf_SetU16(tag, 0); //offset
791 swf_SetU16(tag, 0); //condition
792 swf_SetU8(tag, 0); //action
796 static void s_endButton()
799 setbuttonrecords(stack[stackpos-1].tag);
800 setactionend(stack[stackpos-1].tag);
803 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
807 tag = stack[stackpos].tag;
808 currentrect = stack[stackpos].oldrect;
810 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
811 free(stack[stackpos].name);
814 TAG* removeFromTo(TAG*from, TAG*to)
816 TAG*save = from->prev;
818 TAG*next = from->next;
826 static int parametersChange(history_t* history, int frame)
830 willChange = willChange || history_change(history, frame, "x");
831 willChange = willChange || history_change(history, frame, "y");
832 willChange = willChange || history_change(history, frame, "scalex");
833 willChange = willChange || history_change(history, frame, "scaley");
834 willChange = willChange || history_change(history, frame, "cxform.r0");
835 willChange = willChange || history_change(history, frame, "cxform.g0");
836 willChange = willChange || history_change(history, frame, "cxform.b0");
837 willChange = willChange || history_change(history, frame, "cxform.a0");
838 willChange = willChange || history_change(history, frame, "cxform.r1");
839 willChange = willChange || history_change(history, frame, "cxform.g1");
840 willChange = willChange || history_change(history, frame, "cxform.b1");
841 willChange = willChange || history_change(history, frame, "cxform.a1");
842 willChange = willChange || history_change(history, frame, "rotate");
843 willChange = willChange || history_change(history, frame, "shear");
844 willChange = willChange || history_change(history, frame, "pivot.x");
845 willChange = willChange || history_change(history, frame, "pivot.y");
846 willChange = willChange || history_change(history, frame, "pin.x");
847 willChange = willChange || history_change(history, frame, "pin.y");
848 willChange = willChange || history_change(history, frame, "blendmode");
849 willChange = willChange || history_changeFilter(history, frame);
854 static void free_filterlist(FILTERLIST* f_list)
857 for (i = 0; i < f_list->num; i++)
859 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
860 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
861 free(f_list->filter[i]);
866 static void readParameters(history_t* history, parameters_t* p, int frame)
868 p->x = history_value(history, frame, "x");
869 p->y = history_value(history, frame, "y");
870 p->scalex = history_value(history, frame, "scalex");
871 p->scaley = history_value(history, frame, "scaley");
872 p->cxform.r0 = history_value(history, frame, "cxform.r0");
873 p->cxform.g0 = history_value(history, frame, "cxform.g0");
874 p->cxform.b0 = history_value(history, frame, "cxform.b0");
875 p->cxform.a0 = history_value(history, frame, "cxform.a0");
876 p->cxform.r1 = history_value(history, frame, "cxform.r1");
877 p->cxform.g1 = history_value(history, frame, "cxform.g1");
878 p->cxform.b1 = history_value(history, frame, "cxform.b1");
879 p->cxform.a1 = history_value(history, frame, "cxform.a1");
880 p->rotate = history_rotateValue(history, frame);
881 p->shear = history_value(history, frame, "shear");
882 p->pivot.x = history_value(history, frame, "pivot.x");
883 p->pivot.y = history_value(history, frame, "pivot.y");
884 p->pin.x = history_value(history, frame, "pin.x");
885 p->pin.y = history_value(history, frame, "pin.y");
886 p->blendmode = history_value(history, frame, "blendmode");
887 p->filters = history_filterValue(history, frame);
890 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
894 swf_GetPlaceObject(NULL, &po);
898 po.cxform = p->cxform;
904 po.blendmode = p->blendmode;
907 po.filters = p->filters;
908 swf_SetPlaceObject(tag, &po);
911 static void writeInstance(instance_t* i)
915 int frame = i->history->firstFrame;
916 TAG* tag = i->history->firstTag;
917 history_processFlags(i->history);
918 while (frame < currentframe)
921 while (tag->id != ST_SHOWFRAME)
923 if (parametersChange(i->history, frame))
925 readParameters(i->history, &p, frame);
926 m = s_instancepos(i->character->size, &p);
928 if(p.blendmode || p.filters)
929 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
931 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
932 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
934 free_filterlist(p.filters);
941 void dumpSWF(SWF*swf)
943 TAG* tag = swf->firstTag;
944 printf("vvvvvvvvvvvvvvvvvvvvv\n");
946 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
949 printf("^^^^^^^^^^^^^^^^^^^^^\n");
952 static void s_endSprite()
954 SRECT r = currentrect;
956 if(stack[stackpos].cut)
957 tag = removeFromTo(stack[stackpos].cut, tag);
961 stringarray_t* index =dictionary_index(&instances);
963 for (num = 0; num < dictionary_count(&instances); num++)
965 char* name = stringarray_at(index, num);
968 i = dictionary_lookup(&instances, name);
975 tag = swf_InsertTag(tag, ST_SHOWFRAME);
976 tag = swf_InsertTag(tag, ST_END);
978 tag = stack[stackpos].tag;
981 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
982 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
984 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
985 swf_SetU16(tag, stack[stackpos].id);
986 swf_SetRect(tag, &stack[stackpos].scalegrid);
990 syntaxerror("internal error(7)");
991 /* TODO: before clearing, prepend "<spritename>." to names and
992 copy into old instances dict */
993 dictionary_free_all(&instances, free_instance);
995 currentframe = stack[stackpos].oldframe;
996 currentrect = stack[stackpos].oldrect;
997 currentdepth = stack[stackpos].olddepth;
998 instances = stack[stackpos].oldinstances;
1000 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1001 free(stack[stackpos].name);
1004 static void s_endSWF()
1011 stringarray_t* index = dictionary_index(&instances);
1013 for (num = 0; num < dictionary_count(&instances); num++)
1015 char* name = stringarray_at(index, num);
1018 i = dictionary_lookup(&instances, name);
1023 if(stack[stackpos].cut)
1024 tag = removeFromTo(stack[stackpos].cut, tag);
1028 swf = stack[stackpos].swf;
1029 filename = stack[stackpos].filename;
1031 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1032 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1033 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1035 tag = swf_InsertTag(tag, ST_END);
1037 swf_OptimizeTagOrder(swf);
1043 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1044 swf->movieSize = currentrect; /* "autocrop" */
1047 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1048 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1049 swf->movieSize.ymax += 20;
1050 warning("Empty bounding box for movie");
1053 if(do_cgi || !strcmp(filename, "-"))
1054 fi = fileno(stdout);
1056 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1058 syntaxerror("couldn't create output file %s", filename);
1061 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1063 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1077 if(stack[stackpos-1].type == 0)
1078 syntaxerror("End of file encountered in .flash block");
1079 if(stack[stackpos-1].type == 1)
1080 syntaxerror("End of file encountered in .sprite block");
1081 if(stack[stackpos-1].type == 2)
1082 syntaxerror("End of file encountered in .clip block");
1088 return currentframe+1;
1091 void s_frame(int nr, int cut, char*name, char anchor)
1097 syntaxerror("Illegal frame number");
1098 nr--; // internally, frame 1 is frame 0
1100 for(t=currentframe;t<nr;t++) {
1101 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1102 if(t==nr-1 && name && *name) {
1103 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1104 swf_SetString(tag, name);
1106 swf_SetU8(tag, 1); //make this an anchor
1109 if(nr == 0 && currentframe == 0 && name && *name) {
1110 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1111 swf_SetString(tag, name);
1113 swf_SetU8(tag, 1); //make this an anchor
1118 syntaxerror("Can't cut, frame empty");
1120 stack[stackpos].cut = tag;
1126 int parseColor2(char*str, RGBA*color);
1128 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1132 gradient_t*gradient;
1134 if(name[0] == '#') {
1135 parseColor2(name, &color);
1136 return swf_ShapeAddSolidFillStyle(s, &color);
1137 } else if ((texture = dictionary_lookup(&textures, name))) {
1138 return swf_ShapeAddFillStyle2(s, &texture->fs);
1139 } else if((image = dictionary_lookup(&images, name))) {
1141 swf_GetMatrix(0, &m);
1142 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1143 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1146 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1147 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1151 swf_GetMatrix(0, &rot);
1152 ccos = cos(-gradient->rotate*2*M_PI/360);
1153 csin = sin(-gradient->rotate*2*M_PI/360);
1154 rot.sx = ccos*65536;
1155 rot.r1 = -csin*65536;
1156 rot.r0 = csin*65536;
1157 rot.sy = ccos*65536;
1158 r2 = swf_TurnRect(*r, &rot);
1159 swf_GetMatrix(0, &m);
1160 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1161 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1162 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1163 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1164 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1165 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1166 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1167 } else if (parseColor2(name, &color)) {
1168 return swf_ShapeAddSolidFillStyle(s, &color);
1170 syntaxerror("not a color/fillstyle: %s", name);
1175 RGBA black={r:0,g:0,b:0,a:0};
1176 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1185 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1188 linewidth = linewidth>=20?linewidth-20:0;
1189 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1192 fs1 = addFillStyle(s, &r2, texture);
1195 r.xmin = r2.xmin-linewidth/2;
1196 r.ymin = r2.ymin-linewidth/2;
1197 r.xmax = r2.xmax+linewidth/2;
1198 r.ymax = r2.ymax+linewidth/2;
1199 swf_SetRect(tag,&r);
1200 swf_SetShapeHeader(tag,s);
1201 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1202 swf_ShapeSetLine(tag,s,width,0);
1203 swf_ShapeSetLine(tag,s,0,height);
1204 swf_ShapeSetLine(tag,s,-width,0);
1205 swf_ShapeSetLine(tag,s,0,-height);
1206 swf_ShapeSetEnd(tag);
1209 s_addcharacter(name, id, tag, r);
1213 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1219 outline = dictionary_lookup(&outlines, outlinename);
1221 syntaxerror("outline %s not defined", outlinename);
1225 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1228 linewidth = linewidth>=20?linewidth-20:0;
1229 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1232 fs1 = addFillStyle(s, &r2, texture);
1235 rect.xmin = r2.xmin-linewidth/2;
1236 rect.ymin = r2.ymin-linewidth/2;
1237 rect.xmax = r2.xmax+linewidth/2;
1238 rect.ymax = r2.ymax+linewidth/2;
1240 swf_SetRect(tag,&rect);
1241 swf_SetShapeStyles(tag, s);
1242 swf_ShapeCountBits(s,0,0);
1243 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1244 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1245 swf_SetShapeBits(tag, s);
1246 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1249 s_addcharacter(name, id, tag, rect);
1253 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1258 r2.xmin = r2.ymin = 0;
1262 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1265 linewidth = linewidth>=20?linewidth-20:0;
1266 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1269 fs1 = addFillStyle(s, &r2, texture);
1271 rect.xmin = r2.xmin-linewidth/2;
1272 rect.ymin = r2.ymin-linewidth/2;
1273 rect.xmax = r2.xmax+linewidth/2;
1274 rect.ymax = r2.ymax+linewidth/2;
1276 swf_SetRect(tag,&rect);
1277 swf_SetShapeHeader(tag,s);
1278 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1279 swf_ShapeSetCircle(tag, s, r,r,r,r);
1280 swf_ShapeSetEnd(tag);
1283 s_addcharacter(name, id, tag, rect);
1287 void s_textshape(char*name, char*fontname, float size, char*_text)
1290 U8*text = (U8*)_text;
1294 font = dictionary_lookup(&fonts, fontname);
1296 syntaxerror("font \"%s\" not known!", fontname);
1298 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1299 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1300 s_box(name, 0, 0, black, 20, 0);
1303 g = font->ascii2glyph[text[0]];
1305 outline = malloc(sizeof(outline_t));
1306 memset(outline, 0, sizeof(outline_t));
1307 outline->shape = font->glyph[g].shape;
1308 outline->bbox = font->layout->bounds[g];
1312 swf_Shape11DrawerInit(&draw, 0);
1313 swf_DrawText(&draw, font, (int)(size*100), _text);
1315 outline->shape = swf_ShapeDrawerToShape(&draw);
1316 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1317 draw.dealloc(&draw);
1320 if(dictionary_lookup(&outlines, name))
1321 syntaxerror("outline %s defined twice", name);
1322 dictionary_put2(&outlines, name, outline);
1325 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1330 font = dictionary_lookup(&fonts, fontname);
1332 syntaxerror("font \"%s\" not known!", fontname);
1334 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1335 swf_SetU16(tag, id);
1336 if(!font->numchars) {
1337 s_box(name, 0, 0, black, 20, 0);
1340 r = swf_SetDefineText(tag, font, &color, text, size);
1342 if(stack[0].swf->fileVersion >= 8) {
1343 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1344 swf_SetU16(tag, id);
1345 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1346 swf_SetU32(tag, 0);//thickness
1347 swf_SetU32(tag, 0);//sharpness
1348 swf_SetU8(tag, 0);//reserved
1351 s_addcharacter(name, id, tag, r);
1355 void s_quicktime(char*name, char*url)
1360 memset(&r, 0, sizeof(r));
1362 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1363 swf_SetU16(tag, id);
1364 swf_SetString(tag, url);
1366 s_addcharacter(name, id, tag, r);
1370 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)
1373 EditTextLayout layout;
1376 if(fontname && *fontname) {
1377 flags |= ET_USEOUTLINES;
1378 font = dictionary_lookup(&fonts, fontname);
1380 syntaxerror("font \"%s\" not known!", fontname);
1382 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1383 swf_SetU16(tag, id);
1384 layout.align = align;
1385 layout.leftmargin = 0;
1386 layout.rightmargin = 0;
1394 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1396 s_addcharacter(name, id, tag, r);
1400 /* type: either "jpeg" or "png"
1402 void s_image(char*name, char*type, char*filename, int quality)
1404 /* an image is actually two folded: 1st bitmap, 2nd character.
1405 Both of them can be used separately */
1407 /* step 1: the bitmap */
1411 if(!strcmp(type,"jpeg")) {
1412 #ifndef HAVE_JPEGLIB
1413 warning("no jpeg support compiled in");
1414 s_box(name, 0, 0, black, 20, 0);
1417 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1418 swf_SetU16(tag, imageID);
1420 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1421 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1424 swf_GetJPEGSize(filename, &width, &height);
1431 s_addimage(name, id, tag, r);
1434 } else if(!strcmp(type,"png")) {
1436 swf_SetU16(tag, imageID);
1438 getPNG(filename, &width, &height, (unsigned char**)&data);
1441 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1444 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1445 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1446 swf_SetU16(tag, imageID);
1447 swf_SetLosslessImage(tag, data, width, height);
1454 s_addimage(name, id, tag, r);
1457 warning("image type \"%s\" not supported yet!", type);
1458 s_box(name, 0, 0, black, 20, 0);
1462 /* step 2: the character */
1463 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1464 swf_SetU16(tag, id);
1465 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1467 s_addcharacter(name, id, tag, r);
1471 void s_getBitmapSize(char*name, int*width, int*height)
1473 character_t* image = dictionary_lookup(&images, name);
1474 gradient_t* gradient = dictionary_lookup(&gradients,name);
1476 *width = image->size.xmax;
1477 *height = image->size.ymax;
1481 /* internal SWF gradient size */
1482 if(gradient->radial) {
1491 syntaxerror("No such bitmap/gradient: %s", name);
1494 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1496 if(dictionary_lookup(&textures, name))
1497 syntaxerror("texture %s defined twice", name);
1498 gradient_t* gradient = dictionary_lookup(&gradients, object);
1499 character_t* bitmap = dictionary_lookup(&images, object);
1500 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1502 FILLSTYLE*fs = &texture->fs;
1504 memset(&p, 0, sizeof(parameters_t));
1507 fs->type = FILL_TILED;
1508 fs->id_bitmap = bitmap->id;
1509 } else if(gradient) {
1510 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1511 fs->gradient = gradient->gradient;
1513 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1514 makeMatrix(&fs->m, &p);
1515 if(gradient && !gradient->radial) {
1522 p2 = swf_TurnPoint(p1, &m);
1531 dictionary_put2(&textures, name, texture);
1534 void s_font(char*name, char*filename)
1537 font = dictionary_lookup(&fonts, name);
1540 /* fix the layout. Only needed for old fonts */
1542 for(t=0;t<font->numchars;t++) {
1543 font->glyph[t].advance = 0;
1546 swf_FontCreateLayout(font);
1549 swf_FontReduce_swfc(font);
1550 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1551 swf_FontSetDefine2(tag, font);
1552 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1554 swf_SetU16(tag, id);
1555 swf_SetString(tag, name);
1562 typedef struct _sound_t
1568 void s_sound(char*name, char*filename)
1570 struct WAV wav, wav2;
1574 unsigned numsamples = 1;
1575 unsigned blocksize = 1152;
1578 if(dictionary_lookup(&sounds, name))
1579 syntaxerror("sound %s defined twice", name);
1581 if(wav_read(&wav, filename))
1584 wav_convert2mono(&wav, &wav2, 44100);
1585 samples = (U16*)wav2.data;
1586 numsamples = wav2.size/2;
1588 #ifdef WORDS_BIGENDIAN
1590 for(t=0;t<numsamples;t++)
1591 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1595 if(mp3_read(&mp3, filename))
1597 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1603 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1608 if(numsamples%blocksize != 0)
1610 // apply padding, so that block is a multiple of blocksize
1611 int numblocks = (numsamples+blocksize-1)/blocksize;
1614 numsamples2 = numblocks * blocksize;
1615 samples2 = malloc(sizeof(U16)*numsamples2);
1616 memcpy(samples2, samples, numsamples*sizeof(U16));
1617 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1618 numsamples = numsamples2;
1623 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1624 swf_SetU16(tag, id); //id
1627 swf_SetSoundDefineMP3(
1628 tag, mp3.data, mp3.size,
1635 swf_SetSoundDefine(tag, samples, numsamples);
1637 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1638 swf_SetU16(tag, id);
1639 swf_SetString(tag, name);
1640 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1642 swf_SetU16(tag, id);
1643 swf_SetString(tag, name);
1645 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1649 dictionary_put2(&sounds, name, sound);
1657 static char* gradient_getToken(const char**p)
1661 while(**p && strchr(" \t\n\r", **p)) {
1665 while(**p && !strchr(" \t\n\r", **p)) {
1668 result = malloc((*p)-start+1);
1669 memcpy(result,start,(*p)-start+1);
1670 result[(*p)-start] = 0;
1674 float parsePercent(char*str);
1675 RGBA parseColor(char*str);
1677 GRADIENT parseGradient(const char*str)
1681 const char* p = str;
1682 memset(&gradient, 0, sizeof(GRADIENT));
1683 gradient.ratios = rfx_calloc(16*sizeof(U8));
1684 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1688 char*posstr,*colorstr;
1691 posstr = gradient_getToken(&p);
1697 pos = (int)(parsePercent(posstr)*255.0);
1702 rfx_free(gradient.ratios);
1703 rfx_free(gradient.rgba);
1705 syntaxerror("Error in shape data: Color expected after %s", posstr);
1707 colorstr = gradient_getToken(&p);
1708 color = parseColor(colorstr);
1709 if(gradient.num == 16)
1711 warning("gradient record too big- max size is 16, rest ignored");
1714 gradient.ratios[gradient.num] = pos;
1715 gradient.rgba[gradient.num] = color;
1724 FILTERLIST* parseFilters(char* list)
1726 if (!strcmp(list, "no_filters"))
1729 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1731 char* f_start = list;
1735 f_end = strchr(f_start, ',');
1738 f = dictionary_lookup(&filters, f_start);
1742 syntaxerror("unknown filter %s", f_start);
1744 if (f_list->num == 8)
1746 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1749 f_list->filter[f_list->num] = f;
1754 f_start = f_end + 1;
1762 void s_gradient(char*name, const char*text, int radial, int rotate)
1764 gradient_t* gradient;
1765 gradient = malloc(sizeof(gradient_t));
1766 memset(gradient, 0, sizeof(gradient_t));
1767 gradient->gradient = parseGradient(text);
1768 gradient->radial = radial;
1769 gradient->rotate = rotate;
1771 dictionary_put2(&gradients, name, gradient);
1774 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1775 float angle, float distance, float strength, char innershadow,
1776 char knockout, char composite, char ontop, int passes)
1778 if(dictionary_lookup(&filters, name))
1779 syntaxerror("filter %s defined twice", name);
1781 gradient_t* g = dictionary_lookup(&gradients, gradient);
1783 syntaxerror("unknown gradient %s", gradient);
1787 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1788 filter->type = FILTERTYPE_GRADIENTGLOW;
1789 filter->gradient = &g->gradient;
1790 filter->blurx = blurx;
1791 filter->blury = blury;
1792 filter->strength = strength;
1793 filter->angle = angle;
1794 filter->distance = distance;
1795 filter->innershadow = innershadow;
1796 filter->knockout = knockout;
1797 filter->composite = composite;
1798 filter->ontop = ontop;
1799 filter->passes = passes;
1801 dictionary_put2(&filters, name, filter);
1804 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)
1806 if(dictionary_lookup(&filters, name))
1807 syntaxerror("filter %s defined twice", name);
1810 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1811 filter->type = FILTERTYPE_DROPSHADOW;
1812 filter->color= color;
1813 filter->blurx = blurx;
1814 filter->blury = blury;
1815 filter->strength = strength;
1816 filter->angle = angle;
1817 filter->distance = distance;
1818 filter->innershadow = innershadow;
1819 filter->knockout = knockout;
1820 filter->composite = composite;
1821 filter->passes = passes;
1823 dictionary_put2(&filters, name, filter);
1826 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)
1828 if(dictionary_lookup(&filters, name))
1829 syntaxerror("filter %s defined twice", name);
1832 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1833 filter->type = FILTERTYPE_BEVEL;
1834 filter->shadow = shadow;
1835 filter->highlight = highlight;
1836 filter->blurx = blurx;
1837 filter->blury = blury;
1838 filter->strength = strength;
1839 filter->angle = angle;
1840 filter->distance = distance;
1841 filter->innershadow = innershadow;
1842 filter->knockout = knockout;
1843 filter->composite = composite;
1844 filter->ontop = ontop;
1845 filter->passes = passes;
1847 dictionary_put2(&filters, name, filter);
1850 void s_blur(char*name, double blurx, double blury, int passes)
1852 if(dictionary_lookup(&filters, name))
1853 syntaxerror("filter %s defined twice", name);
1855 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1856 filter->type = FILTERTYPE_BLUR;
1857 filter->blurx = blurx;
1858 filter->blury = blury;
1859 filter->passes = passes;
1861 dictionary_put2(&filters, name, filter);
1864 void s_action(const char*text)
1867 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1871 syntaxerror("Couldn't compile ActionScript");
1874 tag = swf_InsertTag(tag, ST_DOACTION);
1876 swf_ActionSet(tag, a);
1881 void s_initaction(const char*character, const char*text)
1885 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1889 syntaxerror("Couldn't compile ActionScript");
1892 c = (character_t*)dictionary_lookup(&characters, character);
1894 tag = swf_InsertTag(tag, ST_DOINITACTION);
1895 swf_SetU16(tag, c->id);
1896 swf_ActionSet(tag, a);
1901 int s_swf3action(char*name, char*action)
1904 instance_t* object = 0;
1906 object = (instance_t*)dictionary_lookup(&instances, name);
1907 if(!object && name && *name) {
1908 /* we have a name, but couldn't find it. Abort. */
1911 a = action_SetTarget(0, name);
1912 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1913 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1914 else if(!strcmp(action, "stop")) a = action_Stop(a);
1915 else if(!strcmp(action, "play")) a = action_Play(a);
1916 a = action_SetTarget(a, "");
1919 tag = swf_InsertTag(tag, ST_DOACTION);
1920 swf_ActionSet(tag, a);
1925 void s_outline(char*name, char*format, char*source)
1927 if(dictionary_lookup(&outlines, name))
1928 syntaxerror("outline %s defined twice", name);
1937 //swf_Shape10DrawerInit(&draw, 0);
1938 swf_Shape11DrawerInit(&draw, 0);
1940 draw_string(&draw, source);
1942 shape = swf_ShapeDrawerToShape(&draw);
1943 bounds = swf_ShapeDrawerGetBBox(&draw);
1944 draw.dealloc(&draw);
1946 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1947 outline->shape = shape;
1948 outline->bbox = bounds;
1950 dictionary_put2(&outlines, name, outline);
1953 int s_playsound(char*name, int loops, int nomultiple, int stop)
1959 sound = dictionary_lookup(&sounds, name);
1963 tag = swf_InsertTag(tag, ST_STARTSOUND);
1964 swf_SetU16(tag, sound->id); //id
1965 memset(&info, 0, sizeof(info));
1968 info.nomultiple = nomultiple;
1969 swf_SetSoundInfo(tag, &info);
1973 void s_includeswf(char*name, char*filename)
1981 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1982 f = open(filename,O_RDONLY|O_BINARY);
1984 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1985 s_box(name, 0, 0, black, 20, 0);
1988 if (swf_ReadSWF(f,&swf)<0) {
1989 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1990 s_box(name, 0, 0, black, 20, 0);
1995 /* FIXME: The following sets the bounding Box for the character.
1996 It is wrong for two reasons:
1997 a) It may be too small (in case objects in the movie clip at the borders)
1998 b) it may be too big (because the poor movie never got autocropped)
2002 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2003 swf_SetU16(tag, id);
2004 swf_SetU16(tag, swf.frameCount);
2006 swf_Relocate(&swf, idmap);
2008 ftag = swf.firstTag;
2012 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2013 if(cutout[t] == ftag->id) {
2017 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2019 if(ftag->id == ST_END)
2024 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2025 /* We simply dump all tags right after the sprite
2026 header, relying on the fact that swf_OptimizeTagOrder() will
2027 sort things out for us later.
2028 We also rely on the fact that the imported SWF is well-formed.
2030 tag = swf_InsertTag(tag, ftag->id);
2031 swf_SetBlock(tag, ftag->data, ftag->len);
2037 syntaxerror("Included file %s contains errors", filename);
2038 tag = swf_InsertTag(tag, ST_END);
2042 s_addcharacter(name, id, tag, r);
2045 SRECT s_getCharBBox(char*name)
2047 character_t* c = dictionary_lookup(&characters, name);
2048 if(!c) syntaxerror("character '%s' unknown(2)", name);
2051 SRECT s_getInstanceBBox(char*name)
2053 instance_t * i = dictionary_lookup(&instances, name);
2055 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2057 if(!c) syntaxerror("internal error(5)");
2060 void s_getParameters(char*name, parameters_t* p)
2062 instance_t * i = dictionary_lookup(&instances, name);
2064 syntaxerror("instance '%s' unknown(10)", name);
2065 if (change_sets_all)
2066 readParameters(i->history, p, currentframe);
2071 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2073 history_begin(i->history, "x", currentframe, tag, p->x);
2074 history_begin(i->history, "y", currentframe, tag, p->y);
2075 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2076 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2077 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2078 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2079 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2080 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2081 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2082 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2083 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2084 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2085 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2086 history_begin(i->history, "shear", currentframe, tag, p->shear);
2087 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2088 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2089 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2090 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2091 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2092 history_beginFilter(i->history, currentframe, tag, p->filters);
2093 history_begin(i->history, "flags", currentframe, tag, 0);
2096 void s_startclip(char*instance, char*character, parameters_t p)
2098 character_t* c = dictionary_lookup(&characters, character);
2102 syntaxerror("character %s not known", character);
2104 i = s_addinstance(instance, c, currentdepth);
2106 m = s_instancepos(i->character->size, &p);
2108 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2109 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2110 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2112 stack[stackpos].tag = tag;
2113 stack[stackpos].type = 2;
2116 setStartparameters(i, &p, tag);
2123 swf_SetTagPos(stack[stackpos].tag, 0);
2124 swf_GetPlaceObject(stack[stackpos].tag, &p);
2125 p.clipdepth = currentdepth;
2127 swf_ClearTag(stack[stackpos].tag);
2128 swf_SetPlaceObject(stack[stackpos].tag, &p);
2132 void s_put(char*instance, char*character, parameters_t p)
2134 character_t* c = dictionary_lookup(&characters, character);
2138 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2140 i = s_addinstance(instance, c, currentdepth);
2142 m = s_instancepos(i->character->size, &p);
2144 if(p.blendmode || p.filters)
2146 if(stack[0].swf->fileVersion < 8)
2149 warning("blendmodes only supported for flash version>=8");
2151 warning("filters only supported for flash version>=8");
2153 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2156 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2157 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2158 setStartparameters(i, &p, tag);
2162 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2165 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2167 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2168 if (p.set & SF_SCALEX)
2169 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2170 if (p.set & SF_SCALEY)
2171 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2172 if (p.set & SF_CX_R)
2174 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2175 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2177 if (p.set & SF_CX_G)
2179 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2180 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2182 if (p.set & SF_CX_B)
2184 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2185 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2187 if (p.set & SF_CX_A)
2189 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2190 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2192 if (p.set & SF_ROTATE)
2193 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2194 if (p.set & SF_SHEAR)
2195 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2196 if (p.set & SF_PIVOT)
2198 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2199 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2203 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2204 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2206 if (p.set & SF_BLEND)
2207 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2208 if (p.set & SF_FILTER)
2209 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2212 void s_jump(char* instance, parameters_t p)
2214 instance_t* i = dictionary_lookup(&instances, instance);
2216 syntaxerror("instance %s not known", instance);
2217 recordChanges(i->history, p, CF_JUMP, 0);
2220 void s_change(char*instance, parameters_t p, interpolation_t* inter)
2222 instance_t* i = dictionary_lookup(&instances, instance);
2224 syntaxerror("instance %s not known", instance);
2225 recordChanges(i->history, p, CF_CHANGE, inter);
2228 void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2230 instance_t* i = dictionary_lookup(&instances, instance);
2232 syntaxerror("instance %s not known", instance);
2233 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2236 void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
2238 instance_t* i = dictionary_lookup(&instances, instance);
2240 syntaxerror("instance %s not known", instance);
2241 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2244 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2247 void s_delinstance(char*instance)
2249 instance_t* i = dictionary_lookup(&instances, instance);
2251 syntaxerror("instance %s not known", instance);
2253 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2254 swf_SetU16(tag, i->depth);
2255 dictionary_del(&instances, instance);
2258 void s_schange(char*instance, parameters_t p, interpolation_t* inter)
2260 instance_t* i = dictionary_lookup(&instances, instance);
2262 syntaxerror("instance %s not known", instance);
2263 recordChanges(i->history, p, CF_SCHANGE, inter);
2269 syntaxerror(".end unexpected");
2270 switch (stack[stackpos-1].type)
2285 syntaxerror("internal error 1");
2289 // ------------------------------------------------------------------------
2291 typedef int command_func_t(map_t*args);
2293 SRECT parseBox(char*str)
2295 SRECT r = {0,0,0,0};
2296 float xmin, xmax, ymin, ymax;
2297 char*x = strchr(str, 'x');
2299 if(!strcmp(str, "autocrop")) {
2300 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2304 d1 = strchr(x+1, ':');
2306 d2 = strchr(d1+1, ':');
2308 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2312 else if(d1 && !d2) {
2313 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2319 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2324 r.xmin = (SCOORD)(xmin*20);
2325 r.ymin = (SCOORD)(ymin*20);
2326 r.xmax = (SCOORD)(xmax*20);
2327 r.ymax = (SCOORD)(ymax*20);
2330 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2333 float parseFloat(char*str)
2337 int parseInt(char*str)
2342 if(str[0]=='+' || str[0]=='-')
2346 if(str[t]<'0' || str[t]>'9')
2347 syntaxerror("Not an Integer: \"%s\"", str);
2350 int parseRawTwip(char*str)
2354 if(str[0]=='+' || str[0]=='-') {
2359 dot = strchr(str, '.');
2363 return sign*parseInt(str)*20;
2365 char* old = strdup(str);
2366 int l=strlen(dot+1);
2369 for(s=str;s<dot-1;s++)
2370 if(*s<'0' || *s>'9')
2373 syntaxerror("Not a coordinate: \"%s\"", str);
2376 if(*s<'0' || *s>'9')
2379 syntaxerror("Not a coordinate: \"%s\"", str);
2381 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2382 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2385 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2389 return sign*(atoi(str)*20);
2391 return sign*(atoi(str)*20+atoi(dot)*2);
2393 return sign*(atoi(str)*20+atoi(dot)/5);
2398 static dictionary_t defines;
2399 static int defines_initialized = 0;
2400 static mem_t define_values;
2402 int parseTwip(char*str)
2404 /* TODO: make this a proper expression parser */
2417 if((*p == '+' || *p == '-' || *p == 0) && lastpos) {
2423 if(defines_initialized) {
2424 l = (int)dictionary_lookup(&defines, lastpos);
2427 v = *(int*)&define_values.buffer[l-1];
2429 v = parseRawTwip(lastpos);
2440 int parseArc(char* str)
2442 if (!strcmp(str, "short"))
2444 if (!strcmp(str, "long"))
2446 syntaxerror("invalid value for the arc parameter: %s", str);
2450 int parseDir(char* str)
2452 if (!strcmp(str, "clockwise"))
2454 if (!strcmp(str, "counterclockwise"))
2456 syntaxerror("invalid value for the dir parameter: %s", str);
2460 int isPoint(char*str)
2462 if(strchr(str, '('))
2468 SPOINT parsePoint(char*str)
2472 int l = strlen(str);
2473 char*comma = strchr(str, ',');
2474 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2475 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2476 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2477 p.x = parseTwip(tmp);
2478 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2479 p.y = parseTwip(tmp);
2483 int parseColor2(char*str, RGBA*color)
2485 int l = strlen(str);
2489 struct {unsigned char r,g,b;char*name;} colors[] =
2490 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2491 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2492 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2493 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2494 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2495 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2496 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2497 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2498 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2499 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2500 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2501 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2505 if(str[0]=='#' && (l==7 || l==9)) {
2506 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2508 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2510 color->r = r; color->g = g; color->b = b; color->a = a;
2513 int len=strlen(str);
2515 if(strchr(str, '/')) {
2516 len = strchr(str, '/')-str;
2517 sscanf(str+len+1,"%02x", &alpha);
2519 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2520 if(!strncmp(str, colors[t].name, len)) {
2525 color->r = r; color->g = g; color->b = b; color->a = a;
2531 RGBA parseColor(char*str)
2534 if(!parseColor2(str, &c))
2535 syntaxerror("Expression '%s' is not a color", str);
2539 typedef struct _muladd {
2544 MULADD parseMulAdd(char*str)
2547 char* str2 = (char*)malloc(strlen(str)+5);
2554 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2555 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2556 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2557 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2558 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2559 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2560 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2561 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2562 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2563 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2565 syntaxerror("'%s' is not a valid color transform expression", str);
2567 m.add = (int)(add*256);
2568 m.mul = (int)(mul*256);
2573 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2575 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2576 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2578 if(a<-32768) a=-32768;
2579 if(a>32767) a=32767;
2580 if(m<-32768) m=-32768;
2581 if(m>32767) m=32767;
2587 float parsePxOrPercent(char*fontname, char*str)
2589 int l = strlen(str);
2590 if(strchr(str, '%'))
2591 return parsePercent(str);
2592 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2593 float p = atof(str);
2594 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2596 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2600 float parsePercent(char*str)
2602 int l = strlen(str);
2606 return atoi(str)/100.0;
2608 syntaxerror("Expression '%s' is not a percentage", str);
2611 int isPercent(char*str)
2613 return str[strlen(str)-1]=='%';
2615 int parseNewSize(char*str, int size)
2618 return parsePercent(str)*size;
2620 return (int)(atof(str)*20);
2623 int isColor(char*str)
2626 return parseColor2(str, &c);
2629 static char* lu(map_t* args, char*name)
2631 char* value = map_lookup(args, name);
2633 map_dump(args, stdout, "");
2634 syntaxerror("internal error 2: value %s should be set", name);
2639 static int c_flash(map_t*args)
2641 char* filename = map_lookup(args, "filename");
2642 char* compressstr = lu(args, "compress");
2643 char* change_modestr = lu(args, "change-sets-all");
2644 char* exportstr = lu(args, "export");
2645 SRECT bbox = parseBox(lu(args, "bbox"));
2646 int version = parseInt(lu(args, "version"));
2647 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2648 RGBA color = parseColor(lu(args, "background"));
2651 if(!filename || !*filename) {
2652 /* for compatibility */
2653 filename = map_lookup(args, "name");
2654 if(!filename || !*filename) {
2657 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2658 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2662 if(!filename || override_outputname)
2663 filename = outputname;
2665 if(!strcmp(compressstr, "default"))
2666 compress = version>=6;
2667 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2669 else if(!strcmp(compressstr, "no"))
2671 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2673 if(!strcmp(change_modestr, "yes"))
2674 change_sets_all = 1;
2676 if(strcmp(change_modestr, "no"))
2677 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2679 do_exports=atoi(exportstr);
2681 s_swf(filename, bbox, version, fps, compress, color);
2684 int isRelative(char*str)
2686 return !strncmp(str, "<plus>", 6) ||
2687 !strncmp(str, "<minus>", 7);
2689 char* getOffset(char*str)
2691 if(!strncmp(str, "<plus>", 6))
2693 if(!strncmp(str, "<minus>", 7))
2695 syntaxerror("internal error (347)");
2698 int getSign(char*str)
2700 if(!strncmp(str, "<plus>", 6))
2702 if(!strncmp(str, "<minus>", 7))
2704 syntaxerror("internal error (348)");
2708 static dictionary_t points;
2709 static mem_t mpoints;
2710 static int points_initialized = 0;
2712 static int c_interpolation(map_t *args)
2715 char* name = lu(args, "name");
2716 if (dictionary_lookup(&interpolations, name))
2717 syntaxerror("interpolation %s defined twice", name);
2719 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2720 char* functionstr = lu(args, "function");
2721 inter->function = 0;
2722 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2723 if (!strcmp(functionstr,interpolationFunctions[i]))
2725 inter->function = i + 1;
2728 if (!inter->function)
2729 syntaxerror("unkown interpolation function %s", functionstr);
2730 inter->speed = parseFloat(lu(args, "speed"));
2731 inter->amplitude = parseTwip(lu(args, "amplitude"));
2732 inter->growth = parseFloat(lu(args, "growth"));
2733 inter->bounces = parseInt(lu(args, "bounces"));
2734 inter->damping = parseFloat(lu(args, "damping"));
2735 inter->slope = parseFloat(lu(args, "slope"));
2737 dictionary_put2(&interpolations, name, inter);
2741 SPOINT getPoint(SRECT r, char*name)
2744 if(!strcmp(name, "center")) {
2746 p.x = (r.xmin + r.xmax)/2;
2747 p.y = (r.ymin + r.ymax)/2;
2750 if (!strcmp(name, "bottom-center")) {
2752 p.x = (r.xmin + r.xmax)/2;
2756 if (!strcmp(name, "top-center")) {
2758 p.x = (r.xmin + r.xmax)/2;
2762 if (!strcmp(name, "top-left")) {
2768 if (!strcmp(name, "top-right")) {
2774 if (!strcmp(name, "bottom-right")) {
2780 if (!strcmp(name, "bottom-left")) {
2786 if (!strcmp(name, "left-center")) {
2789 p.y = (r.ymin + r.ymax)/2;
2792 if (!strcmp(name, "right-center")) {
2795 p.y = (r.ymin + r.ymax)/2;
2800 if(points_initialized)
2801 l = (int)dictionary_lookup(&points, name);
2803 syntaxerror("Invalid point: \"%s\".", name);
2805 return *(SPOINT*)&mpoints.buffer[l-1];
2809 static int texture2(char*name, char*object, map_t*args, int errors)
2812 char*xstr = map_lookup(args, "x");
2813 char*ystr = map_lookup(args, "y");
2814 char*widthstr = map_lookup(args, "width");
2815 char*heightstr = map_lookup(args, "height");
2816 char*scalestr = map_lookup(args, "scale");
2817 char*scalexstr = map_lookup(args, "scalex");
2818 char*scaleystr = map_lookup(args, "scaley");
2819 char*rotatestr = map_lookup(args, "rotate");
2820 char* shearstr = map_lookup(args, "shear");
2821 char* radiusstr = map_lookup(args, "r");
2823 float scalex = 1.0, scaley = 1.0;
2824 float rotate=0, shear=0;
2826 if(!*xstr && !*ystr) {
2828 syntaxerror("x and y must be set");
2831 if(*scalestr && (*scalexstr || *scaleystr)) {
2832 syntaxerror("scale and scalex/scaley can't both be set");
2835 if((*widthstr || *heightstr) && *radiusstr) {
2836 syntaxerror("width/height and radius can't both be set");
2839 widthstr = radiusstr;
2840 heightstr = radiusstr;
2842 if(!*xstr) xstr="0";
2843 if(!*ystr) ystr="0";
2844 if(!*rotatestr) rotatestr="0";
2845 if(!*shearstr) shearstr="0";
2848 scalex = scaley = parsePercent(scalestr);
2849 } else if(*scalexstr || *scaleystr) {
2850 if(scalexstr) scalex = parsePercent(scalexstr);
2851 if(scaleystr) scaley = parsePercent(scaleystr);
2852 } else if(*widthstr || *heightstr) {
2855 s_getBitmapSize(object, &width, &height);
2857 scalex = (float)parseTwip(widthstr)/(float)width;
2859 scaley = (float)parseTwip(heightstr)/(float)height;
2861 x = parseTwip(xstr);
2862 y = parseTwip(ystr);
2863 rotate = parseFloat(rotatestr);
2864 shear = parseFloat(shearstr);
2866 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2871 static int c_texture(map_t*args)
2873 char*name = lu(args, "instance");
2874 char*object = lu(args, "character");
2875 return texture2(name, object, args, 1);
2878 static int c_gradient(map_t*args)
2880 char*name = lu(args, "name");
2881 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2882 int rotate = parseInt(lu(args, "rotate"));
2886 syntaxerror("colon (:) expected");
2888 if(dictionary_lookup(&gradients, name))
2889 syntaxerror("gradient %s defined twice", name);
2891 s_gradient(name, text, radial, rotate);
2893 /* check whether we also have placement information,
2894 which would make this a positioned gradient.
2895 If there is placement information, texture2() will
2896 add a texture, which has priority over the gradient.
2898 texture2(name, name, args, 0);
2902 static char* checkFiltername(map_t* args)
2904 char* name = lu(args, "name");
2905 if (strchr(name, ','))
2906 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
2910 static int c_blur(map_t*args)
2912 char*name = checkFiltername(args);
2913 char*blurstr = lu(args, "blur");
2914 char*blurxstr = lu(args, "blurx");
2915 char*blurystr = lu(args, "blury");
2916 float blurx=1.0, blury=1.0;
2918 blurx = parseFloat(blurstr);
2919 blury = parseFloat(blurstr);
2922 blurx = parseFloat(blurxstr);
2924 blury = parseFloat(blurystr);
2925 int passes = parseInt(lu(args, "passes"));
2926 s_blur(name, blurx, blury, passes);
2930 static int c_gradientglow(map_t*args)
2932 char*name = checkFiltername(args);
2933 char*gradient = lu(args, "gradient");
2934 char*blurstr = lu(args, "blur");
2935 char*blurxstr = lu(args, "blurx");
2936 char*blurystr = lu(args, "blury");
2937 float blurx=1.0, blury=1.0;
2939 blurx = parseFloat(blurstr);
2940 blury = parseFloat(blurstr);
2943 blurx = parseFloat(blurxstr);
2945 blury = parseFloat(blurystr);
2947 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2948 float distance = parseFloat(lu(args, "distance"));
2949 float strength = parseFloat(lu(args, "strength"));
2950 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2951 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2952 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2953 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2954 int passes = parseInt(lu(args, "passes"));
2956 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2960 static int c_dropshadow(map_t*args)
2962 char*name = checkFiltername(args);
2963 RGBA color = parseColor(lu(args, "color"));
2964 char*blurstr = lu(args, "blur");
2965 char*blurxstr = lu(args, "blurx");
2966 char*blurystr = lu(args, "blury");
2967 float blurx=1.0, blury=1.0;
2969 blurx = parseFloat(blurstr);
2970 blury = parseFloat(blurstr);
2973 blurx = parseFloat(blurxstr);
2975 blury = parseFloat(blurystr);
2977 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2978 float distance = parseFloat(lu(args, "distance"));
2979 float strength = parseFloat(lu(args, "strength"));
2980 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2981 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2982 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2983 int passes = parseInt(lu(args, "passes"));
2985 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2989 static int c_bevel(map_t*args)
2991 char*name = checkFiltername(args);
2992 RGBA shadow = parseColor(lu(args, "shadow"));
2993 RGBA highlight = parseColor(lu(args, "highlight"));
2994 char*blurstr = lu(args, "blur");
2995 char*blurxstr = lu(args, "blurx");
2996 char*blurystr = lu(args, "blury");
2997 float blurx=1.0, blury=1.0;
2999 blurx = parseFloat(blurstr);
3000 blury = parseFloat(blurstr);
3003 blurx = parseFloat(blurxstr);
3005 blury = parseFloat(blurystr);
3007 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3008 float distance = parseFloat(lu(args, "distance"));
3009 float strength = parseFloat(lu(args, "strength"));
3010 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3011 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3012 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3013 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3014 int passes = parseInt(lu(args, "passes"));
3016 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3020 static int c_define(map_t*args)
3022 char*name = lu(args, "name");
3023 char*value = lu(args, "value");
3025 if(!defines_initialized) {
3026 dictionary_init(&defines);
3027 mem_init(&define_values);
3028 defines_initialized = 1;
3030 int val = parseTwip(value);
3031 int pos = mem_put(&define_values, &val, sizeof(val));
3033 string_set(&s, name);
3034 dictionary_put(&defines, s, (void*)(pos+1));
3037 static int c_point(map_t*args)
3039 char*name = lu(args, "name");
3043 if(!points_initialized) {
3044 dictionary_init(&points);
3046 points_initialized = 1;
3048 p.x = parseTwip(lu(args, "x"));
3049 p.y = parseTwip(lu(args, "y"));
3050 pos = mem_put(&mpoints, &p, sizeof(p));
3051 string_set(&s1, name);
3052 dictionary_put(&points, s1, (void*)(pos+1));
3055 static int c_play(map_t*args)
3057 char*name = lu(args, "name");
3058 char*loop = lu(args, "loop");
3059 char*nomultiple = lu(args, "nomultiple");
3061 if(!strcmp(nomultiple, "nomultiple"))
3064 nm = parseInt(nomultiple);
3066 if(s_playsound(name, parseInt(loop), nm, 0)) {
3068 } else if(s_swf3action(name, "play")) {
3074 static int c_stop(map_t*args)
3076 char*name = map_lookup(args, "name");
3078 if(s_playsound(name, 0,0,1))
3080 else if(s_swf3action(name, "stop"))
3082 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3086 static int c_nextframe(map_t*args)
3088 char*name = lu(args, "name");
3090 if(s_swf3action(name, "nextframe")) {
3093 syntaxerror("I don't know anything about movie \"%s\"", name);
3097 static int c_previousframe(map_t*args)
3099 char*name = lu(args, "name");
3101 if(s_swf3action(name, "previousframe")) {
3104 syntaxerror("I don't know anything about movie \"%s\"", name);
3108 static int c_movement(map_t*args, int type)
3110 char*instance = lu(args, "name");
3118 xstr = lu(args, "x");
3119 ystr = lu(args, "y");
3121 s_getParameters(instance, &p);
3126 if(isRelative(xstr))
3128 if(type == PT_PUT || type == PT_STARTCLIP)
3129 syntaxerror("relative x values not allowed for initial put or startclip");
3130 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3134 p.x = parseTwip(xstr);
3140 if(isRelative(ystr))
3142 if(type == PT_PUT || type == PT_STARTCLIP)
3143 syntaxerror("relative y values not allowed for initial put or startclip");
3144 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3148 p.y = parseTwip(ystr);
3153 if (change_sets_all)
3161 char* interstr = lu(args, "interpolation");
3162 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3164 syntaxerror("unkown interpolation %s", interstr);
3165 s_change(instance, p, inter);
3170 char* interstr = lu(args, "interpolation");
3171 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3173 syntaxerror("unkown interpolation %s", interstr);
3174 s_schange(instance, p, inter);
3179 char* rstr = lu(args, "r");
3180 int radius = parseTwip(rstr);
3182 syntaxerror("sweep not possible: radius must be greater than 0.");
3183 char* dirstr = lu(args, "dir");
3184 int clockwise = parseDir(dirstr);
3185 char* arcstr = lu(args, "arc");
3186 int short_arc = parseArc(arcstr);
3187 char* interstr = lu(args, "interpolation");
3188 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3190 syntaxerror("unkown interpolation %s", interstr);
3191 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3198 static int c_placement(map_t*args, int type)
3200 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3203 char* luminancestr = lu(args, "luminance");
3204 char* scalestr = lu(args, "scale");
3205 char* scalexstr = lu(args, "scalex");
3206 char* scaleystr = lu(args, "scaley");
3207 char* rotatestr = lu(args, "rotate");
3208 char* shearstr = lu(args, "shear");
3209 char* xstr="", *pivotstr="";
3210 char* ystr="", *anglestr="";
3211 char*above = lu(args, "above"); /*FIXME*/
3212 char*below = lu(args, "below");
3213 char* rstr = lu(args, "red");
3214 char* gstr = lu(args, "green");
3215 char* bstr = lu(args, "blue");
3216 char* astr = lu(args, "alpha");
3217 char* pinstr = lu(args, "pin");
3218 char* as = map_lookup(args, "as");
3219 char* blendmode = lu(args, "blend");
3220 char* filterstr = lu(args, "filter");
3231 { // (?) .rotate or .arcchange
3232 pivotstr = lu(args, "pivot");
3233 anglestr = lu(args, "angle");
3237 xstr = lu(args, "x");
3238 ystr = lu(args, "y");
3242 luminance = parseMulAdd(luminancestr);
3246 luminance.mul = 256;
3251 if(scalexstr[0]||scaleystr[0])
3252 syntaxerror("scalex/scaley and scale cannot both be set");
3253 scalexstr = scaleystr = scalestr;
3256 if(type == PT_PUT || type == PT_STARTCLIP) {
3258 character = lu(args, "character");
3259 parameters_clear(&p);
3260 } else if (type == PT_BUTTON) {
3261 character = lu(args, "name");
3262 parameters_clear(&p);
3265 s_getParameters(instance, &p);
3271 if(isRelative(xstr))
3273 if(type == PT_PUT || type == PT_STARTCLIP)
3274 syntaxerror("relative x values not allowed for initial put or startclip");
3275 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3279 p.x = parseTwip(xstr);
3285 if(isRelative(ystr))
3287 if(type == PT_PUT || type == PT_STARTCLIP)
3288 syntaxerror("relative y values not allowed for initial put or startclip");
3289 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3293 p.y = parseTwip(ystr);
3298 /* scale, scalex, scaley */
3300 oldbbox = s_getCharBBox(character);
3302 oldbbox = s_getInstanceBBox(instance);
3303 oldwidth = oldbbox.xmax - oldbbox.xmin;
3304 oldheight = oldbbox.ymax - oldbbox.ymin;
3311 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3312 set = set | SF_SCALEX;
3320 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3321 set = set | SF_SCALEY;
3327 if(isRelative(rotatestr))
3328 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3330 p.rotate = parseFloat(rotatestr);
3331 set = set | SF_ROTATE;
3337 if(isRelative(shearstr))
3338 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3340 p.shear = parseFloat(shearstr);
3341 set = set | SF_SHEAR;
3346 if(isPoint(pivotstr))
3347 p.pivot = parsePoint(pivotstr);
3349 p.pivot = getPoint(oldbbox, pivotstr);
3350 set = set | SF_PIVOT;
3356 p.pin = parsePoint(pinstr);
3358 p.pin = getPoint(oldbbox, pinstr);
3362 /* color transform */
3364 if(rstr[0] || luminancestr[0])
3368 r = parseMulAdd(rstr);
3371 r.add = p.cxform.r0;
3372 r.mul = p.cxform.r1;
3374 r = mergeMulAdd(r, luminance);
3375 p.cxform.r0 = r.mul;
3376 p.cxform.r1 = r.add;
3377 set = set | SF_CX_R;
3379 if(gstr[0] || luminancestr[0])
3383 g = parseMulAdd(gstr);
3386 g.add = p.cxform.g0;
3387 g.mul = p.cxform.g1;
3389 g = mergeMulAdd(g, luminance);
3390 p.cxform.g0 = g.mul;
3391 p.cxform.g1 = g.add;
3392 set = set | SF_CX_G;
3394 if(bstr[0] || luminancestr[0])
3398 b = parseMulAdd(bstr);
3401 b.add = p.cxform.b0;
3402 b.mul = p.cxform.b1;
3404 b = mergeMulAdd(b, luminance);
3405 p.cxform.b0 = b.mul;
3406 p.cxform.b1 = b.add;
3407 set = set | SF_CX_B;
3411 MULADD a = parseMulAdd(astr);
3412 p.cxform.a0 = a.mul;
3413 p.cxform.a1 = a.add;
3414 set = set | SF_CX_A;
3421 for(t = 0; blendModeNames[t]; t++)
3423 if(!strcmp(blendModeNames[t], blendmode))
3431 syntaxerror("unknown blend mode: '%s'", blendmode);
3433 p.blendmode = blend;
3434 set = set | SF_BLEND;
3439 p.filters = parseFilters(filterstr);
3440 set = set | SF_FILTER;
3443 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3444 warning("As of version 0.8.2 using the .change command to modify an \
3445 object's position on the stage is considered deprecated. Future \
3446 versions may consider x and y parameters for the .change command \
3447 to be illegal; please use the .move command.");
3449 if (change_sets_all)
3456 s_put(instance, character, p);
3460 char* interstr = lu(args, "interpolation");
3461 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3463 syntaxerror("unkown interpolation %s", interstr);
3464 s_change(instance, p, inter);
3469 char* interstr = lu(args, "interpolation");
3470 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3472 syntaxerror("unkown interpolation %s", interstr);
3473 s_schange(instance, p, inter);
3477 s_jump(instance, p);
3480 s_startclip(instance, character, p);
3484 s_buttonput(character, as, p);
3486 s_buttonput(character, "shape", p);
3492 static int c_put(map_t*args)
3494 c_placement(args, PT_PUT);
3497 static int c_change(map_t*args)
3499 if (currentframe == 0)
3500 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3501 c_placement(args, PT_CHANGE);
3504 static int c_schange(map_t*args)
3506 c_placement(args, PT_SCHANGE);
3509 static int c_move(map_t* args)
3511 c_movement(args, PT_MOVE);
3514 static int c_smove(map_t* args)
3516 c_movement(args, PT_SMOVE);
3519 static int c_sweep(map_t* args)
3521 c_movement(args, PT_SWEEP);
3524 static int c_arcchange(map_t*args)
3526 c_placement(args, 0);
3529 static int c_jump(map_t*args)
3531 c_placement(args, PT_JUMP);
3534 static int c_startclip(map_t*args)
3536 c_placement(args, PT_STARTCLIP);
3539 static int c_show(map_t*args)
3541 c_placement(args, PT_BUTTON);
3544 static int c_toggle(map_t* args)
3546 char*instance = lu(args, "name");
3547 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3548 char* alignstr = lu(args, "fixed_alignment");
3549 if (!strcmp(alignstr, "on"))
3550 flagsOn += IF_FIXED_ALIGNMENT;
3552 if (!strcmp(alignstr, "off"))
3553 flagsOff -= IF_FIXED_ALIGNMENT;
3555 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3556 s_toggle(instance, flagsOn, flagsOff);
3559 static int c_del(map_t*args)
3561 char*instance = lu(args, "name");
3562 s_delinstance(instance);
3565 static int c_end(map_t*args)
3570 static int c_sprite(map_t*args)
3572 char* name = lu(args, "name");
3573 char* scalinggrid = lu(args, "scalinggrid");
3575 if(scalinggrid && *scalinggrid) {
3576 SRECT r = parseBox(scalinggrid);
3583 static int c_frame(map_t*args)
3585 char*framestr = lu(args, "n");
3586 char*cutstr = lu(args, "cut");
3588 char*name = lu(args, "name");
3589 char*anchor = lu(args, "anchor");
3592 if(!strcmp(anchor, "anchor") && !*name)
3597 if(strcmp(cutstr, "no"))
3599 if(isRelative(framestr)) {
3600 frame = s_getframe();
3601 if(getSign(framestr)<0)
3602 syntaxerror("relative frame expressions must be positive");
3603 frame += parseInt(getOffset(framestr));
3606 frame = parseInt(framestr);
3607 if(s_getframe() >= frame
3608 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3609 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3611 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3614 static int c_primitive(map_t*args)
3616 char*name = lu(args, "name");
3617 char*command = lu(args, "commandname");
3618 int width=0, height=0, r=0;
3619 int linewidth = parseTwip(lu(args, "line"));
3620 char*colorstr = lu(args, "color");
3621 RGBA color = parseColor(colorstr);
3622 char*fillstr = lu(args, "fill");
3629 if(!strcmp(command, "circle"))
3631 else if(!strcmp(command, "filled"))
3635 width = parseTwip(lu(args, "width"));
3636 height = parseTwip(lu(args, "height"));
3637 } else if (type==1) {
3638 r = parseTwip(lu(args, "r"));
3639 } else if (type==2) {
3640 outline = lu(args, "outline");
3643 if(!strcmp(fillstr, "fill"))
3645 if(!strcmp(fillstr, "none"))
3647 if(width<0 || height<0 || linewidth<0 || r<0)
3648 syntaxerror("values width, height, line, r must be positive");
3650 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3651 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3652 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3656 static int c_textshape(map_t*args)
3658 char*name = lu(args, "name");
3659 char*text = lu(args, "text");
3660 char*font = lu(args, "font");
3661 float size = parsePxOrPercent(font, lu(args, "size"));
3663 s_textshape(name, font, size, text);
3667 static int c_swf(map_t*args)
3669 char*name = lu(args, "name");
3670 char*filename = lu(args, "filename");
3671 char*command = lu(args, "commandname");
3672 if(!strcmp(command, "shape"))
3673 warning("Please use .swf instead of .shape");
3674 s_includeswf(name, filename);
3678 static int c_font(map_t*args)
3680 char*name = lu(args, "name");
3681 char*filename = lu(args, "filename");
3682 s_font(name, filename);
3686 static int c_sound(map_t*args)
3688 char*name = lu(args, "name");
3689 char*filename = lu(args, "filename");
3690 s_sound(name, filename);
3694 static int c_text(map_t*args)
3696 char*name = lu(args, "name");
3697 char*text = lu(args, "text");
3698 char*font = lu(args, "font");
3699 float size = parsePxOrPercent(font, lu(args, "size"));
3700 RGBA color = parseColor(lu(args, "color"));
3701 s_text(name, font, text, (int)(size*100), color);
3705 static int c_soundtrack(map_t*args)
3710 static int c_quicktime(map_t*args)
3712 char*name = lu(args, "name");
3713 char*url = lu(args, "url");
3714 s_quicktime(name, url);
3718 static int c_image(map_t*args)
3720 char*command = lu(args, "commandname");
3721 char*name = lu(args, "name");
3722 char*filename = lu(args, "filename");
3723 if(!strcmp(command,"jpeg")) {
3724 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3725 s_image(name, "jpeg", filename, quality);
3727 s_image(name, "png", filename, 0);
3732 static int c_outline(map_t*args)
3734 char*name = lu(args, "name");
3735 char*format = lu(args, "format");
3739 syntaxerror("colon (:) expected");
3741 s_outline(name, format, text);
3745 int fakechar(map_t*args)
3747 char*name = lu(args, "name");
3748 s_box(name, 0, 0, black, 20, 0);
3752 static int c_egon(map_t*args) {return fakechar(args);}
3753 static int c_button(map_t*args) {
3754 char*name = lu(args, "name");
3758 static int current_button_flags = 0;
3759 static int c_on_press(map_t*args)
3761 char*position = lu(args, "position");
3763 if(!strcmp(position, "inside")) {
3764 current_button_flags |= BC_OVERUP_OVERDOWN;
3765 } else if(!strcmp(position, "outside")) {
3766 //current_button_flags |= BC_IDLE_OUTDOWN;
3767 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3768 } else if(!strcmp(position, "anywhere")) {
3769 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3772 if(type == RAWDATA) {
3774 s_buttonaction(current_button_flags, action);
3775 current_button_flags = 0;
3781 static int c_on_release(map_t*args)
3783 char*position = lu(args, "position");
3785 if(!strcmp(position, "inside")) {
3786 current_button_flags |= BC_OVERDOWN_OVERUP;
3787 } else if(!strcmp(position, "outside")) {
3788 current_button_flags |= BC_OUTDOWN_IDLE;
3789 } else if(!strcmp(position, "anywhere")) {
3790 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3793 if(type == RAWDATA) {
3795 s_buttonaction(current_button_flags, action);
3796 current_button_flags = 0;
3802 static int c_on_move_in(map_t*args)
3804 char*position = lu(args, "state");
3806 if(!strcmp(position, "pressed")) {
3807 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3808 } else if(!strcmp(position, "not_pressed")) {
3809 current_button_flags |= BC_IDLE_OVERUP;
3810 } else if(!strcmp(position, "any")) {
3811 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3814 if(type == RAWDATA) {
3816 s_buttonaction(current_button_flags, action);
3817 current_button_flags = 0;
3823 static int c_on_move_out(map_t*args)
3825 char*position = lu(args, "state");
3827 if(!strcmp(position, "pressed")) {
3828 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3829 } else if(!strcmp(position, "not_pressed")) {
3830 current_button_flags |= BC_OVERUP_IDLE;
3831 } else if(!strcmp(position, "any")) {
3832 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3835 if(type == RAWDATA) {
3837 s_buttonaction(current_button_flags, action);
3838 current_button_flags = 0;
3844 static int c_on_key(map_t*args)
3846 char*key = lu(args, "key");
3848 if(strlen(key)==1) {
3851 current_button_flags |= 0x4000 + (key[0]*0x200);
3853 syntaxerror("invalid character: %c"+key[0]);
3858 <ctrl-x> = 0x200*(x-'a')
3862 syntaxerror("invalid key: %s",key);
3865 if(type == RAWDATA) {
3867 s_buttonaction(current_button_flags, action);
3868 current_button_flags = 0;
3875 static int c_edittext(map_t*args)
3877 //"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"},
3878 char*name = lu(args, "name");
3879 char*font = lu(args, "font");
3880 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3881 int width = parseTwip(lu(args, "width"));
3882 int height = parseTwip(lu(args, "height"));
3883 char*text = lu(args, "text");
3884 RGBA color = parseColor(lu(args, "color"));
3885 int maxlength = parseInt(lu(args, "maxlength"));
3886 char*variable = lu(args, "variable");
3887 char*passwordstr = lu(args, "password");
3888 char*wordwrapstr = lu(args, "wordwrap");
3889 char*multilinestr = lu(args, "multiline");
3890 char*htmlstr = lu(args, "html");
3891 char*noselectstr = lu(args, "noselect");
3892 char*readonlystr = lu(args, "readonly");
3893 char*borderstr = lu(args, "border");
3894 char*autosizestr = lu(args, "autosize");
3895 char*alignstr = lu(args, "align");
3899 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3900 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3901 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3902 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3903 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3904 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3905 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3906 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3907 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3908 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3909 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3910 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3911 else syntaxerror("Unknown alignment: %s", alignstr);
3913 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3917 static int c_morphshape(map_t*args) {return fakechar(args);}
3918 static int c_movie(map_t*args) {return fakechar(args);}
3920 static char* readfile(const char*filename)
3922 FILE*fi = fopen(filename, "rb");
3926 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3927 fseek(fi, 0, SEEK_END);
3929 fseek(fi, 0, SEEK_SET);
3930 text = rfx_alloc(l+1);
3931 fread(text, l, 1, fi);
3937 static int c_action(map_t*args)
3939 char* filename = map_lookup(args, "filename");
3940 if(!filename ||!*filename) {
3942 if(type != RAWDATA) {
3943 syntaxerror("colon (:) expected");
3947 s_action(readfile(filename));
3953 static int c_initaction(map_t*args)
3955 char* character = lu(args, "name");
3956 char* filename = map_lookup(args, "filename");
3957 if(!filename ||!*filename) {
3959 if(type != RAWDATA) {
3960 syntaxerror("colon (:) expected");
3962 s_initaction(character, text);
3964 s_initaction(character, readfile(filename));
3972 command_func_t* func;
3975 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
3976 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3977 // "import" type stuff
3978 {"swf", c_swf, "name filename"},
3979 {"shape", c_swf, "name filename"},
3980 {"jpeg", c_image, "name filename quality=80%"},
3981 {"png", c_image, "name filename"},
3982 {"movie", c_movie, "name filename"},
3983 {"sound", c_sound, "name filename"},
3984 {"font", c_font, "name filename glyphs="},
3985 {"soundtrack", c_soundtrack, "filename"},
3986 {"quicktime", c_quicktime, "url"},
3988 // generators of primitives
3990 {"define", c_define, "name value=0"},
3991 {"point", c_point, "name x=0 y=0"},
3992 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3993 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
3994 {"outline", c_outline, "name format=simple"},
3995 {"textshape", c_textshape, "name font size=100% text"},
3998 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3999 {"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"},
4000 {"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"},
4001 {"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"},
4003 // character generators
4004 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4005 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4006 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4008 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4009 {"text", c_text, "name text font size=100% color=white"},
4010 {"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="},
4011 {"morphshape", c_morphshape, "name start end"},
4012 {"button", c_button, "name"},
4013 {"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="},
4014 {"on_press", c_on_press, "position=inside"},
4015 {"on_release", c_on_release, "position=anywhere"},
4016 {"on_move_in", c_on_move_in, "state=not_pressed"},
4017 {"on_move_out", c_on_move_out, "state=not_pressed"},
4018 {"on_key", c_on_key, "key=any"},
4021 {"play", c_play, "name loop=0 @nomultiple=0"},
4022 {"stop", c_stop, "name= "},
4023 {"nextframe", c_nextframe, "name"},
4024 {"previousframe", c_previousframe, "name"},
4026 // object placement tags
4027 {"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="},
4028 {"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="},
4029 {"move", c_move, "name x= y= interpolation=linear"},
4030 {"smove", c_smove, "name x= y= interpolation=linear"},
4031 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4032 {"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"},
4033 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4034 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4035 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4036 {"del", c_del, "name"},
4037 // virtual object placement
4038 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4040 {"toggle", c_toggle, "name fixed_alignment="},
4042 // commands which start a block
4043 //startclip (see above)
4044 {"sprite", c_sprite, "name scalinggrid="},
4045 {"action", c_action, "filename="},
4046 {"initaction", c_initaction, "name filename="},
4052 static map_t parseArguments(char*command, char*pattern)
4068 string_set(&t1, "commandname");
4069 string_set(&t2, command);
4070 map_put(&result, t1, t2);
4072 if(!pattern || !*pattern)
4079 if(!strncmp("<i> ", x, 3)) {
4081 if(type == COMMAND || type == RAWDATA) {
4083 syntaxerror("character name expected");
4085 name[pos].str = "instance";
4087 value[pos].str = text;
4088 value[pos].len = strlen(text);
4092 if(type == ASSIGNMENT)
4095 name[pos].str = "character";
4097 value[pos].str = text;
4098 value[pos].len = strlen(text);
4106 isboolean[pos] = (x[0] =='@');
4119 name[pos].len = d-x;
4124 name[pos].len = e-x;
4125 value[pos].str = e+1;
4126 value[pos].len = d-e-1;
4134 /* for(t=0;t<len;t++) {
4135 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4136 isboolean[t]?"(boolean)":"");
4141 if(type == RAWDATA || type == COMMAND) {
4146 // first, search for boolean arguments
4147 for(pos=0;pos<len;pos++)
4149 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4151 if(type == ASSIGNMENT)
4153 value[pos].str = text;
4154 value[pos].len = strlen(text);
4155 /*printf("setting boolean parameter %s (to %s)\n",
4156 strdup_n(name[pos], namelen[pos]),
4157 strdup_n(value[pos], valuelen[pos]));*/
4162 // second, search for normal arguments
4164 for(pos=0;pos<len;pos++)
4166 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4167 (type != ASSIGNMENT && !set[pos])) {
4169 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4171 if(type == ASSIGNMENT)
4174 value[pos].str = text;
4175 value[pos].len = strlen(text);
4177 printf("setting parameter %s (to %s)\n",
4178 strdup_n(name[pos].str, name[pos].len),
4179 strdup_n(value[pos].str, value[pos].len));
4185 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4189 for(t=0;t<len;t++) {
4190 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4193 for(t=0;t<len;t++) {
4194 if(value[t].str && value[t].str[0] == '*') {
4195 //relative default- take value from some other parameter
4197 for(s=0;s<len;s++) {
4198 if(value[s].len == value[t].len-1 &&
4199 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4200 value[t].str = value[s].str;
4203 if(value[t].str == 0) {
4205 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4209 /* ok, now construct the dictionary from the parameters */
4213 map_put(&result, name[t], value[t]);
4217 static void parseArgumentsForCommand(char*command)
4222 msg("<verbose> parse Command: %s (line %d)", command, line);
4224 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4225 if(!strcmp(arguments[t].command, command)) {
4227 /* ugly hack- will be removed soon (once documentation and .sc generating
4228 utilities have been changed) */
4229 if(!strcmp(command, "swf") && !stackpos) {
4230 warning("Please use .flash instead of .swf- this will be mandatory soon");
4235 args = parseArguments(command, arguments[t].arguments);
4241 syntaxerror("command %s not known", command);
4243 // catch missing .flash directives at the beginning of a file
4244 if(strcmp(command, "flash") && !stackpos)
4246 syntaxerror("No movie defined- use .flash first");
4250 printf(".%s\n", command);fflush(stdout);
4251 map_dump(&args, stdout, "\t");fflush(stdout);
4254 (*arguments[nr].func)(&args);
4256 /*if(!strcmp(command, "button") ||
4257 !strcmp(command, "action")) {
4260 if(type == COMMAND) {
4261 if(!strcmp(text, "end"))
4276 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4277 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4278 * No syntax checking is done */
4279 static void analyseArgumentsForCommand(char*command)
4285 msg("<verbose> analyse Command: %s (line %d)", command, line);
4287 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4289 if(!strcmp(arguments[t].command, command))
4291 args = parseArguments(command, arguments[t].arguments);
4297 printf(".%s\n", command);fflush(stdout);
4298 map_dump(&args, stdout, "\t");fflush(stdout);
4300 char* name = lu(&args, "name");
4301 if (!strcmp(command, "font"))
4303 if(dictionary_lookup(&fonts, name))
4304 syntaxerror("font %s defined twice", name);
4307 fontfile = lu(&args, "filename");
4308 font = swf_LoadFont(fontfile);
4310 warning("Couldn't open font file \"%s\"", fontfile);
4311 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4312 memset(font, 0, sizeof(SWFFONT));
4314 swf_FontUseUTF8(font, lu(&args, "glyphs"));
4315 swf_FontPrepareForEditText(font);
4316 dictionary_put2(&fonts, name, font);
4320 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
4322 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4324 if (!strcmp(command, "edittext"))
4325 swf_FontUseAll(font);
4327 swf_FontUseUTF8(font, lu(&args, "text"));
4333 void skipParameters()
4337 while (type != COMMAND);
4341 void findFontUsage()
4343 char* fontRelated = "font;text;textshape;edittext;";
4344 while(!noMoreTokens())
4348 syntaxerror("command expected");
4349 if (strstr(fontRelated, text))
4350 analyseArgumentsForCommand(text);
4352 if(strcmp(text, "end"))
4361 dictionary_init(&fonts);
4362 cleanUp = &freeFontDictionary;
4366 int main (int argc,char ** argv)
4369 processargs(argc, argv);
4370 initLog(0,-1,0,0,-1,verbose);
4373 args_callback_usage(argv[0]);
4377 file = generateTokens(filename);
4379 fprintf(stderr, "parser returned error.\n");
4386 while(!noMoreTokens()) {
4389 syntaxerror("command expected");
4390 parseArgumentsForCommand(text);