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);
1553 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1555 swf_SetU16(tag, id);
1556 swf_SetString(tag, name);
1564 typedef struct _sound_t
1570 void s_sound(char*name, char*filename)
1572 struct WAV wav, wav2;
1576 unsigned numsamples = 1;
1577 unsigned blocksize = 1152;
1580 if(dictionary_lookup(&sounds, name))
1581 syntaxerror("sound %s defined twice", name);
1583 if(wav_read(&wav, filename))
1586 wav_convert2mono(&wav, &wav2, 44100);
1587 samples = (U16*)wav2.data;
1588 numsamples = wav2.size/2;
1590 #ifdef WORDS_BIGENDIAN
1592 for(t=0;t<numsamples;t++)
1593 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1597 if(mp3_read(&mp3, filename))
1599 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1605 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1610 if(numsamples%blocksize != 0)
1612 // apply padding, so that block is a multiple of blocksize
1613 int numblocks = (numsamples+blocksize-1)/blocksize;
1616 numsamples2 = numblocks * blocksize;
1617 samples2 = malloc(sizeof(U16)*numsamples2);
1618 memcpy(samples2, samples, numsamples*sizeof(U16));
1619 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1620 numsamples = numsamples2;
1625 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1626 swf_SetU16(tag, id); //id
1629 swf_SetSoundDefineMP3(
1630 tag, mp3.data, mp3.size,
1637 swf_SetSoundDefine(tag, samples, numsamples);
1640 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1641 swf_SetU16(tag, id);
1642 swf_SetString(tag, name);
1643 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1645 swf_SetU16(tag, id);
1646 swf_SetString(tag, name);
1649 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1653 dictionary_put2(&sounds, name, sound);
1661 static char* gradient_getToken(const char**p)
1665 while(**p && strchr(" \t\n\r", **p)) {
1669 while(**p && !strchr(" \t\n\r", **p)) {
1672 result = malloc((*p)-start+1);
1673 memcpy(result,start,(*p)-start+1);
1674 result[(*p)-start] = 0;
1678 float parsePercent(char*str);
1679 RGBA parseColor(char*str);
1681 GRADIENT parseGradient(const char*str)
1685 const char* p = str;
1686 memset(&gradient, 0, sizeof(GRADIENT));
1687 gradient.ratios = rfx_calloc(16*sizeof(U8));
1688 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1692 char*posstr,*colorstr;
1695 posstr = gradient_getToken(&p);
1701 pos = (int)(parsePercent(posstr)*255.0);
1706 rfx_free(gradient.ratios);
1707 rfx_free(gradient.rgba);
1709 syntaxerror("Error in shape data: Color expected after %s", posstr);
1711 colorstr = gradient_getToken(&p);
1712 color = parseColor(colorstr);
1713 if(gradient.num == 16)
1715 warning("gradient record too big- max size is 16, rest ignored");
1718 gradient.ratios[gradient.num] = pos;
1719 gradient.rgba[gradient.num] = color;
1728 FILTERLIST* parseFilters(char* list)
1730 if (!strcmp(list, "no_filters"))
1733 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1735 char* f_start = list;
1739 f_end = strchr(f_start, ',');
1742 f = dictionary_lookup(&filters, f_start);
1746 syntaxerror("unknown filter %s", f_start);
1748 if (f_list->num == 8)
1750 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1753 f_list->filter[f_list->num] = f;
1758 f_start = f_end + 1;
1766 void s_gradient(char*name, const char*text, int radial, int rotate)
1768 gradient_t* gradient;
1769 gradient = malloc(sizeof(gradient_t));
1770 memset(gradient, 0, sizeof(gradient_t));
1771 gradient->gradient = parseGradient(text);
1772 gradient->radial = radial;
1773 gradient->rotate = rotate;
1775 dictionary_put2(&gradients, name, gradient);
1778 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1779 float angle, float distance, float strength, char innershadow,
1780 char knockout, char composite, char ontop, int passes)
1782 if(dictionary_lookup(&filters, name))
1783 syntaxerror("filter %s defined twice", name);
1785 gradient_t* g = dictionary_lookup(&gradients, gradient);
1787 syntaxerror("unknown gradient %s", gradient);
1791 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1792 filter->type = FILTERTYPE_GRADIENTGLOW;
1793 filter->gradient = &g->gradient;
1794 filter->blurx = blurx;
1795 filter->blury = blury;
1796 filter->strength = strength;
1797 filter->angle = angle;
1798 filter->distance = distance;
1799 filter->innershadow = innershadow;
1800 filter->knockout = knockout;
1801 filter->composite = composite;
1802 filter->ontop = ontop;
1803 filter->passes = passes;
1805 dictionary_put2(&filters, name, filter);
1808 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)
1810 if(dictionary_lookup(&filters, name))
1811 syntaxerror("filter %s defined twice", name);
1814 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1815 filter->type = FILTERTYPE_DROPSHADOW;
1816 filter->color= color;
1817 filter->blurx = blurx;
1818 filter->blury = blury;
1819 filter->strength = strength;
1820 filter->angle = angle;
1821 filter->distance = distance;
1822 filter->innershadow = innershadow;
1823 filter->knockout = knockout;
1824 filter->composite = composite;
1825 filter->passes = passes;
1827 dictionary_put2(&filters, name, filter);
1830 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)
1832 if(dictionary_lookup(&filters, name))
1833 syntaxerror("filter %s defined twice", name);
1836 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1837 filter->type = FILTERTYPE_BEVEL;
1838 filter->shadow = shadow;
1839 filter->highlight = highlight;
1840 filter->blurx = blurx;
1841 filter->blury = blury;
1842 filter->strength = strength;
1843 filter->angle = angle;
1844 filter->distance = distance;
1845 filter->innershadow = innershadow;
1846 filter->knockout = knockout;
1847 filter->composite = composite;
1848 filter->ontop = ontop;
1849 filter->passes = passes;
1851 dictionary_put2(&filters, name, filter);
1854 void s_blur(char*name, double blurx, double blury, int passes)
1856 if(dictionary_lookup(&filters, name))
1857 syntaxerror("filter %s defined twice", name);
1859 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1860 filter->type = FILTERTYPE_BLUR;
1861 filter->blurx = blurx;
1862 filter->blury = blury;
1863 filter->passes = passes;
1865 dictionary_put2(&filters, name, filter);
1868 void s_action(const char*text)
1871 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1875 syntaxerror("Couldn't compile ActionScript");
1878 tag = swf_InsertTag(tag, ST_DOACTION);
1880 swf_ActionSet(tag, a);
1885 void s_initaction(const char*character, const char*text)
1889 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1893 syntaxerror("Couldn't compile ActionScript");
1896 c = (character_t*)dictionary_lookup(&characters, character);
1898 tag = swf_InsertTag(tag, ST_DOINITACTION);
1899 swf_SetU16(tag, c->id);
1900 swf_ActionSet(tag, a);
1905 int s_swf3action(char*name, char*action)
1908 instance_t* object = 0;
1910 object = (instance_t*)dictionary_lookup(&instances, name);
1911 if(!object && name && *name) {
1912 /* we have a name, but couldn't find it. Abort. */
1915 a = action_SetTarget(0, name);
1916 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1917 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1918 else if(!strcmp(action, "stop")) a = action_Stop(a);
1919 else if(!strcmp(action, "play")) a = action_Play(a);
1920 a = action_SetTarget(a, "");
1923 tag = swf_InsertTag(tag, ST_DOACTION);
1924 swf_ActionSet(tag, a);
1929 void s_outline(char*name, char*format, char*source)
1931 if(dictionary_lookup(&outlines, name))
1932 syntaxerror("outline %s defined twice", name);
1941 //swf_Shape10DrawerInit(&draw, 0);
1942 swf_Shape11DrawerInit(&draw, 0);
1944 draw_string(&draw, source);
1946 shape = swf_ShapeDrawerToShape(&draw);
1947 bounds = swf_ShapeDrawerGetBBox(&draw);
1948 draw.dealloc(&draw);
1950 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1951 outline->shape = shape;
1952 outline->bbox = bounds;
1954 dictionary_put2(&outlines, name, outline);
1957 int s_playsound(char*name, int loops, int nomultiple, int stop)
1963 sound = dictionary_lookup(&sounds, name);
1967 tag = swf_InsertTag(tag, ST_STARTSOUND);
1968 swf_SetU16(tag, sound->id); //id
1969 memset(&info, 0, sizeof(info));
1972 info.nomultiple = nomultiple;
1973 swf_SetSoundInfo(tag, &info);
1977 void s_includeswf(char*name, char*filename)
1985 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1986 f = open(filename,O_RDONLY|O_BINARY);
1988 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1989 s_box(name, 0, 0, black, 20, 0);
1992 if (swf_ReadSWF(f,&swf)<0) {
1993 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1994 s_box(name, 0, 0, black, 20, 0);
1999 /* FIXME: The following sets the bounding Box for the character.
2000 It is wrong for two reasons:
2001 a) It may be too small (in case objects in the movie clip at the borders)
2002 b) it may be too big (because the poor movie never got autocropped)
2006 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2007 swf_SetU16(tag, id);
2008 swf_SetU16(tag, swf.frameCount);
2010 swf_Relocate(&swf, idmap);
2012 ftag = swf.firstTag;
2016 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2017 if(cutout[t] == ftag->id) {
2021 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2023 if(ftag->id == ST_END)
2028 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2029 /* We simply dump all tags right after the sprite
2030 header, relying on the fact that swf_OptimizeTagOrder() will
2031 sort things out for us later.
2032 We also rely on the fact that the imported SWF is well-formed.
2034 tag = swf_InsertTag(tag, ftag->id);
2035 swf_SetBlock(tag, ftag->data, ftag->len);
2041 syntaxerror("Included file %s contains errors", filename);
2042 tag = swf_InsertTag(tag, ST_END);
2046 s_addcharacter(name, id, tag, r);
2049 SRECT s_getCharBBox(char*name)
2051 character_t* c = dictionary_lookup(&characters, name);
2052 if(!c) syntaxerror("character '%s' unknown(2)", name);
2055 SRECT s_getInstanceBBox(char*name)
2057 instance_t * i = dictionary_lookup(&instances, name);
2059 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2061 if(!c) syntaxerror("internal error(5)");
2064 void s_getParameters(char*name, parameters_t* p)
2066 instance_t * i = dictionary_lookup(&instances, name);
2068 syntaxerror("instance '%s' unknown(10)", name);
2069 if (change_sets_all)
2070 readParameters(i->history, p, currentframe);
2075 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2077 history_begin(i->history, "x", currentframe, tag, p->x);
2078 history_begin(i->history, "y", currentframe, tag, p->y);
2079 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2080 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2081 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2082 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2083 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2084 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2085 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2086 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2087 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2088 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2089 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2090 history_begin(i->history, "shear", currentframe, tag, p->shear);
2091 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2092 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2093 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2094 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2095 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2096 history_beginFilter(i->history, currentframe, tag, p->filters);
2097 history_begin(i->history, "flags", currentframe, tag, 0);
2100 void s_startclip(char*instance, char*character, parameters_t p)
2102 character_t* c = dictionary_lookup(&characters, character);
2106 syntaxerror("character %s not known", character);
2108 i = s_addinstance(instance, c, currentdepth);
2110 m = s_instancepos(i->character->size, &p);
2112 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2113 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2114 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2116 stack[stackpos].tag = tag;
2117 stack[stackpos].type = 2;
2120 setStartparameters(i, &p, tag);
2127 swf_SetTagPos(stack[stackpos].tag, 0);
2128 swf_GetPlaceObject(stack[stackpos].tag, &p);
2129 p.clipdepth = currentdepth;
2131 swf_ClearTag(stack[stackpos].tag);
2132 swf_SetPlaceObject(stack[stackpos].tag, &p);
2136 void s_put(char*instance, char*character, parameters_t p)
2138 character_t* c = dictionary_lookup(&characters, character);
2142 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2144 i = s_addinstance(instance, c, currentdepth);
2146 m = s_instancepos(i->character->size, &p);
2148 if(p.blendmode || p.filters)
2150 if(stack[0].swf->fileVersion < 8)
2153 warning("blendmodes only supported for flash version>=8");
2155 warning("filters only supported for flash version>=8");
2157 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2160 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2161 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2162 setStartparameters(i, &p, tag);
2166 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2169 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2171 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2172 if (p.set & SF_SCALEX)
2173 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2174 if (p.set & SF_SCALEY)
2175 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2176 if (p.set & SF_CX_R)
2178 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2179 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2181 if (p.set & SF_CX_G)
2183 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2184 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2186 if (p.set & SF_CX_B)
2188 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2189 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2191 if (p.set & SF_CX_A)
2193 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2194 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2196 if (p.set & SF_ROTATE)
2197 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2198 if (p.set & SF_SHEAR)
2199 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2200 if (p.set & SF_PIVOT)
2202 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2203 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2207 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2208 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2210 if (p.set & SF_BLEND)
2211 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2212 if (p.set & SF_FILTER)
2213 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2216 void s_jump(char* instance, parameters_t p)
2218 instance_t* i = dictionary_lookup(&instances, instance);
2220 syntaxerror("instance %s not known", instance);
2221 recordChanges(i->history, p, CF_JUMP, 0);
2224 void s_change(char*instance, parameters_t p, interpolation_t* inter)
2226 instance_t* i = dictionary_lookup(&instances, instance);
2228 syntaxerror("instance %s not known", instance);
2229 recordChanges(i->history, p, CF_CHANGE, inter);
2232 void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2234 instance_t* i = dictionary_lookup(&instances, instance);
2236 syntaxerror("instance %s not known", instance);
2237 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2240 void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
2242 instance_t* i = dictionary_lookup(&instances, instance);
2244 syntaxerror("instance %s not known", instance);
2245 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2248 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2251 void s_delinstance(char*instance)
2253 instance_t* i = dictionary_lookup(&instances, instance);
2255 syntaxerror("instance %s not known", instance);
2257 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2258 swf_SetU16(tag, i->depth);
2259 dictionary_del(&instances, instance);
2262 void s_schange(char*instance, parameters_t p, interpolation_t* inter)
2264 instance_t* i = dictionary_lookup(&instances, instance);
2266 syntaxerror("instance %s not known", instance);
2267 recordChanges(i->history, p, CF_SCHANGE, inter);
2273 syntaxerror(".end unexpected");
2274 switch (stack[stackpos-1].type)
2289 syntaxerror("internal error 1");
2293 // ------------------------------------------------------------------------
2295 typedef int command_func_t(map_t*args);
2297 SRECT parseBox(char*str)
2299 SRECT r = {0,0,0,0};
2300 float xmin, xmax, ymin, ymax;
2301 char*x = strchr(str, 'x');
2303 if(!strcmp(str, "autocrop")) {
2304 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2308 d1 = strchr(x+1, ':');
2310 d2 = strchr(d1+1, ':');
2312 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2316 else if(d1 && !d2) {
2317 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2323 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2328 r.xmin = (SCOORD)(xmin*20);
2329 r.ymin = (SCOORD)(ymin*20);
2330 r.xmax = (SCOORD)(xmax*20);
2331 r.ymax = (SCOORD)(ymax*20);
2334 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2337 float parseFloat(char*str)
2341 int parseInt(char*str)
2346 if(str[0]=='+' || str[0]=='-')
2350 if(str[t]<'0' || str[t]>'9')
2351 syntaxerror("Not an Integer: \"%s\"", str);
2354 int parseRawTwip(char*str)
2358 if(str[0]=='+' || str[0]=='-') {
2363 dot = strchr(str, '.');
2367 return sign*parseInt(str)*20;
2369 char* old = strdup(str);
2370 int l=strlen(dot+1);
2373 for(s=str;s<dot-1;s++)
2374 if(*s<'0' || *s>'9')
2377 syntaxerror("Not a coordinate: \"%s\"", str);
2380 if(*s<'0' || *s>'9')
2383 syntaxerror("Not a coordinate: \"%s\"", str);
2385 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2386 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2389 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2393 return sign*(atoi(str)*20);
2395 return sign*(atoi(str)*20+atoi(dot)*2);
2397 return sign*(atoi(str)*20+atoi(dot)/5);
2402 static dictionary_t defines;
2403 static int defines_initialized = 0;
2404 static mem_t define_values;
2406 int parseTwip(char*str)
2408 /* TODO: make this a proper expression parser */
2414 if(*p == '+' || *p == '-' || *p == '/' || *p == '*')
2419 if((*p == '+' || *p == '-' || *p == '/' || *p == '*' || *p == 0) && lastpos) {
2425 if(defines_initialized) {
2426 l = (int)dictionary_lookup(&defines, lastpos);
2429 v = *(int*)&define_values.buffer[l-1];
2431 v = parseRawTwip(lastpos);
2451 int parseArc(char* str)
2453 if (!strcmp(str, "short"))
2455 if (!strcmp(str, "long"))
2457 syntaxerror("invalid value for the arc parameter: %s", str);
2461 int parseDir(char* str)
2463 if (!strcmp(str, "clockwise"))
2465 if (!strcmp(str, "counterclockwise"))
2467 syntaxerror("invalid value for the dir parameter: %s", str);
2471 int isPoint(char*str)
2473 if(strchr(str, '('))
2479 SPOINT parsePoint(char*str)
2483 int l = strlen(str);
2484 char*comma = strchr(str, ',');
2485 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2486 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2487 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2488 p.x = parseTwip(tmp);
2489 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2490 p.y = parseTwip(tmp);
2494 int parseColor2(char*str, RGBA*color)
2496 int l = strlen(str);
2500 struct {unsigned char r,g,b;char*name;} colors[] =
2501 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2502 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2503 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2504 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2505 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2506 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2507 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2508 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2509 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2510 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2511 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2512 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2516 if(str[0]=='#' && (l==7 || l==9)) {
2517 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2519 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2521 color->r = r; color->g = g; color->b = b; color->a = a;
2524 int len=strlen(str);
2526 if(strchr(str, '/')) {
2527 len = strchr(str, '/')-str;
2528 sscanf(str+len+1,"%02x", &alpha);
2530 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2531 if(!strncmp(str, colors[t].name, len)) {
2536 color->r = r; color->g = g; color->b = b; color->a = a;
2542 RGBA parseColor(char*str)
2545 if(!parseColor2(str, &c))
2546 syntaxerror("Expression '%s' is not a color", str);
2550 typedef struct _muladd {
2555 MULADD parseMulAdd(char*str)
2558 char* str2 = (char*)malloc(strlen(str)+5);
2565 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2566 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2567 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2568 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2569 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2570 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2571 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2572 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2573 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2574 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2576 syntaxerror("'%s' is not a valid color transform expression", str);
2578 m.add = (int)(add*256);
2579 m.mul = (int)(mul*256);
2584 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2586 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2587 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2589 if(a<-32768) a=-32768;
2590 if(a>32767) a=32767;
2591 if(m<-32768) m=-32768;
2592 if(m>32767) m=32767;
2598 float parsePxOrPercent(char*fontname, char*str)
2600 int l = strlen(str);
2601 if(strchr(str, '%'))
2602 return parsePercent(str);
2603 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2604 float p = atof(str);
2605 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2607 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2611 float parsePercent(char*str)
2613 int l = strlen(str);
2617 return atoi(str)/100.0;
2619 syntaxerror("Expression '%s' is not a percentage", str);
2622 int isPercent(char*str)
2624 return str[strlen(str)-1]=='%';
2626 int parseNewSize(char*str, int size)
2629 return parsePercent(str)*size;
2631 return (int)(atof(str)*20);
2634 int isColor(char*str)
2637 return parseColor2(str, &c);
2640 static char* lu(map_t* args, char*name)
2642 char* value = map_lookup(args, name);
2644 map_dump(args, stdout, "");
2645 syntaxerror("internal error 2: value %s should be set", name);
2650 static int c_flash(map_t*args)
2652 char* filename = map_lookup(args, "filename");
2653 char* compressstr = lu(args, "compress");
2654 char* change_modestr = lu(args, "change-sets-all");
2655 char* exportstr = lu(args, "export");
2656 SRECT bbox = parseBox(lu(args, "bbox"));
2657 int version = parseInt(lu(args, "version"));
2658 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2659 RGBA color = parseColor(lu(args, "background"));
2662 if(!filename || !*filename) {
2663 /* for compatibility */
2664 filename = map_lookup(args, "name");
2665 if(!filename || !*filename) {
2668 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2669 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2673 if(!filename || override_outputname)
2674 filename = outputname;
2676 if(!strcmp(compressstr, "default"))
2677 compress = version>=6;
2678 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2680 else if(!strcmp(compressstr, "no"))
2682 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2684 if(!strcmp(change_modestr, "yes"))
2685 change_sets_all = 1;
2687 if(strcmp(change_modestr, "no"))
2688 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2690 do_exports=atoi(exportstr);
2692 s_swf(filename, bbox, version, fps, compress, color);
2695 int isRelative(char*str)
2697 return !strncmp(str, "<plus>", 6) ||
2698 !strncmp(str, "<minus>", 7);
2700 char* getOffset(char*str)
2702 if(!strncmp(str, "<plus>", 6))
2704 if(!strncmp(str, "<minus>", 7))
2706 syntaxerror("internal error (347)");
2709 int getSign(char*str)
2711 if(!strncmp(str, "<plus>", 6))
2713 if(!strncmp(str, "<minus>", 7))
2715 syntaxerror("internal error (348)");
2719 static dictionary_t points;
2720 static mem_t mpoints;
2721 static int points_initialized = 0;
2723 static int c_interpolation(map_t *args)
2726 char* name = lu(args, "name");
2727 if (dictionary_lookup(&interpolations, name))
2728 syntaxerror("interpolation %s defined twice", name);
2730 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2731 char* functionstr = lu(args, "function");
2732 inter->function = 0;
2733 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2734 if (!strcmp(functionstr,interpolationFunctions[i]))
2736 inter->function = i + 1;
2739 if (!inter->function)
2740 syntaxerror("unkown interpolation function %s", functionstr);
2741 inter->speed = parseFloat(lu(args, "speed"));
2742 inter->amplitude = parseTwip(lu(args, "amplitude"));
2743 inter->growth = parseFloat(lu(args, "growth"));
2744 inter->bounces = parseInt(lu(args, "bounces"));
2745 inter->damping = parseFloat(lu(args, "damping"));
2746 inter->slope = parseFloat(lu(args, "slope"));
2748 dictionary_put2(&interpolations, name, inter);
2752 SPOINT getPoint(SRECT r, char*name)
2755 if(!strcmp(name, "center")) {
2757 p.x = (r.xmin + r.xmax)/2;
2758 p.y = (r.ymin + r.ymax)/2;
2761 if (!strcmp(name, "bottom-center")) {
2763 p.x = (r.xmin + r.xmax)/2;
2767 if (!strcmp(name, "top-center")) {
2769 p.x = (r.xmin + r.xmax)/2;
2773 if (!strcmp(name, "top-left")) {
2779 if (!strcmp(name, "top-right")) {
2785 if (!strcmp(name, "bottom-right")) {
2791 if (!strcmp(name, "bottom-left")) {
2797 if (!strcmp(name, "left-center")) {
2800 p.y = (r.ymin + r.ymax)/2;
2803 if (!strcmp(name, "right-center")) {
2806 p.y = (r.ymin + r.ymax)/2;
2811 if(points_initialized)
2812 l = (int)dictionary_lookup(&points, name);
2814 syntaxerror("Invalid point: \"%s\".", name);
2816 return *(SPOINT*)&mpoints.buffer[l-1];
2820 static int texture2(char*name, char*object, map_t*args, int errors)
2823 char*xstr = map_lookup(args, "x");
2824 char*ystr = map_lookup(args, "y");
2825 char*widthstr = map_lookup(args, "width");
2826 char*heightstr = map_lookup(args, "height");
2827 char*scalestr = map_lookup(args, "scale");
2828 char*scalexstr = map_lookup(args, "scalex");
2829 char*scaleystr = map_lookup(args, "scaley");
2830 char*rotatestr = map_lookup(args, "rotate");
2831 char* shearstr = map_lookup(args, "shear");
2832 char* radiusstr = map_lookup(args, "r");
2834 float scalex = 1.0, scaley = 1.0;
2835 float rotate=0, shear=0;
2837 if(!*xstr && !*ystr) {
2839 syntaxerror("x and y must be set");
2842 if(*scalestr && (*scalexstr || *scaleystr)) {
2843 syntaxerror("scale and scalex/scaley can't both be set");
2846 if((*widthstr || *heightstr) && *radiusstr) {
2847 syntaxerror("width/height and radius can't both be set");
2850 widthstr = radiusstr;
2851 heightstr = radiusstr;
2853 if(!*xstr) xstr="0";
2854 if(!*ystr) ystr="0";
2855 if(!*rotatestr) rotatestr="0";
2856 if(!*shearstr) shearstr="0";
2859 scalex = scaley = parsePercent(scalestr);
2860 } else if(*scalexstr || *scaleystr) {
2861 if(scalexstr) scalex = parsePercent(scalexstr);
2862 if(scaleystr) scaley = parsePercent(scaleystr);
2863 } else if(*widthstr || *heightstr) {
2866 s_getBitmapSize(object, &width, &height);
2868 scalex = (float)parseTwip(widthstr)/(float)width;
2870 scaley = (float)parseTwip(heightstr)/(float)height;
2872 x = parseTwip(xstr);
2873 y = parseTwip(ystr);
2874 rotate = parseFloat(rotatestr);
2875 shear = parseFloat(shearstr);
2877 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2882 static int c_texture(map_t*args)
2884 char*name = lu(args, "instance");
2885 char*object = lu(args, "character");
2886 return texture2(name, object, args, 1);
2889 static int c_gradient(map_t*args)
2891 char*name = lu(args, "name");
2892 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2893 int rotate = parseInt(lu(args, "rotate"));
2897 syntaxerror("colon (:) expected");
2899 if(dictionary_lookup(&gradients, name))
2900 syntaxerror("gradient %s defined twice", name);
2902 s_gradient(name, text, radial, rotate);
2904 /* check whether we also have placement information,
2905 which would make this a positioned gradient.
2906 If there is placement information, texture2() will
2907 add a texture, which has priority over the gradient.
2909 texture2(name, name, args, 0);
2913 static char* checkFiltername(map_t* args)
2915 char* name = lu(args, "name");
2916 if (strchr(name, ','))
2917 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
2921 static int c_blur(map_t*args)
2923 char*name = checkFiltername(args);
2924 char*blurstr = lu(args, "blur");
2925 char*blurxstr = lu(args, "blurx");
2926 char*blurystr = lu(args, "blury");
2927 float blurx=1.0, blury=1.0;
2929 blurx = parseFloat(blurstr);
2930 blury = parseFloat(blurstr);
2933 blurx = parseFloat(blurxstr);
2935 blury = parseFloat(blurystr);
2936 int passes = parseInt(lu(args, "passes"));
2937 s_blur(name, blurx, blury, passes);
2941 static int c_gradientglow(map_t*args)
2943 char*name = checkFiltername(args);
2944 char*gradient = lu(args, "gradient");
2945 char*blurstr = lu(args, "blur");
2946 char*blurxstr = lu(args, "blurx");
2947 char*blurystr = lu(args, "blury");
2948 float blurx=1.0, blury=1.0;
2950 blurx = parseFloat(blurstr);
2951 blury = parseFloat(blurstr);
2954 blurx = parseFloat(blurxstr);
2956 blury = parseFloat(blurystr);
2958 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2959 float distance = parseFloat(lu(args, "distance"));
2960 float strength = parseFloat(lu(args, "strength"));
2961 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2962 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2963 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2964 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2965 int passes = parseInt(lu(args, "passes"));
2967 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2971 static int c_dropshadow(map_t*args)
2973 char*name = checkFiltername(args);
2974 RGBA color = parseColor(lu(args, "color"));
2975 char*blurstr = lu(args, "blur");
2976 char*blurxstr = lu(args, "blurx");
2977 char*blurystr = lu(args, "blury");
2978 float blurx=1.0, blury=1.0;
2980 blurx = parseFloat(blurstr);
2981 blury = parseFloat(blurstr);
2984 blurx = parseFloat(blurxstr);
2986 blury = parseFloat(blurystr);
2988 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2989 float distance = parseFloat(lu(args, "distance"));
2990 float strength = parseFloat(lu(args, "strength"));
2991 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2992 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2993 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2994 int passes = parseInt(lu(args, "passes"));
2996 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3000 static int c_bevel(map_t*args)
3002 char*name = checkFiltername(args);
3003 RGBA shadow = parseColor(lu(args, "shadow"));
3004 RGBA highlight = parseColor(lu(args, "highlight"));
3005 char*blurstr = lu(args, "blur");
3006 char*blurxstr = lu(args, "blurx");
3007 char*blurystr = lu(args, "blury");
3008 float blurx=1.0, blury=1.0;
3010 blurx = parseFloat(blurstr);
3011 blury = parseFloat(blurstr);
3014 blurx = parseFloat(blurxstr);
3016 blury = parseFloat(blurystr);
3018 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3019 float distance = parseFloat(lu(args, "distance"));
3020 float strength = parseFloat(lu(args, "strength"));
3021 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3022 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3023 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3024 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3025 int passes = parseInt(lu(args, "passes"));
3027 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3031 static int c_define(map_t*args)
3033 char*name = lu(args, "name");
3034 char*value = lu(args, "value");
3036 if(!defines_initialized) {
3037 dictionary_init(&defines);
3038 mem_init(&define_values);
3039 defines_initialized = 1;
3041 int val = parseTwip(value);
3042 int pos = mem_put(&define_values, &val, sizeof(val));
3044 string_set(&s, name);
3045 dictionary_put(&defines, s, (void*)(pos+1));
3048 static int c_point(map_t*args)
3050 char*name = lu(args, "name");
3054 if(!points_initialized) {
3055 dictionary_init(&points);
3057 points_initialized = 1;
3059 p.x = parseTwip(lu(args, "x"));
3060 p.y = parseTwip(lu(args, "y"));
3061 pos = mem_put(&mpoints, &p, sizeof(p));
3062 string_set(&s1, name);
3063 dictionary_put(&points, s1, (void*)(pos+1));
3066 static int c_play(map_t*args)
3068 char*name = lu(args, "name");
3069 char*loop = lu(args, "loop");
3070 char*nomultiple = lu(args, "nomultiple");
3072 if(!strcmp(nomultiple, "nomultiple"))
3075 nm = parseInt(nomultiple);
3077 if(s_playsound(name, parseInt(loop), nm, 0)) {
3079 } else if(s_swf3action(name, "play")) {
3085 static int c_stop(map_t*args)
3087 char*name = map_lookup(args, "name");
3089 if(s_playsound(name, 0,0,1))
3091 else if(s_swf3action(name, "stop"))
3093 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3097 static int c_nextframe(map_t*args)
3099 char*name = lu(args, "name");
3101 if(s_swf3action(name, "nextframe")) {
3104 syntaxerror("I don't know anything about movie \"%s\"", name);
3108 static int c_previousframe(map_t*args)
3110 char*name = lu(args, "name");
3112 if(s_swf3action(name, "previousframe")) {
3115 syntaxerror("I don't know anything about movie \"%s\"", name);
3119 static int c_movement(map_t*args, int type)
3121 char*instance = lu(args, "name");
3129 xstr = lu(args, "x");
3130 ystr = lu(args, "y");
3132 s_getParameters(instance, &p);
3137 if(isRelative(xstr))
3139 if(type == PT_PUT || type == PT_STARTCLIP)
3140 syntaxerror("relative x values not allowed for initial put or startclip");
3141 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3145 p.x = parseTwip(xstr);
3151 if(isRelative(ystr))
3153 if(type == PT_PUT || type == PT_STARTCLIP)
3154 syntaxerror("relative y values not allowed for initial put or startclip");
3155 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3159 p.y = parseTwip(ystr);
3164 if (change_sets_all)
3172 char* interstr = lu(args, "interpolation");
3173 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3175 syntaxerror("unkown interpolation %s", interstr);
3176 s_change(instance, p, inter);
3181 char* interstr = lu(args, "interpolation");
3182 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3184 syntaxerror("unkown interpolation %s", interstr);
3185 s_schange(instance, p, inter);
3190 char* rstr = lu(args, "r");
3191 int radius = parseTwip(rstr);
3193 syntaxerror("sweep not possible: radius must be greater than 0.");
3194 char* dirstr = lu(args, "dir");
3195 int clockwise = parseDir(dirstr);
3196 char* arcstr = lu(args, "arc");
3197 int short_arc = parseArc(arcstr);
3198 char* interstr = lu(args, "interpolation");
3199 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3201 syntaxerror("unkown interpolation %s", interstr);
3202 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3209 static int c_placement(map_t*args, int type)
3211 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3214 char* luminancestr = lu(args, "luminance");
3215 char* scalestr = lu(args, "scale");
3216 char* scalexstr = lu(args, "scalex");
3217 char* scaleystr = lu(args, "scaley");
3218 char* rotatestr = lu(args, "rotate");
3219 char* shearstr = lu(args, "shear");
3220 char* xstr="", *pivotstr="";
3221 char* ystr="", *anglestr="";
3222 char*above = lu(args, "above"); /*FIXME*/
3223 char*below = lu(args, "below");
3224 char* rstr = lu(args, "red");
3225 char* gstr = lu(args, "green");
3226 char* bstr = lu(args, "blue");
3227 char* astr = lu(args, "alpha");
3228 char* pinstr = lu(args, "pin");
3229 char* as = map_lookup(args, "as");
3230 char* blendmode = lu(args, "blend");
3231 char* filterstr = lu(args, "filter");
3242 { // (?) .rotate or .arcchange
3243 pivotstr = lu(args, "pivot");
3244 anglestr = lu(args, "angle");
3248 xstr = lu(args, "x");
3249 ystr = lu(args, "y");
3253 luminance = parseMulAdd(luminancestr);
3257 luminance.mul = 256;
3262 if(scalexstr[0]||scaleystr[0])
3263 syntaxerror("scalex/scaley and scale cannot both be set");
3264 scalexstr = scaleystr = scalestr;
3267 if(type == PT_PUT || type == PT_STARTCLIP) {
3269 character = lu(args, "character");
3270 parameters_clear(&p);
3271 } else if (type == PT_BUTTON) {
3272 character = lu(args, "name");
3273 parameters_clear(&p);
3276 s_getParameters(instance, &p);
3282 if(isRelative(xstr))
3284 if(type == PT_PUT || type == PT_STARTCLIP)
3285 syntaxerror("relative x values not allowed for initial put or startclip");
3286 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3290 p.x = parseTwip(xstr);
3296 if(isRelative(ystr))
3298 if(type == PT_PUT || type == PT_STARTCLIP)
3299 syntaxerror("relative y values not allowed for initial put or startclip");
3300 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3304 p.y = parseTwip(ystr);
3309 /* scale, scalex, scaley */
3311 oldbbox = s_getCharBBox(character);
3313 oldbbox = s_getInstanceBBox(instance);
3314 oldwidth = oldbbox.xmax - oldbbox.xmin;
3315 oldheight = oldbbox.ymax - oldbbox.ymin;
3322 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3323 set = set | SF_SCALEX;
3331 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3332 set = set | SF_SCALEY;
3338 if(isRelative(rotatestr))
3339 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3341 p.rotate = parseFloat(rotatestr);
3342 set = set | SF_ROTATE;
3348 if(isRelative(shearstr))
3349 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3351 p.shear = parseFloat(shearstr);
3352 set = set | SF_SHEAR;
3357 if(isPoint(pivotstr))
3358 p.pivot = parsePoint(pivotstr);
3360 p.pivot = getPoint(oldbbox, pivotstr);
3361 set = set | SF_PIVOT;
3367 p.pin = parsePoint(pinstr);
3369 p.pin = getPoint(oldbbox, pinstr);
3373 /* color transform */
3375 if(rstr[0] || luminancestr[0])
3379 r = parseMulAdd(rstr);
3382 r.add = p.cxform.r0;
3383 r.mul = p.cxform.r1;
3385 r = mergeMulAdd(r, luminance);
3386 p.cxform.r0 = r.mul;
3387 p.cxform.r1 = r.add;
3388 set = set | SF_CX_R;
3390 if(gstr[0] || luminancestr[0])
3394 g = parseMulAdd(gstr);
3397 g.add = p.cxform.g0;
3398 g.mul = p.cxform.g1;
3400 g = mergeMulAdd(g, luminance);
3401 p.cxform.g0 = g.mul;
3402 p.cxform.g1 = g.add;
3403 set = set | SF_CX_G;
3405 if(bstr[0] || luminancestr[0])
3409 b = parseMulAdd(bstr);
3412 b.add = p.cxform.b0;
3413 b.mul = p.cxform.b1;
3415 b = mergeMulAdd(b, luminance);
3416 p.cxform.b0 = b.mul;
3417 p.cxform.b1 = b.add;
3418 set = set | SF_CX_B;
3422 MULADD a = parseMulAdd(astr);
3423 p.cxform.a0 = a.mul;
3424 p.cxform.a1 = a.add;
3425 set = set | SF_CX_A;
3432 for(t = 0; blendModeNames[t]; t++)
3434 if(!strcmp(blendModeNames[t], blendmode))
3442 syntaxerror("unknown blend mode: '%s'", blendmode);
3444 p.blendmode = blend;
3445 set = set | SF_BLEND;
3450 p.filters = parseFilters(filterstr);
3451 set = set | SF_FILTER;
3454 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3455 warning("As of version 0.8.2 using the .change command to modify an \
3456 object's position on the stage is considered deprecated. Future \
3457 versions may consider x and y parameters for the .change command \
3458 to be illegal; please use the .move command.");
3460 if (change_sets_all)
3467 s_put(instance, character, p);
3471 char* interstr = lu(args, "interpolation");
3472 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3474 syntaxerror("unkown interpolation %s", interstr);
3475 s_change(instance, p, inter);
3480 char* interstr = lu(args, "interpolation");
3481 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3483 syntaxerror("unkown interpolation %s", interstr);
3484 s_schange(instance, p, inter);
3488 s_jump(instance, p);
3491 s_startclip(instance, character, p);
3495 s_buttonput(character, as, p);
3497 s_buttonput(character, "shape", p);
3503 static int c_put(map_t*args)
3505 c_placement(args, PT_PUT);
3508 static int c_change(map_t*args)
3510 if (currentframe == 0)
3511 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3512 c_placement(args, PT_CHANGE);
3515 static int c_schange(map_t*args)
3517 c_placement(args, PT_SCHANGE);
3520 static int c_move(map_t* args)
3522 c_movement(args, PT_MOVE);
3525 static int c_smove(map_t* args)
3527 c_movement(args, PT_SMOVE);
3530 static int c_sweep(map_t* args)
3532 c_movement(args, PT_SWEEP);
3535 static int c_arcchange(map_t*args)
3537 c_placement(args, 0);
3540 static int c_jump(map_t*args)
3542 c_placement(args, PT_JUMP);
3545 static int c_startclip(map_t*args)
3547 c_placement(args, PT_STARTCLIP);
3550 static int c_show(map_t*args)
3552 c_placement(args, PT_BUTTON);
3555 static int c_toggle(map_t* args)
3557 char*instance = lu(args, "name");
3558 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3559 char* alignstr = lu(args, "fixed_alignment");
3560 if (!strcmp(alignstr, "on"))
3561 flagsOn += IF_FIXED_ALIGNMENT;
3563 if (!strcmp(alignstr, "off"))
3564 flagsOff -= IF_FIXED_ALIGNMENT;
3566 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3567 s_toggle(instance, flagsOn, flagsOff);
3570 static int c_del(map_t*args)
3572 char*instance = lu(args, "name");
3573 s_delinstance(instance);
3576 static int c_end(map_t*args)
3581 static int c_sprite(map_t*args)
3583 char* name = lu(args, "name");
3584 char* scalinggrid = lu(args, "scalinggrid");
3586 if(scalinggrid && *scalinggrid) {
3587 SRECT r = parseBox(scalinggrid);
3594 static int c_frame(map_t*args)
3596 char*framestr = lu(args, "n");
3597 char*cutstr = lu(args, "cut");
3599 char*name = lu(args, "name");
3600 char*anchor = lu(args, "anchor");
3603 if(!strcmp(anchor, "anchor") && !*name)
3608 if(strcmp(cutstr, "no"))
3610 if(isRelative(framestr)) {
3611 frame = s_getframe();
3612 if(getSign(framestr)<0)
3613 syntaxerror("relative frame expressions must be positive");
3614 frame += parseInt(getOffset(framestr));
3617 frame = parseInt(framestr);
3618 if(s_getframe() >= frame
3619 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3620 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3622 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3625 static int c_primitive(map_t*args)
3627 char*name = lu(args, "name");
3628 char*command = lu(args, "commandname");
3629 int width=0, height=0, r=0;
3630 int linewidth = parseTwip(lu(args, "line"));
3631 char*colorstr = lu(args, "color");
3632 RGBA color = parseColor(colorstr);
3633 char*fillstr = lu(args, "fill");
3640 if(!strcmp(command, "circle"))
3642 else if(!strcmp(command, "filled"))
3646 width = parseTwip(lu(args, "width"));
3647 height = parseTwip(lu(args, "height"));
3648 } else if (type==1) {
3649 r = parseTwip(lu(args, "r"));
3650 } else if (type==2) {
3651 outline = lu(args, "outline");
3654 if(!strcmp(fillstr, "fill"))
3656 if(!strcmp(fillstr, "none"))
3658 if(width<0 || height<0 || linewidth<0 || r<0)
3659 syntaxerror("values width, height, line, r must be positive");
3661 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3662 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3663 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3667 static int c_textshape(map_t*args)
3669 char*name = lu(args, "name");
3670 char*text = lu(args, "text");
3671 char*font = lu(args, "font");
3672 float size = parsePxOrPercent(font, lu(args, "size"));
3674 s_textshape(name, font, size, text);
3678 static int c_swf(map_t*args)
3680 char*name = lu(args, "name");
3681 char*filename = lu(args, "filename");
3682 char*command = lu(args, "commandname");
3683 if(!strcmp(command, "shape"))
3684 warning("Please use .swf instead of .shape");
3685 s_includeswf(name, filename);
3689 static int c_font(map_t*args)
3691 char*name = lu(args, "name");
3692 char*filename = lu(args, "filename");
3693 s_font(name, filename);
3697 static int c_sound(map_t*args)
3699 char*name = lu(args, "name");
3700 char*filename = lu(args, "filename");
3701 s_sound(name, filename);
3705 static int c_text(map_t*args)
3707 char*name = lu(args, "name");
3708 char*text = lu(args, "text");
3709 char*font = lu(args, "font");
3710 float size = parsePxOrPercent(font, lu(args, "size"));
3711 RGBA color = parseColor(lu(args, "color"));
3712 s_text(name, font, text, (int)(size*100), color);
3716 static int c_soundtrack(map_t*args)
3721 static int c_quicktime(map_t*args)
3723 char*name = lu(args, "name");
3724 char*url = lu(args, "url");
3725 s_quicktime(name, url);
3729 static int c_image(map_t*args)
3731 char*command = lu(args, "commandname");
3732 char*name = lu(args, "name");
3733 char*filename = lu(args, "filename");
3734 if(!strcmp(command,"jpeg")) {
3735 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3736 s_image(name, "jpeg", filename, quality);
3738 s_image(name, "png", filename, 0);
3743 static int c_outline(map_t*args)
3745 char*name = lu(args, "name");
3746 char*format = lu(args, "format");
3750 syntaxerror("colon (:) expected");
3752 s_outline(name, format, text);
3756 int fakechar(map_t*args)
3758 char*name = lu(args, "name");
3759 s_box(name, 0, 0, black, 20, 0);
3763 static int c_egon(map_t*args) {return fakechar(args);}
3764 static int c_button(map_t*args) {
3765 char*name = lu(args, "name");
3769 static int current_button_flags = 0;
3770 static int c_on_press(map_t*args)
3772 char*position = lu(args, "position");
3774 if(!strcmp(position, "inside")) {
3775 current_button_flags |= BC_OVERUP_OVERDOWN;
3776 } else if(!strcmp(position, "outside")) {
3777 //current_button_flags |= BC_IDLE_OUTDOWN;
3778 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3779 } else if(!strcmp(position, "anywhere")) {
3780 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3783 if(type == RAWDATA) {
3785 s_buttonaction(current_button_flags, action);
3786 current_button_flags = 0;
3792 static int c_on_release(map_t*args)
3794 char*position = lu(args, "position");
3796 if(!strcmp(position, "inside")) {
3797 current_button_flags |= BC_OVERDOWN_OVERUP;
3798 } else if(!strcmp(position, "outside")) {
3799 current_button_flags |= BC_OUTDOWN_IDLE;
3800 } else if(!strcmp(position, "anywhere")) {
3801 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3804 if(type == RAWDATA) {
3806 s_buttonaction(current_button_flags, action);
3807 current_button_flags = 0;
3813 static int c_on_move_in(map_t*args)
3815 char*position = lu(args, "state");
3817 if(!strcmp(position, "pressed")) {
3818 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3819 } else if(!strcmp(position, "not_pressed")) {
3820 current_button_flags |= BC_IDLE_OVERUP;
3821 } else if(!strcmp(position, "any")) {
3822 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3825 if(type == RAWDATA) {
3827 s_buttonaction(current_button_flags, action);
3828 current_button_flags = 0;
3834 static int c_on_move_out(map_t*args)
3836 char*position = lu(args, "state");
3838 if(!strcmp(position, "pressed")) {
3839 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3840 } else if(!strcmp(position, "not_pressed")) {
3841 current_button_flags |= BC_OVERUP_IDLE;
3842 } else if(!strcmp(position, "any")) {
3843 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3846 if(type == RAWDATA) {
3848 s_buttonaction(current_button_flags, action);
3849 current_button_flags = 0;
3855 static int c_on_key(map_t*args)
3857 char*key = lu(args, "key");
3859 if(strlen(key)==1) {
3862 current_button_flags |= 0x4000 + (key[0]*0x200);
3864 syntaxerror("invalid character: %c"+key[0]);
3869 <ctrl-x> = 0x200*(x-'a')
3873 syntaxerror("invalid key: %s",key);
3876 if(type == RAWDATA) {
3878 s_buttonaction(current_button_flags, action);
3879 current_button_flags = 0;
3886 static int c_edittext(map_t*args)
3888 //"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"},
3889 char*name = lu(args, "name");
3890 char*font = lu(args, "font");
3891 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3892 int width = parseTwip(lu(args, "width"));
3893 int height = parseTwip(lu(args, "height"));
3894 char*text = lu(args, "text");
3895 RGBA color = parseColor(lu(args, "color"));
3896 int maxlength = parseInt(lu(args, "maxlength"));
3897 char*variable = lu(args, "variable");
3898 char*passwordstr = lu(args, "password");
3899 char*wordwrapstr = lu(args, "wordwrap");
3900 char*multilinestr = lu(args, "multiline");
3901 char*htmlstr = lu(args, "html");
3902 char*noselectstr = lu(args, "noselect");
3903 char*readonlystr = lu(args, "readonly");
3904 char*borderstr = lu(args, "border");
3905 char*autosizestr = lu(args, "autosize");
3906 char*alignstr = lu(args, "align");
3910 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3911 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3912 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3913 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3914 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3915 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3916 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3917 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3918 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3919 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3920 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3921 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3922 else syntaxerror("Unknown alignment: %s", alignstr);
3924 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3928 static int c_morphshape(map_t*args) {return fakechar(args);}
3929 static int c_movie(map_t*args) {return fakechar(args);}
3931 static char* readfile(const char*filename)
3933 FILE*fi = fopen(filename, "rb");
3937 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3938 fseek(fi, 0, SEEK_END);
3940 fseek(fi, 0, SEEK_SET);
3941 text = rfx_alloc(l+1);
3942 fread(text, l, 1, fi);
3948 static int c_action(map_t*args)
3950 char* filename = map_lookup(args, "filename");
3951 if(!filename ||!*filename) {
3953 if(type != RAWDATA) {
3954 syntaxerror("colon (:) expected");
3958 s_action(readfile(filename));
3964 static int c_initaction(map_t*args)
3966 char* character = lu(args, "name");
3967 char* filename = map_lookup(args, "filename");
3968 if(!filename ||!*filename) {
3970 if(type != RAWDATA) {
3971 syntaxerror("colon (:) expected");
3973 s_initaction(character, text);
3975 s_initaction(character, readfile(filename));
3983 command_func_t* func;
3986 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
3987 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3988 // "import" type stuff
3989 {"swf", c_swf, "name filename"},
3990 {"shape", c_swf, "name filename"},
3991 {"jpeg", c_image, "name filename quality=80%"},
3992 {"png", c_image, "name filename"},
3993 {"movie", c_movie, "name filename"},
3994 {"sound", c_sound, "name filename"},
3995 {"font", c_font, "name filename glyphs="},
3996 {"soundtrack", c_soundtrack, "filename"},
3997 {"quicktime", c_quicktime, "url"},
3999 // generators of primitives
4001 {"define", c_define, "name value=0"},
4002 {"point", c_point, "name x=0 y=0"},
4003 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4004 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4005 {"outline", c_outline, "name format=simple"},
4006 {"textshape", c_textshape, "name font size=100% text"},
4009 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4010 {"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"},
4011 {"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"},
4012 {"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"},
4014 // character generators
4015 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4016 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4017 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4019 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4020 {"text", c_text, "name text font size=100% color=white"},
4021 {"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="},
4022 {"morphshape", c_morphshape, "name start end"},
4023 {"button", c_button, "name"},
4024 {"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="},
4025 {"on_press", c_on_press, "position=inside"},
4026 {"on_release", c_on_release, "position=anywhere"},
4027 {"on_move_in", c_on_move_in, "state=not_pressed"},
4028 {"on_move_out", c_on_move_out, "state=not_pressed"},
4029 {"on_key", c_on_key, "key=any"},
4032 {"play", c_play, "name loop=0 @nomultiple=0"},
4033 {"stop", c_stop, "name= "},
4034 {"nextframe", c_nextframe, "name"},
4035 {"previousframe", c_previousframe, "name"},
4037 // object placement tags
4038 {"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="},
4039 {"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="},
4040 {"move", c_move, "name x= y= interpolation=linear"},
4041 {"smove", c_smove, "name x= y= interpolation=linear"},
4042 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4043 {"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"},
4044 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4045 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4046 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4047 {"del", c_del, "name"},
4048 // virtual object placement
4049 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4051 {"toggle", c_toggle, "name fixed_alignment="},
4053 // commands which start a block
4054 //startclip (see above)
4055 {"sprite", c_sprite, "name scalinggrid="},
4056 {"action", c_action, "filename="},
4057 {"initaction", c_initaction, "name filename="},
4063 static map_t parseArguments(char*command, char*pattern)
4079 string_set(&t1, "commandname");
4080 string_set(&t2, command);
4081 map_put(&result, t1, t2);
4083 if(!pattern || !*pattern)
4090 if(!strncmp("<i> ", x, 3)) {
4092 if(type == COMMAND || type == RAWDATA) {
4094 syntaxerror("character name expected");
4096 name[pos].str = "instance";
4098 value[pos].str = text;
4099 value[pos].len = strlen(text);
4103 if(type == ASSIGNMENT)
4106 name[pos].str = "character";
4108 value[pos].str = text;
4109 value[pos].len = strlen(text);
4117 isboolean[pos] = (x[0] =='@');
4130 name[pos].len = d-x;
4135 name[pos].len = e-x;
4136 value[pos].str = e+1;
4137 value[pos].len = d-e-1;
4145 /* for(t=0;t<len;t++) {
4146 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4147 isboolean[t]?"(boolean)":"");
4152 if(type == RAWDATA || type == COMMAND) {
4157 // first, search for boolean arguments
4158 for(pos=0;pos<len;pos++)
4160 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4162 if(type == ASSIGNMENT)
4164 value[pos].str = text;
4165 value[pos].len = strlen(text);
4166 /*printf("setting boolean parameter %s (to %s)\n",
4167 strdup_n(name[pos], namelen[pos]),
4168 strdup_n(value[pos], valuelen[pos]));*/
4173 // second, search for normal arguments
4175 for(pos=0;pos<len;pos++)
4177 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4178 (type != ASSIGNMENT && !set[pos])) {
4180 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4182 if(type == ASSIGNMENT)
4185 value[pos].str = text;
4186 value[pos].len = strlen(text);
4188 printf("setting parameter %s (to %s)\n",
4189 strdup_n(name[pos].str, name[pos].len),
4190 strdup_n(value[pos].str, value[pos].len));
4196 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4200 for(t=0;t<len;t++) {
4201 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4204 for(t=0;t<len;t++) {
4205 if(value[t].str && value[t].str[0] == '*') {
4206 //relative default- take value from some other parameter
4208 for(s=0;s<len;s++) {
4209 if(value[s].len == value[t].len-1 &&
4210 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4211 value[t].str = value[s].str;
4214 if(value[t].str == 0) {
4216 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4220 /* ok, now construct the dictionary from the parameters */
4224 map_put(&result, name[t], value[t]);
4228 static void parseArgumentsForCommand(char*command)
4233 msg("<verbose> parse Command: %s (line %d)", command, line);
4235 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4236 if(!strcmp(arguments[t].command, command)) {
4238 /* ugly hack- will be removed soon (once documentation and .sc generating
4239 utilities have been changed) */
4240 if(!strcmp(command, "swf") && !stackpos) {
4241 warning("Please use .flash instead of .swf- this will be mandatory soon");
4246 args = parseArguments(command, arguments[t].arguments);
4252 syntaxerror("command %s not known", command);
4254 // catch missing .flash directives at the beginning of a file
4255 if(strcmp(command, "flash") && !stackpos)
4257 syntaxerror("No movie defined- use .flash first");
4261 printf(".%s\n", command);fflush(stdout);
4262 map_dump(&args, stdout, "\t");fflush(stdout);
4265 (*arguments[nr].func)(&args);
4267 /*if(!strcmp(command, "button") ||
4268 !strcmp(command, "action")) {
4271 if(type == COMMAND) {
4272 if(!strcmp(text, "end"))
4287 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4288 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4289 * No syntax checking is done */
4290 static void analyseArgumentsForCommand(char*command)
4296 U8* glyphs_to_include;
4297 msg("<verbose> analyse Command: %s (line %d)", command, line);
4299 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4301 if(!strcmp(arguments[t].command, command))
4303 args = parseArguments(command, arguments[t].arguments);
4309 printf(".%s\n", command);fflush(stdout);
4310 map_dump(&args, stdout, "\t");fflush(stdout);
4312 char* name = lu(&args, "name");
4313 if (!strcmp(command, "font"))
4315 if(dictionary_lookup(&fonts, name))
4316 syntaxerror("font %s defined twice", name);
4319 fontfile = lu(&args, "filename");
4320 font = swf_LoadFont(fontfile);
4322 warning("Couldn't open font file \"%s\"", fontfile);
4323 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4324 memset(font, 0, sizeof(SWFFONT));
4328 swf_FontPrepareForEditText(font);
4329 glyphs_to_include = lu(&args, "glyphs");
4330 if (!strcmp(glyphs_to_include, "all"))
4332 swf_FontUseAll(font);
4333 font->use->glyphs_specified = 1;
4337 if (strcmp (glyphs_to_include, ""))
4339 swf_FontUseUTF8(font, glyphs_to_include);
4340 font->use->glyphs_specified = 1;
4343 swf_FontInitUsage(font);
4346 dictionary_put2(&fonts, name, font);
4350 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
4352 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4354 if (font->use && !font->use->glyphs_specified)
4356 if (!strcmp(command, "edittext"))
4358 swf_FontUseAll(font);
4359 font->use->glyphs_specified = 1;
4362 swf_FontUseUTF8(font, lu(&args, "text"));
4369 void skipParameters()
4373 while (type != COMMAND);
4377 void findFontUsage()
4379 char* fontRelated = "font;text;textshape;edittext;";
4380 while(!noMoreTokens())
4384 syntaxerror("command expected");
4385 if (strstr(fontRelated, text))
4386 analyseArgumentsForCommand(text);
4388 if(strcmp(text, "end"))
4397 dictionary_init(&fonts);
4398 cleanUp = &freeFontDictionary;
4402 int main (int argc,char ** argv)
4405 processargs(argc, argv);
4406 initLog(0,-1,0,0,-1,verbose);
4409 args_callback_usage(argv[0]);
4413 file = generateTokens(filename);
4415 fprintf(stderr, "parser returned error.\n");
4422 while(!noMoreTokens()) {
4425 syntaxerror("command expected");
4426 parseArgumentsForCommand(text);