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;
819 if(swf_isAllowedSpriteTag(from))
827 static int parametersChange(history_t* history, int frame)
831 willChange = willChange || history_change(history, frame, "x");
832 willChange = willChange || history_change(history, frame, "y");
833 willChange = willChange || history_change(history, frame, "scalex");
834 willChange = willChange || history_change(history, frame, "scaley");
835 willChange = willChange || history_change(history, frame, "cxform.r0");
836 willChange = willChange || history_change(history, frame, "cxform.g0");
837 willChange = willChange || history_change(history, frame, "cxform.b0");
838 willChange = willChange || history_change(history, frame, "cxform.a0");
839 willChange = willChange || history_change(history, frame, "cxform.r1");
840 willChange = willChange || history_change(history, frame, "cxform.g1");
841 willChange = willChange || history_change(history, frame, "cxform.b1");
842 willChange = willChange || history_change(history, frame, "cxform.a1");
843 willChange = willChange || history_change(history, frame, "rotate");
844 willChange = willChange || history_change(history, frame, "shear");
845 willChange = willChange || history_change(history, frame, "pivot.x");
846 willChange = willChange || history_change(history, frame, "pivot.y");
847 willChange = willChange || history_change(history, frame, "pin.x");
848 willChange = willChange || history_change(history, frame, "pin.y");
849 willChange = willChange || history_change(history, frame, "blendmode");
850 willChange = willChange || history_changeFilter(history, frame);
855 static void free_filterlist(FILTERLIST* f_list)
858 for (i = 0; i < f_list->num; i++)
860 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
861 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
862 free(f_list->filter[i]);
867 static void readParameters(history_t* history, parameters_t* p, int frame)
869 p->x = history_value(history, frame, "x");
870 p->y = history_value(history, frame, "y");
871 p->scalex = history_value(history, frame, "scalex");
872 p->scaley = history_value(history, frame, "scaley");
873 p->cxform.r0 = history_value(history, frame, "cxform.r0");
874 p->cxform.g0 = history_value(history, frame, "cxform.g0");
875 p->cxform.b0 = history_value(history, frame, "cxform.b0");
876 p->cxform.a0 = history_value(history, frame, "cxform.a0");
877 p->cxform.r1 = history_value(history, frame, "cxform.r1");
878 p->cxform.g1 = history_value(history, frame, "cxform.g1");
879 p->cxform.b1 = history_value(history, frame, "cxform.b1");
880 p->cxform.a1 = history_value(history, frame, "cxform.a1");
881 p->rotate = history_rotateValue(history, frame);
882 p->shear = history_value(history, frame, "shear");
883 p->pivot.x = history_value(history, frame, "pivot.x");
884 p->pivot.y = history_value(history, frame, "pivot.y");
885 p->pin.x = history_value(history, frame, "pin.x");
886 p->pin.y = history_value(history, frame, "pin.y");
887 p->blendmode = history_value(history, frame, "blendmode");
888 p->filters = history_filterValue(history, frame);
891 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
895 swf_GetPlaceObject(NULL, &po);
899 po.cxform = p->cxform;
905 po.blendmode = p->blendmode;
908 po.filters = p->filters;
909 swf_SetPlaceObject(tag, &po);
912 static void writeInstance(instance_t* i)
916 int frame = i->history->firstFrame;
917 TAG* tag = i->history->firstTag;
918 history_processFlags(i->history);
919 while (frame < currentframe)
922 while (tag->id != ST_SHOWFRAME)
924 if (parametersChange(i->history, frame))
926 readParameters(i->history, &p, frame);
927 m = s_instancepos(i->character->size, &p);
929 if(p.blendmode || p.filters)
930 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
932 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
933 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
935 free_filterlist(p.filters);
942 void dumpSWF(SWF*swf)
944 TAG* tag = swf->firstTag;
945 printf("vvvvvvvvvvvvvvvvvvvvv\n");
947 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
950 printf("^^^^^^^^^^^^^^^^^^^^^\n");
953 static void s_endSprite()
955 SRECT r = currentrect;
959 stringarray_t* index =dictionary_index(&instances);
961 for (num = 0; num < dictionary_count(&instances); num++)
963 char* name = stringarray_at(index, num);
966 i = dictionary_lookup(&instances, name);
971 if(stack[stackpos].cut)
972 tag = removeFromTo(stack[stackpos].cut, tag);
974 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
975 // so let's make sure 'tag' point to the current tag again.
979 tag = swf_InsertTag(tag, ST_SHOWFRAME);
980 tag = swf_InsertTag(tag, ST_END);
982 tag = stack[stackpos].tag;
985 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
986 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
988 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
989 swf_SetU16(tag, stack[stackpos].id);
990 swf_SetRect(tag, &stack[stackpos].scalegrid);
994 syntaxerror("internal error(7)");
995 /* TODO: before clearing, prepend "<spritename>." to names and
996 copy into old instances dict */
997 dictionary_free_all(&instances, free_instance);
999 currentframe = stack[stackpos].oldframe;
1000 currentrect = stack[stackpos].oldrect;
1001 currentdepth = stack[stackpos].olddepth;
1002 instances = stack[stackpos].oldinstances;
1004 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1005 free(stack[stackpos].name);
1008 static void s_endSWF()
1015 stringarray_t* index = dictionary_index(&instances);
1017 for (num = 0; num < dictionary_count(&instances); num++)
1019 char* name = stringarray_at(index, num);
1022 i = dictionary_lookup(&instances, name);
1027 if(stack[stackpos].cut)
1028 tag = removeFromTo(stack[stackpos].cut, tag);
1032 swf = stack[stackpos].swf;
1033 filename = stack[stackpos].filename;
1035 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1036 // so let's make sure 'tag' point to the current tag again.
1040 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1041 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1042 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1044 tag = swf_InsertTag(tag, ST_END);
1046 swf_OptimizeTagOrder(swf);
1052 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1053 swf->movieSize = currentrect; /* "autocrop" */
1056 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1057 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1058 swf->movieSize.ymax += 20;
1059 warning("Empty bounding box for movie");
1062 if(do_cgi || !strcmp(filename, "-"))
1063 fi = fileno(stdout);
1065 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1067 syntaxerror("couldn't create output file %s", filename);
1070 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1072 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1086 if(stack[stackpos-1].type == 0)
1087 syntaxerror("End of file encountered in .flash block");
1088 if(stack[stackpos-1].type == 1)
1089 syntaxerror("End of file encountered in .sprite block");
1090 if(stack[stackpos-1].type == 2)
1091 syntaxerror("End of file encountered in .clip block");
1097 return currentframe+1;
1100 void s_frame(int nr, int cut, char*name, char anchor)
1106 syntaxerror("Illegal frame number");
1107 nr--; // internally, frame 1 is frame 0
1109 for(t=currentframe;t<nr;t++) {
1110 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1111 if(t==nr-1 && name && *name) {
1112 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1113 swf_SetString(tag, name);
1115 swf_SetU8(tag, 1); //make this an anchor
1118 if(nr == 0 && currentframe == 0 && name && *name) {
1119 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1120 swf_SetString(tag, name);
1122 swf_SetU8(tag, 1); //make this an anchor
1127 syntaxerror("Can't cut, frame empty");
1129 stack[stackpos].cut = tag;
1135 int parseColor2(char*str, RGBA*color);
1137 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1141 gradient_t*gradient;
1143 if(name[0] == '#') {
1144 parseColor2(name, &color);
1145 return swf_ShapeAddSolidFillStyle(s, &color);
1146 } else if ((texture = dictionary_lookup(&textures, name))) {
1147 return swf_ShapeAddFillStyle2(s, &texture->fs);
1148 } else if((image = dictionary_lookup(&images, name))) {
1150 swf_GetMatrix(0, &m);
1151 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1152 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1155 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1156 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1160 swf_GetMatrix(0, &rot);
1161 ccos = cos(-gradient->rotate*2*M_PI/360);
1162 csin = sin(-gradient->rotate*2*M_PI/360);
1163 rot.sx = ccos*65536;
1164 rot.r1 = -csin*65536;
1165 rot.r0 = csin*65536;
1166 rot.sy = ccos*65536;
1167 r2 = swf_TurnRect(*r, &rot);
1168 swf_GetMatrix(0, &m);
1169 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1170 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1171 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1172 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1173 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1174 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1175 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1176 } else if (parseColor2(name, &color)) {
1177 return swf_ShapeAddSolidFillStyle(s, &color);
1179 syntaxerror("not a color/fillstyle: %s", name);
1184 RGBA black={r:0,g:0,b:0,a:0};
1185 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1194 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1197 linewidth = linewidth>=20?linewidth-20:0;
1198 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1201 fs1 = addFillStyle(s, &r2, texture);
1204 r.xmin = r2.xmin-linewidth/2;
1205 r.ymin = r2.ymin-linewidth/2;
1206 r.xmax = r2.xmax+linewidth/2;
1207 r.ymax = r2.ymax+linewidth/2;
1208 swf_SetRect(tag,&r);
1209 swf_SetShapeHeader(tag,s);
1210 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1211 swf_ShapeSetLine(tag,s,width,0);
1212 swf_ShapeSetLine(tag,s,0,height);
1213 swf_ShapeSetLine(tag,s,-width,0);
1214 swf_ShapeSetLine(tag,s,0,-height);
1215 swf_ShapeSetEnd(tag);
1218 s_addcharacter(name, id, tag, r);
1222 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1228 outline = dictionary_lookup(&outlines, outlinename);
1230 syntaxerror("outline %s not defined", outlinename);
1234 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1237 linewidth = linewidth>=20?linewidth-20:0;
1238 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1241 fs1 = addFillStyle(s, &r2, texture);
1244 rect.xmin = r2.xmin-linewidth/2;
1245 rect.ymin = r2.ymin-linewidth/2;
1246 rect.xmax = r2.xmax+linewidth/2;
1247 rect.ymax = r2.ymax+linewidth/2;
1249 swf_SetRect(tag,&rect);
1250 swf_SetShapeStyles(tag, s);
1251 swf_ShapeCountBits(s,0,0);
1252 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1253 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1254 swf_SetShapeBits(tag, s);
1255 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1258 s_addcharacter(name, id, tag, rect);
1262 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1267 r2.xmin = r2.ymin = 0;
1271 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1274 linewidth = linewidth>=20?linewidth-20:0;
1275 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1278 fs1 = addFillStyle(s, &r2, texture);
1280 rect.xmin = r2.xmin-linewidth/2;
1281 rect.ymin = r2.ymin-linewidth/2;
1282 rect.xmax = r2.xmax+linewidth/2;
1283 rect.ymax = r2.ymax+linewidth/2;
1285 swf_SetRect(tag,&rect);
1286 swf_SetShapeHeader(tag,s);
1287 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1288 swf_ShapeSetCircle(tag, s, r,r,r,r);
1289 swf_ShapeSetEnd(tag);
1292 s_addcharacter(name, id, tag, rect);
1296 void s_textshape(char*name, char*fontname, float size, char*_text)
1299 U8*text = (U8*)_text;
1303 font = dictionary_lookup(&fonts, fontname);
1305 syntaxerror("font \"%s\" not known!", fontname);
1307 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1308 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1309 s_box(name, 0, 0, black, 20, 0);
1312 g = font->ascii2glyph[text[0]];
1314 outline = malloc(sizeof(outline_t));
1315 memset(outline, 0, sizeof(outline_t));
1316 outline->shape = font->glyph[g].shape;
1317 outline->bbox = font->layout->bounds[g];
1321 swf_Shape11DrawerInit(&draw, 0);
1322 swf_DrawText(&draw, font, (int)(size*100), _text);
1324 outline->shape = swf_ShapeDrawerToShape(&draw);
1325 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1326 draw.dealloc(&draw);
1329 if(dictionary_lookup(&outlines, name))
1330 syntaxerror("outline %s defined twice", name);
1331 dictionary_put2(&outlines, name, outline);
1334 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1339 font = dictionary_lookup(&fonts, fontname);
1341 syntaxerror("font \"%s\" not known!", fontname);
1343 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1344 swf_SetU16(tag, id);
1345 if(!font->numchars) {
1346 s_box(name, 0, 0, black, 20, 0);
1349 r = swf_SetDefineText(tag, font, &color, text, size);
1351 if(stack[0].swf->fileVersion >= 8) {
1352 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1353 swf_SetU16(tag, id);
1354 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1355 swf_SetU32(tag, 0);//thickness
1356 swf_SetU32(tag, 0);//sharpness
1357 swf_SetU8(tag, 0);//reserved
1360 s_addcharacter(name, id, tag, r);
1364 void s_quicktime(char*name, char*url)
1369 memset(&r, 0, sizeof(r));
1371 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1372 swf_SetU16(tag, id);
1373 swf_SetString(tag, url);
1375 s_addcharacter(name, id, tag, r);
1379 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)
1382 EditTextLayout layout;
1385 if(fontname && *fontname) {
1386 flags |= ET_USEOUTLINES;
1387 font = dictionary_lookup(&fonts, fontname);
1389 syntaxerror("font \"%s\" not known!", fontname);
1391 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1392 swf_SetU16(tag, id);
1393 layout.align = align;
1394 layout.leftmargin = 0;
1395 layout.rightmargin = 0;
1403 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1405 s_addcharacter(name, id, tag, r);
1409 /* type: either "jpeg" or "png"
1411 void s_image(char*name, char*type, char*filename, int quality)
1413 /* an image is actually two folded: 1st bitmap, 2nd character.
1414 Both of them can be used separately */
1416 /* step 1: the bitmap */
1420 if(!strcmp(type,"jpeg")) {
1421 #ifndef HAVE_JPEGLIB
1422 warning("no jpeg support compiled in");
1423 s_box(name, 0, 0, black, 20, 0);
1426 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1427 swf_SetU16(tag, imageID);
1429 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1430 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1433 swf_GetJPEGSize(filename, &width, &height);
1440 s_addimage(name, id, tag, r);
1443 } else if(!strcmp(type,"png")) {
1445 swf_SetU16(tag, imageID);
1447 getPNG(filename, &width, &height, (unsigned char**)&data);
1450 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1453 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1454 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1455 swf_SetU16(tag, imageID);
1456 swf_SetLosslessImage(tag, data, width, height);
1463 s_addimage(name, id, tag, r);
1466 warning("image type \"%s\" not supported yet!", type);
1467 s_box(name, 0, 0, black, 20, 0);
1471 /* step 2: the character */
1472 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1473 swf_SetU16(tag, id);
1474 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1476 s_addcharacter(name, id, tag, r);
1480 void s_getBitmapSize(char*name, int*width, int*height)
1482 character_t* image = dictionary_lookup(&images, name);
1483 gradient_t* gradient = dictionary_lookup(&gradients,name);
1485 *width = image->size.xmax;
1486 *height = image->size.ymax;
1490 /* internal SWF gradient size */
1491 if(gradient->radial) {
1500 syntaxerror("No such bitmap/gradient: %s", name);
1503 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1505 if(dictionary_lookup(&textures, name))
1506 syntaxerror("texture %s defined twice", name);
1507 gradient_t* gradient = dictionary_lookup(&gradients, object);
1508 character_t* bitmap = dictionary_lookup(&images, object);
1509 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1511 FILLSTYLE*fs = &texture->fs;
1513 memset(&p, 0, sizeof(parameters_t));
1516 fs->type = FILL_TILED;
1517 fs->id_bitmap = bitmap->id;
1518 } else if(gradient) {
1519 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1520 fs->gradient = gradient->gradient;
1522 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1523 makeMatrix(&fs->m, &p);
1524 if(gradient && !gradient->radial) {
1531 p2 = swf_TurnPoint(p1, &m);
1540 dictionary_put2(&textures, name, texture);
1543 void s_font(char*name, char*filename)
1546 font = dictionary_lookup(&fonts, name);
1549 /* fix the layout. Only needed for old fonts */
1551 for(t=0;t<font->numchars;t++) {
1552 font->glyph[t].advance = 0;
1555 swf_FontCreateLayout(font);
1558 swf_FontReduce_swfc(font);
1559 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1560 swf_FontSetDefine2(tag, font);
1562 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1564 swf_SetU16(tag, id);
1565 swf_SetString(tag, name);
1573 typedef struct _sound_t
1579 void s_sound(char*name, char*filename)
1581 struct WAV wav, wav2;
1585 unsigned numsamples = 1;
1586 unsigned blocksize = 1152;
1589 if(dictionary_lookup(&sounds, name))
1590 syntaxerror("sound %s defined twice", name);
1592 if(wav_read(&wav, filename))
1595 wav_convert2mono(&wav, &wav2, 44100);
1596 samples = (U16*)wav2.data;
1597 numsamples = wav2.size/2;
1599 #ifdef WORDS_BIGENDIAN
1601 for(t=0;t<numsamples;t++)
1602 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1606 if(mp3_read(&mp3, filename))
1608 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1614 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1619 if(numsamples%blocksize != 0)
1621 // apply padding, so that block is a multiple of blocksize
1622 int numblocks = (numsamples+blocksize-1)/blocksize;
1625 numsamples2 = numblocks * blocksize;
1626 samples2 = malloc(sizeof(U16)*numsamples2);
1627 memcpy(samples2, samples, numsamples*sizeof(U16));
1628 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1629 numsamples = numsamples2;
1634 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1635 swf_SetU16(tag, id); //id
1638 swf_SetSoundDefineMP3(
1639 tag, mp3.data, mp3.size,
1646 swf_SetSoundDefine(tag, samples, numsamples);
1649 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1650 swf_SetU16(tag, id);
1651 swf_SetString(tag, name);
1652 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1654 swf_SetU16(tag, id);
1655 swf_SetString(tag, name);
1658 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1662 dictionary_put2(&sounds, name, sound);
1670 static char* gradient_getToken(const char**p)
1674 while(**p && strchr(" \t\n\r", **p)) {
1678 while(**p && !strchr(" \t\n\r", **p)) {
1681 result = malloc((*p)-start+1);
1682 memcpy(result,start,(*p)-start+1);
1683 result[(*p)-start] = 0;
1687 float parsePercent(char*str);
1688 RGBA parseColor(char*str);
1690 GRADIENT parseGradient(const char*str)
1694 const char* p = str;
1695 memset(&gradient, 0, sizeof(GRADIENT));
1696 gradient.ratios = rfx_calloc(16*sizeof(U8));
1697 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1701 char*posstr,*colorstr;
1704 posstr = gradient_getToken(&p);
1710 pos = (int)(parsePercent(posstr)*255.0);
1715 rfx_free(gradient.ratios);
1716 rfx_free(gradient.rgba);
1718 syntaxerror("Error in shape data: Color expected after %s", posstr);
1720 colorstr = gradient_getToken(&p);
1721 color = parseColor(colorstr);
1722 if(gradient.num == 16)
1724 warning("gradient record too big- max size is 16, rest ignored");
1727 gradient.ratios[gradient.num] = pos;
1728 gradient.rgba[gradient.num] = color;
1737 FILTERLIST* parseFilters(char* list)
1739 if (!strcmp(list, "no_filters"))
1742 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1744 char* f_start = list;
1748 f_end = strchr(f_start, ',');
1751 f = dictionary_lookup(&filters, f_start);
1755 syntaxerror("unknown filter %s", f_start);
1757 if (f_list->num == 8)
1759 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1762 f_list->filter[f_list->num] = f;
1767 f_start = f_end + 1;
1775 void s_gradient(char*name, const char*text, int radial, int rotate)
1777 gradient_t* gradient;
1778 gradient = malloc(sizeof(gradient_t));
1779 memset(gradient, 0, sizeof(gradient_t));
1780 gradient->gradient = parseGradient(text);
1781 gradient->radial = radial;
1782 gradient->rotate = rotate;
1784 dictionary_put2(&gradients, name, gradient);
1787 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1788 float angle, float distance, float strength, char innershadow,
1789 char knockout, char composite, char ontop, int passes)
1791 if(dictionary_lookup(&filters, name))
1792 syntaxerror("filter %s defined twice", name);
1794 gradient_t* g = dictionary_lookup(&gradients, gradient);
1796 syntaxerror("unknown gradient %s", gradient);
1800 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1801 filter->type = FILTERTYPE_GRADIENTGLOW;
1802 filter->gradient = &g->gradient;
1803 filter->blurx = blurx;
1804 filter->blury = blury;
1805 filter->strength = strength;
1806 filter->angle = angle;
1807 filter->distance = distance;
1808 filter->innershadow = innershadow;
1809 filter->knockout = knockout;
1810 filter->composite = composite;
1811 filter->ontop = ontop;
1812 filter->passes = passes;
1814 dictionary_put2(&filters, name, filter);
1817 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)
1819 if(dictionary_lookup(&filters, name))
1820 syntaxerror("filter %s defined twice", name);
1823 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1824 filter->type = FILTERTYPE_DROPSHADOW;
1825 filter->color= color;
1826 filter->blurx = blurx;
1827 filter->blury = blury;
1828 filter->strength = strength;
1829 filter->angle = angle;
1830 filter->distance = distance;
1831 filter->innershadow = innershadow;
1832 filter->knockout = knockout;
1833 filter->composite = composite;
1834 filter->passes = passes;
1836 dictionary_put2(&filters, name, filter);
1839 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)
1841 if(dictionary_lookup(&filters, name))
1842 syntaxerror("filter %s defined twice", name);
1845 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1846 filter->type = FILTERTYPE_BEVEL;
1847 filter->shadow = shadow;
1848 filter->highlight = highlight;
1849 filter->blurx = blurx;
1850 filter->blury = blury;
1851 filter->strength = strength;
1852 filter->angle = angle;
1853 filter->distance = distance;
1854 filter->innershadow = innershadow;
1855 filter->knockout = knockout;
1856 filter->composite = composite;
1857 filter->ontop = ontop;
1858 filter->passes = passes;
1860 dictionary_put2(&filters, name, filter);
1863 void s_blur(char*name, double blurx, double blury, int passes)
1865 if(dictionary_lookup(&filters, name))
1866 syntaxerror("filter %s defined twice", name);
1868 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1869 filter->type = FILTERTYPE_BLUR;
1870 filter->blurx = blurx;
1871 filter->blury = blury;
1872 filter->passes = passes;
1874 dictionary_put2(&filters, name, filter);
1877 void s_action(const char*text)
1880 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1884 syntaxerror("Couldn't compile ActionScript");
1887 tag = swf_InsertTag(tag, ST_DOACTION);
1889 swf_ActionSet(tag, a);
1894 void s_initaction(const char*character, const char*text)
1898 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1902 syntaxerror("Couldn't compile ActionScript");
1905 c = (character_t*)dictionary_lookup(&characters, character);
1907 tag = swf_InsertTag(tag, ST_DOINITACTION);
1908 swf_SetU16(tag, c->id);
1909 swf_ActionSet(tag, a);
1914 int s_swf3action(char*name, char*action)
1917 instance_t* object = 0;
1919 object = (instance_t*)dictionary_lookup(&instances, name);
1920 if(!object && name && *name) {
1921 /* we have a name, but couldn't find it. Abort. */
1924 a = action_SetTarget(0, name);
1925 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1926 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1927 else if(!strcmp(action, "stop")) a = action_Stop(a);
1928 else if(!strcmp(action, "play")) a = action_Play(a);
1929 a = action_SetTarget(a, "");
1932 tag = swf_InsertTag(tag, ST_DOACTION);
1933 swf_ActionSet(tag, a);
1938 void s_outline(char*name, char*format, char*source)
1940 if(dictionary_lookup(&outlines, name))
1941 syntaxerror("outline %s defined twice", name);
1950 //swf_Shape10DrawerInit(&draw, 0);
1951 swf_Shape11DrawerInit(&draw, 0);
1953 draw_string(&draw, source);
1955 shape = swf_ShapeDrawerToShape(&draw);
1956 bounds = swf_ShapeDrawerGetBBox(&draw);
1957 draw.dealloc(&draw);
1959 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1960 outline->shape = shape;
1961 outline->bbox = bounds;
1963 dictionary_put2(&outlines, name, outline);
1966 int s_playsound(char*name, int loops, int nomultiple, int stop)
1972 sound = dictionary_lookup(&sounds, name);
1976 tag = swf_InsertTag(tag, ST_STARTSOUND);
1977 swf_SetU16(tag, sound->id); //id
1978 memset(&info, 0, sizeof(info));
1981 info.nomultiple = nomultiple;
1982 swf_SetSoundInfo(tag, &info);
1986 void s_includeswf(char*name, char*filename)
1994 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1995 f = open(filename,O_RDONLY|O_BINARY);
1997 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1998 s_box(name, 0, 0, black, 20, 0);
2001 if (swf_ReadSWF(f,&swf)<0) {
2002 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
2003 s_box(name, 0, 0, black, 20, 0);
2008 /* FIXME: The following sets the bounding Box for the character.
2009 It is wrong for two reasons:
2010 a) It may be too small (in case objects in the movie clip at the borders)
2011 b) it may be too big (because the poor movie never got autocropped)
2015 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2016 swf_SetU16(tag, id);
2017 swf_SetU16(tag, swf.frameCount);
2019 swf_Relocate(&swf, idmap);
2021 ftag = swf.firstTag;
2025 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2026 if(cutout[t] == ftag->id) {
2030 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2032 if(ftag->id == ST_END)
2037 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2038 /* We simply dump all tags right after the sprite
2039 header, relying on the fact that swf_OptimizeTagOrder() will
2040 sort things out for us later.
2041 We also rely on the fact that the imported SWF is well-formed.
2043 tag = swf_InsertTag(tag, ftag->id);
2044 swf_SetBlock(tag, ftag->data, ftag->len);
2050 syntaxerror("Included file %s contains errors", filename);
2051 tag = swf_InsertTag(tag, ST_END);
2055 s_addcharacter(name, id, tag, r);
2058 SRECT s_getCharBBox(char*name)
2060 character_t* c = dictionary_lookup(&characters, name);
2061 if(!c) syntaxerror("character '%s' unknown(2)", name);
2064 SRECT s_getInstanceBBox(char*name)
2066 instance_t * i = dictionary_lookup(&instances, name);
2068 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2070 if(!c) syntaxerror("internal error(5)");
2073 void s_getParameters(char*name, parameters_t* p)
2075 instance_t * i = dictionary_lookup(&instances, name);
2077 syntaxerror("instance '%s' unknown(10)", name);
2078 if (change_sets_all)
2079 readParameters(i->history, p, currentframe);
2084 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2086 history_begin(i->history, "x", currentframe, tag, p->x);
2087 history_begin(i->history, "y", currentframe, tag, p->y);
2088 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2089 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2090 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2091 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2092 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2093 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2094 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2095 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2096 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2097 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2098 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2099 history_begin(i->history, "shear", currentframe, tag, p->shear);
2100 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2101 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2102 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2103 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2104 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2105 history_beginFilter(i->history, currentframe, tag, p->filters);
2106 history_begin(i->history, "flags", currentframe, tag, 0);
2109 void s_startclip(char*instance, char*character, parameters_t p)
2111 character_t* c = dictionary_lookup(&characters, character);
2115 syntaxerror("character %s not known", character);
2117 i = s_addinstance(instance, c, currentdepth);
2119 m = s_instancepos(i->character->size, &p);
2121 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2122 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2123 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2125 stack[stackpos].tag = tag;
2126 stack[stackpos].type = 2;
2129 setStartparameters(i, &p, tag);
2136 swf_SetTagPos(stack[stackpos].tag, 0);
2137 swf_GetPlaceObject(stack[stackpos].tag, &p);
2138 p.clipdepth = currentdepth;
2140 swf_ClearTag(stack[stackpos].tag);
2141 swf_SetPlaceObject(stack[stackpos].tag, &p);
2145 void s_put(char*instance, char*character, parameters_t p)
2147 character_t* c = dictionary_lookup(&characters, character);
2151 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2153 i = s_addinstance(instance, c, currentdepth);
2155 m = s_instancepos(i->character->size, &p);
2157 if(p.blendmode || p.filters)
2159 if(stack[0].swf->fileVersion < 8)
2162 warning("blendmodes only supported for flash version>=8");
2164 warning("filters only supported for flash version>=8");
2166 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2169 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2170 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2171 setStartparameters(i, &p, tag);
2175 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2178 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2180 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2181 if (p.set & SF_SCALEX)
2182 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2183 if (p.set & SF_SCALEY)
2184 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2185 if (p.set & SF_CX_R)
2187 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2188 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2190 if (p.set & SF_CX_G)
2192 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2193 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2195 if (p.set & SF_CX_B)
2197 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2198 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2200 if (p.set & SF_CX_A)
2202 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2203 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2205 if (p.set & SF_ROTATE)
2206 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2207 if (p.set & SF_SHEAR)
2208 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2209 if (p.set & SF_PIVOT)
2211 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2212 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2216 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2217 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2219 if (p.set & SF_BLEND)
2220 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2221 if (p.set & SF_FILTER)
2222 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2225 void s_jump(char* instance, parameters_t p)
2227 instance_t* i = dictionary_lookup(&instances, instance);
2229 syntaxerror("instance %s not known", instance);
2230 recordChanges(i->history, p, CF_JUMP, 0);
2233 void s_change(char*instance, parameters_t p, interpolation_t* inter)
2235 instance_t* i = dictionary_lookup(&instances, instance);
2237 syntaxerror("instance %s not known", instance);
2238 recordChanges(i->history, p, CF_CHANGE, inter);
2241 void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2243 instance_t* i = dictionary_lookup(&instances, instance);
2245 syntaxerror("instance %s not known", instance);
2246 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2249 void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
2251 instance_t* i = dictionary_lookup(&instances, instance);
2253 syntaxerror("instance %s not known", instance);
2254 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2257 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2260 void s_delinstance(char*instance)
2262 instance_t* i = dictionary_lookup(&instances, instance);
2264 syntaxerror("instance %s not known", instance);
2266 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2267 swf_SetU16(tag, i->depth);
2268 dictionary_del(&instances, instance);
2271 void s_schange(char*instance, parameters_t p, interpolation_t* inter)
2273 instance_t* i = dictionary_lookup(&instances, instance);
2275 syntaxerror("instance %s not known", instance);
2276 recordChanges(i->history, p, CF_SCHANGE, inter);
2282 syntaxerror(".end unexpected");
2283 switch (stack[stackpos-1].type)
2298 syntaxerror("internal error 1");
2302 // ------------------------------------------------------------------------
2304 typedef int command_func_t(map_t*args);
2306 SRECT parseBox(char*str)
2308 SRECT r = {0,0,0,0};
2309 float xmin, xmax, ymin, ymax;
2310 char*x = strchr(str, 'x');
2312 if(!strcmp(str, "autocrop")) {
2313 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2317 d1 = strchr(x+1, ':');
2319 d2 = strchr(d1+1, ':');
2321 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2325 else if(d1 && !d2) {
2326 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2332 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2337 r.xmin = (SCOORD)(xmin*20);
2338 r.ymin = (SCOORD)(ymin*20);
2339 r.xmax = (SCOORD)(xmax*20);
2340 r.ymax = (SCOORD)(ymax*20);
2343 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2346 float parseFloat(char*str)
2350 int parseInt(char*str)
2355 if(str[0]=='+' || str[0]=='-')
2359 if(str[t]<'0' || str[t]>'9')
2360 syntaxerror("Not an Integer: \"%s\"", str);
2363 int parseRawTwip(char*str)
2367 if(str[0]=='+' || str[0]=='-') {
2372 dot = strchr(str, '.');
2376 return sign*parseInt(str)*20;
2378 char* old = strdup(str);
2379 int l=strlen(dot+1);
2382 for(s=str;s<dot-1;s++)
2383 if(*s<'0' || *s>'9')
2386 syntaxerror("Not a coordinate: \"%s\"", str);
2389 if(*s<'0' || *s>'9')
2392 syntaxerror("Not a coordinate: \"%s\"", str);
2394 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2395 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2398 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2402 return sign*(atoi(str)*20);
2404 return sign*(atoi(str)*20+atoi(dot)*2);
2406 return sign*(atoi(str)*20+atoi(dot)/5);
2411 static dictionary_t defines;
2412 static int defines_initialized = 0;
2413 static mem_t define_values;
2415 int parseTwip(char*str)
2417 /* TODO: make this a proper expression parser */
2423 if(*p == '+' || *p == '-' || *p == '/' || *p == '*')
2428 if((*p == '+' || *p == '-' || *p == '/' || *p == '*' || *p == 0) && lastpos) {
2434 if(defines_initialized) {
2435 l = (int)dictionary_lookup(&defines, lastpos);
2438 v = *(int*)&define_values.buffer[l-1];
2440 v = parseRawTwip(lastpos);
2460 int parseArc(char* str)
2462 if (!strcmp(str, "short"))
2464 if (!strcmp(str, "long"))
2466 syntaxerror("invalid value for the arc parameter: %s", str);
2470 int parseDir(char* str)
2472 if (!strcmp(str, "clockwise"))
2474 if (!strcmp(str, "counterclockwise"))
2476 syntaxerror("invalid value for the dir parameter: %s", str);
2480 int isPoint(char*str)
2482 if(strchr(str, '('))
2488 SPOINT parsePoint(char*str)
2492 int l = strlen(str);
2493 char*comma = strchr(str, ',');
2494 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2495 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2496 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2497 p.x = parseTwip(tmp);
2498 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2499 p.y = parseTwip(tmp);
2503 int parseColor2(char*str, RGBA*color)
2505 int l = strlen(str);
2509 struct {unsigned char r,g,b;char*name;} colors[] =
2510 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2511 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2512 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2513 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2514 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2515 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2516 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2517 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2518 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2519 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2520 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2521 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2525 if(str[0]=='#' && (l==7 || l==9)) {
2526 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2528 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2530 color->r = r; color->g = g; color->b = b; color->a = a;
2533 int len=strlen(str);
2535 if(strchr(str, '/')) {
2536 len = strchr(str, '/')-str;
2537 sscanf(str+len+1,"%02x", &alpha);
2539 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2540 if(!strncmp(str, colors[t].name, len)) {
2545 color->r = r; color->g = g; color->b = b; color->a = a;
2551 RGBA parseColor(char*str)
2554 if(!parseColor2(str, &c))
2555 syntaxerror("Expression '%s' is not a color", str);
2559 typedef struct _muladd {
2564 MULADD parseMulAdd(char*str)
2567 char* str2 = (char*)malloc(strlen(str)+5);
2574 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2575 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2576 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2577 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2578 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2579 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2580 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2581 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2582 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2583 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2585 syntaxerror("'%s' is not a valid color transform expression", str);
2587 m.add = (int)(add*256);
2588 m.mul = (int)(mul*256);
2593 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2595 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2596 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2598 if(a<-32768) a=-32768;
2599 if(a>32767) a=32767;
2600 if(m<-32768) m=-32768;
2601 if(m>32767) m=32767;
2607 float parsePxOrPercent(char*fontname, char*str)
2609 int l = strlen(str);
2610 if(strchr(str, '%'))
2611 return parsePercent(str);
2612 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2613 float p = atof(str);
2614 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2616 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2620 float parsePercent(char*str)
2622 int l = strlen(str);
2626 return atoi(str)/100.0;
2628 syntaxerror("Expression '%s' is not a percentage", str);
2631 int isPercent(char*str)
2633 return str[strlen(str)-1]=='%';
2635 int parseNewSize(char*str, int size)
2638 return parsePercent(str)*size;
2640 return (int)(atof(str)*20);
2643 int isColor(char*str)
2646 return parseColor2(str, &c);
2649 static char* lu(map_t* args, char*name)
2651 char* value = map_lookup(args, name);
2653 map_dump(args, stdout, "");
2654 syntaxerror("internal error 2: value %s should be set", name);
2659 static int c_flash(map_t*args)
2661 char* filename = map_lookup(args, "filename");
2662 char* compressstr = lu(args, "compress");
2663 char* change_modestr = lu(args, "change-sets-all");
2664 char* exportstr = lu(args, "export");
2665 SRECT bbox = parseBox(lu(args, "bbox"));
2666 int version = parseInt(lu(args, "version"));
2667 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2668 RGBA color = parseColor(lu(args, "background"));
2671 if(!filename || !*filename) {
2672 /* for compatibility */
2673 filename = map_lookup(args, "name");
2674 if(!filename || !*filename) {
2677 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2678 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2682 if(!filename || override_outputname)
2683 filename = outputname;
2685 if(!strcmp(compressstr, "default"))
2686 compress = version>=6;
2687 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2689 else if(!strcmp(compressstr, "no"))
2691 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2693 if(!strcmp(change_modestr, "yes"))
2694 change_sets_all = 1;
2696 if(strcmp(change_modestr, "no"))
2697 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2699 do_exports=atoi(exportstr);
2701 s_swf(filename, bbox, version, fps, compress, color);
2704 int isRelative(char*str)
2706 return !strncmp(str, "<plus>", 6) ||
2707 !strncmp(str, "<minus>", 7);
2709 char* getOffset(char*str)
2711 if(!strncmp(str, "<plus>", 6))
2713 if(!strncmp(str, "<minus>", 7))
2715 syntaxerror("internal error (347)");
2718 int getSign(char*str)
2720 if(!strncmp(str, "<plus>", 6))
2722 if(!strncmp(str, "<minus>", 7))
2724 syntaxerror("internal error (348)");
2728 static dictionary_t points;
2729 static mem_t mpoints;
2730 static int points_initialized = 0;
2732 static int c_interpolation(map_t *args)
2735 char* name = lu(args, "name");
2736 if (dictionary_lookup(&interpolations, name))
2737 syntaxerror("interpolation %s defined twice", name);
2739 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2740 char* functionstr = lu(args, "function");
2741 inter->function = 0;
2742 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2743 if (!strcmp(functionstr,interpolationFunctions[i]))
2745 inter->function = i + 1;
2748 if (!inter->function)
2749 syntaxerror("unkown interpolation function %s", functionstr);
2750 inter->speed = parseFloat(lu(args, "speed"));
2751 inter->amplitude = parseTwip(lu(args, "amplitude"));
2752 inter->growth = parseFloat(lu(args, "growth"));
2753 inter->bounces = parseInt(lu(args, "bounces"));
2754 inter->damping = parseFloat(lu(args, "damping"));
2755 inter->slope = parseFloat(lu(args, "slope"));
2757 dictionary_put2(&interpolations, name, inter);
2761 SPOINT getPoint(SRECT r, char*name)
2764 if(!strcmp(name, "center")) {
2766 p.x = (r.xmin + r.xmax)/2;
2767 p.y = (r.ymin + r.ymax)/2;
2770 if (!strcmp(name, "bottom-center")) {
2772 p.x = (r.xmin + r.xmax)/2;
2776 if (!strcmp(name, "top-center")) {
2778 p.x = (r.xmin + r.xmax)/2;
2782 if (!strcmp(name, "top-left")) {
2788 if (!strcmp(name, "top-right")) {
2794 if (!strcmp(name, "bottom-right")) {
2800 if (!strcmp(name, "bottom-left")) {
2806 if (!strcmp(name, "left-center")) {
2809 p.y = (r.ymin + r.ymax)/2;
2812 if (!strcmp(name, "right-center")) {
2815 p.y = (r.ymin + r.ymax)/2;
2820 if(points_initialized)
2821 l = (int)dictionary_lookup(&points, name);
2823 syntaxerror("Invalid point: \"%s\".", name);
2825 return *(SPOINT*)&mpoints.buffer[l-1];
2829 static int texture2(char*name, char*object, map_t*args, int errors)
2832 char*xstr = map_lookup(args, "x");
2833 char*ystr = map_lookup(args, "y");
2834 char*widthstr = map_lookup(args, "width");
2835 char*heightstr = map_lookup(args, "height");
2836 char*scalestr = map_lookup(args, "scale");
2837 char*scalexstr = map_lookup(args, "scalex");
2838 char*scaleystr = map_lookup(args, "scaley");
2839 char*rotatestr = map_lookup(args, "rotate");
2840 char* shearstr = map_lookup(args, "shear");
2841 char* radiusstr = map_lookup(args, "r");
2843 float scalex = 1.0, scaley = 1.0;
2844 float rotate=0, shear=0;
2846 if(!*xstr && !*ystr) {
2848 syntaxerror("x and y must be set");
2851 if(*scalestr && (*scalexstr || *scaleystr)) {
2852 syntaxerror("scale and scalex/scaley can't both be set");
2855 if((*widthstr || *heightstr) && *radiusstr) {
2856 syntaxerror("width/height and radius can't both be set");
2859 widthstr = radiusstr;
2860 heightstr = radiusstr;
2862 if(!*xstr) xstr="0";
2863 if(!*ystr) ystr="0";
2864 if(!*rotatestr) rotatestr="0";
2865 if(!*shearstr) shearstr="0";
2868 scalex = scaley = parsePercent(scalestr);
2869 } else if(*scalexstr || *scaleystr) {
2870 if(scalexstr) scalex = parsePercent(scalexstr);
2871 if(scaleystr) scaley = parsePercent(scaleystr);
2872 } else if(*widthstr || *heightstr) {
2875 s_getBitmapSize(object, &width, &height);
2877 scalex = (float)parseTwip(widthstr)/(float)width;
2879 scaley = (float)parseTwip(heightstr)/(float)height;
2881 x = parseTwip(xstr);
2882 y = parseTwip(ystr);
2883 rotate = parseFloat(rotatestr);
2884 shear = parseFloat(shearstr);
2886 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2891 static int c_texture(map_t*args)
2893 char*name = lu(args, "instance");
2894 char*object = lu(args, "character");
2895 return texture2(name, object, args, 1);
2898 static int c_gradient(map_t*args)
2900 char*name = lu(args, "name");
2901 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2902 int rotate = parseInt(lu(args, "rotate"));
2906 syntaxerror("colon (:) expected");
2908 if(dictionary_lookup(&gradients, name))
2909 syntaxerror("gradient %s defined twice", name);
2911 s_gradient(name, text, radial, rotate);
2913 /* check whether we also have placement information,
2914 which would make this a positioned gradient.
2915 If there is placement information, texture2() will
2916 add a texture, which has priority over the gradient.
2918 texture2(name, name, args, 0);
2922 static char* checkFiltername(map_t* args)
2924 char* name = lu(args, "name");
2925 if (strchr(name, ','))
2926 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
2930 static int c_blur(map_t*args)
2932 char*name = checkFiltername(args);
2933 char*blurstr = lu(args, "blur");
2934 char*blurxstr = lu(args, "blurx");
2935 char*blurystr = lu(args, "blury");
2936 float blurx=1.0, blury=1.0;
2938 blurx = parseFloat(blurstr);
2939 blury = parseFloat(blurstr);
2942 blurx = parseFloat(blurxstr);
2944 blury = parseFloat(blurystr);
2945 int passes = parseInt(lu(args, "passes"));
2946 s_blur(name, blurx, blury, passes);
2950 static int c_gradientglow(map_t*args)
2952 char*name = checkFiltername(args);
2953 char*gradient = lu(args, "gradient");
2954 char*blurstr = lu(args, "blur");
2955 char*blurxstr = lu(args, "blurx");
2956 char*blurystr = lu(args, "blury");
2957 float blurx=1.0, blury=1.0;
2959 blurx = parseFloat(blurstr);
2960 blury = parseFloat(blurstr);
2963 blurx = parseFloat(blurxstr);
2965 blury = parseFloat(blurystr);
2967 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2968 float distance = parseFloat(lu(args, "distance"));
2969 float strength = parseFloat(lu(args, "strength"));
2970 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2971 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2972 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2973 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2974 int passes = parseInt(lu(args, "passes"));
2976 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2980 static int c_dropshadow(map_t*args)
2982 char*name = checkFiltername(args);
2983 RGBA color = parseColor(lu(args, "color"));
2984 char*blurstr = lu(args, "blur");
2985 char*blurxstr = lu(args, "blurx");
2986 char*blurystr = lu(args, "blury");
2987 float blurx=1.0, blury=1.0;
2989 blurx = parseFloat(blurstr);
2990 blury = parseFloat(blurstr);
2993 blurx = parseFloat(blurxstr);
2995 blury = parseFloat(blurystr);
2997 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2998 float distance = parseFloat(lu(args, "distance"));
2999 float strength = parseFloat(lu(args, "strength"));
3000 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3001 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3002 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3003 int passes = parseInt(lu(args, "passes"));
3005 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3009 static int c_bevel(map_t*args)
3011 char*name = checkFiltername(args);
3012 RGBA shadow = parseColor(lu(args, "shadow"));
3013 RGBA highlight = parseColor(lu(args, "highlight"));
3014 char*blurstr = lu(args, "blur");
3015 char*blurxstr = lu(args, "blurx");
3016 char*blurystr = lu(args, "blury");
3017 float blurx=1.0, blury=1.0;
3019 blurx = parseFloat(blurstr);
3020 blury = parseFloat(blurstr);
3023 blurx = parseFloat(blurxstr);
3025 blury = parseFloat(blurystr);
3027 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3028 float distance = parseFloat(lu(args, "distance"));
3029 float strength = parseFloat(lu(args, "strength"));
3030 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3031 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3032 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3033 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3034 int passes = parseInt(lu(args, "passes"));
3036 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3040 static int c_define(map_t*args)
3042 char*name = lu(args, "name");
3043 char*value = lu(args, "value");
3045 if(!defines_initialized) {
3046 dictionary_init(&defines);
3047 mem_init(&define_values);
3048 defines_initialized = 1;
3050 int val = parseTwip(value);
3051 int pos = mem_put(&define_values, &val, sizeof(val));
3053 string_set(&s, name);
3054 dictionary_put(&defines, s, (void*)(pos+1));
3057 static int c_point(map_t*args)
3059 char*name = lu(args, "name");
3063 if(!points_initialized) {
3064 dictionary_init(&points);
3066 points_initialized = 1;
3068 p.x = parseTwip(lu(args, "x"));
3069 p.y = parseTwip(lu(args, "y"));
3070 pos = mem_put(&mpoints, &p, sizeof(p));
3071 string_set(&s1, name);
3072 dictionary_put(&points, s1, (void*)(pos+1));
3075 static int c_play(map_t*args)
3077 char*name = lu(args, "name");
3078 char*loop = lu(args, "loop");
3079 char*nomultiple = lu(args, "nomultiple");
3081 if(!strcmp(nomultiple, "nomultiple"))
3084 nm = parseInt(nomultiple);
3086 if(s_playsound(name, parseInt(loop), nm, 0)) {
3088 } else if(s_swf3action(name, "play")) {
3094 static int c_stop(map_t*args)
3096 char*name = map_lookup(args, "name");
3098 if(s_playsound(name, 0,0,1))
3100 else if(s_swf3action(name, "stop"))
3102 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3106 static int c_nextframe(map_t*args)
3108 char*name = lu(args, "name");
3110 if(s_swf3action(name, "nextframe")) {
3113 syntaxerror("I don't know anything about movie \"%s\"", name);
3117 static int c_previousframe(map_t*args)
3119 char*name = lu(args, "name");
3121 if(s_swf3action(name, "previousframe")) {
3124 syntaxerror("I don't know anything about movie \"%s\"", name);
3128 static int c_movement(map_t*args, int type)
3130 char*instance = lu(args, "name");
3138 xstr = lu(args, "x");
3139 ystr = lu(args, "y");
3141 s_getParameters(instance, &p);
3146 if(isRelative(xstr))
3148 if(type == PT_PUT || type == PT_STARTCLIP)
3149 syntaxerror("relative x values not allowed for initial put or startclip");
3150 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3154 p.x = parseTwip(xstr);
3160 if(isRelative(ystr))
3162 if(type == PT_PUT || type == PT_STARTCLIP)
3163 syntaxerror("relative y values not allowed for initial put or startclip");
3164 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3168 p.y = parseTwip(ystr);
3173 if (change_sets_all)
3181 char* interstr = lu(args, "interpolation");
3182 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3184 syntaxerror("unkown interpolation %s", interstr);
3185 s_change(instance, p, inter);
3190 char* interstr = lu(args, "interpolation");
3191 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3193 syntaxerror("unkown interpolation %s", interstr);
3194 s_schange(instance, p, inter);
3199 char* rstr = lu(args, "r");
3200 int radius = parseTwip(rstr);
3202 syntaxerror("sweep not possible: radius must be greater than 0.");
3203 char* dirstr = lu(args, "dir");
3204 int clockwise = parseDir(dirstr);
3205 char* arcstr = lu(args, "arc");
3206 int short_arc = parseArc(arcstr);
3207 char* interstr = lu(args, "interpolation");
3208 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3210 syntaxerror("unkown interpolation %s", interstr);
3211 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3218 static int c_placement(map_t*args, int type)
3220 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3223 char* luminancestr = lu(args, "luminance");
3224 char* scalestr = lu(args, "scale");
3225 char* scalexstr = lu(args, "scalex");
3226 char* scaleystr = lu(args, "scaley");
3227 char* rotatestr = lu(args, "rotate");
3228 char* shearstr = lu(args, "shear");
3229 char* xstr="", *pivotstr="";
3230 char* ystr="", *anglestr="";
3231 char*above = lu(args, "above"); /*FIXME*/
3232 char*below = lu(args, "below");
3233 char* rstr = lu(args, "red");
3234 char* gstr = lu(args, "green");
3235 char* bstr = lu(args, "blue");
3236 char* astr = lu(args, "alpha");
3237 char* pinstr = lu(args, "pin");
3238 char* as = map_lookup(args, "as");
3239 char* blendmode = lu(args, "blend");
3240 char* filterstr = lu(args, "filter");
3251 { // (?) .rotate or .arcchange
3252 pivotstr = lu(args, "pivot");
3253 anglestr = lu(args, "angle");
3257 xstr = lu(args, "x");
3258 ystr = lu(args, "y");
3262 luminance = parseMulAdd(luminancestr);
3266 luminance.mul = 256;
3271 if(scalexstr[0]||scaleystr[0])
3272 syntaxerror("scalex/scaley and scale cannot both be set");
3273 scalexstr = scaleystr = scalestr;
3276 if(type == PT_PUT || type == PT_STARTCLIP) {
3278 character = lu(args, "character");
3279 parameters_clear(&p);
3280 } else if (type == PT_BUTTON) {
3281 character = lu(args, "name");
3282 parameters_clear(&p);
3285 s_getParameters(instance, &p);
3291 if(isRelative(xstr))
3293 if(type == PT_PUT || type == PT_STARTCLIP)
3294 syntaxerror("relative x values not allowed for initial put or startclip");
3295 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3299 p.x = parseTwip(xstr);
3305 if(isRelative(ystr))
3307 if(type == PT_PUT || type == PT_STARTCLIP)
3308 syntaxerror("relative y values not allowed for initial put or startclip");
3309 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3313 p.y = parseTwip(ystr);
3318 /* scale, scalex, scaley */
3320 oldbbox = s_getCharBBox(character);
3322 oldbbox = s_getInstanceBBox(instance);
3323 oldwidth = oldbbox.xmax - oldbbox.xmin;
3324 oldheight = oldbbox.ymax - oldbbox.ymin;
3331 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3332 set = set | SF_SCALEX;
3340 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3341 set = set | SF_SCALEY;
3347 if(isRelative(rotatestr))
3348 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3350 p.rotate = parseFloat(rotatestr);
3351 set = set | SF_ROTATE;
3357 if(isRelative(shearstr))
3358 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3360 p.shear = parseFloat(shearstr);
3361 set = set | SF_SHEAR;
3366 if(isPoint(pivotstr))
3367 p.pivot = parsePoint(pivotstr);
3369 p.pivot = getPoint(oldbbox, pivotstr);
3370 set = set | SF_PIVOT;
3376 p.pin = parsePoint(pinstr);
3378 p.pin = getPoint(oldbbox, pinstr);
3382 /* color transform */
3384 if(rstr[0] || luminancestr[0])
3388 r = parseMulAdd(rstr);
3391 r.add = p.cxform.r0;
3392 r.mul = p.cxform.r1;
3394 r = mergeMulAdd(r, luminance);
3395 p.cxform.r0 = r.mul;
3396 p.cxform.r1 = r.add;
3397 set = set | SF_CX_R;
3399 if(gstr[0] || luminancestr[0])
3403 g = parseMulAdd(gstr);
3406 g.add = p.cxform.g0;
3407 g.mul = p.cxform.g1;
3409 g = mergeMulAdd(g, luminance);
3410 p.cxform.g0 = g.mul;
3411 p.cxform.g1 = g.add;
3412 set = set | SF_CX_G;
3414 if(bstr[0] || luminancestr[0])
3418 b = parseMulAdd(bstr);
3421 b.add = p.cxform.b0;
3422 b.mul = p.cxform.b1;
3424 b = mergeMulAdd(b, luminance);
3425 p.cxform.b0 = b.mul;
3426 p.cxform.b1 = b.add;
3427 set = set | SF_CX_B;
3431 MULADD a = parseMulAdd(astr);
3432 p.cxform.a0 = a.mul;
3433 p.cxform.a1 = a.add;
3434 set = set | SF_CX_A;
3441 for(t = 0; blendModeNames[t]; t++)
3443 if(!strcmp(blendModeNames[t], blendmode))
3451 syntaxerror("unknown blend mode: '%s'", blendmode);
3453 p.blendmode = blend;
3454 set = set | SF_BLEND;
3459 p.filters = parseFilters(filterstr);
3460 set = set | SF_FILTER;
3463 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3464 warning("As of version 0.8.2 using the .change command to modify an \
3465 object's position on the stage is considered deprecated. Future \
3466 versions may consider x and y parameters for the .change command \
3467 to be illegal; please use the .move command.");
3469 if (change_sets_all)
3476 s_put(instance, character, p);
3480 char* interstr = lu(args, "interpolation");
3481 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3483 syntaxerror("unkown interpolation %s", interstr);
3484 s_change(instance, p, inter);
3489 char* interstr = lu(args, "interpolation");
3490 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3492 syntaxerror("unkown interpolation %s", interstr);
3493 s_schange(instance, p, inter);
3497 s_jump(instance, p);
3500 s_startclip(instance, character, p);
3504 s_buttonput(character, as, p);
3506 s_buttonput(character, "shape", p);
3512 static int c_put(map_t*args)
3514 c_placement(args, PT_PUT);
3517 static int c_change(map_t*args)
3519 if (currentframe == 0)
3520 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3521 c_placement(args, PT_CHANGE);
3524 static int c_schange(map_t*args)
3526 c_placement(args, PT_SCHANGE);
3529 static int c_move(map_t* args)
3531 c_movement(args, PT_MOVE);
3534 static int c_smove(map_t* args)
3536 c_movement(args, PT_SMOVE);
3539 static int c_sweep(map_t* args)
3541 c_movement(args, PT_SWEEP);
3544 static int c_arcchange(map_t*args)
3546 c_placement(args, 0);
3549 static int c_jump(map_t*args)
3551 c_placement(args, PT_JUMP);
3554 static int c_startclip(map_t*args)
3556 c_placement(args, PT_STARTCLIP);
3559 static int c_show(map_t*args)
3561 c_placement(args, PT_BUTTON);
3564 static int c_toggle(map_t* args)
3566 char*instance = lu(args, "name");
3567 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3568 char* alignstr = lu(args, "fixed_alignment");
3569 if (!strcmp(alignstr, "on"))
3570 flagsOn += IF_FIXED_ALIGNMENT;
3572 if (!strcmp(alignstr, "off"))
3573 flagsOff -= IF_FIXED_ALIGNMENT;
3575 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3576 s_toggle(instance, flagsOn, flagsOff);
3579 static int c_del(map_t*args)
3581 char*instance = lu(args, "name");
3582 s_delinstance(instance);
3585 static int c_end(map_t*args)
3590 static int c_sprite(map_t*args)
3592 char* name = lu(args, "name");
3593 char* scalinggrid = lu(args, "scalinggrid");
3595 if(scalinggrid && *scalinggrid) {
3596 SRECT r = parseBox(scalinggrid);
3603 static int c_frame(map_t*args)
3605 char*framestr = lu(args, "n");
3606 char*cutstr = lu(args, "cut");
3608 char*name = lu(args, "name");
3609 char*anchor = lu(args, "anchor");
3612 if(!strcmp(anchor, "anchor") && !*name)
3617 if(strcmp(cutstr, "no"))
3619 if(isRelative(framestr)) {
3620 frame = s_getframe();
3621 if(getSign(framestr)<0)
3622 syntaxerror("relative frame expressions must be positive");
3623 frame += parseInt(getOffset(framestr));
3626 frame = parseInt(framestr);
3627 if(s_getframe() >= frame
3628 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3629 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3631 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3634 static int c_primitive(map_t*args)
3636 char*name = lu(args, "name");
3637 char*command = lu(args, "commandname");
3638 int width=0, height=0, r=0;
3639 int linewidth = parseTwip(lu(args, "line"));
3640 char*colorstr = lu(args, "color");
3641 RGBA color = parseColor(colorstr);
3642 char*fillstr = lu(args, "fill");
3649 if(!strcmp(command, "circle"))
3651 else if(!strcmp(command, "filled"))
3655 width = parseTwip(lu(args, "width"));
3656 height = parseTwip(lu(args, "height"));
3657 } else if (type==1) {
3658 r = parseTwip(lu(args, "r"));
3659 } else if (type==2) {
3660 outline = lu(args, "outline");
3663 if(!strcmp(fillstr, "fill"))
3665 if(!strcmp(fillstr, "none"))
3667 if(width<0 || height<0 || linewidth<0 || r<0)
3668 syntaxerror("values width, height, line, r must be positive");
3670 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3671 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3672 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3676 static int c_textshape(map_t*args)
3678 char*name = lu(args, "name");
3679 char*text = lu(args, "text");
3680 char*font = lu(args, "font");
3681 float size = parsePxOrPercent(font, lu(args, "size"));
3683 s_textshape(name, font, size, text);
3687 static int c_swf(map_t*args)
3689 char*name = lu(args, "name");
3690 char*filename = lu(args, "filename");
3691 char*command = lu(args, "commandname");
3692 if(!strcmp(command, "shape"))
3693 warning("Please use .swf instead of .shape");
3694 s_includeswf(name, filename);
3698 static int c_font(map_t*args)
3700 char*name = lu(args, "name");
3701 char*filename = lu(args, "filename");
3702 s_font(name, filename);
3706 static int c_sound(map_t*args)
3708 char*name = lu(args, "name");
3709 char*filename = lu(args, "filename");
3710 s_sound(name, filename);
3714 static int c_text(map_t*args)
3716 char*name = lu(args, "name");
3717 char*text = lu(args, "text");
3718 char*font = lu(args, "font");
3719 float size = parsePxOrPercent(font, lu(args, "size"));
3720 RGBA color = parseColor(lu(args, "color"));
3721 s_text(name, font, text, (int)(size*100), color);
3725 static int c_soundtrack(map_t*args)
3730 static int c_quicktime(map_t*args)
3732 char*name = lu(args, "name");
3733 char*url = lu(args, "url");
3734 s_quicktime(name, url);
3738 static int c_image(map_t*args)
3740 char*command = lu(args, "commandname");
3741 char*name = lu(args, "name");
3742 char*filename = lu(args, "filename");
3743 if(!strcmp(command,"jpeg")) {
3744 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3745 s_image(name, "jpeg", filename, quality);
3747 s_image(name, "png", filename, 0);
3752 static int c_outline(map_t*args)
3754 char*name = lu(args, "name");
3755 char*format = lu(args, "format");
3759 syntaxerror("colon (:) expected");
3761 s_outline(name, format, text);
3765 int fakechar(map_t*args)
3767 char*name = lu(args, "name");
3768 s_box(name, 0, 0, black, 20, 0);
3772 static int c_egon(map_t*args) {return fakechar(args);}
3773 static int c_button(map_t*args) {
3774 char*name = lu(args, "name");
3778 static int current_button_flags = 0;
3779 static int c_on_press(map_t*args)
3781 char*position = lu(args, "position");
3783 if(!strcmp(position, "inside")) {
3784 current_button_flags |= BC_OVERUP_OVERDOWN;
3785 } else if(!strcmp(position, "outside")) {
3786 //current_button_flags |= BC_IDLE_OUTDOWN;
3787 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3788 } else if(!strcmp(position, "anywhere")) {
3789 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3792 if(type == RAWDATA) {
3794 s_buttonaction(current_button_flags, action);
3795 current_button_flags = 0;
3801 static int c_on_release(map_t*args)
3803 char*position = lu(args, "position");
3805 if(!strcmp(position, "inside")) {
3806 current_button_flags |= BC_OVERDOWN_OVERUP;
3807 } else if(!strcmp(position, "outside")) {
3808 current_button_flags |= BC_OUTDOWN_IDLE;
3809 } else if(!strcmp(position, "anywhere")) {
3810 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3813 if(type == RAWDATA) {
3815 s_buttonaction(current_button_flags, action);
3816 current_button_flags = 0;
3822 static int c_on_move_in(map_t*args)
3824 char*position = lu(args, "state");
3826 if(!strcmp(position, "pressed")) {
3827 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3828 } else if(!strcmp(position, "not_pressed")) {
3829 current_button_flags |= BC_IDLE_OVERUP;
3830 } else if(!strcmp(position, "any")) {
3831 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3834 if(type == RAWDATA) {
3836 s_buttonaction(current_button_flags, action);
3837 current_button_flags = 0;
3843 static int c_on_move_out(map_t*args)
3845 char*position = lu(args, "state");
3847 if(!strcmp(position, "pressed")) {
3848 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3849 } else if(!strcmp(position, "not_pressed")) {
3850 current_button_flags |= BC_OVERUP_IDLE;
3851 } else if(!strcmp(position, "any")) {
3852 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3855 if(type == RAWDATA) {
3857 s_buttonaction(current_button_flags, action);
3858 current_button_flags = 0;
3864 static int c_on_key(map_t*args)
3866 char*key = lu(args, "key");
3868 if(strlen(key)==1) {
3871 current_button_flags |= 0x4000 + (key[0]*0x200);
3873 syntaxerror("invalid character: %c"+key[0]);
3878 <ctrl-x> = 0x200*(x-'a')
3882 syntaxerror("invalid key: %s",key);
3885 if(type == RAWDATA) {
3887 s_buttonaction(current_button_flags, action);
3888 current_button_flags = 0;
3895 static int c_edittext(map_t*args)
3897 //"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"},
3898 char*name = lu(args, "name");
3899 char*font = lu(args, "font");
3900 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3901 int width = parseTwip(lu(args, "width"));
3902 int height = parseTwip(lu(args, "height"));
3903 char*text = lu(args, "text");
3904 RGBA color = parseColor(lu(args, "color"));
3905 int maxlength = parseInt(lu(args, "maxlength"));
3906 char*variable = lu(args, "variable");
3907 char*passwordstr = lu(args, "password");
3908 char*wordwrapstr = lu(args, "wordwrap");
3909 char*multilinestr = lu(args, "multiline");
3910 char*htmlstr = lu(args, "html");
3911 char*noselectstr = lu(args, "noselect");
3912 char*readonlystr = lu(args, "readonly");
3913 char*borderstr = lu(args, "border");
3914 char*autosizestr = lu(args, "autosize");
3915 char*alignstr = lu(args, "align");
3919 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3920 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3921 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3922 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3923 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3924 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3925 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3926 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3927 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3928 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3929 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3930 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3931 else syntaxerror("Unknown alignment: %s", alignstr);
3933 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3937 static int c_morphshape(map_t*args) {return fakechar(args);}
3938 static int c_movie(map_t*args) {return fakechar(args);}
3940 static char* readfile(const char*filename)
3942 FILE*fi = fopen(filename, "rb");
3946 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3947 fseek(fi, 0, SEEK_END);
3949 fseek(fi, 0, SEEK_SET);
3950 text = rfx_alloc(l+1);
3951 fread(text, l, 1, fi);
3957 static int c_action(map_t*args)
3959 char* filename = map_lookup(args, "filename");
3960 if(!filename ||!*filename) {
3962 if(type != RAWDATA) {
3963 syntaxerror("colon (:) expected");
3967 s_action(readfile(filename));
3973 static int c_initaction(map_t*args)
3975 char* character = lu(args, "name");
3976 char* filename = map_lookup(args, "filename");
3977 if(!filename ||!*filename) {
3979 if(type != RAWDATA) {
3980 syntaxerror("colon (:) expected");
3982 s_initaction(character, text);
3984 s_initaction(character, readfile(filename));
3992 command_func_t* func;
3995 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
3996 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3997 // "import" type stuff
3998 {"swf", c_swf, "name filename"},
3999 {"shape", c_swf, "name filename"},
4000 {"jpeg", c_image, "name filename quality=80%"},
4001 {"png", c_image, "name filename"},
4002 {"movie", c_movie, "name filename"},
4003 {"sound", c_sound, "name filename"},
4004 {"font", c_font, "name filename glyphs="},
4005 {"soundtrack", c_soundtrack, "filename"},
4006 {"quicktime", c_quicktime, "url"},
4008 // generators of primitives
4010 {"define", c_define, "name value=0"},
4011 {"point", c_point, "name x=0 y=0"},
4012 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4013 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4014 {"outline", c_outline, "name format=simple"},
4015 {"textshape", c_textshape, "name font size=100% text"},
4018 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4019 {"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"},
4020 {"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"},
4021 {"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"},
4023 // character generators
4024 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4025 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4026 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4028 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4029 {"text", c_text, "name text font size=100% color=white"},
4030 {"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="},
4031 {"morphshape", c_morphshape, "name start end"},
4032 {"button", c_button, "name"},
4033 {"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="},
4034 {"on_press", c_on_press, "position=inside"},
4035 {"on_release", c_on_release, "position=anywhere"},
4036 {"on_move_in", c_on_move_in, "state=not_pressed"},
4037 {"on_move_out", c_on_move_out, "state=not_pressed"},
4038 {"on_key", c_on_key, "key=any"},
4041 {"play", c_play, "name loop=0 @nomultiple=0"},
4042 {"stop", c_stop, "name= "},
4043 {"nextframe", c_nextframe, "name"},
4044 {"previousframe", c_previousframe, "name"},
4046 // object placement tags
4047 {"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="},
4048 {"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="},
4049 {"move", c_move, "name x= y= interpolation=linear"},
4050 {"smove", c_smove, "name x= y= interpolation=linear"},
4051 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4052 {"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"},
4053 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4054 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4055 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4056 {"del", c_del, "name"},
4057 // virtual object placement
4058 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4060 {"toggle", c_toggle, "name fixed_alignment="},
4062 // commands which start a block
4063 //startclip (see above)
4064 {"sprite", c_sprite, "name scalinggrid="},
4065 {"action", c_action, "filename="},
4066 {"initaction", c_initaction, "name filename="},
4072 static map_t parseArguments(char*command, char*pattern)
4088 string_set(&t1, "commandname");
4089 string_set(&t2, command);
4090 map_put(&result, t1, t2);
4092 if(!pattern || !*pattern)
4099 if(!strncmp("<i> ", x, 3)) {
4101 if(type == COMMAND || type == RAWDATA) {
4103 syntaxerror("character name expected");
4105 name[pos].str = "instance";
4107 value[pos].str = text;
4108 value[pos].len = strlen(text);
4112 if(type == ASSIGNMENT)
4115 name[pos].str = "character";
4117 value[pos].str = text;
4118 value[pos].len = strlen(text);
4126 isboolean[pos] = (x[0] =='@');
4139 name[pos].len = d-x;
4144 name[pos].len = e-x;
4145 value[pos].str = e+1;
4146 value[pos].len = d-e-1;
4154 /* for(t=0;t<len;t++) {
4155 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4156 isboolean[t]?"(boolean)":"");
4161 if(type == RAWDATA || type == COMMAND) {
4166 // first, search for boolean arguments
4167 for(pos=0;pos<len;pos++)
4169 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4171 if(type == ASSIGNMENT)
4173 value[pos].str = text;
4174 value[pos].len = strlen(text);
4175 /*printf("setting boolean parameter %s (to %s)\n",
4176 strdup_n(name[pos], namelen[pos]),
4177 strdup_n(value[pos], valuelen[pos]));*/
4182 // second, search for normal arguments
4184 for(pos=0;pos<len;pos++)
4186 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4187 (type != ASSIGNMENT && !set[pos])) {
4189 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4191 if(type == ASSIGNMENT)
4194 value[pos].str = text;
4195 value[pos].len = strlen(text);
4197 printf("setting parameter %s (to %s)\n",
4198 strdup_n(name[pos].str, name[pos].len),
4199 strdup_n(value[pos].str, value[pos].len));
4205 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4209 for(t=0;t<len;t++) {
4210 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4213 for(t=0;t<len;t++) {
4214 if(value[t].str && value[t].str[0] == '*') {
4215 //relative default- take value from some other parameter
4217 for(s=0;s<len;s++) {
4218 if(value[s].len == value[t].len-1 &&
4219 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4220 value[t].str = value[s].str;
4223 if(value[t].str == 0) {
4225 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4229 /* ok, now construct the dictionary from the parameters */
4233 map_put(&result, name[t], value[t]);
4237 static void parseArgumentsForCommand(char*command)
4242 msg("<verbose> parse Command: %s (line %d)", command, line);
4244 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4245 if(!strcmp(arguments[t].command, command)) {
4247 /* ugly hack- will be removed soon (once documentation and .sc generating
4248 utilities have been changed) */
4249 if(!strcmp(command, "swf") && !stackpos) {
4250 warning("Please use .flash instead of .swf- this will be mandatory soon");
4255 args = parseArguments(command, arguments[t].arguments);
4261 syntaxerror("command %s not known", command);
4263 // catch missing .flash directives at the beginning of a file
4264 if(strcmp(command, "flash") && !stackpos)
4266 syntaxerror("No movie defined- use .flash first");
4270 printf(".%s\n", command);fflush(stdout);
4271 map_dump(&args, stdout, "\t");fflush(stdout);
4274 (*arguments[nr].func)(&args);
4276 /*if(!strcmp(command, "button") ||
4277 !strcmp(command, "action")) {
4280 if(type == COMMAND) {
4281 if(!strcmp(text, "end"))
4296 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4297 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4298 * No syntax checking is done */
4299 static void analyseArgumentsForCommand(char*command)
4305 U8* glyphs_to_include;
4306 msg("<verbose> analyse Command: %s (line %d)", command, line);
4308 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4310 if(!strcmp(arguments[t].command, command))
4312 args = parseArguments(command, arguments[t].arguments);
4318 printf(".%s\n", command);fflush(stdout);
4319 map_dump(&args, stdout, "\t");fflush(stdout);
4321 char* name = lu(&args, "name");
4322 if (!strcmp(command, "font"))
4324 if(dictionary_lookup(&fonts, name))
4325 syntaxerror("font %s defined twice", name);
4328 fontfile = lu(&args, "filename");
4329 font = swf_LoadFont(fontfile);
4331 warning("Couldn't open font file \"%s\"", fontfile);
4332 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4333 memset(font, 0, sizeof(SWFFONT));
4337 swf_FontPrepareForEditText(font);
4338 glyphs_to_include = lu(&args, "glyphs");
4339 if (!strcmp(glyphs_to_include, "all"))
4341 swf_FontUseAll(font);
4342 font->use->glyphs_specified = 1;
4346 if (strcmp (glyphs_to_include, ""))
4348 swf_FontUseUTF8(font, glyphs_to_include);
4349 font->use->glyphs_specified = 1;
4352 swf_FontInitUsage(font);
4355 dictionary_put2(&fonts, name, font);
4359 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
4361 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4363 if (font->use && !font->use->glyphs_specified)
4365 if (!strcmp(command, "edittext"))
4367 swf_FontUseAll(font);
4368 font->use->glyphs_specified = 1;
4371 swf_FontUseUTF8(font, lu(&args, "text"));
4378 void skipParameters()
4382 while (type != COMMAND);
4386 void findFontUsage()
4388 char* fontRelated = "font;text;textshape;edittext;";
4389 while(!noMoreTokens())
4393 syntaxerror("command expected");
4394 if (strstr(fontRelated, text))
4395 analyseArgumentsForCommand(text);
4397 if(strcmp(text, "end"))
4406 dictionary_init(&fonts);
4407 cleanUp = &freeFontDictionary;
4411 int main (int argc,char ** argv)
4414 processargs(argc, argv);
4415 initLog(0,-1,0,0,-1,verbose);
4418 args_callback_usage(argv[0]);
4422 file = generateTokens(filename);
4424 fprintf(stderr, "parser returned error.\n");
4431 while(!noMoreTokens()) {
4434 syntaxerror("command expected");
4435 parseArgumentsForCommand(text);