2 Compiles swf code (.sc) files into .swf files.
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/drawer.h"
32 #include "../lib/log.h"
33 #include "../lib/args.h"
35 #include "../lib/mp3.h"
36 #include "../lib/wav.h"
38 #include "../lib/png.h"
39 #include "swfc-feedback.h"
40 #include "swfc-interpolation.h"
41 #include "swfc-history.h"
44 static char * outputname = "output.swf";
45 static int verbose = 2;
46 static int optimize = 0;
47 static int override_outputname = 0;
48 static int do_cgi = 0;
49 static int change_sets_all = 0;
50 static int do_exports = 0;
52 static struct options_t options[] = {
61 int args_callback_option(char*name,char*val)
63 if(!strcmp(name, "V")) {
64 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
67 else if(!strcmp(name, "o")) {
69 override_outputname = 1;
72 else if(!strcmp(name, "O")) {
76 else if(!strcmp(name, "C")) {
80 else if(!strcmp(name, "v")) {
85 printf("Unknown option: -%s\n", name);
90 int args_callback_longoption(char*name,char*val)
92 return args_long2shortoption(options, name, val);
94 void args_callback_usage(char *name)
97 printf("Usage: %s [-o file.swf] file.sc\n", name);
99 printf("-h , --help Print short help message and exit\n");
100 printf("-V , --version Print version info and exit\n");
101 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
102 printf("-v , --verbose Increase verbosity. \n");
103 printf("-o , --output <filename> Set output file to <filename>.\n");
106 int args_callback_command(char*name,char*val)
109 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
116 static struct token_t* file;
123 static void readToken()
125 type = file[pos].type;
127 syntaxerror("unexpected end of file");
129 text = file[pos].text;
130 textlen = strlen(text);
131 line = file[pos].line;
132 column = file[pos].column;
134 //printf("---> %d(%s) %s\n", type, type_names[type], text);
137 static void pushBack()
140 if(!pos) syntaxerror("internal error 3");
145 textlen = strlen(text);
148 column = file[p].column;
151 static int noMoreTokens()
153 if(file[pos].type == END)
171 // ------------------------------ swf routines ----------------------------
175 int type; //0=swf, 1=sprite, 2=clip, 3=button
181 /* for sprites (1): */
187 dictionary_t oldinstances;
194 static int stackpos = 0;
196 static dictionary_t characters;
197 static dictionary_t images;
198 static dictionary_t textures;
199 static dictionary_t outlines;
200 static dictionary_t gradients;
201 static dictionary_t filters;
202 static dictionary_t interpolations;
203 static char idmap[65536];
204 static TAG*tag = 0; //current tag
206 static int id; //current character id
207 static int currentframe; //current frame in current level
208 static SRECT currentrect; //current bounding box in current level
209 static U16 currentdepth;
210 static dictionary_t instances;
211 static dictionary_t fonts;
212 static dictionary_t sounds;
213 static dictionary_t fontUsage;
215 typedef struct _parameters {
217 float scalex, scaley;
223 U8 blendmode; //not interpolated
225 U16 set; // bits indicating wether a parameter was set in the c_placement function
226 U16 flags; // bits to toggle anything you may care to implement as a toggle
229 typedef struct _character {
235 typedef struct _instance {
236 character_t*character;
238 parameters_t parameters;
242 typedef struct _outline {
247 typedef struct _gradient {
253 typedef struct _filter {
257 typedef struct _texture {
261 char* interpolationFunctions[] = {"linear", \
262 "quadIn", "quadOut", "quadInOut", \
263 "cubicIn", "cubicOut", "cubicInOut", \
264 "quartIn", "quartOut", "quartInOut", \
265 "quintIn", "quintOut", "quintInOut", \
266 "circleIn", "circleOut", "circleInOut", \
267 "exponentialIn", "exponentialOut", "exponentialInOut", \
268 "sineIn", "sineOut", "sineInOut", \
269 "elasticIn", "elasticOut", "elasticInOut", \
270 "backIn", "backOut", "backInOut", \
271 "bounceIn", "bounceOut", "bounceInOut", \
272 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
274 static void character_init(character_t*c)
276 memset(c, 0, sizeof(character_t));
279 static character_t* character_new()
282 c = (character_t*)malloc(sizeof(character_t));
287 static void instance_init(instance_t*i)
289 memset(i, 0, sizeof(instance_t));
290 i->history = history_new();
293 static void instance_free(instance_t* i)
295 history_free(i->history);
299 static instance_t* instance_new()
302 c = (instance_t*)malloc(sizeof(instance_t));
307 static void free_instance(void* i)
309 instance_free((instance_t*)i);
312 static void free_font(void* f)
314 swf_FontFree((SWFFONT*)f);
317 static void gradient_free(GRADIENT* grad)
324 static void free_gradient(void* grad)
326 gradient_free((GRADIENT*) grad);
329 static void outline_free(outline_t* o)
331 free(o->shape->data);
336 static void free_outline(void* o)
338 outline_free((outline_t*)o);
341 static void freeDictionaries()
343 dictionary_free_all(&instances, free_instance);
344 dictionary_free_all(&characters, free);
345 dictionary_free_all(&images, free);
346 dictionary_free_all(&textures, free);
347 dictionary_free_all(&outlines, free_outline);
348 dictionary_free_all(&gradients, free_gradient);
349 dictionary_free_all(&filters, free);
350 dictionary_free_all(&fonts, free_font);
351 dictionary_free_all(&sounds, free);
352 dictionary_free_all(&interpolations, free);
356 static void freeFontDictionary()
358 dictionary_free_all(&fonts, free_font);
361 static void incrementid()
365 syntaxerror("Out of character ids.");
370 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
372 if(dictionary_lookup(&characters, name))
373 syntaxerror("character %s defined twice", name);
374 character_t* c = character_new();
376 c->definingTag = ctag;
379 dictionary_put2(&characters, name, c);
382 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
384 swf_SetString(tag, name);
385 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
388 swf_SetString(tag, name);
391 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
393 if(dictionary_lookup(&images, name))
394 syntaxerror("image %s defined twice", name);
396 character_t* c = character_new();
397 c->definingTag = ctag;
400 dictionary_put2(&images, name, c);
402 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
404 if(dictionary_lookup(&instances, name))
405 syntaxerror("object %s defined twice", name);
406 instance_t* i = instance_new();
409 //swf_GetMatrix(0, &i->matrix);
410 dictionary_put2(&instances, name, i);
414 static void parameters_clear(parameters_t*p)
417 p->scalex = 1.0; p->scaley = 1.0;
420 p->pivot.x = 0; p->pivot.y = 0;
425 swf_GetCXForm(0, &p->cxform, 1);
428 static void makeMatrix(MATRIX*m, parameters_t*p)
437 sx = p->scalex*cos(p->rotate/360*2*M_PI);
438 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
439 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
440 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
442 m->sx = (int)(sx*65536+0.5);
443 m->r1 = (int)(r1*65536+0.5);
444 m->r0 = (int)(r0*65536+0.5);
445 m->sy = (int)(sy*65536+0.5);
449 h = swf_TurnPoint(p->pin, m);
454 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
459 r = swf_TurnRect(rect, &m);
460 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
461 currentrect.xmax == 0 && currentrect.ymax == 0)
464 swf_ExpandRect2(¤trect, &r);
470 interpolation_t* new;
471 new = (interpolation_t*)malloc(sizeof(interpolation_t));
472 new->function = IF_LINEAR;
473 dictionary_put2(&interpolations, "linear", new);
475 new = (interpolation_t*)malloc(sizeof(interpolation_t));
476 new->function = IF_QUAD_IN;
478 dictionary_put2(&interpolations, "quadIn", new);
479 new = (interpolation_t*)malloc(sizeof(interpolation_t));
480 new->function = IF_QUAD_OUT;
482 dictionary_put2(&interpolations, "quadOut", new);
483 new = (interpolation_t*)malloc(sizeof(interpolation_t));
484 new->function = IF_QUAD_IN_OUT;
486 dictionary_put2(&interpolations, "quadInOut", new);
488 new = (interpolation_t*)malloc(sizeof(interpolation_t));
489 new->function = IF_CUBIC_IN;
491 dictionary_put2(&interpolations, "cubicIn", new);
492 new = (interpolation_t*)malloc(sizeof(interpolation_t));
493 new->function = IF_CUBIC_OUT;
495 dictionary_put2(&interpolations, "cubicOut", new);
496 new = (interpolation_t*)malloc(sizeof(interpolation_t));
497 new->function = IF_CUBIC_IN_OUT;
499 dictionary_put2(&interpolations, "cubicInOut", new);
501 new = (interpolation_t*)malloc(sizeof(interpolation_t));
502 new->function = IF_QUART_IN;
504 dictionary_put2(&interpolations, "quartIn", new);
505 new = (interpolation_t*)malloc(sizeof(interpolation_t));
506 new->function = IF_QUART_OUT;
508 dictionary_put2(&interpolations, "quartOut", new);
509 new = (interpolation_t*)malloc(sizeof(interpolation_t));
510 new->function = IF_QUART_IN_OUT;
512 dictionary_put2(&interpolations, "quartInOut", new);
514 new = (interpolation_t*)malloc(sizeof(interpolation_t));
515 new->function = IF_QUINT_IN;
517 dictionary_put2(&interpolations, "quintIn", new);
518 new = (interpolation_t*)malloc(sizeof(interpolation_t));
519 new->function = IF_QUINT_OUT;
521 dictionary_put2(&interpolations, "quintOut", new);
522 new = (interpolation_t*)malloc(sizeof(interpolation_t));
523 new->function = IF_QUINT_IN_OUT;
525 dictionary_put2(&interpolations, "quintInOut", new);
527 new = (interpolation_t*)malloc(sizeof(interpolation_t));
528 new->function = IF_CIRCLE_IN;
529 dictionary_put2(&interpolations, "circleIn", new);
530 new = (interpolation_t*)malloc(sizeof(interpolation_t));
531 new->function = IF_CIRCLE_OUT;
532 dictionary_put2(&interpolations, "circleOut", new);
533 new = (interpolation_t*)malloc(sizeof(interpolation_t));
534 new->function = IF_CIRCLE_IN_OUT;
535 dictionary_put2(&interpolations, "circleInOut", new);
537 new = (interpolation_t*)malloc(sizeof(interpolation_t));
538 new->function = IF_EXPONENTIAL_IN;
539 dictionary_put2(&interpolations, "exponentialIn", new);
540 new = (interpolation_t*)malloc(sizeof(interpolation_t));
541 new->function = IF_EXPONENTIAL_OUT;
542 dictionary_put2(&interpolations, "exponentialOut", new);
543 new = (interpolation_t*)malloc(sizeof(interpolation_t));
544 new->function = IF_EXPONENTIAL_IN_OUT;
545 dictionary_put2(&interpolations, "exponentialInOut", new);
547 new = (interpolation_t*)malloc(sizeof(interpolation_t));
548 new->function = IF_SINE_IN;
549 dictionary_put2(&interpolations, "sineIn", new);
550 new = (interpolation_t*)malloc(sizeof(interpolation_t));
551 new->function = IF_SINE_OUT;
552 dictionary_put2(&interpolations, "sineOut", new);
553 new = (interpolation_t*)malloc(sizeof(interpolation_t));
554 new->function = IF_SINE_IN_OUT;
555 dictionary_put2(&interpolations, "sineInOut", new);
558 memset(&c, 0, sizeof(RGBA));
559 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
560 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
561 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
562 noGradient->gradient.num = 2;
563 noGradient->gradient.rgba[0] = c;
564 noGradient->gradient.ratios[0] = 0;
565 noGradient->gradient.rgba[1] = c;
566 noGradient->gradient.ratios[1] = 255;
567 noGradient->radial = 0;
568 noGradient->rotate = 0;
569 dictionary_put2(&gradients, "no_gradient", noGradient);
572 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
573 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
574 FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
575 dictionary_put2(&filters, "no_filters", dummy);
576 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
578 dictionary_put2(&filters, "no_blur", noBlur);
579 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
581 noBevel->composite = 1;
582 dictionary_put2(&filters, "no_bevel", noBevel);
583 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
584 noDropshadow->passes = 1;
585 noDropshadow->composite = 1;
586 dictionary_put2(&filters, "no_dropshadow", noDropshadow);
587 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
588 noGradientGlow->passes = 1;
589 noGradientGlow->composite = 1;
590 noGradientGlow->gradient = &noGradient->gradient;
591 dictionary_put2(&filters, "no_gradientglow", noGradientGlow);
594 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
597 syntaxerror(".swf blocks can't be nested");
598 if(stackpos==sizeof(stack)/sizeof(stack[0]))
599 syntaxerror("too many levels of recursion");
601 SWF*swf = (SWF*)malloc(sizeof(SWF));
603 memset(swf, 0, sizeof(swf));
604 swf->fileVersion = version;
606 swf->frameRate = fps;
607 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
608 swf->compressed = compress;
609 swf_SetRGB(tag,&background);
611 dictionary_init(&characters);
612 dictionary_init(&images);
613 dictionary_init(&textures);
614 dictionary_init(&outlines);
615 dictionary_init(&gradients);
616 dictionary_init(&filters);
617 dictionary_init(&instances);
618 dictionary_init(&sounds);
619 dictionary_init(&interpolations);
621 cleanUp = &freeDictionaries;
623 memset(&stack[stackpos], 0, sizeof(stack[0]));
624 stack[stackpos].type = 0;
625 stack[stackpos].filename = strdup(name);
626 stack[stackpos].swf = swf;
627 stack[stackpos].oldframe = -1;
631 memset(¤trect, 0, sizeof(currentrect));
634 memset(idmap, 0, sizeof(idmap));
638 void s_sprite(char*name, SRECT*scalegrid)
640 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
641 swf_SetU16(tag, id); //id
642 swf_SetU16(tag, 0); //frames
644 memset(&stack[stackpos], 0, sizeof(stack[0]));
645 stack[stackpos].type = 1;
646 stack[stackpos].oldframe = currentframe;
647 stack[stackpos].olddepth = currentdepth;
648 stack[stackpos].oldrect = currentrect;
649 stack[stackpos].oldinstances = instances;
650 stack[stackpos].tag = tag;
651 stack[stackpos].id = id;
652 stack[stackpos].name = strdup(name);
654 stack[stackpos].scalegrid = *scalegrid;
656 memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
659 /* FIXME: those four fields should be bundled together */
660 dictionary_init(&instances);
663 memset(¤trect, 0, sizeof(currentrect));
669 typedef struct _buttonrecord
677 typedef struct _button
681 buttonrecord_t records[4];
684 static button_t mybutton;
686 void s_button(char*name)
688 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
689 swf_SetU16(tag, id); //id
690 swf_ButtonSetFlags(tag, 0); //menu=no
692 memset(&mybutton, 0, sizeof(mybutton));
694 memset(&stack[stackpos], 0, sizeof(stack[0]));
695 stack[stackpos].type = 3;
696 stack[stackpos].tag = tag;
697 stack[stackpos].id = id;
698 stack[stackpos].name = strdup(name);
699 stack[stackpos].oldrect = currentrect;
700 memset(¤trect, 0, sizeof(currentrect));
705 void s_buttonput(char*character, char*as, parameters_t p)
707 character_t* c = dictionary_lookup(&characters, character);
712 if(!stackpos || (stack[stackpos-1].type != 3)) {
713 syntaxerror(".show may only appear in .button");
716 syntaxerror("character %s not known (in .shape %s)", character, character);
718 if(mybutton.endofshapes) {
719 syntaxerror("a .do may not precede a .show", character, character);
722 m = s_instancepos(c->size, &p);
730 if(*s==',' || *s==0) {
731 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
732 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
733 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
734 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
735 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
736 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
743 static void setbuttonrecords(TAG*tag)
745 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
746 if(!mybutton.endofshapes) {
749 if(!mybutton.records[3].set) {
750 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
754 if(mybutton.records[t].set) {
755 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
758 swf_SetU8(tag,0); // end of button records
759 mybutton.endofshapes = 1;
763 void s_buttonaction(int flags, char*action)
769 setbuttonrecords(stack[stackpos-1].tag);
771 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
773 syntaxerror("Couldn't compile ActionScript");
776 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
777 swf_ActionSet(stack[stackpos-1].tag, a);
778 mybutton.nr_actions++;
783 static void setactionend(TAG*tag)
785 if(!mybutton.nr_actions) {
786 /* no actions means we didn't have an actionoffset,
787 which means we can't signal the end of the
788 buttonaction records, so, *sigh*, we have
789 to insert a dummy record */
790 swf_SetU16(tag, 0); //offset
791 swf_SetU16(tag, 0); //condition
792 swf_SetU8(tag, 0); //action
796 static void s_endButton()
799 setbuttonrecords(stack[stackpos-1].tag);
800 setactionend(stack[stackpos-1].tag);
803 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
807 tag = stack[stackpos].tag;
808 currentrect = stack[stackpos].oldrect;
810 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
811 free(stack[stackpos].name);
814 TAG* removeFromTo(TAG*from, TAG*to)
816 TAG*save = from->prev;
818 TAG*next = from->next;
826 static int parametersChange(history_t* history, int frame)
830 willChange = willChange || history_change(history, frame, "x");
831 willChange = willChange || history_change(history, frame, "y");
832 willChange = willChange || history_change(history, frame, "scalex");
833 willChange = willChange || history_change(history, frame, "scaley");
834 willChange = willChange || history_change(history, frame, "cxform.r0");
835 willChange = willChange || history_change(history, frame, "cxform.g0");
836 willChange = willChange || history_change(history, frame, "cxform.b0");
837 willChange = willChange || history_change(history, frame, "cxform.a0");
838 willChange = willChange || history_change(history, frame, "cxform.r1");
839 willChange = willChange || history_change(history, frame, "cxform.g1");
840 willChange = willChange || history_change(history, frame, "cxform.b1");
841 willChange = willChange || history_change(history, frame, "cxform.a1");
842 willChange = willChange || history_change(history, frame, "rotate");
843 willChange = willChange || history_change(history, frame, "shear");
844 willChange = willChange || history_change(history, frame, "pivot.x");
845 willChange = willChange || history_change(history, frame, "pivot.y");
846 willChange = willChange || history_change(history, frame, "pin.x");
847 willChange = willChange || history_change(history, frame, "pin.y");
848 willChange = willChange || history_change(history, frame, "blendmode");
849 willChange = willChange || history_changeFilter(history, frame);
854 static void free_filterlist(FILTERLIST* f_list)
857 for (i = 0; i < f_list->num; i++)
859 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
860 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
861 free(f_list->filter[i]);
866 static void readParameters(history_t* history, parameters_t* p, int frame)
868 p->x = history_value(history, frame, "x");
869 p->y = history_value(history, frame, "y");
870 p->scalex = history_value(history, frame, "scalex");
871 p->scaley = history_value(history, frame, "scaley");
872 p->cxform.r0 = history_value(history, frame, "cxform.r0");
873 p->cxform.g0 = history_value(history, frame, "cxform.g0");
874 p->cxform.b0 = history_value(history, frame, "cxform.b0");
875 p->cxform.a0 = history_value(history, frame, "cxform.a0");
876 p->cxform.r1 = history_value(history, frame, "cxform.r1");
877 p->cxform.g1 = history_value(history, frame, "cxform.g1");
878 p->cxform.b1 = history_value(history, frame, "cxform.b1");
879 p->cxform.a1 = history_value(history, frame, "cxform.a1");
880 p->rotate = history_rotateValue(history, frame);
881 p->shear = history_value(history, frame, "shear");
882 p->pivot.x = history_value(history, frame, "pivot.x");
883 p->pivot.y = history_value(history, frame, "pivot.y");
884 p->pin.x = history_value(history, frame, "pin.x");
885 p->pin.y = history_value(history, frame, "pin.y");
886 p->blendmode = history_value(history, frame, "blendmode");
887 p->filters = history_filterValue(history, frame);
890 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
894 swf_GetPlaceObject(NULL, &po);
898 po.cxform = p->cxform;
904 po.blendmode = p->blendmode;
907 po.filters = p->filters;
908 swf_SetPlaceObject(tag, &po);
911 static void writeInstance(instance_t* i)
915 int frame = i->history->firstFrame;
916 TAG* tag = i->history->firstTag;
917 history_processFlags(i->history);
918 while (frame < currentframe)
921 while (tag->id != ST_SHOWFRAME)
923 if (parametersChange(i->history, frame))
925 readParameters(i->history, &p, frame);
926 m = s_instancepos(i->character->size, &p);
928 if(p.blendmode || p.filters)
929 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
931 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
932 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
934 free_filterlist(p.filters);
941 void dumpSWF(SWF*swf)
943 TAG* tag = swf->firstTag;
944 printf("vvvvvvvvvvvvvvvvvvvvv\n");
946 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
949 printf("^^^^^^^^^^^^^^^^^^^^^\n");
952 static void s_endSprite()
954 SRECT r = currentrect;
956 if(stack[stackpos].cut)
957 tag = removeFromTo(stack[stackpos].cut, tag);
961 stringarray_t* index =dictionary_index(&instances);
963 for (num = 0; num < dictionary_count(&instances); num++)
965 char* name = stringarray_at(index, num);
968 i = dictionary_lookup(&instances, name);
975 tag = swf_InsertTag(tag, ST_SHOWFRAME);
976 tag = swf_InsertTag(tag, ST_END);
978 tag = stack[stackpos].tag;
981 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
982 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
984 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
985 swf_SetU16(tag, stack[stackpos].id);
986 swf_SetRect(tag, &stack[stackpos].scalegrid);
990 syntaxerror("internal error(7)");
991 /* TODO: before clearing, prepend "<spritename>." to names and
992 copy into old instances dict */
993 dictionary_free_all(&instances, free_instance);
995 currentframe = stack[stackpos].oldframe;
996 currentrect = stack[stackpos].oldrect;
997 currentdepth = stack[stackpos].olddepth;
998 instances = stack[stackpos].oldinstances;
1000 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1001 free(stack[stackpos].name);
1004 static void s_endSWF()
1011 stringarray_t* index = dictionary_index(&instances);
1013 for (num = 0; num < dictionary_count(&instances); num++)
1015 char* name = stringarray_at(index, num);
1018 i = dictionary_lookup(&instances, name);
1023 if(stack[stackpos].cut)
1024 tag = removeFromTo(stack[stackpos].cut, tag);
1028 swf = stack[stackpos].swf;
1029 filename = stack[stackpos].filename;
1031 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1032 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1033 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1035 tag = swf_InsertTag(tag, ST_END);
1037 swf_OptimizeTagOrder(swf);
1043 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1044 swf->movieSize = currentrect; /* "autocrop" */
1047 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1048 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1049 swf->movieSize.ymax += 20;
1050 warning("Empty bounding box for movie");
1053 if(do_cgi || !strcmp(filename, "-"))
1054 fi = fileno(stdout);
1056 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1058 syntaxerror("couldn't create output file %s", filename);
1061 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1063 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1077 if(stack[stackpos-1].type == 0)
1078 syntaxerror("End of file encountered in .flash block");
1079 if(stack[stackpos-1].type == 1)
1080 syntaxerror("End of file encountered in .sprite block");
1081 if(stack[stackpos-1].type == 2)
1082 syntaxerror("End of file encountered in .clip block");
1088 return currentframe+1;
1091 void s_frame(int nr, int cut, char*name, char anchor)
1097 syntaxerror("Illegal frame number");
1098 nr--; // internally, frame 1 is frame 0
1100 for(t=currentframe;t<nr;t++) {
1101 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1102 if(t==nr-1 && name && *name) {
1103 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1104 swf_SetString(tag, name);
1106 swf_SetU8(tag, 1); //make this an anchor
1109 if(nr == 0 && currentframe == 0 && name && *name) {
1110 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1111 swf_SetString(tag, name);
1113 swf_SetU8(tag, 1); //make this an anchor
1118 syntaxerror("Can't cut, frame empty");
1120 stack[stackpos].cut = tag;
1126 int parseColor2(char*str, RGBA*color);
1128 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1132 gradient_t*gradient;
1134 if(name[0] == '#') {
1135 parseColor2(name, &color);
1136 return swf_ShapeAddSolidFillStyle(s, &color);
1137 } else if ((texture = dictionary_lookup(&textures, name))) {
1138 return swf_ShapeAddFillStyle2(s, &texture->fs);
1139 } else if((image = dictionary_lookup(&images, name))) {
1141 swf_GetMatrix(0, &m);
1142 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1143 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1146 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1147 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1151 swf_GetMatrix(0, &rot);
1152 ccos = cos(-gradient->rotate*2*M_PI/360);
1153 csin = sin(-gradient->rotate*2*M_PI/360);
1154 rot.sx = ccos*65536;
1155 rot.r1 = -csin*65536;
1156 rot.r0 = csin*65536;
1157 rot.sy = ccos*65536;
1158 r2 = swf_TurnRect(*r, &rot);
1159 swf_GetMatrix(0, &m);
1160 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1161 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1162 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1163 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1164 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1165 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1166 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1167 } else if (parseColor2(name, &color)) {
1168 return swf_ShapeAddSolidFillStyle(s, &color);
1170 syntaxerror("not a color/fillstyle: %s", name);
1175 RGBA black={r:0,g:0,b:0,a:0};
1176 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1185 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1188 linewidth = linewidth>=20?linewidth-20:0;
1189 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1192 fs1 = addFillStyle(s, &r2, texture);
1195 r.xmin = r2.xmin-linewidth/2;
1196 r.ymin = r2.ymin-linewidth/2;
1197 r.xmax = r2.xmax+linewidth/2;
1198 r.ymax = r2.ymax+linewidth/2;
1199 swf_SetRect(tag,&r);
1200 swf_SetShapeHeader(tag,s);
1201 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1202 swf_ShapeSetLine(tag,s,width,0);
1203 swf_ShapeSetLine(tag,s,0,height);
1204 swf_ShapeSetLine(tag,s,-width,0);
1205 swf_ShapeSetLine(tag,s,0,-height);
1206 swf_ShapeSetEnd(tag);
1209 s_addcharacter(name, id, tag, r);
1213 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1219 outline = dictionary_lookup(&outlines, outlinename);
1221 syntaxerror("outline %s not defined", outlinename);
1225 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1228 linewidth = linewidth>=20?linewidth-20:0;
1229 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1232 fs1 = addFillStyle(s, &r2, texture);
1235 rect.xmin = r2.xmin-linewidth/2;
1236 rect.ymin = r2.ymin-linewidth/2;
1237 rect.xmax = r2.xmax+linewidth/2;
1238 rect.ymax = r2.ymax+linewidth/2;
1240 swf_SetRect(tag,&rect);
1241 swf_SetShapeStyles(tag, s);
1242 swf_ShapeCountBits(s,0,0);
1243 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1244 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1245 swf_SetShapeBits(tag, s);
1246 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1249 s_addcharacter(name, id, tag, rect);
1253 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1258 r2.xmin = r2.ymin = 0;
1262 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1265 linewidth = linewidth>=20?linewidth-20:0;
1266 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1269 fs1 = addFillStyle(s, &r2, texture);
1271 rect.xmin = r2.xmin-linewidth/2;
1272 rect.ymin = r2.ymin-linewidth/2;
1273 rect.xmax = r2.xmax+linewidth/2;
1274 rect.ymax = r2.ymax+linewidth/2;
1276 swf_SetRect(tag,&rect);
1277 swf_SetShapeHeader(tag,s);
1278 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1279 swf_ShapeSetCircle(tag, s, r,r,r,r);
1280 swf_ShapeSetEnd(tag);
1283 s_addcharacter(name, id, tag, rect);
1287 void s_textshape(char*name, char*fontname, float size, char*_text)
1290 U8*text = (U8*)_text;
1294 font = dictionary_lookup(&fonts, fontname);
1296 syntaxerror("font \"%s\" not known!", fontname);
1298 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1299 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1300 s_box(name, 0, 0, black, 20, 0);
1303 g = font->ascii2glyph[text[0]];
1305 outline = malloc(sizeof(outline_t));
1306 memset(outline, 0, sizeof(outline_t));
1307 outline->shape = font->glyph[g].shape;
1308 outline->bbox = font->layout->bounds[g];
1312 swf_Shape11DrawerInit(&draw, 0);
1313 swf_DrawText(&draw, font, (int)(size*100), _text);
1315 outline->shape = swf_ShapeDrawerToShape(&draw);
1316 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1317 draw.dealloc(&draw);
1320 if(dictionary_lookup(&outlines, name))
1321 syntaxerror("outline %s defined twice", name);
1322 dictionary_put2(&outlines, name, outline);
1325 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1330 font = dictionary_lookup(&fonts, fontname);
1332 syntaxerror("font \"%s\" not known!", fontname);
1334 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1335 swf_SetU16(tag, id);
1336 if(!font->numchars) {
1337 s_box(name, 0, 0, black, 20, 0);
1340 r = swf_SetDefineText(tag, font, &color, text, size);
1342 if(stack[0].swf->fileVersion >= 8) {
1343 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1344 swf_SetU16(tag, id);
1345 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1346 swf_SetU32(tag, 0);//thickness
1347 swf_SetU32(tag, 0);//sharpness
1348 swf_SetU8(tag, 0);//reserved
1351 s_addcharacter(name, id, tag, r);
1355 void s_quicktime(char*name, char*url)
1360 memset(&r, 0, sizeof(r));
1362 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1363 swf_SetU16(tag, id);
1364 swf_SetString(tag, url);
1366 s_addcharacter(name, id, tag, r);
1370 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags, int align)
1373 EditTextLayout layout;
1376 if(fontname && *fontname) {
1377 flags |= ET_USEOUTLINES;
1378 font = dictionary_lookup(&fonts, fontname);
1380 syntaxerror("font \"%s\" not known!", fontname);
1382 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1383 swf_SetU16(tag, id);
1384 layout.align = align;
1385 layout.leftmargin = 0;
1386 layout.rightmargin = 0;
1394 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1396 s_addcharacter(name, id, tag, r);
1400 /* type: either "jpeg" or "png"
1402 void s_image(char*name, char*type, char*filename, int quality)
1404 /* an image is actually two folded: 1st bitmap, 2nd character.
1405 Both of them can be used separately */
1407 /* step 1: the bitmap */
1411 if(!strcmp(type,"jpeg")) {
1412 #ifndef HAVE_JPEGLIB
1413 warning("no jpeg support compiled in");
1414 s_box(name, 0, 0, black, 20, 0);
1417 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1418 swf_SetU16(tag, imageID);
1420 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1421 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1424 swf_GetJPEGSize(filename, &width, &height);
1431 s_addimage(name, id, tag, r);
1434 } else if(!strcmp(type,"png")) {
1436 swf_SetU16(tag, imageID);
1438 getPNG(filename, &width, &height, (unsigned char**)&data);
1441 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1444 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1445 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1446 swf_SetU16(tag, imageID);
1447 swf_SetLosslessImage(tag, data, width, height);
1454 s_addimage(name, id, tag, r);
1457 warning("image type \"%s\" not supported yet!", type);
1458 s_box(name, 0, 0, black, 20, 0);
1462 /* step 2: the character */
1463 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1464 swf_SetU16(tag, id);
1465 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1467 s_addcharacter(name, id, tag, r);
1471 void s_getBitmapSize(char*name, int*width, int*height)
1473 character_t* image = dictionary_lookup(&images, name);
1474 gradient_t* gradient = dictionary_lookup(&gradients,name);
1476 *width = image->size.xmax;
1477 *height = image->size.ymax;
1481 /* internal SWF gradient size */
1482 if(gradient->radial) {
1491 syntaxerror("No such bitmap/gradient: %s", name);
1494 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1496 if(dictionary_lookup(&textures, name))
1497 syntaxerror("texture %s defined twice", name);
1498 gradient_t* gradient = dictionary_lookup(&gradients, object);
1499 character_t* bitmap = dictionary_lookup(&images, object);
1500 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1502 FILLSTYLE*fs = &texture->fs;
1504 memset(&p, 0, sizeof(parameters_t));
1507 fs->type = FILL_TILED;
1508 fs->id_bitmap = bitmap->id;
1509 } else if(gradient) {
1510 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1511 fs->gradient = gradient->gradient;
1513 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1514 makeMatrix(&fs->m, &p);
1515 if(gradient && !gradient->radial) {
1522 p2 = swf_TurnPoint(p1, &m);
1531 dictionary_put2(&textures, name, texture);
1534 void s_font(char*name, char*filename)
1537 font = dictionary_lookup(&fonts, name);
1540 /* fix the layout. Only needed for old fonts */
1542 for(t=0;t<font->numchars;t++) {
1543 font->glyph[t].advance = 0;
1546 swf_FontCreateLayout(font);
1549 swf_FontReduce_swfc(font);
1550 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1551 swf_FontSetDefine2(tag, font);
1552 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1554 swf_SetU16(tag, id);
1555 swf_SetString(tag, name);
1562 typedef struct _sound_t
1568 void s_sound(char*name, char*filename)
1570 struct WAV wav, wav2;
1574 unsigned numsamples = 1;
1575 unsigned blocksize = 1152;
1578 if(dictionary_lookup(&sounds, name))
1579 syntaxerror("sound %s defined twice", name);
1581 if(wav_read(&wav, filename))
1584 wav_convert2mono(&wav, &wav2, 44100);
1585 samples = (U16*)wav2.data;
1586 numsamples = wav2.size/2;
1588 #ifdef WORDS_BIGENDIAN
1590 for(t=0;t<numsamples;t++)
1591 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1595 if(mp3_read(&mp3, filename))
1597 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1603 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1608 if(numsamples%blocksize != 0)
1610 // apply padding, so that block is a multiple of blocksize
1611 int numblocks = (numsamples+blocksize-1)/blocksize;
1614 numsamples2 = numblocks * blocksize;
1615 samples2 = malloc(sizeof(U16)*numsamples2);
1616 memcpy(samples2, samples, numsamples*sizeof(U16));
1617 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1618 numsamples = numsamples2;
1623 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1624 swf_SetU16(tag, id); //id
1627 swf_SetSoundDefineMP3(
1628 tag, mp3.data, mp3.size,
1635 swf_SetSoundDefine(tag, samples, numsamples);
1637 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1638 swf_SetU16(tag, id);
1639 swf_SetString(tag, name);
1640 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1642 swf_SetU16(tag, id);
1643 swf_SetString(tag, name);
1645 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1649 dictionary_put2(&sounds, name, sound);
1657 static char* gradient_getToken(const char**p)
1661 while(**p && strchr(" \t\n\r", **p)) {
1665 while(**p && !strchr(" \t\n\r", **p)) {
1668 result = malloc((*p)-start+1);
1669 memcpy(result,start,(*p)-start+1);
1670 result[(*p)-start] = 0;
1674 float parsePercent(char*str);
1675 RGBA parseColor(char*str);
1677 GRADIENT parseGradient(const char*str)
1681 const char* p = str;
1682 memset(&gradient, 0, sizeof(GRADIENT));
1683 gradient.ratios = rfx_calloc(16*sizeof(U8));
1684 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1688 char*posstr,*colorstr;
1691 posstr = gradient_getToken(&p);
1697 pos = (int)(parsePercent(posstr)*255.0);
1702 rfx_free(gradient.ratios);
1703 rfx_free(gradient.rgba);
1705 syntaxerror("Error in shape data: Color expected after %s", posstr);
1707 colorstr = gradient_getToken(&p);
1708 color = parseColor(colorstr);
1709 if(gradient.num == 16)
1711 warning("gradient record too big- max size is 16, rest ignored");
1714 gradient.ratios[gradient.num] = pos;
1715 gradient.rgba[gradient.num] = color;
1724 FILTERLIST* parseFilters(char* list)
1726 if (!strcmp(list, "no_filters"))
1729 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1731 char* f_start = list;
1735 f_end = strchr(f_start, ',');
1738 f = dictionary_lookup(&filters, f_start);
1742 syntaxerror("unknown filter %s", f_start);
1744 if (f_list->num == 8)
1746 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1749 f_list->filter[f_list->num] = f;
1754 f_start = f_end + 1;
1762 void s_gradient(char*name, const char*text, int radial, int rotate)
1764 gradient_t* gradient;
1765 gradient = malloc(sizeof(gradient_t));
1766 memset(gradient, 0, sizeof(gradient_t));
1767 gradient->gradient = parseGradient(text);
1768 gradient->radial = radial;
1769 gradient->rotate = rotate;
1771 dictionary_put2(&gradients, name, gradient);
1774 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1775 float angle, float distance, float strength, char innershadow,
1776 char knockout, char composite, char ontop, int passes)
1778 if(dictionary_lookup(&filters, name))
1779 syntaxerror("filter %s defined twice", name);
1781 gradient_t* g = dictionary_lookup(&gradients, gradient);
1783 syntaxerror("unknown gradient %s", gradient);
1787 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1788 filter->type = FILTERTYPE_GRADIENTGLOW;
1789 filter->gradient = &g->gradient;
1790 filter->blurx = blurx;
1791 filter->blury = blury;
1792 filter->strength = strength;
1793 filter->angle = angle;
1794 filter->distance = distance;
1795 filter->innershadow = innershadow;
1796 filter->knockout = knockout;
1797 filter->composite = composite;
1798 filter->ontop = ontop;
1799 filter->passes = passes;
1801 dictionary_put2(&filters, name, filter);
1804 void s_dropshadow(char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
1806 if(dictionary_lookup(&filters, name))
1807 syntaxerror("filter %s defined twice", name);
1810 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1811 filter->type = FILTERTYPE_DROPSHADOW;
1812 filter->color= color;
1813 filter->blurx = blurx;
1814 filter->blury = blury;
1815 filter->strength = strength;
1816 filter->angle = angle;
1817 filter->distance = distance;
1818 filter->innershadow = innershadow;
1819 filter->knockout = knockout;
1820 filter->composite = composite;
1821 filter->passes = passes;
1823 dictionary_put2(&filters, name, filter);
1826 void s_bevel(char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes)
1828 if(dictionary_lookup(&filters, name))
1829 syntaxerror("filter %s defined twice", name);
1832 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1833 filter->type = FILTERTYPE_BEVEL;
1834 filter->shadow = shadow;
1835 filter->highlight = highlight;
1836 filter->blurx = blurx;
1837 filter->blury = blury;
1838 filter->strength = strength;
1839 filter->angle = angle;
1840 filter->distance = distance;
1841 filter->innershadow = innershadow;
1842 filter->knockout = knockout;
1843 filter->composite = composite;
1844 filter->ontop = ontop;
1845 filter->passes = passes;
1847 dictionary_put2(&filters, name, filter);
1850 void s_blur(char*name, double blurx, double blury, int passes)
1852 if(dictionary_lookup(&filters, name))
1853 syntaxerror("filter %s defined twice", name);
1855 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1856 filter->type = FILTERTYPE_BLUR;
1857 filter->blurx = blurx;
1858 filter->blury = blury;
1859 filter->passes = passes;
1861 dictionary_put2(&filters, name, filter);
1864 void s_action(const char*text)
1867 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1871 syntaxerror("Couldn't compile ActionScript");
1874 tag = swf_InsertTag(tag, ST_DOACTION);
1876 swf_ActionSet(tag, a);
1881 void s_initaction(const char*character, const char*text)
1885 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1889 syntaxerror("Couldn't compile ActionScript");
1892 c = (character_t*)dictionary_lookup(&characters, character);
1894 tag = swf_InsertTag(tag, ST_DOINITACTION);
1895 swf_SetU16(tag, c->id);
1896 swf_ActionSet(tag, a);
1901 int s_swf3action(char*name, char*action)
1904 instance_t* object = 0;
1906 object = (instance_t*)dictionary_lookup(&instances, name);
1907 if(!object && name && *name) {
1908 /* we have a name, but couldn't find it. Abort. */
1911 a = action_SetTarget(0, name);
1912 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1913 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1914 else if(!strcmp(action, "stop")) a = action_Stop(a);
1915 else if(!strcmp(action, "play")) a = action_Play(a);
1916 a = action_SetTarget(a, "");
1919 tag = swf_InsertTag(tag, ST_DOACTION);
1920 swf_ActionSet(tag, a);
1925 void s_outline(char*name, char*format, char*source)
1927 if(dictionary_lookup(&outlines, name))
1928 syntaxerror("outline %s defined twice", name);
1937 //swf_Shape10DrawerInit(&draw, 0);
1938 swf_Shape11DrawerInit(&draw, 0);
1940 draw_string(&draw, source);
1942 shape = swf_ShapeDrawerToShape(&draw);
1943 bounds = swf_ShapeDrawerGetBBox(&draw);
1944 draw.dealloc(&draw);
1946 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1947 outline->shape = shape;
1948 outline->bbox = bounds;
1950 dictionary_put2(&outlines, name, outline);
1953 int s_playsound(char*name, int loops, int nomultiple, int stop)
1959 sound = dictionary_lookup(&sounds, name);
1963 tag = swf_InsertTag(tag, ST_STARTSOUND);
1964 swf_SetU16(tag, sound->id); //id
1965 memset(&info, 0, sizeof(info));
1968 info.nomultiple = nomultiple;
1969 swf_SetSoundInfo(tag, &info);
1973 void s_includeswf(char*name, char*filename)
1981 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1982 f = open(filename,O_RDONLY|O_BINARY);
1984 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1985 s_box(name, 0, 0, black, 20, 0);
1988 if (swf_ReadSWF(f,&swf)<0) {
1989 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1990 s_box(name, 0, 0, black, 20, 0);
1995 /* FIXME: The following sets the bounding Box for the character.
1996 It is wrong for two reasons:
1997 a) It may be too small (in case objects in the movie clip at the borders)
1998 b) it may be too big (because the poor movie never got autocropped)
2002 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2003 swf_SetU16(tag, id);
2004 swf_SetU16(tag, swf.frameCount);
2006 swf_Relocate(&swf, idmap);
2008 ftag = swf.firstTag;
2012 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2013 if(cutout[t] == ftag->id) {
2017 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2019 if(ftag->id == ST_END)
2024 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2025 /* We simply dump all tags right after the sprite
2026 header, relying on the fact that swf_OptimizeTagOrder() will
2027 sort things out for us later.
2028 We also rely on the fact that the imported SWF is well-formed.
2030 tag = swf_InsertTag(tag, ftag->id);
2031 swf_SetBlock(tag, ftag->data, ftag->len);
2037 syntaxerror("Included file %s contains errors", filename);
2038 tag = swf_InsertTag(tag, ST_END);
2042 s_addcharacter(name, id, tag, r);
2045 SRECT s_getCharBBox(char*name)
2047 character_t* c = dictionary_lookup(&characters, name);
2048 if(!c) syntaxerror("character '%s' unknown(2)", name);
2051 SRECT s_getInstanceBBox(char*name)
2053 instance_t * i = dictionary_lookup(&instances, name);
2055 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2057 if(!c) syntaxerror("internal error(5)");
2060 void s_getParameters(char*name, parameters_t* p)
2062 instance_t * i = dictionary_lookup(&instances, name);
2064 syntaxerror("instance '%s' unknown(10)", name);
2065 if (change_sets_all)
2066 readParameters(i->history, p, currentframe);
2071 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2073 history_begin(i->history, "x", currentframe, tag, p->x);
2074 history_begin(i->history, "y", currentframe, tag, p->y);
2075 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2076 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2077 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2078 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2079 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2080 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2081 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2082 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2083 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2084 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2085 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2086 history_begin(i->history, "shear", currentframe, tag, p->shear);
2087 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2088 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2089 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2090 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2091 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2092 history_beginFilter(i->history, currentframe, tag, p->filters);
2093 history_begin(i->history, "flags", currentframe, tag, 0);
2096 void s_startclip(char*instance, char*character, parameters_t p)
2098 character_t* c = dictionary_lookup(&characters, character);
2102 syntaxerror("character %s not known", character);
2104 i = s_addinstance(instance, c, currentdepth);
2106 m = s_instancepos(i->character->size, &p);
2108 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2109 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2110 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2112 stack[stackpos].tag = tag;
2113 stack[stackpos].type = 2;
2116 setStartparameters(i, &p, tag);
2123 swf_SetTagPos(stack[stackpos].tag, 0);
2124 swf_GetPlaceObject(stack[stackpos].tag, &p);
2125 p.clipdepth = currentdepth;
2127 swf_ClearTag(stack[stackpos].tag);
2128 swf_SetPlaceObject(stack[stackpos].tag, &p);
2132 void s_put(char*instance, char*character, parameters_t p)
2134 character_t* c = dictionary_lookup(&characters, character);
2138 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2140 i = s_addinstance(instance, c, currentdepth);
2142 m = s_instancepos(i->character->size, &p);
2144 if(p.blendmode || p.filters)
2146 if(stack[0].swf->fileVersion < 8)
2149 warning("blendmodes only supported for flash version>=8");
2151 warning("filters only supported for flash version>=8");
2153 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2156 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2157 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2158 setStartparameters(i, &p, tag);
2162 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2165 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2167 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2168 if (p.set & SF_SCALEX)
2169 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2170 if (p.set & SF_SCALEY)
2171 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2172 if (p.set & SF_CX_R)
2174 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2175 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2177 if (p.set & SF_CX_G)
2179 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2180 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2182 if (p.set & SF_CX_B)
2184 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2185 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2187 if (p.set & SF_CX_A)
2189 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2190 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2192 if (p.set & SF_ROTATE)
2193 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2194 if (p.set & SF_SHEAR)
2195 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2196 if (p.set & SF_PIVOT)
2198 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2199 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2203 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2204 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2206 if (p.set & SF_BLEND)
2207 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2208 if (p.set & SF_FILTER)
2209 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2212 void s_jump(char* instance, parameters_t p)
2214 instance_t* i = dictionary_lookup(&instances, instance);
2216 syntaxerror("instance %s not known", instance);
2217 recordChanges(i->history, p, CF_JUMP, 0);
2220 void s_change(char*instance, parameters_t p, interpolation_t* inter)
2222 instance_t* i = dictionary_lookup(&instances, instance);
2224 syntaxerror("instance %s not known", instance);
2225 recordChanges(i->history, p, CF_CHANGE, inter);
2228 void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2230 instance_t* i = dictionary_lookup(&instances, instance);
2232 syntaxerror("instance %s not known", instance);
2233 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2236 void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
2238 instance_t* i = dictionary_lookup(&instances, instance);
2240 syntaxerror("instance %s not known", instance);
2241 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2244 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2247 void s_delinstance(char*instance)
2249 instance_t* i = dictionary_lookup(&instances, instance);
2251 syntaxerror("instance %s not known", instance);
2253 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2254 swf_SetU16(tag, i->depth);
2255 dictionary_del(&instances, instance);
2258 void s_schange(char*instance, parameters_t p, interpolation_t* inter)
2260 instance_t* i = dictionary_lookup(&instances, instance);
2262 syntaxerror("instance %s not known", instance);
2263 recordChanges(i->history, p, CF_SCHANGE, inter);
2269 syntaxerror(".end unexpected");
2270 switch (stack[stackpos-1].type)
2285 syntaxerror("internal error 1");
2289 // ------------------------------------------------------------------------
2291 typedef int command_func_t(map_t*args);
2293 SRECT parseBox(char*str)
2295 SRECT r = {0,0,0,0};
2296 float xmin, xmax, ymin, ymax;
2297 char*x = strchr(str, 'x');
2299 if(!strcmp(str, "autocrop")) {
2300 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2304 d1 = strchr(x+1, ':');
2306 d2 = strchr(d1+1, ':');
2308 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2312 else if(d1 && !d2) {
2313 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2319 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2324 r.xmin = (SCOORD)(xmin*20);
2325 r.ymin = (SCOORD)(ymin*20);
2326 r.xmax = (SCOORD)(xmax*20);
2327 r.ymax = (SCOORD)(ymax*20);
2330 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2333 float parseFloat(char*str)
2337 int parseInt(char*str)
2342 if(str[0]=='+' || str[0]=='-')
2346 if(str[t]<'0' || str[t]>'9')
2347 syntaxerror("Not an Integer: \"%s\"", str);
2350 int parseRawTwip(char*str)
2354 if(str[0]=='+' || str[0]=='-') {
2359 dot = strchr(str, '.');
2363 return sign*parseInt(str)*20;
2365 char* old = strdup(str);
2366 int l=strlen(dot+1);
2369 for(s=str;s<dot-1;s++)
2370 if(*s<'0' || *s>'9')
2373 syntaxerror("Not a coordinate: \"%s\"", str);
2376 if(*s<'0' || *s>'9')
2379 syntaxerror("Not a coordinate: \"%s\"", str);
2381 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2382 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2385 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2389 return sign*(atoi(str)*20);
2391 return sign*(atoi(str)*20+atoi(dot)*2);
2393 return sign*(atoi(str)*20+atoi(dot)/5);
2398 static dictionary_t defines;
2399 static int defines_initialized = 0;
2400 static mem_t define_values;
2402 int parseTwip(char*str)
2404 /* TODO: make this a proper expression parser */
2410 if(*p == '+' || *p == '-' || *p == '/' || *p == '*')
2415 if((*p == '+' || *p == '-' || *p == '/' || *p == '*' || *p == 0) && lastpos) {
2421 if(defines_initialized) {
2422 l = (int)dictionary_lookup(&defines, lastpos);
2425 v = *(int*)&define_values.buffer[l-1];
2427 v = parseRawTwip(lastpos);
2447 int parseArc(char* str)
2449 if (!strcmp(str, "short"))
2451 if (!strcmp(str, "long"))
2453 syntaxerror("invalid value for the arc parameter: %s", str);
2457 int parseDir(char* str)
2459 if (!strcmp(str, "clockwise"))
2461 if (!strcmp(str, "counterclockwise"))
2463 syntaxerror("invalid value for the dir parameter: %s", str);
2467 int isPoint(char*str)
2469 if(strchr(str, '('))
2475 SPOINT parsePoint(char*str)
2479 int l = strlen(str);
2480 char*comma = strchr(str, ',');
2481 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2482 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2483 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2484 p.x = parseTwip(tmp);
2485 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2486 p.y = parseTwip(tmp);
2490 int parseColor2(char*str, RGBA*color)
2492 int l = strlen(str);
2496 struct {unsigned char r,g,b;char*name;} colors[] =
2497 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2498 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2499 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2500 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2501 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2502 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2503 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2504 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2505 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2506 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2507 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2508 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2512 if(str[0]=='#' && (l==7 || l==9)) {
2513 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2515 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2517 color->r = r; color->g = g; color->b = b; color->a = a;
2520 int len=strlen(str);
2522 if(strchr(str, '/')) {
2523 len = strchr(str, '/')-str;
2524 sscanf(str+len+1,"%02x", &alpha);
2526 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2527 if(!strncmp(str, colors[t].name, len)) {
2532 color->r = r; color->g = g; color->b = b; color->a = a;
2538 RGBA parseColor(char*str)
2541 if(!parseColor2(str, &c))
2542 syntaxerror("Expression '%s' is not a color", str);
2546 typedef struct _muladd {
2551 MULADD parseMulAdd(char*str)
2554 char* str2 = (char*)malloc(strlen(str)+5);
2561 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2562 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2563 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2564 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2565 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2566 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2567 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2568 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2569 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2570 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2572 syntaxerror("'%s' is not a valid color transform expression", str);
2574 m.add = (int)(add*256);
2575 m.mul = (int)(mul*256);
2580 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2582 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2583 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2585 if(a<-32768) a=-32768;
2586 if(a>32767) a=32767;
2587 if(m<-32768) m=-32768;
2588 if(m>32767) m=32767;
2594 float parsePxOrPercent(char*fontname, char*str)
2596 int l = strlen(str);
2597 if(strchr(str, '%'))
2598 return parsePercent(str);
2599 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2600 float p = atof(str);
2601 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2603 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2607 float parsePercent(char*str)
2609 int l = strlen(str);
2613 return atoi(str)/100.0;
2615 syntaxerror("Expression '%s' is not a percentage", str);
2618 int isPercent(char*str)
2620 return str[strlen(str)-1]=='%';
2622 int parseNewSize(char*str, int size)
2625 return parsePercent(str)*size;
2627 return (int)(atof(str)*20);
2630 int isColor(char*str)
2633 return parseColor2(str, &c);
2636 static char* lu(map_t* args, char*name)
2638 char* value = map_lookup(args, name);
2640 map_dump(args, stdout, "");
2641 syntaxerror("internal error 2: value %s should be set", name);
2646 static int c_flash(map_t*args)
2648 char* filename = map_lookup(args, "filename");
2649 char* compressstr = lu(args, "compress");
2650 char* change_modestr = lu(args, "change-sets-all");
2651 char* exportstr = lu(args, "export");
2652 SRECT bbox = parseBox(lu(args, "bbox"));
2653 int version = parseInt(lu(args, "version"));
2654 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2655 RGBA color = parseColor(lu(args, "background"));
2658 if(!filename || !*filename) {
2659 /* for compatibility */
2660 filename = map_lookup(args, "name");
2661 if(!filename || !*filename) {
2664 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2665 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2669 if(!filename || override_outputname)
2670 filename = outputname;
2672 if(!strcmp(compressstr, "default"))
2673 compress = version>=6;
2674 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2676 else if(!strcmp(compressstr, "no"))
2678 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2680 if(!strcmp(change_modestr, "yes"))
2681 change_sets_all = 1;
2683 if(strcmp(change_modestr, "no"))
2684 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2686 do_exports=atoi(exportstr);
2688 s_swf(filename, bbox, version, fps, compress, color);
2691 int isRelative(char*str)
2693 return !strncmp(str, "<plus>", 6) ||
2694 !strncmp(str, "<minus>", 7);
2696 char* getOffset(char*str)
2698 if(!strncmp(str, "<plus>", 6))
2700 if(!strncmp(str, "<minus>", 7))
2702 syntaxerror("internal error (347)");
2705 int getSign(char*str)
2707 if(!strncmp(str, "<plus>", 6))
2709 if(!strncmp(str, "<minus>", 7))
2711 syntaxerror("internal error (348)");
2715 static dictionary_t points;
2716 static mem_t mpoints;
2717 static int points_initialized = 0;
2719 static int c_interpolation(map_t *args)
2722 char* name = lu(args, "name");
2723 if (dictionary_lookup(&interpolations, name))
2724 syntaxerror("interpolation %s defined twice", name);
2726 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2727 char* functionstr = lu(args, "function");
2728 inter->function = 0;
2729 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2730 if (!strcmp(functionstr,interpolationFunctions[i]))
2732 inter->function = i + 1;
2735 if (!inter->function)
2736 syntaxerror("unkown interpolation function %s", functionstr);
2737 inter->speed = parseFloat(lu(args, "speed"));
2738 inter->amplitude = parseTwip(lu(args, "amplitude"));
2739 inter->growth = parseFloat(lu(args, "growth"));
2740 inter->bounces = parseInt(lu(args, "bounces"));
2741 inter->damping = parseFloat(lu(args, "damping"));
2742 inter->slope = parseFloat(lu(args, "slope"));
2744 dictionary_put2(&interpolations, name, inter);
2748 SPOINT getPoint(SRECT r, char*name)
2751 if(!strcmp(name, "center")) {
2753 p.x = (r.xmin + r.xmax)/2;
2754 p.y = (r.ymin + r.ymax)/2;
2757 if (!strcmp(name, "bottom-center")) {
2759 p.x = (r.xmin + r.xmax)/2;
2763 if (!strcmp(name, "top-center")) {
2765 p.x = (r.xmin + r.xmax)/2;
2769 if (!strcmp(name, "top-left")) {
2775 if (!strcmp(name, "top-right")) {
2781 if (!strcmp(name, "bottom-right")) {
2787 if (!strcmp(name, "bottom-left")) {
2793 if (!strcmp(name, "left-center")) {
2796 p.y = (r.ymin + r.ymax)/2;
2799 if (!strcmp(name, "right-center")) {
2802 p.y = (r.ymin + r.ymax)/2;
2807 if(points_initialized)
2808 l = (int)dictionary_lookup(&points, name);
2810 syntaxerror("Invalid point: \"%s\".", name);
2812 return *(SPOINT*)&mpoints.buffer[l-1];
2816 static int texture2(char*name, char*object, map_t*args, int errors)
2819 char*xstr = map_lookup(args, "x");
2820 char*ystr = map_lookup(args, "y");
2821 char*widthstr = map_lookup(args, "width");
2822 char*heightstr = map_lookup(args, "height");
2823 char*scalestr = map_lookup(args, "scale");
2824 char*scalexstr = map_lookup(args, "scalex");
2825 char*scaleystr = map_lookup(args, "scaley");
2826 char*rotatestr = map_lookup(args, "rotate");
2827 char* shearstr = map_lookup(args, "shear");
2828 char* radiusstr = map_lookup(args, "r");
2830 float scalex = 1.0, scaley = 1.0;
2831 float rotate=0, shear=0;
2833 if(!*xstr && !*ystr) {
2835 syntaxerror("x and y must be set");
2838 if(*scalestr && (*scalexstr || *scaleystr)) {
2839 syntaxerror("scale and scalex/scaley can't both be set");
2842 if((*widthstr || *heightstr) && *radiusstr) {
2843 syntaxerror("width/height and radius can't both be set");
2846 widthstr = radiusstr;
2847 heightstr = radiusstr;
2849 if(!*xstr) xstr="0";
2850 if(!*ystr) ystr="0";
2851 if(!*rotatestr) rotatestr="0";
2852 if(!*shearstr) shearstr="0";
2855 scalex = scaley = parsePercent(scalestr);
2856 } else if(*scalexstr || *scaleystr) {
2857 if(scalexstr) scalex = parsePercent(scalexstr);
2858 if(scaleystr) scaley = parsePercent(scaleystr);
2859 } else if(*widthstr || *heightstr) {
2862 s_getBitmapSize(object, &width, &height);
2864 scalex = (float)parseTwip(widthstr)/(float)width;
2866 scaley = (float)parseTwip(heightstr)/(float)height;
2868 x = parseTwip(xstr);
2869 y = parseTwip(ystr);
2870 rotate = parseFloat(rotatestr);
2871 shear = parseFloat(shearstr);
2873 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2878 static int c_texture(map_t*args)
2880 char*name = lu(args, "instance");
2881 char*object = lu(args, "character");
2882 return texture2(name, object, args, 1);
2885 static int c_gradient(map_t*args)
2887 char*name = lu(args, "name");
2888 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2889 int rotate = parseInt(lu(args, "rotate"));
2893 syntaxerror("colon (:) expected");
2895 if(dictionary_lookup(&gradients, name))
2896 syntaxerror("gradient %s defined twice", name);
2898 s_gradient(name, text, radial, rotate);
2900 /* check whether we also have placement information,
2901 which would make this a positioned gradient.
2902 If there is placement information, texture2() will
2903 add a texture, which has priority over the gradient.
2905 texture2(name, name, args, 0);
2909 static char* checkFiltername(map_t* args)
2911 char* name = lu(args, "name");
2912 if (strchr(name, ','))
2913 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
2917 static int c_blur(map_t*args)
2919 char*name = checkFiltername(args);
2920 char*blurstr = lu(args, "blur");
2921 char*blurxstr = lu(args, "blurx");
2922 char*blurystr = lu(args, "blury");
2923 float blurx=1.0, blury=1.0;
2925 blurx = parseFloat(blurstr);
2926 blury = parseFloat(blurstr);
2929 blurx = parseFloat(blurxstr);
2931 blury = parseFloat(blurystr);
2932 int passes = parseInt(lu(args, "passes"));
2933 s_blur(name, blurx, blury, passes);
2937 static int c_gradientglow(map_t*args)
2939 char*name = checkFiltername(args);
2940 char*gradient = lu(args, "gradient");
2941 char*blurstr = lu(args, "blur");
2942 char*blurxstr = lu(args, "blurx");
2943 char*blurystr = lu(args, "blury");
2944 float blurx=1.0, blury=1.0;
2946 blurx = parseFloat(blurstr);
2947 blury = parseFloat(blurstr);
2950 blurx = parseFloat(blurxstr);
2952 blury = parseFloat(blurystr);
2954 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2955 float distance = parseFloat(lu(args, "distance"));
2956 float strength = parseFloat(lu(args, "strength"));
2957 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2958 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2959 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2960 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2961 int passes = parseInt(lu(args, "passes"));
2963 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2967 static int c_dropshadow(map_t*args)
2969 char*name = checkFiltername(args);
2970 RGBA color = parseColor(lu(args, "color"));
2971 char*blurstr = lu(args, "blur");
2972 char*blurxstr = lu(args, "blurx");
2973 char*blurystr = lu(args, "blury");
2974 float blurx=1.0, blury=1.0;
2976 blurx = parseFloat(blurstr);
2977 blury = parseFloat(blurstr);
2980 blurx = parseFloat(blurxstr);
2982 blury = parseFloat(blurystr);
2984 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2985 float distance = parseFloat(lu(args, "distance"));
2986 float strength = parseFloat(lu(args, "strength"));
2987 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2988 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2989 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2990 int passes = parseInt(lu(args, "passes"));
2992 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2996 static int c_bevel(map_t*args)
2998 char*name = checkFiltername(args);
2999 RGBA shadow = parseColor(lu(args, "shadow"));
3000 RGBA highlight = parseColor(lu(args, "highlight"));
3001 char*blurstr = lu(args, "blur");
3002 char*blurxstr = lu(args, "blurx");
3003 char*blurystr = lu(args, "blury");
3004 float blurx=1.0, blury=1.0;
3006 blurx = parseFloat(blurstr);
3007 blury = parseFloat(blurstr);
3010 blurx = parseFloat(blurxstr);
3012 blury = parseFloat(blurystr);
3014 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3015 float distance = parseFloat(lu(args, "distance"));
3016 float strength = parseFloat(lu(args, "strength"));
3017 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3018 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3019 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3020 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3021 int passes = parseInt(lu(args, "passes"));
3023 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3027 static int c_define(map_t*args)
3029 char*name = lu(args, "name");
3030 char*value = lu(args, "value");
3032 if(!defines_initialized) {
3033 dictionary_init(&defines);
3034 mem_init(&define_values);
3035 defines_initialized = 1;
3037 int val = parseTwip(value);
3038 int pos = mem_put(&define_values, &val, sizeof(val));
3040 string_set(&s, name);
3041 dictionary_put(&defines, s, (void*)(pos+1));
3044 static int c_point(map_t*args)
3046 char*name = lu(args, "name");
3050 if(!points_initialized) {
3051 dictionary_init(&points);
3053 points_initialized = 1;
3055 p.x = parseTwip(lu(args, "x"));
3056 p.y = parseTwip(lu(args, "y"));
3057 pos = mem_put(&mpoints, &p, sizeof(p));
3058 string_set(&s1, name);
3059 dictionary_put(&points, s1, (void*)(pos+1));
3062 static int c_play(map_t*args)
3064 char*name = lu(args, "name");
3065 char*loop = lu(args, "loop");
3066 char*nomultiple = lu(args, "nomultiple");
3068 if(!strcmp(nomultiple, "nomultiple"))
3071 nm = parseInt(nomultiple);
3073 if(s_playsound(name, parseInt(loop), nm, 0)) {
3075 } else if(s_swf3action(name, "play")) {
3081 static int c_stop(map_t*args)
3083 char*name = map_lookup(args, "name");
3085 if(s_playsound(name, 0,0,1))
3087 else if(s_swf3action(name, "stop"))
3089 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3093 static int c_nextframe(map_t*args)
3095 char*name = lu(args, "name");
3097 if(s_swf3action(name, "nextframe")) {
3100 syntaxerror("I don't know anything about movie \"%s\"", name);
3104 static int c_previousframe(map_t*args)
3106 char*name = lu(args, "name");
3108 if(s_swf3action(name, "previousframe")) {
3111 syntaxerror("I don't know anything about movie \"%s\"", name);
3115 static int c_movement(map_t*args, int type)
3117 char*instance = lu(args, "name");
3125 xstr = lu(args, "x");
3126 ystr = lu(args, "y");
3128 s_getParameters(instance, &p);
3133 if(isRelative(xstr))
3135 if(type == PT_PUT || type == PT_STARTCLIP)
3136 syntaxerror("relative x values not allowed for initial put or startclip");
3137 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3141 p.x = parseTwip(xstr);
3147 if(isRelative(ystr))
3149 if(type == PT_PUT || type == PT_STARTCLIP)
3150 syntaxerror("relative y values not allowed for initial put or startclip");
3151 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3155 p.y = parseTwip(ystr);
3160 if (change_sets_all)
3168 char* interstr = lu(args, "interpolation");
3169 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3171 syntaxerror("unkown interpolation %s", interstr);
3172 s_change(instance, p, inter);
3177 char* interstr = lu(args, "interpolation");
3178 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3180 syntaxerror("unkown interpolation %s", interstr);
3181 s_schange(instance, p, inter);
3186 char* rstr = lu(args, "r");
3187 int radius = parseTwip(rstr);
3189 syntaxerror("sweep not possible: radius must be greater than 0.");
3190 char* dirstr = lu(args, "dir");
3191 int clockwise = parseDir(dirstr);
3192 char* arcstr = lu(args, "arc");
3193 int short_arc = parseArc(arcstr);
3194 char* interstr = lu(args, "interpolation");
3195 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3197 syntaxerror("unkown interpolation %s", interstr);
3198 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3205 static int c_placement(map_t*args, int type)
3207 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3210 char* luminancestr = lu(args, "luminance");
3211 char* scalestr = lu(args, "scale");
3212 char* scalexstr = lu(args, "scalex");
3213 char* scaleystr = lu(args, "scaley");
3214 char* rotatestr = lu(args, "rotate");
3215 char* shearstr = lu(args, "shear");
3216 char* xstr="", *pivotstr="";
3217 char* ystr="", *anglestr="";
3218 char*above = lu(args, "above"); /*FIXME*/
3219 char*below = lu(args, "below");
3220 char* rstr = lu(args, "red");
3221 char* gstr = lu(args, "green");
3222 char* bstr = lu(args, "blue");
3223 char* astr = lu(args, "alpha");
3224 char* pinstr = lu(args, "pin");
3225 char* as = map_lookup(args, "as");
3226 char* blendmode = lu(args, "blend");
3227 char* filterstr = lu(args, "filter");
3238 { // (?) .rotate or .arcchange
3239 pivotstr = lu(args, "pivot");
3240 anglestr = lu(args, "angle");
3244 xstr = lu(args, "x");
3245 ystr = lu(args, "y");
3249 luminance = parseMulAdd(luminancestr);
3253 luminance.mul = 256;
3258 if(scalexstr[0]||scaleystr[0])
3259 syntaxerror("scalex/scaley and scale cannot both be set");
3260 scalexstr = scaleystr = scalestr;
3263 if(type == PT_PUT || type == PT_STARTCLIP) {
3265 character = lu(args, "character");
3266 parameters_clear(&p);
3267 } else if (type == PT_BUTTON) {
3268 character = lu(args, "name");
3269 parameters_clear(&p);
3272 s_getParameters(instance, &p);
3278 if(isRelative(xstr))
3280 if(type == PT_PUT || type == PT_STARTCLIP)
3281 syntaxerror("relative x values not allowed for initial put or startclip");
3282 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3286 p.x = parseTwip(xstr);
3292 if(isRelative(ystr))
3294 if(type == PT_PUT || type == PT_STARTCLIP)
3295 syntaxerror("relative y values not allowed for initial put or startclip");
3296 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3300 p.y = parseTwip(ystr);
3305 /* scale, scalex, scaley */
3307 oldbbox = s_getCharBBox(character);
3309 oldbbox = s_getInstanceBBox(instance);
3310 oldwidth = oldbbox.xmax - oldbbox.xmin;
3311 oldheight = oldbbox.ymax - oldbbox.ymin;
3318 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3319 set = set | SF_SCALEX;
3327 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3328 set = set | SF_SCALEY;
3334 if(isRelative(rotatestr))
3335 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3337 p.rotate = parseFloat(rotatestr);
3338 set = set | SF_ROTATE;
3344 if(isRelative(shearstr))
3345 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3347 p.shear = parseFloat(shearstr);
3348 set = set | SF_SHEAR;
3353 if(isPoint(pivotstr))
3354 p.pivot = parsePoint(pivotstr);
3356 p.pivot = getPoint(oldbbox, pivotstr);
3357 set = set | SF_PIVOT;
3363 p.pin = parsePoint(pinstr);
3365 p.pin = getPoint(oldbbox, pinstr);
3369 /* color transform */
3371 if(rstr[0] || luminancestr[0])
3375 r = parseMulAdd(rstr);
3378 r.add = p.cxform.r0;
3379 r.mul = p.cxform.r1;
3381 r = mergeMulAdd(r, luminance);
3382 p.cxform.r0 = r.mul;
3383 p.cxform.r1 = r.add;
3384 set = set | SF_CX_R;
3386 if(gstr[0] || luminancestr[0])
3390 g = parseMulAdd(gstr);
3393 g.add = p.cxform.g0;
3394 g.mul = p.cxform.g1;
3396 g = mergeMulAdd(g, luminance);
3397 p.cxform.g0 = g.mul;
3398 p.cxform.g1 = g.add;
3399 set = set | SF_CX_G;
3401 if(bstr[0] || luminancestr[0])
3405 b = parseMulAdd(bstr);
3408 b.add = p.cxform.b0;
3409 b.mul = p.cxform.b1;
3411 b = mergeMulAdd(b, luminance);
3412 p.cxform.b0 = b.mul;
3413 p.cxform.b1 = b.add;
3414 set = set | SF_CX_B;
3418 MULADD a = parseMulAdd(astr);
3419 p.cxform.a0 = a.mul;
3420 p.cxform.a1 = a.add;
3421 set = set | SF_CX_A;
3428 for(t = 0; blendModeNames[t]; t++)
3430 if(!strcmp(blendModeNames[t], blendmode))
3438 syntaxerror("unknown blend mode: '%s'", blendmode);
3440 p.blendmode = blend;
3441 set = set | SF_BLEND;
3446 p.filters = parseFilters(filterstr);
3447 set = set | SF_FILTER;
3450 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3451 warning("As of version 0.8.2 using the .change command to modify an \
3452 object's position on the stage is considered deprecated. Future \
3453 versions may consider x and y parameters for the .change command \
3454 to be illegal; please use the .move command.");
3456 if (change_sets_all)
3463 s_put(instance, character, p);
3467 char* interstr = lu(args, "interpolation");
3468 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3470 syntaxerror("unkown interpolation %s", interstr);
3471 s_change(instance, p, inter);
3476 char* interstr = lu(args, "interpolation");
3477 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3479 syntaxerror("unkown interpolation %s", interstr);
3480 s_schange(instance, p, inter);
3484 s_jump(instance, p);
3487 s_startclip(instance, character, p);
3491 s_buttonput(character, as, p);
3493 s_buttonput(character, "shape", p);
3499 static int c_put(map_t*args)
3501 c_placement(args, PT_PUT);
3504 static int c_change(map_t*args)
3506 if (currentframe == 0)
3507 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3508 c_placement(args, PT_CHANGE);
3511 static int c_schange(map_t*args)
3513 c_placement(args, PT_SCHANGE);
3516 static int c_move(map_t* args)
3518 c_movement(args, PT_MOVE);
3521 static int c_smove(map_t* args)
3523 c_movement(args, PT_SMOVE);
3526 static int c_sweep(map_t* args)
3528 c_movement(args, PT_SWEEP);
3531 static int c_arcchange(map_t*args)
3533 c_placement(args, 0);
3536 static int c_jump(map_t*args)
3538 c_placement(args, PT_JUMP);
3541 static int c_startclip(map_t*args)
3543 c_placement(args, PT_STARTCLIP);
3546 static int c_show(map_t*args)
3548 c_placement(args, PT_BUTTON);
3551 static int c_toggle(map_t* args)
3553 char*instance = lu(args, "name");
3554 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3555 char* alignstr = lu(args, "fixed_alignment");
3556 if (!strcmp(alignstr, "on"))
3557 flagsOn += IF_FIXED_ALIGNMENT;
3559 if (!strcmp(alignstr, "off"))
3560 flagsOff -= IF_FIXED_ALIGNMENT;
3562 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3563 s_toggle(instance, flagsOn, flagsOff);
3566 static int c_del(map_t*args)
3568 char*instance = lu(args, "name");
3569 s_delinstance(instance);
3572 static int c_end(map_t*args)
3577 static int c_sprite(map_t*args)
3579 char* name = lu(args, "name");
3580 char* scalinggrid = lu(args, "scalinggrid");
3582 if(scalinggrid && *scalinggrid) {
3583 SRECT r = parseBox(scalinggrid);
3590 static int c_frame(map_t*args)
3592 char*framestr = lu(args, "n");
3593 char*cutstr = lu(args, "cut");
3595 char*name = lu(args, "name");
3596 char*anchor = lu(args, "anchor");
3599 if(!strcmp(anchor, "anchor") && !*name)
3604 if(strcmp(cutstr, "no"))
3606 if(isRelative(framestr)) {
3607 frame = s_getframe();
3608 if(getSign(framestr)<0)
3609 syntaxerror("relative frame expressions must be positive");
3610 frame += parseInt(getOffset(framestr));
3613 frame = parseInt(framestr);
3614 if(s_getframe() >= frame
3615 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3616 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3618 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3621 static int c_primitive(map_t*args)
3623 char*name = lu(args, "name");
3624 char*command = lu(args, "commandname");
3625 int width=0, height=0, r=0;
3626 int linewidth = parseTwip(lu(args, "line"));
3627 char*colorstr = lu(args, "color");
3628 RGBA color = parseColor(colorstr);
3629 char*fillstr = lu(args, "fill");
3636 if(!strcmp(command, "circle"))
3638 else if(!strcmp(command, "filled"))
3642 width = parseTwip(lu(args, "width"));
3643 height = parseTwip(lu(args, "height"));
3644 } else if (type==1) {
3645 r = parseTwip(lu(args, "r"));
3646 } else if (type==2) {
3647 outline = lu(args, "outline");
3650 if(!strcmp(fillstr, "fill"))
3652 if(!strcmp(fillstr, "none"))
3654 if(width<0 || height<0 || linewidth<0 || r<0)
3655 syntaxerror("values width, height, line, r must be positive");
3657 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3658 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3659 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3663 static int c_textshape(map_t*args)
3665 char*name = lu(args, "name");
3666 char*text = lu(args, "text");
3667 char*font = lu(args, "font");
3668 float size = parsePxOrPercent(font, lu(args, "size"));
3670 s_textshape(name, font, size, text);
3674 static int c_swf(map_t*args)
3676 char*name = lu(args, "name");
3677 char*filename = lu(args, "filename");
3678 char*command = lu(args, "commandname");
3679 if(!strcmp(command, "shape"))
3680 warning("Please use .swf instead of .shape");
3681 s_includeswf(name, filename);
3685 static int c_font(map_t*args)
3687 char*name = lu(args, "name");
3688 char*filename = lu(args, "filename");
3689 s_font(name, filename);
3693 static int c_sound(map_t*args)
3695 char*name = lu(args, "name");
3696 char*filename = lu(args, "filename");
3697 s_sound(name, filename);
3701 static int c_text(map_t*args)
3703 char*name = lu(args, "name");
3704 char*text = lu(args, "text");
3705 char*font = lu(args, "font");
3706 float size = parsePxOrPercent(font, lu(args, "size"));
3707 RGBA color = parseColor(lu(args, "color"));
3708 s_text(name, font, text, (int)(size*100), color);
3712 static int c_soundtrack(map_t*args)
3717 static int c_quicktime(map_t*args)
3719 char*name = lu(args, "name");
3720 char*url = lu(args, "url");
3721 s_quicktime(name, url);
3725 static int c_image(map_t*args)
3727 char*command = lu(args, "commandname");
3728 char*name = lu(args, "name");
3729 char*filename = lu(args, "filename");
3730 if(!strcmp(command,"jpeg")) {
3731 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3732 s_image(name, "jpeg", filename, quality);
3734 s_image(name, "png", filename, 0);
3739 static int c_outline(map_t*args)
3741 char*name = lu(args, "name");
3742 char*format = lu(args, "format");
3746 syntaxerror("colon (:) expected");
3748 s_outline(name, format, text);
3752 int fakechar(map_t*args)
3754 char*name = lu(args, "name");
3755 s_box(name, 0, 0, black, 20, 0);
3759 static int c_egon(map_t*args) {return fakechar(args);}
3760 static int c_button(map_t*args) {
3761 char*name = lu(args, "name");
3765 static int current_button_flags = 0;
3766 static int c_on_press(map_t*args)
3768 char*position = lu(args, "position");
3770 if(!strcmp(position, "inside")) {
3771 current_button_flags |= BC_OVERUP_OVERDOWN;
3772 } else if(!strcmp(position, "outside")) {
3773 //current_button_flags |= BC_IDLE_OUTDOWN;
3774 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3775 } else if(!strcmp(position, "anywhere")) {
3776 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3779 if(type == RAWDATA) {
3781 s_buttonaction(current_button_flags, action);
3782 current_button_flags = 0;
3788 static int c_on_release(map_t*args)
3790 char*position = lu(args, "position");
3792 if(!strcmp(position, "inside")) {
3793 current_button_flags |= BC_OVERDOWN_OVERUP;
3794 } else if(!strcmp(position, "outside")) {
3795 current_button_flags |= BC_OUTDOWN_IDLE;
3796 } else if(!strcmp(position, "anywhere")) {
3797 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3800 if(type == RAWDATA) {
3802 s_buttonaction(current_button_flags, action);
3803 current_button_flags = 0;
3809 static int c_on_move_in(map_t*args)
3811 char*position = lu(args, "state");
3813 if(!strcmp(position, "pressed")) {
3814 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3815 } else if(!strcmp(position, "not_pressed")) {
3816 current_button_flags |= BC_IDLE_OVERUP;
3817 } else if(!strcmp(position, "any")) {
3818 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3821 if(type == RAWDATA) {
3823 s_buttonaction(current_button_flags, action);
3824 current_button_flags = 0;
3830 static int c_on_move_out(map_t*args)
3832 char*position = lu(args, "state");
3834 if(!strcmp(position, "pressed")) {
3835 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3836 } else if(!strcmp(position, "not_pressed")) {
3837 current_button_flags |= BC_OVERUP_IDLE;
3838 } else if(!strcmp(position, "any")) {
3839 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3842 if(type == RAWDATA) {
3844 s_buttonaction(current_button_flags, action);
3845 current_button_flags = 0;
3851 static int c_on_key(map_t*args)
3853 char*key = lu(args, "key");
3855 if(strlen(key)==1) {
3858 current_button_flags |= 0x4000 + (key[0]*0x200);
3860 syntaxerror("invalid character: %c"+key[0]);
3865 <ctrl-x> = 0x200*(x-'a')
3869 syntaxerror("invalid key: %s",key);
3872 if(type == RAWDATA) {
3874 s_buttonaction(current_button_flags, action);
3875 current_button_flags = 0;
3882 static int c_edittext(map_t*args)
3884 //"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"},
3885 char*name = lu(args, "name");
3886 char*font = lu(args, "font");
3887 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3888 int width = parseTwip(lu(args, "width"));
3889 int height = parseTwip(lu(args, "height"));
3890 char*text = lu(args, "text");
3891 RGBA color = parseColor(lu(args, "color"));
3892 int maxlength = parseInt(lu(args, "maxlength"));
3893 char*variable = lu(args, "variable");
3894 char*passwordstr = lu(args, "password");
3895 char*wordwrapstr = lu(args, "wordwrap");
3896 char*multilinestr = lu(args, "multiline");
3897 char*htmlstr = lu(args, "html");
3898 char*noselectstr = lu(args, "noselect");
3899 char*readonlystr = lu(args, "readonly");
3900 char*borderstr = lu(args, "border");
3901 char*autosizestr = lu(args, "autosize");
3902 char*alignstr = lu(args, "align");
3906 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3907 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3908 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3909 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3910 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3911 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3912 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3913 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3914 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3915 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3916 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3917 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3918 else syntaxerror("Unknown alignment: %s", alignstr);
3920 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3924 static int c_morphshape(map_t*args) {return fakechar(args);}
3925 static int c_movie(map_t*args) {return fakechar(args);}
3927 static char* readfile(const char*filename)
3929 FILE*fi = fopen(filename, "rb");
3933 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3934 fseek(fi, 0, SEEK_END);
3936 fseek(fi, 0, SEEK_SET);
3937 text = rfx_alloc(l+1);
3938 fread(text, l, 1, fi);
3944 static int c_action(map_t*args)
3946 char* filename = map_lookup(args, "filename");
3947 if(!filename ||!*filename) {
3949 if(type != RAWDATA) {
3950 syntaxerror("colon (:) expected");
3954 s_action(readfile(filename));
3960 static int c_initaction(map_t*args)
3962 char* character = lu(args, "name");
3963 char* filename = map_lookup(args, "filename");
3964 if(!filename ||!*filename) {
3966 if(type != RAWDATA) {
3967 syntaxerror("colon (:) expected");
3969 s_initaction(character, text);
3971 s_initaction(character, readfile(filename));
3979 command_func_t* func;
3982 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
3983 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3984 // "import" type stuff
3985 {"swf", c_swf, "name filename"},
3986 {"shape", c_swf, "name filename"},
3987 {"jpeg", c_image, "name filename quality=80%"},
3988 {"png", c_image, "name filename"},
3989 {"movie", c_movie, "name filename"},
3990 {"sound", c_sound, "name filename"},
3991 {"font", c_font, "name filename glyphs="},
3992 {"soundtrack", c_soundtrack, "filename"},
3993 {"quicktime", c_quicktime, "url"},
3995 // generators of primitives
3997 {"define", c_define, "name value=0"},
3998 {"point", c_point, "name x=0 y=0"},
3999 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4000 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4001 {"outline", c_outline, "name format=simple"},
4002 {"textshape", c_textshape, "name font size=100% text"},
4005 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4006 {"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"},
4007 {"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"},
4008 {"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"},
4010 // character generators
4011 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4012 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4013 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4015 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4016 {"text", c_text, "name text font size=100% color=white"},
4017 {"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="},
4018 {"morphshape", c_morphshape, "name start end"},
4019 {"button", c_button, "name"},
4020 {"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="},
4021 {"on_press", c_on_press, "position=inside"},
4022 {"on_release", c_on_release, "position=anywhere"},
4023 {"on_move_in", c_on_move_in, "state=not_pressed"},
4024 {"on_move_out", c_on_move_out, "state=not_pressed"},
4025 {"on_key", c_on_key, "key=any"},
4028 {"play", c_play, "name loop=0 @nomultiple=0"},
4029 {"stop", c_stop, "name= "},
4030 {"nextframe", c_nextframe, "name"},
4031 {"previousframe", c_previousframe, "name"},
4033 // object placement tags
4034 {"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="},
4035 {"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="},
4036 {"move", c_move, "name x= y= interpolation=linear"},
4037 {"smove", c_smove, "name x= y= interpolation=linear"},
4038 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4039 {"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"},
4040 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4041 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4042 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4043 {"del", c_del, "name"},
4044 // virtual object placement
4045 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4047 {"toggle", c_toggle, "name fixed_alignment="},
4049 // commands which start a block
4050 //startclip (see above)
4051 {"sprite", c_sprite, "name scalinggrid="},
4052 {"action", c_action, "filename="},
4053 {"initaction", c_initaction, "name filename="},
4059 static map_t parseArguments(char*command, char*pattern)
4075 string_set(&t1, "commandname");
4076 string_set(&t2, command);
4077 map_put(&result, t1, t2);
4079 if(!pattern || !*pattern)
4086 if(!strncmp("<i> ", x, 3)) {
4088 if(type == COMMAND || type == RAWDATA) {
4090 syntaxerror("character name expected");
4092 name[pos].str = "instance";
4094 value[pos].str = text;
4095 value[pos].len = strlen(text);
4099 if(type == ASSIGNMENT)
4102 name[pos].str = "character";
4104 value[pos].str = text;
4105 value[pos].len = strlen(text);
4113 isboolean[pos] = (x[0] =='@');
4126 name[pos].len = d-x;
4131 name[pos].len = e-x;
4132 value[pos].str = e+1;
4133 value[pos].len = d-e-1;
4141 /* for(t=0;t<len;t++) {
4142 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4143 isboolean[t]?"(boolean)":"");
4148 if(type == RAWDATA || type == COMMAND) {
4153 // first, search for boolean arguments
4154 for(pos=0;pos<len;pos++)
4156 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4158 if(type == ASSIGNMENT)
4160 value[pos].str = text;
4161 value[pos].len = strlen(text);
4162 /*printf("setting boolean parameter %s (to %s)\n",
4163 strdup_n(name[pos], namelen[pos]),
4164 strdup_n(value[pos], valuelen[pos]));*/
4169 // second, search for normal arguments
4171 for(pos=0;pos<len;pos++)
4173 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4174 (type != ASSIGNMENT && !set[pos])) {
4176 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4178 if(type == ASSIGNMENT)
4181 value[pos].str = text;
4182 value[pos].len = strlen(text);
4184 printf("setting parameter %s (to %s)\n",
4185 strdup_n(name[pos].str, name[pos].len),
4186 strdup_n(value[pos].str, value[pos].len));
4192 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4196 for(t=0;t<len;t++) {
4197 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4200 for(t=0;t<len;t++) {
4201 if(value[t].str && value[t].str[0] == '*') {
4202 //relative default- take value from some other parameter
4204 for(s=0;s<len;s++) {
4205 if(value[s].len == value[t].len-1 &&
4206 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4207 value[t].str = value[s].str;
4210 if(value[t].str == 0) {
4212 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4216 /* ok, now construct the dictionary from the parameters */
4220 map_put(&result, name[t], value[t]);
4224 static void parseArgumentsForCommand(char*command)
4229 msg("<verbose> parse Command: %s (line %d)", command, line);
4231 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4232 if(!strcmp(arguments[t].command, command)) {
4234 /* ugly hack- will be removed soon (once documentation and .sc generating
4235 utilities have been changed) */
4236 if(!strcmp(command, "swf") && !stackpos) {
4237 warning("Please use .flash instead of .swf- this will be mandatory soon");
4242 args = parseArguments(command, arguments[t].arguments);
4248 syntaxerror("command %s not known", command);
4250 // catch missing .flash directives at the beginning of a file
4251 if(strcmp(command, "flash") && !stackpos)
4253 syntaxerror("No movie defined- use .flash first");
4257 printf(".%s\n", command);fflush(stdout);
4258 map_dump(&args, stdout, "\t");fflush(stdout);
4261 (*arguments[nr].func)(&args);
4263 /*if(!strcmp(command, "button") ||
4264 !strcmp(command, "action")) {
4267 if(type == COMMAND) {
4268 if(!strcmp(text, "end"))
4283 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4284 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4285 * No syntax checking is done */
4286 static void analyseArgumentsForCommand(char*command)
4292 U8* glyphs_to_include;
4293 msg("<verbose> analyse Command: %s (line %d)", command, line);
4295 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4297 if(!strcmp(arguments[t].command, command))
4299 args = parseArguments(command, arguments[t].arguments);
4305 printf(".%s\n", command);fflush(stdout);
4306 map_dump(&args, stdout, "\t");fflush(stdout);
4308 char* name = lu(&args, "name");
4309 if (!strcmp(command, "font"))
4311 if(dictionary_lookup(&fonts, name))
4312 syntaxerror("font %s defined twice", name);
4315 fontfile = lu(&args, "filename");
4316 font = swf_LoadFont(fontfile);
4318 warning("Couldn't open font file \"%s\"", fontfile);
4319 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4320 memset(font, 0, sizeof(SWFFONT));
4324 swf_FontPrepareForEditText(font);
4325 glyphs_to_include = lu(&args, "glyphs");
4326 if (!strcmp(glyphs_to_include, "all"))
4328 swf_FontUseAll(font);
4329 font->use->glyphs_specified = 1;
4333 if (strcmp (glyphs_to_include, ""))
4335 swf_FontUseUTF8(font, glyphs_to_include);
4336 font->use->glyphs_specified = 1;
4339 swf_FontInitUsage(font);
4342 dictionary_put2(&fonts, name, font);
4346 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
4348 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4350 if (font->use && !font->use->glyphs_specified)
4352 if (!strcmp(command, "edittext"))
4354 swf_FontUseAll(font);
4355 font->use->glyphs_specified = 1;
4358 swf_FontUseUTF8(font, lu(&args, "text"));
4365 void skipParameters()
4369 while (type != COMMAND);
4373 void findFontUsage()
4375 char* fontRelated = "font;text;textshape;edittext;";
4376 while(!noMoreTokens())
4380 syntaxerror("command expected");
4381 if (strstr(fontRelated, text))
4382 analyseArgumentsForCommand(text);
4384 if(strcmp(text, "end"))
4393 dictionary_init(&fonts);
4394 cleanUp = &freeFontDictionary;
4398 int main (int argc,char ** argv)
4401 processargs(argc, argv);
4402 initLog(0,-1,0,0,-1,verbose);
4405 args_callback_usage(argv[0]);
4409 file = generateTokens(filename);
4411 fprintf(stderr, "parser returned error.\n");
4418 while(!noMoreTokens()) {
4421 syntaxerror("command expected");
4422 parseArgumentsForCommand(text);