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);
2443 printf("%f %c= %f\n", val/20.0, ex, v/20.0);
2458 printf("%s -> %.2f\n", str, val/20.0);
2462 int parseArc(char* str)
2464 if (!strcmp(str, "short"))
2466 if (!strcmp(str, "long"))
2468 syntaxerror("invalid value for the arc parameter: %s", str);
2472 int parseDir(char* str)
2474 if (!strcmp(str, "clockwise"))
2476 if (!strcmp(str, "counterclockwise"))
2478 syntaxerror("invalid value for the dir parameter: %s", str);
2482 int isPoint(char*str)
2484 if(strchr(str, '('))
2490 SPOINT parsePoint(char*str)
2494 int l = strlen(str);
2495 char*comma = strchr(str, ',');
2496 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2497 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2498 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2499 p.x = parseTwip(tmp);
2500 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2501 p.y = parseTwip(tmp);
2505 int parseColor2(char*str, RGBA*color)
2507 int l = strlen(str);
2511 struct {unsigned char r,g,b;char*name;} colors[] =
2512 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2513 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2514 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2515 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2516 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2517 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2518 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2519 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2520 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2521 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2522 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2523 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2527 if(str[0]=='#' && (l==7 || l==9)) {
2528 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2530 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2532 color->r = r; color->g = g; color->b = b; color->a = a;
2535 int len=strlen(str);
2537 if(strchr(str, '/')) {
2538 len = strchr(str, '/')-str;
2539 sscanf(str+len+1,"%02x", &alpha);
2541 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2542 if(!strncmp(str, colors[t].name, len)) {
2547 color->r = r; color->g = g; color->b = b; color->a = a;
2553 RGBA parseColor(char*str)
2556 if(!parseColor2(str, &c))
2557 syntaxerror("Expression '%s' is not a color", str);
2561 typedef struct _muladd {
2566 MULADD parseMulAdd(char*str)
2569 char* str2 = (char*)malloc(strlen(str)+5);
2576 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2577 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2578 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2579 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2580 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2581 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2582 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2583 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2584 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2585 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2587 syntaxerror("'%s' is not a valid color transform expression", str);
2589 m.add = (int)(add*256);
2590 m.mul = (int)(mul*256);
2595 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2597 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2598 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2600 if(a<-32768) a=-32768;
2601 if(a>32767) a=32767;
2602 if(m<-32768) m=-32768;
2603 if(m>32767) m=32767;
2609 float parsePxOrPercent(char*fontname, char*str)
2611 int l = strlen(str);
2612 if(strchr(str, '%'))
2613 return parsePercent(str);
2614 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2615 float p = atof(str);
2616 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2618 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2622 float parsePercent(char*str)
2624 int l = strlen(str);
2628 return atoi(str)/100.0;
2630 syntaxerror("Expression '%s' is not a percentage", str);
2633 int isPercent(char*str)
2635 return str[strlen(str)-1]=='%';
2637 int parseNewSize(char*str, int size)
2640 return parsePercent(str)*size;
2642 return (int)(atof(str)*20);
2645 int isColor(char*str)
2648 return parseColor2(str, &c);
2651 static char* lu(map_t* args, char*name)
2653 char* value = map_lookup(args, name);
2655 map_dump(args, stdout, "");
2656 syntaxerror("internal error 2: value %s should be set", name);
2661 static int c_flash(map_t*args)
2663 char* filename = map_lookup(args, "filename");
2664 char* compressstr = lu(args, "compress");
2665 char* change_modestr = lu(args, "change-sets-all");
2666 char* exportstr = lu(args, "export");
2667 SRECT bbox = parseBox(lu(args, "bbox"));
2668 int version = parseInt(lu(args, "version"));
2669 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2670 RGBA color = parseColor(lu(args, "background"));
2673 if(!filename || !*filename) {
2674 /* for compatibility */
2675 filename = map_lookup(args, "name");
2676 if(!filename || !*filename) {
2679 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2680 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2684 if(!filename || override_outputname)
2685 filename = outputname;
2687 if(!strcmp(compressstr, "default"))
2688 compress = version>=6;
2689 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2691 else if(!strcmp(compressstr, "no"))
2693 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2695 if(!strcmp(change_modestr, "yes"))
2696 change_sets_all = 1;
2698 if(strcmp(change_modestr, "no"))
2699 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2701 do_exports=atoi(exportstr);
2703 s_swf(filename, bbox, version, fps, compress, color);
2706 int isRelative(char*str)
2708 return !strncmp(str, "<plus>", 6) ||
2709 !strncmp(str, "<minus>", 7);
2711 char* getOffset(char*str)
2713 if(!strncmp(str, "<plus>", 6))
2715 if(!strncmp(str, "<minus>", 7))
2717 syntaxerror("internal error (347)");
2720 int getSign(char*str)
2722 if(!strncmp(str, "<plus>", 6))
2724 if(!strncmp(str, "<minus>", 7))
2726 syntaxerror("internal error (348)");
2730 static dictionary_t points;
2731 static mem_t mpoints;
2732 static int points_initialized = 0;
2734 static int c_interpolation(map_t *args)
2737 char* name = lu(args, "name");
2738 if (dictionary_lookup(&interpolations, name))
2739 syntaxerror("interpolation %s defined twice", name);
2741 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2742 char* functionstr = lu(args, "function");
2743 inter->function = 0;
2744 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2745 if (!strcmp(functionstr,interpolationFunctions[i]))
2747 inter->function = i + 1;
2750 if (!inter->function)
2751 syntaxerror("unkown interpolation function %s", functionstr);
2752 inter->speed = parseFloat(lu(args, "speed"));
2753 inter->amplitude = parseTwip(lu(args, "amplitude"));
2754 inter->growth = parseFloat(lu(args, "growth"));
2755 inter->bounces = parseInt(lu(args, "bounces"));
2756 inter->damping = parseFloat(lu(args, "damping"));
2757 inter->slope = parseFloat(lu(args, "slope"));
2759 dictionary_put2(&interpolations, name, inter);
2763 SPOINT getPoint(SRECT r, char*name)
2766 if(!strcmp(name, "center")) {
2768 p.x = (r.xmin + r.xmax)/2;
2769 p.y = (r.ymin + r.ymax)/2;
2772 if (!strcmp(name, "bottom-center")) {
2774 p.x = (r.xmin + r.xmax)/2;
2778 if (!strcmp(name, "top-center")) {
2780 p.x = (r.xmin + r.xmax)/2;
2784 if (!strcmp(name, "top-left")) {
2790 if (!strcmp(name, "top-right")) {
2796 if (!strcmp(name, "bottom-right")) {
2802 if (!strcmp(name, "bottom-left")) {
2808 if (!strcmp(name, "left-center")) {
2811 p.y = (r.ymin + r.ymax)/2;
2814 if (!strcmp(name, "right-center")) {
2817 p.y = (r.ymin + r.ymax)/2;
2822 if(points_initialized)
2823 l = (int)dictionary_lookup(&points, name);
2825 syntaxerror("Invalid point: \"%s\".", name);
2827 return *(SPOINT*)&mpoints.buffer[l-1];
2831 static int texture2(char*name, char*object, map_t*args, int errors)
2834 char*xstr = map_lookup(args, "x");
2835 char*ystr = map_lookup(args, "y");
2836 char*widthstr = map_lookup(args, "width");
2837 char*heightstr = map_lookup(args, "height");
2838 char*scalestr = map_lookup(args, "scale");
2839 char*scalexstr = map_lookup(args, "scalex");
2840 char*scaleystr = map_lookup(args, "scaley");
2841 char*rotatestr = map_lookup(args, "rotate");
2842 char* shearstr = map_lookup(args, "shear");
2843 char* radiusstr = map_lookup(args, "r");
2845 float scalex = 1.0, scaley = 1.0;
2846 float rotate=0, shear=0;
2848 if(!*xstr && !*ystr) {
2850 syntaxerror("x and y must be set");
2853 if(*scalestr && (*scalexstr || *scaleystr)) {
2854 syntaxerror("scale and scalex/scaley can't both be set");
2857 if((*widthstr || *heightstr) && *radiusstr) {
2858 syntaxerror("width/height and radius can't both be set");
2861 widthstr = radiusstr;
2862 heightstr = radiusstr;
2864 if(!*xstr) xstr="0";
2865 if(!*ystr) ystr="0";
2866 if(!*rotatestr) rotatestr="0";
2867 if(!*shearstr) shearstr="0";
2870 scalex = scaley = parsePercent(scalestr);
2871 } else if(*scalexstr || *scaleystr) {
2872 if(scalexstr) scalex = parsePercent(scalexstr);
2873 if(scaleystr) scaley = parsePercent(scaleystr);
2874 } else if(*widthstr || *heightstr) {
2877 s_getBitmapSize(object, &width, &height);
2879 scalex = (float)parseTwip(widthstr)/(float)width;
2881 scaley = (float)parseTwip(heightstr)/(float)height;
2883 x = parseTwip(xstr);
2884 y = parseTwip(ystr);
2885 rotate = parseFloat(rotatestr);
2886 shear = parseFloat(shearstr);
2888 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2893 static int c_texture(map_t*args)
2895 char*name = lu(args, "instance");
2896 char*object = lu(args, "character");
2897 return texture2(name, object, args, 1);
2900 static int c_gradient(map_t*args)
2902 char*name = lu(args, "name");
2903 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2904 int rotate = parseInt(lu(args, "rotate"));
2908 syntaxerror("colon (:) expected");
2910 if(dictionary_lookup(&gradients, name))
2911 syntaxerror("gradient %s defined twice", name);
2913 s_gradient(name, text, radial, rotate);
2915 /* check whether we also have placement information,
2916 which would make this a positioned gradient.
2917 If there is placement information, texture2() will
2918 add a texture, which has priority over the gradient.
2920 texture2(name, name, args, 0);
2924 static char* checkFiltername(map_t* args)
2926 char* name = lu(args, "name");
2927 if (strchr(name, ','))
2928 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
2932 static int c_blur(map_t*args)
2934 char*name = checkFiltername(args);
2935 char*blurstr = lu(args, "blur");
2936 char*blurxstr = lu(args, "blurx");
2937 char*blurystr = lu(args, "blury");
2938 float blurx=1.0, blury=1.0;
2940 blurx = parseFloat(blurstr);
2941 blury = parseFloat(blurstr);
2944 blurx = parseFloat(blurxstr);
2946 blury = parseFloat(blurystr);
2947 int passes = parseInt(lu(args, "passes"));
2948 s_blur(name, blurx, blury, passes);
2952 static int c_gradientglow(map_t*args)
2954 char*name = checkFiltername(args);
2955 char*gradient = lu(args, "gradient");
2956 char*blurstr = lu(args, "blur");
2957 char*blurxstr = lu(args, "blurx");
2958 char*blurystr = lu(args, "blury");
2959 float blurx=1.0, blury=1.0;
2961 blurx = parseFloat(blurstr);
2962 blury = parseFloat(blurstr);
2965 blurx = parseFloat(blurxstr);
2967 blury = parseFloat(blurystr);
2969 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2970 float distance = parseFloat(lu(args, "distance"));
2971 float strength = parseFloat(lu(args, "strength"));
2972 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2973 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2974 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2975 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2976 int passes = parseInt(lu(args, "passes"));
2978 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2982 static int c_dropshadow(map_t*args)
2984 char*name = checkFiltername(args);
2985 RGBA color = parseColor(lu(args, "color"));
2986 char*blurstr = lu(args, "blur");
2987 char*blurxstr = lu(args, "blurx");
2988 char*blurystr = lu(args, "blury");
2989 float blurx=1.0, blury=1.0;
2991 blurx = parseFloat(blurstr);
2992 blury = parseFloat(blurstr);
2995 blurx = parseFloat(blurxstr);
2997 blury = parseFloat(blurystr);
2999 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3000 float distance = parseFloat(lu(args, "distance"));
3001 float strength = parseFloat(lu(args, "strength"));
3002 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3003 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3004 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3005 int passes = parseInt(lu(args, "passes"));
3007 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3011 static int c_bevel(map_t*args)
3013 char*name = checkFiltername(args);
3014 RGBA shadow = parseColor(lu(args, "shadow"));
3015 RGBA highlight = parseColor(lu(args, "highlight"));
3016 char*blurstr = lu(args, "blur");
3017 char*blurxstr = lu(args, "blurx");
3018 char*blurystr = lu(args, "blury");
3019 float blurx=1.0, blury=1.0;
3021 blurx = parseFloat(blurstr);
3022 blury = parseFloat(blurstr);
3025 blurx = parseFloat(blurxstr);
3027 blury = parseFloat(blurystr);
3029 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3030 float distance = parseFloat(lu(args, "distance"));
3031 float strength = parseFloat(lu(args, "strength"));
3032 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3033 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3034 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3035 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3036 int passes = parseInt(lu(args, "passes"));
3038 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3042 static int c_define(map_t*args)
3044 char*name = lu(args, "name");
3045 char*value = lu(args, "value");
3047 if(!defines_initialized) {
3048 dictionary_init(&defines);
3049 mem_init(&define_values);
3050 defines_initialized = 1;
3052 int val = parseTwip(value);
3053 int pos = mem_put(&define_values, &val, sizeof(val));
3055 string_set(&s, name);
3056 dictionary_put(&defines, s, (void*)(pos+1));
3059 static int c_point(map_t*args)
3061 char*name = lu(args, "name");
3065 if(!points_initialized) {
3066 dictionary_init(&points);
3068 points_initialized = 1;
3070 p.x = parseTwip(lu(args, "x"));
3071 p.y = parseTwip(lu(args, "y"));
3072 pos = mem_put(&mpoints, &p, sizeof(p));
3073 string_set(&s1, name);
3074 dictionary_put(&points, s1, (void*)(pos+1));
3077 static int c_play(map_t*args)
3079 char*name = lu(args, "name");
3080 char*loop = lu(args, "loop");
3081 char*nomultiple = lu(args, "nomultiple");
3083 if(!strcmp(nomultiple, "nomultiple"))
3086 nm = parseInt(nomultiple);
3088 if(s_playsound(name, parseInt(loop), nm, 0)) {
3090 } else if(s_swf3action(name, "play")) {
3096 static int c_stop(map_t*args)
3098 char*name = map_lookup(args, "name");
3100 if(s_playsound(name, 0,0,1))
3102 else if(s_swf3action(name, "stop"))
3104 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3108 static int c_nextframe(map_t*args)
3110 char*name = lu(args, "name");
3112 if(s_swf3action(name, "nextframe")) {
3115 syntaxerror("I don't know anything about movie \"%s\"", name);
3119 static int c_previousframe(map_t*args)
3121 char*name = lu(args, "name");
3123 if(s_swf3action(name, "previousframe")) {
3126 syntaxerror("I don't know anything about movie \"%s\"", name);
3130 static int c_movement(map_t*args, int type)
3132 char*instance = lu(args, "name");
3140 xstr = lu(args, "x");
3141 ystr = lu(args, "y");
3143 s_getParameters(instance, &p);
3148 if(isRelative(xstr))
3150 if(type == PT_PUT || type == PT_STARTCLIP)
3151 syntaxerror("relative x values not allowed for initial put or startclip");
3152 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3156 p.x = parseTwip(xstr);
3162 if(isRelative(ystr))
3164 if(type == PT_PUT || type == PT_STARTCLIP)
3165 syntaxerror("relative y values not allowed for initial put or startclip");
3166 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3170 p.y = parseTwip(ystr);
3175 if (change_sets_all)
3183 char* interstr = lu(args, "interpolation");
3184 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3186 syntaxerror("unkown interpolation %s", interstr);
3187 s_change(instance, p, inter);
3192 char* interstr = lu(args, "interpolation");
3193 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3195 syntaxerror("unkown interpolation %s", interstr);
3196 s_schange(instance, p, inter);
3201 char* rstr = lu(args, "r");
3202 int radius = parseTwip(rstr);
3204 syntaxerror("sweep not possible: radius must be greater than 0.");
3205 char* dirstr = lu(args, "dir");
3206 int clockwise = parseDir(dirstr);
3207 char* arcstr = lu(args, "arc");
3208 int short_arc = parseArc(arcstr);
3209 char* interstr = lu(args, "interpolation");
3210 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3212 syntaxerror("unkown interpolation %s", interstr);
3213 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3220 static int c_placement(map_t*args, int type)
3222 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3225 char* luminancestr = lu(args, "luminance");
3226 char* scalestr = lu(args, "scale");
3227 char* scalexstr = lu(args, "scalex");
3228 char* scaleystr = lu(args, "scaley");
3229 char* rotatestr = lu(args, "rotate");
3230 char* shearstr = lu(args, "shear");
3231 char* xstr="", *pivotstr="";
3232 char* ystr="", *anglestr="";
3233 char*above = lu(args, "above"); /*FIXME*/
3234 char*below = lu(args, "below");
3235 char* rstr = lu(args, "red");
3236 char* gstr = lu(args, "green");
3237 char* bstr = lu(args, "blue");
3238 char* astr = lu(args, "alpha");
3239 char* pinstr = lu(args, "pin");
3240 char* as = map_lookup(args, "as");
3241 char* blendmode = lu(args, "blend");
3242 char* filterstr = lu(args, "filter");
3253 { // (?) .rotate or .arcchange
3254 pivotstr = lu(args, "pivot");
3255 anglestr = lu(args, "angle");
3259 xstr = lu(args, "x");
3260 ystr = lu(args, "y");
3264 luminance = parseMulAdd(luminancestr);
3268 luminance.mul = 256;
3273 if(scalexstr[0]||scaleystr[0])
3274 syntaxerror("scalex/scaley and scale cannot both be set");
3275 scalexstr = scaleystr = scalestr;
3278 if(type == PT_PUT || type == PT_STARTCLIP) {
3280 character = lu(args, "character");
3281 parameters_clear(&p);
3282 } else if (type == PT_BUTTON) {
3283 character = lu(args, "name");
3284 parameters_clear(&p);
3287 s_getParameters(instance, &p);
3293 if(isRelative(xstr))
3295 if(type == PT_PUT || type == PT_STARTCLIP)
3296 syntaxerror("relative x values not allowed for initial put or startclip");
3297 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3301 p.x = parseTwip(xstr);
3307 if(isRelative(ystr))
3309 if(type == PT_PUT || type == PT_STARTCLIP)
3310 syntaxerror("relative y values not allowed for initial put or startclip");
3311 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3315 p.y = parseTwip(ystr);
3320 /* scale, scalex, scaley */
3322 oldbbox = s_getCharBBox(character);
3324 oldbbox = s_getInstanceBBox(instance);
3325 oldwidth = oldbbox.xmax - oldbbox.xmin;
3326 oldheight = oldbbox.ymax - oldbbox.ymin;
3333 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3334 set = set | SF_SCALEX;
3342 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3343 set = set | SF_SCALEY;
3349 if(isRelative(rotatestr))
3350 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3352 p.rotate = parseFloat(rotatestr);
3353 set = set | SF_ROTATE;
3359 if(isRelative(shearstr))
3360 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3362 p.shear = parseFloat(shearstr);
3363 set = set | SF_SHEAR;
3368 if(isPoint(pivotstr))
3369 p.pivot = parsePoint(pivotstr);
3371 p.pivot = getPoint(oldbbox, pivotstr);
3372 set = set | SF_PIVOT;
3378 p.pin = parsePoint(pinstr);
3380 p.pin = getPoint(oldbbox, pinstr);
3384 /* color transform */
3386 if(rstr[0] || luminancestr[0])
3390 r = parseMulAdd(rstr);
3393 r.add = p.cxform.r0;
3394 r.mul = p.cxform.r1;
3396 r = mergeMulAdd(r, luminance);
3397 p.cxform.r0 = r.mul;
3398 p.cxform.r1 = r.add;
3399 set = set | SF_CX_R;
3401 if(gstr[0] || luminancestr[0])
3405 g = parseMulAdd(gstr);
3408 g.add = p.cxform.g0;
3409 g.mul = p.cxform.g1;
3411 g = mergeMulAdd(g, luminance);
3412 p.cxform.g0 = g.mul;
3413 p.cxform.g1 = g.add;
3414 set = set | SF_CX_G;
3416 if(bstr[0] || luminancestr[0])
3420 b = parseMulAdd(bstr);
3423 b.add = p.cxform.b0;
3424 b.mul = p.cxform.b1;
3426 b = mergeMulAdd(b, luminance);
3427 p.cxform.b0 = b.mul;
3428 p.cxform.b1 = b.add;
3429 set = set | SF_CX_B;
3433 MULADD a = parseMulAdd(astr);
3434 p.cxform.a0 = a.mul;
3435 p.cxform.a1 = a.add;
3436 set = set | SF_CX_A;
3443 for(t = 0; blendModeNames[t]; t++)
3445 if(!strcmp(blendModeNames[t], blendmode))
3453 syntaxerror("unknown blend mode: '%s'", blendmode);
3455 p.blendmode = blend;
3456 set = set | SF_BLEND;
3461 p.filters = parseFilters(filterstr);
3462 set = set | SF_FILTER;
3465 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3466 warning("As of version 0.8.2 using the .change command to modify an \
3467 object's position on the stage is considered deprecated. Future \
3468 versions may consider x and y parameters for the .change command \
3469 to be illegal; please use the .move command.");
3471 if (change_sets_all)
3478 s_put(instance, character, p);
3482 char* interstr = lu(args, "interpolation");
3483 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3485 syntaxerror("unkown interpolation %s", interstr);
3486 s_change(instance, p, inter);
3491 char* interstr = lu(args, "interpolation");
3492 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3494 syntaxerror("unkown interpolation %s", interstr);
3495 s_schange(instance, p, inter);
3499 s_jump(instance, p);
3502 s_startclip(instance, character, p);
3506 s_buttonput(character, as, p);
3508 s_buttonput(character, "shape", p);
3514 static int c_put(map_t*args)
3516 c_placement(args, PT_PUT);
3519 static int c_change(map_t*args)
3521 if (currentframe == 0)
3522 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3523 c_placement(args, PT_CHANGE);
3526 static int c_schange(map_t*args)
3528 c_placement(args, PT_SCHANGE);
3531 static int c_move(map_t* args)
3533 c_movement(args, PT_MOVE);
3536 static int c_smove(map_t* args)
3538 c_movement(args, PT_SMOVE);
3541 static int c_sweep(map_t* args)
3543 c_movement(args, PT_SWEEP);
3546 static int c_arcchange(map_t*args)
3548 c_placement(args, 0);
3551 static int c_jump(map_t*args)
3553 c_placement(args, PT_JUMP);
3556 static int c_startclip(map_t*args)
3558 c_placement(args, PT_STARTCLIP);
3561 static int c_show(map_t*args)
3563 c_placement(args, PT_BUTTON);
3566 static int c_toggle(map_t* args)
3568 char*instance = lu(args, "name");
3569 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3570 char* alignstr = lu(args, "fixed_alignment");
3571 if (!strcmp(alignstr, "on"))
3572 flagsOn += IF_FIXED_ALIGNMENT;
3574 if (!strcmp(alignstr, "off"))
3575 flagsOff -= IF_FIXED_ALIGNMENT;
3577 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3578 s_toggle(instance, flagsOn, flagsOff);
3581 static int c_del(map_t*args)
3583 char*instance = lu(args, "name");
3584 s_delinstance(instance);
3587 static int c_end(map_t*args)
3592 static int c_sprite(map_t*args)
3594 char* name = lu(args, "name");
3595 char* scalinggrid = lu(args, "scalinggrid");
3597 if(scalinggrid && *scalinggrid) {
3598 SRECT r = parseBox(scalinggrid);
3605 static int c_frame(map_t*args)
3607 char*framestr = lu(args, "n");
3608 char*cutstr = lu(args, "cut");
3610 char*name = lu(args, "name");
3611 char*anchor = lu(args, "anchor");
3614 if(!strcmp(anchor, "anchor") && !*name)
3619 if(strcmp(cutstr, "no"))
3621 if(isRelative(framestr)) {
3622 frame = s_getframe();
3623 if(getSign(framestr)<0)
3624 syntaxerror("relative frame expressions must be positive");
3625 frame += parseInt(getOffset(framestr));
3628 frame = parseInt(framestr);
3629 if(s_getframe() >= frame
3630 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3631 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3633 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3636 static int c_primitive(map_t*args)
3638 char*name = lu(args, "name");
3639 char*command = lu(args, "commandname");
3640 int width=0, height=0, r=0;
3641 int linewidth = parseTwip(lu(args, "line"));
3642 char*colorstr = lu(args, "color");
3643 RGBA color = parseColor(colorstr);
3644 char*fillstr = lu(args, "fill");
3651 if(!strcmp(command, "circle"))
3653 else if(!strcmp(command, "filled"))
3657 width = parseTwip(lu(args, "width"));
3658 height = parseTwip(lu(args, "height"));
3659 } else if (type==1) {
3660 r = parseTwip(lu(args, "r"));
3661 } else if (type==2) {
3662 outline = lu(args, "outline");
3665 if(!strcmp(fillstr, "fill"))
3667 if(!strcmp(fillstr, "none"))
3669 if(width<0 || height<0 || linewidth<0 || r<0)
3670 syntaxerror("values width, height, line, r must be positive");
3672 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3673 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3674 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3678 static int c_textshape(map_t*args)
3680 char*name = lu(args, "name");
3681 char*text = lu(args, "text");
3682 char*font = lu(args, "font");
3683 float size = parsePxOrPercent(font, lu(args, "size"));
3685 s_textshape(name, font, size, text);
3689 static int c_swf(map_t*args)
3691 char*name = lu(args, "name");
3692 char*filename = lu(args, "filename");
3693 char*command = lu(args, "commandname");
3694 if(!strcmp(command, "shape"))
3695 warning("Please use .swf instead of .shape");
3696 s_includeswf(name, filename);
3700 static int c_font(map_t*args)
3702 char*name = lu(args, "name");
3703 char*filename = lu(args, "filename");
3704 s_font(name, filename);
3708 static int c_sound(map_t*args)
3710 char*name = lu(args, "name");
3711 char*filename = lu(args, "filename");
3712 s_sound(name, filename);
3716 static int c_text(map_t*args)
3718 char*name = lu(args, "name");
3719 char*text = lu(args, "text");
3720 char*font = lu(args, "font");
3721 float size = parsePxOrPercent(font, lu(args, "size"));
3722 RGBA color = parseColor(lu(args, "color"));
3723 s_text(name, font, text, (int)(size*100), color);
3727 static int c_soundtrack(map_t*args)
3732 static int c_quicktime(map_t*args)
3734 char*name = lu(args, "name");
3735 char*url = lu(args, "url");
3736 s_quicktime(name, url);
3740 static int c_image(map_t*args)
3742 char*command = lu(args, "commandname");
3743 char*name = lu(args, "name");
3744 char*filename = lu(args, "filename");
3745 if(!strcmp(command,"jpeg")) {
3746 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3747 s_image(name, "jpeg", filename, quality);
3749 s_image(name, "png", filename, 0);
3754 static int c_outline(map_t*args)
3756 char*name = lu(args, "name");
3757 char*format = lu(args, "format");
3761 syntaxerror("colon (:) expected");
3763 s_outline(name, format, text);
3767 int fakechar(map_t*args)
3769 char*name = lu(args, "name");
3770 s_box(name, 0, 0, black, 20, 0);
3774 static int c_egon(map_t*args) {return fakechar(args);}
3775 static int c_button(map_t*args) {
3776 char*name = lu(args, "name");
3780 static int current_button_flags = 0;
3781 static int c_on_press(map_t*args)
3783 char*position = lu(args, "position");
3785 if(!strcmp(position, "inside")) {
3786 current_button_flags |= BC_OVERUP_OVERDOWN;
3787 } else if(!strcmp(position, "outside")) {
3788 //current_button_flags |= BC_IDLE_OUTDOWN;
3789 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3790 } else if(!strcmp(position, "anywhere")) {
3791 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3794 if(type == RAWDATA) {
3796 s_buttonaction(current_button_flags, action);
3797 current_button_flags = 0;
3803 static int c_on_release(map_t*args)
3805 char*position = lu(args, "position");
3807 if(!strcmp(position, "inside")) {
3808 current_button_flags |= BC_OVERDOWN_OVERUP;
3809 } else if(!strcmp(position, "outside")) {
3810 current_button_flags |= BC_OUTDOWN_IDLE;
3811 } else if(!strcmp(position, "anywhere")) {
3812 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3815 if(type == RAWDATA) {
3817 s_buttonaction(current_button_flags, action);
3818 current_button_flags = 0;
3824 static int c_on_move_in(map_t*args)
3826 char*position = lu(args, "state");
3828 if(!strcmp(position, "pressed")) {
3829 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3830 } else if(!strcmp(position, "not_pressed")) {
3831 current_button_flags |= BC_IDLE_OVERUP;
3832 } else if(!strcmp(position, "any")) {
3833 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3836 if(type == RAWDATA) {
3838 s_buttonaction(current_button_flags, action);
3839 current_button_flags = 0;
3845 static int c_on_move_out(map_t*args)
3847 char*position = lu(args, "state");
3849 if(!strcmp(position, "pressed")) {
3850 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3851 } else if(!strcmp(position, "not_pressed")) {
3852 current_button_flags |= BC_OVERUP_IDLE;
3853 } else if(!strcmp(position, "any")) {
3854 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3857 if(type == RAWDATA) {
3859 s_buttonaction(current_button_flags, action);
3860 current_button_flags = 0;
3866 static int c_on_key(map_t*args)
3868 char*key = lu(args, "key");
3870 if(strlen(key)==1) {
3873 current_button_flags |= 0x4000 + (key[0]*0x200);
3875 syntaxerror("invalid character: %c"+key[0]);
3880 <ctrl-x> = 0x200*(x-'a')
3884 syntaxerror("invalid key: %s",key);
3887 if(type == RAWDATA) {
3889 s_buttonaction(current_button_flags, action);
3890 current_button_flags = 0;
3897 static int c_edittext(map_t*args)
3899 //"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"},
3900 char*name = lu(args, "name");
3901 char*font = lu(args, "font");
3902 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3903 int width = parseTwip(lu(args, "width"));
3904 int height = parseTwip(lu(args, "height"));
3905 char*text = lu(args, "text");
3906 RGBA color = parseColor(lu(args, "color"));
3907 int maxlength = parseInt(lu(args, "maxlength"));
3908 char*variable = lu(args, "variable");
3909 char*passwordstr = lu(args, "password");
3910 char*wordwrapstr = lu(args, "wordwrap");
3911 char*multilinestr = lu(args, "multiline");
3912 char*htmlstr = lu(args, "html");
3913 char*noselectstr = lu(args, "noselect");
3914 char*readonlystr = lu(args, "readonly");
3915 char*borderstr = lu(args, "border");
3916 char*autosizestr = lu(args, "autosize");
3917 char*alignstr = lu(args, "align");
3921 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3922 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3923 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3924 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3925 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3926 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3927 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3928 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3929 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3930 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3931 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3932 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3933 else syntaxerror("Unknown alignment: %s", alignstr);
3935 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3939 static int c_morphshape(map_t*args) {return fakechar(args);}
3940 static int c_movie(map_t*args) {return fakechar(args);}
3942 static char* readfile(const char*filename)
3944 FILE*fi = fopen(filename, "rb");
3948 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3949 fseek(fi, 0, SEEK_END);
3951 fseek(fi, 0, SEEK_SET);
3952 text = rfx_alloc(l+1);
3953 fread(text, l, 1, fi);
3959 static int c_action(map_t*args)
3961 char* filename = map_lookup(args, "filename");
3962 if(!filename ||!*filename) {
3964 if(type != RAWDATA) {
3965 syntaxerror("colon (:) expected");
3969 s_action(readfile(filename));
3975 static int c_initaction(map_t*args)
3977 char* character = lu(args, "name");
3978 char* filename = map_lookup(args, "filename");
3979 if(!filename ||!*filename) {
3981 if(type != RAWDATA) {
3982 syntaxerror("colon (:) expected");
3984 s_initaction(character, text);
3986 s_initaction(character, readfile(filename));
3994 command_func_t* func;
3997 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
3998 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3999 // "import" type stuff
4000 {"swf", c_swf, "name filename"},
4001 {"shape", c_swf, "name filename"},
4002 {"jpeg", c_image, "name filename quality=80%"},
4003 {"png", c_image, "name filename"},
4004 {"movie", c_movie, "name filename"},
4005 {"sound", c_sound, "name filename"},
4006 {"font", c_font, "name filename glyphs="},
4007 {"soundtrack", c_soundtrack, "filename"},
4008 {"quicktime", c_quicktime, "url"},
4010 // generators of primitives
4012 {"define", c_define, "name value=0"},
4013 {"point", c_point, "name x=0 y=0"},
4014 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4015 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4016 {"outline", c_outline, "name format=simple"},
4017 {"textshape", c_textshape, "name font size=100% text"},
4020 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4021 {"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"},
4022 {"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"},
4023 {"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"},
4025 // character generators
4026 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4027 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4028 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4030 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4031 {"text", c_text, "name text font size=100% color=white"},
4032 {"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="},
4033 {"morphshape", c_morphshape, "name start end"},
4034 {"button", c_button, "name"},
4035 {"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="},
4036 {"on_press", c_on_press, "position=inside"},
4037 {"on_release", c_on_release, "position=anywhere"},
4038 {"on_move_in", c_on_move_in, "state=not_pressed"},
4039 {"on_move_out", c_on_move_out, "state=not_pressed"},
4040 {"on_key", c_on_key, "key=any"},
4043 {"play", c_play, "name loop=0 @nomultiple=0"},
4044 {"stop", c_stop, "name= "},
4045 {"nextframe", c_nextframe, "name"},
4046 {"previousframe", c_previousframe, "name"},
4048 // object placement tags
4049 {"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="},
4050 {"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="},
4051 {"move", c_move, "name x= y= interpolation=linear"},
4052 {"smove", c_smove, "name x= y= interpolation=linear"},
4053 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4054 {"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"},
4055 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4056 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4057 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4058 {"del", c_del, "name"},
4059 // virtual object placement
4060 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4062 {"toggle", c_toggle, "name fixed_alignment="},
4064 // commands which start a block
4065 //startclip (see above)
4066 {"sprite", c_sprite, "name scalinggrid="},
4067 {"action", c_action, "filename="},
4068 {"initaction", c_initaction, "name filename="},
4074 static map_t parseArguments(char*command, char*pattern)
4090 string_set(&t1, "commandname");
4091 string_set(&t2, command);
4092 map_put(&result, t1, t2);
4094 if(!pattern || !*pattern)
4101 if(!strncmp("<i> ", x, 3)) {
4103 if(type == COMMAND || type == RAWDATA) {
4105 syntaxerror("character name expected");
4107 name[pos].str = "instance";
4109 value[pos].str = text;
4110 value[pos].len = strlen(text);
4114 if(type == ASSIGNMENT)
4117 name[pos].str = "character";
4119 value[pos].str = text;
4120 value[pos].len = strlen(text);
4128 isboolean[pos] = (x[0] =='@');
4141 name[pos].len = d-x;
4146 name[pos].len = e-x;
4147 value[pos].str = e+1;
4148 value[pos].len = d-e-1;
4156 /* for(t=0;t<len;t++) {
4157 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4158 isboolean[t]?"(boolean)":"");
4163 if(type == RAWDATA || type == COMMAND) {
4168 // first, search for boolean arguments
4169 for(pos=0;pos<len;pos++)
4171 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4173 if(type == ASSIGNMENT)
4175 value[pos].str = text;
4176 value[pos].len = strlen(text);
4177 /*printf("setting boolean parameter %s (to %s)\n",
4178 strdup_n(name[pos], namelen[pos]),
4179 strdup_n(value[pos], valuelen[pos]));*/
4184 // second, search for normal arguments
4186 for(pos=0;pos<len;pos++)
4188 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4189 (type != ASSIGNMENT && !set[pos])) {
4191 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4193 if(type == ASSIGNMENT)
4196 value[pos].str = text;
4197 value[pos].len = strlen(text);
4199 printf("setting parameter %s (to %s)\n",
4200 strdup_n(name[pos].str, name[pos].len),
4201 strdup_n(value[pos].str, value[pos].len));
4207 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4211 for(t=0;t<len;t++) {
4212 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4215 for(t=0;t<len;t++) {
4216 if(value[t].str && value[t].str[0] == '*') {
4217 //relative default- take value from some other parameter
4219 for(s=0;s<len;s++) {
4220 if(value[s].len == value[t].len-1 &&
4221 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4222 value[t].str = value[s].str;
4225 if(value[t].str == 0) {
4227 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4231 /* ok, now construct the dictionary from the parameters */
4235 map_put(&result, name[t], value[t]);
4239 static void parseArgumentsForCommand(char*command)
4244 msg("<verbose> parse Command: %s (line %d)", command, line);
4246 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4247 if(!strcmp(arguments[t].command, command)) {
4249 /* ugly hack- will be removed soon (once documentation and .sc generating
4250 utilities have been changed) */
4251 if(!strcmp(command, "swf") && !stackpos) {
4252 warning("Please use .flash instead of .swf- this will be mandatory soon");
4257 args = parseArguments(command, arguments[t].arguments);
4263 syntaxerror("command %s not known", command);
4265 // catch missing .flash directives at the beginning of a file
4266 if(strcmp(command, "flash") && !stackpos)
4268 syntaxerror("No movie defined- use .flash first");
4272 printf(".%s\n", command);fflush(stdout);
4273 map_dump(&args, stdout, "\t");fflush(stdout);
4276 (*arguments[nr].func)(&args);
4278 /*if(!strcmp(command, "button") ||
4279 !strcmp(command, "action")) {
4282 if(type == COMMAND) {
4283 if(!strcmp(text, "end"))
4298 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4299 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4300 * No syntax checking is done */
4301 static void analyseArgumentsForCommand(char*command)
4307 U8* glyphs_to_include;
4308 msg("<verbose> analyse Command: %s (line %d)", command, line);
4310 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4312 if(!strcmp(arguments[t].command, command))
4314 args = parseArguments(command, arguments[t].arguments);
4320 printf(".%s\n", command);fflush(stdout);
4321 map_dump(&args, stdout, "\t");fflush(stdout);
4323 char* name = lu(&args, "name");
4324 if (!strcmp(command, "font"))
4326 if(dictionary_lookup(&fonts, name))
4327 syntaxerror("font %s defined twice", name);
4330 fontfile = lu(&args, "filename");
4331 font = swf_LoadFont(fontfile);
4333 warning("Couldn't open font file \"%s\"", fontfile);
4334 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4335 memset(font, 0, sizeof(SWFFONT));
4339 swf_FontPrepareForEditText(font);
4340 glyphs_to_include = lu(&args, "glyphs");
4341 if (!strcmp(glyphs_to_include, "all"))
4343 swf_FontUseAll(font);
4344 font->use->glyphs_specified = 1;
4348 if (strcmp (glyphs_to_include, ""))
4350 swf_FontUseUTF8(font, glyphs_to_include);
4351 font->use->glyphs_specified = 1;
4354 swf_FontInitUsage(font);
4357 dictionary_put2(&fonts, name, font);
4361 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
4363 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4365 if (font->use && !font->use->glyphs_specified)
4367 if (!strcmp(command, "edittext"))
4369 swf_FontUseAll(font);
4370 font->use->glyphs_specified = 1;
4373 swf_FontUseUTF8(font, lu(&args, "text"));
4380 void skipParameters()
4384 while (type != COMMAND);
4388 void findFontUsage()
4390 char* fontRelated = "font;text;textshape;edittext;";
4391 while(!noMoreTokens())
4395 syntaxerror("command expected");
4396 if (strstr(fontRelated, text))
4397 analyseArgumentsForCommand(text);
4399 if(strcmp(text, "end"))
4408 dictionary_init(&fonts);
4409 cleanUp = &freeFontDictionary;
4413 int main (int argc,char ** argv)
4416 processargs(argc, argv);
4417 initLog(0,-1,0,0,-1,verbose);
4420 args_callback_usage(argv[0]);
4424 file = generateTokens(filename);
4426 fprintf(stderr, "parser returned error.\n");
4433 while(!noMoreTokens()) {
4436 syntaxerror("command expected");
4437 parseArgumentsForCommand(text);