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"
42 static char * filename = 0;
43 static char * outputname = "output.swf";
44 static int verbose = 2;
45 static int optimize = 0;
46 static int override_outputname = 0;
47 static int do_cgi = 0;
49 static struct options_t options[] = {
58 int args_callback_option(char*name,char*val)
60 if(!strcmp(name, "V")) {
61 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
64 else if(!strcmp(name, "o")) {
66 override_outputname = 1;
69 else if(!strcmp(name, "O")) {
73 else if(!strcmp(name, "C")) {
77 else if(!strcmp(name, "v")) {
82 printf("Unknown option: -%s\n", name);
87 int args_callback_longoption(char*name,char*val)
89 return args_long2shortoption(options, name, val);
91 void args_callback_usage(char *name)
94 printf("Usage: %s [-o file.swf] file.sc\n", name);
96 printf("-h , --help Print short help message and exit\n");
97 printf("-V , --version Print version info and exit\n");
98 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
99 printf("-v , --verbose Increase verbosity. \n");
100 printf("-o , --output <filename> Set output file to <filename>.\n");
103 int args_callback_command(char*name,char*val)
106 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
113 static struct token_t* file;
122 static void syntaxerror(char*format, ...)
126 va_start(arglist, format);
127 vsprintf(buf, format, arglist);
129 fprintf(stderr, "\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
133 static void warning(char*format, ...)
137 va_start(arglist, format);
138 vsprintf(buf, format, arglist);
140 fprintf(stderr, "\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
143 static void readToken()
145 type = file[pos].type;
147 syntaxerror("unexpected end of file");
149 text = file[pos].text;
150 textlen = strlen(text);
151 line = file[pos].line;
152 column = file[pos].column;
154 //printf("---> %d(%s) %s\n", type, type_names[type], text);
157 static void pushBack()
160 if(!pos) syntaxerror("internal error 3");
165 textlen = strlen(text);
168 column = file[p].column;
171 static int noMoreTokens()
173 if(file[pos].type == END)
178 // ------------------------------ swf routines ----------------------------
182 int type; //0=swf, 1=sprite, 2=clip, 3=button
188 /* for sprites (1): */
194 dictionary_t oldinstances;
199 static int stackpos = 0;
201 static dictionary_t characters;
202 static dictionary_t images;
203 static dictionary_t textures;
204 static dictionary_t outlines;
205 static dictionary_t gradients;
206 static dictionary_t filters;
207 static char idmap[65536];
208 static TAG*tag = 0; //current tag
210 static int id; //current character id
211 static int currentframe; //current frame in current level
212 static SRECT currentrect; //current bounding box in current level
213 static U16 currentdepth;
214 static dictionary_t instances;
215 static dictionary_t fonts;
216 static dictionary_t sounds;
218 typedef struct _parameters {
220 float scalex, scaley;
226 U8 blendmode; //not interpolated
230 typedef struct _character {
236 typedef struct _instance {
237 character_t*character;
239 parameters_t parameters;
240 TAG* lastTag; //last tag which set the object
241 U16 lastFrame; //frame lastTag is in
244 typedef struct _outline {
249 typedef struct _gradient {
255 typedef struct _filter {
259 typedef struct _texture {
263 static void character_init(character_t*c)
265 memset(c, 0, sizeof(character_t));
267 static character_t* character_new()
270 c = (character_t*)malloc(sizeof(character_t));
274 static void instance_init(instance_t*i)
276 memset(i, 0, sizeof(instance_t));
278 static instance_t* instance_new()
281 c = (instance_t*)malloc(sizeof(instance_t));
286 static void incrementid()
290 syntaxerror("Out of character ids.");
295 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
297 character_t* c = character_new();
299 c->definingTag = ctag;
302 if(dictionary_lookup(&characters, name))
303 syntaxerror("character %s defined twice", name);
304 dictionary_put2(&characters, name, c);
306 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
308 swf_SetString(tag, name);
309 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
312 swf_SetString(tag, name);
314 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
316 character_t* c = character_new();
317 c->definingTag = ctag;
321 if(dictionary_lookup(&images, name))
322 syntaxerror("image %s defined twice", name);
323 dictionary_put2(&images, name, c);
325 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
327 instance_t* i = instance_new();
330 //swf_GetMatrix(0, &i->matrix);
331 if(dictionary_lookup(&instances, name))
332 syntaxerror("object %s defined twice", name);
333 dictionary_put2(&instances, name, i);
337 static void parameters_clear(parameters_t*p)
340 p->scalex = 1.0; p->scaley = 1.0;
343 p->pivot.x = 0; p->pivot.y = 0;
348 swf_GetCXForm(0, &p->cxform, 1);
351 static void makeMatrix(MATRIX*m, parameters_t*p)
360 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
361 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
362 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
363 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
365 m->sx = (int)(sx*65536+0.5);
366 m->r1 = (int)(r1*65536+0.5);
367 m->r0 = (int)(r0*65536+0.5);
368 m->sy = (int)(sy*65536+0.5);
372 h = swf_TurnPoint(p->pin, m);
377 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
382 r = swf_TurnRect(rect, &m);
383 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
384 currentrect.xmax == 0 && currentrect.ymax == 0)
387 swf_ExpandRect2(¤trect, &r);
391 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
393 SWF*swf = (SWF*)malloc(sizeof(SWF));
396 syntaxerror(".swf blocks can't be nested");
398 memset(swf, 0, sizeof(swf));
399 swf->fileVersion = version;
401 swf->frameRate = fps;
402 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
403 swf->compressed = compress;
404 swf_SetRGB(tag,&background);
406 if(stackpos==sizeof(stack)/sizeof(stack[0]))
407 syntaxerror("too many levels of recursion");
409 dictionary_init(&characters);
410 dictionary_init(&images);
411 dictionary_init(&textures);
412 dictionary_init(&outlines);
413 dictionary_init(&gradients);
414 dictionary_init(&filters);
415 dictionary_init(&instances);
416 dictionary_init(&fonts);
417 dictionary_init(&sounds);
419 memset(&stack[stackpos], 0, sizeof(stack[0]));
420 stack[stackpos].type = 0;
421 stack[stackpos].filename = strdup(name);
422 stack[stackpos].swf = swf;
423 stack[stackpos].oldframe = -1;
428 memset(¤trect, 0, sizeof(currentrect));
431 memset(idmap, 0, sizeof(idmap));
435 void s_sprite(char*name)
437 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
438 swf_SetU16(tag, id); //id
439 swf_SetU16(tag, 0); //frames
441 memset(&stack[stackpos], 0, sizeof(stack[0]));
442 stack[stackpos].type = 1;
443 stack[stackpos].oldframe = currentframe;
444 stack[stackpos].olddepth = currentdepth;
445 stack[stackpos].oldrect = currentrect;
446 stack[stackpos].oldinstances = instances;
447 stack[stackpos].tag = tag;
448 stack[stackpos].id = id;
449 stack[stackpos].name = strdup(name);
451 /* FIXME: those four fields should be bundled together */
452 dictionary_init(&instances);
455 memset(¤trect, 0, sizeof(currentrect));
461 typedef struct _buttonrecord
469 typedef struct _button
473 buttonrecord_t records[4];
476 static button_t mybutton;
478 void s_button(char*name)
480 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
481 swf_SetU16(tag, id); //id
482 swf_ButtonSetFlags(tag, 0); //menu=no
484 memset(&mybutton, 0, sizeof(mybutton));
486 memset(&stack[stackpos], 0, sizeof(stack[0]));
487 stack[stackpos].type = 3;
488 stack[stackpos].tag = tag;
489 stack[stackpos].id = id;
490 stack[stackpos].name = strdup(name);
491 stack[stackpos].oldrect = currentrect;
492 memset(¤trect, 0, sizeof(currentrect));
497 void s_buttonput(char*character, char*as, parameters_t p)
499 character_t* c = dictionary_lookup(&characters, character);
504 if(!stackpos || (stack[stackpos-1].type != 3)) {
505 syntaxerror(".show may only appear in .button");
508 syntaxerror("character %s not known (in .shape %s)", character, character);
510 if(mybutton.endofshapes) {
511 syntaxerror("a .do may not precede a .show", character, character);
514 m = s_instancepos(c->size, &p);
522 if(*s==',' || *s==0) {
523 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
524 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
525 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
526 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
527 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
528 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
535 static void setbuttonrecords(TAG*tag)
537 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
538 if(!mybutton.endofshapes) {
541 if(!mybutton.records[3].set) {
542 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
546 if(mybutton.records[t].set) {
547 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
550 swf_SetU8(tag,0); // end of button records
551 mybutton.endofshapes = 1;
555 void s_buttonaction(int flags, char*action)
561 setbuttonrecords(stack[stackpos-1].tag);
563 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
565 syntaxerror("Couldn't compile ActionScript");
568 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
569 swf_ActionSet(stack[stackpos-1].tag, a);
570 mybutton.nr_actions++;
575 static void setactionend(TAG*tag)
577 if(!mybutton.nr_actions) {
578 /* no actions means we didn't have an actionoffset,
579 which means we can't signal the end of the
580 buttonaction records, so, *sigh*, we have
581 to insert a dummy record */
582 swf_SetU16(tag, 0); //offset
583 swf_SetU16(tag, 0); //condition
584 swf_SetU8(tag, 0); //action
588 static void s_endButton()
591 setbuttonrecords(stack[stackpos-1].tag);
592 setactionend(stack[stackpos-1].tag);
595 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
599 tag = stack[stackpos].tag;
600 currentrect = stack[stackpos].oldrect;
602 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
603 free(stack[stackpos].name);
606 TAG* removeFromTo(TAG*from, TAG*to)
608 TAG*save = from->prev;
610 TAG*next = from->next;
618 static void s_endSprite()
620 SRECT r = currentrect;
622 if(stack[stackpos].cut)
623 tag = removeFromTo(stack[stackpos].cut, tag);
627 /* TODO: before clearing, prepend "<spritename>." to names and
628 copy into old instances dict */
629 dictionary_clear(&instances);
631 currentframe = stack[stackpos].oldframe;
632 currentrect = stack[stackpos].oldrect;
633 currentdepth = stack[stackpos].olddepth;
634 instances = stack[stackpos].oldinstances;
636 tag = swf_InsertTag(tag, ST_SHOWFRAME);
637 tag = swf_InsertTag(tag, ST_END);
639 tag = stack[stackpos].tag;
642 syntaxerror("internal error(7)");
644 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
645 free(stack[stackpos].name);
648 static void s_endSWF()
654 if(stack[stackpos].cut)
655 tag = removeFromTo(stack[stackpos].cut, tag);
659 swf = stack[stackpos].swf;
660 filename = stack[stackpos].filename;
662 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
663 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
664 tag = swf_InsertTag(tag, ST_SHOWFRAME);
666 tag = swf_InsertTag(tag, ST_END);
668 swf_OptimizeTagOrder(swf);
674 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
675 swf->movieSize = currentrect; /* "autocrop" */
678 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
679 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
680 swf->movieSize.ymax += 20;
681 warning("Empty bounding box for movie");
684 if(do_cgi || !strcmp(filename, "-"))
687 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
689 syntaxerror("couldn't create output file %s", filename);
692 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
693 else if(swf->compressed)
694 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
696 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
700 dictionary_clear(&instances);
701 dictionary_clear(&characters);
702 dictionary_clear(&images);
703 dictionary_clear(&textures);
704 dictionary_clear(&outlines);
705 dictionary_clear(&gradients); // mem leak
706 dictionary_clear(&filters);
707 dictionary_clear(&fonts);
708 dictionary_clear(&sounds);
718 if(stack[stackpos-1].type == 0)
719 syntaxerror("End of file encountered in .flash block");
720 if(stack[stackpos-1].type == 1)
721 syntaxerror("End of file encountered in .sprite block");
722 if(stack[stackpos-1].type == 2)
723 syntaxerror("End of file encountered in .clip block");
729 return currentframe+1;
732 void s_frame(int nr, int cut, char*name, char anchor)
738 syntaxerror("Illegal frame number");
739 nr--; // internally, frame 1 is frame 0
741 for(t=currentframe;t<nr;t++) {
742 tag = swf_InsertTag(tag, ST_SHOWFRAME);
743 if(t==nr-1 && name && *name) {
744 tag = swf_InsertTag(tag, ST_FRAMELABEL);
745 swf_SetString(tag, name);
747 swf_SetU8(tag, 1); //make this an anchor
750 if(nr == 0 && currentframe == 0 && name && *name) {
751 tag = swf_InsertTag(tag, ST_FRAMELABEL);
752 swf_SetString(tag, name);
754 swf_SetU8(tag, 1); //make this an anchor
759 syntaxerror("Can't cut, frame empty");
761 stack[stackpos].cut = tag;
767 int parseColor2(char*str, RGBA*color);
769 int addFillStyle(SHAPE*s, SRECT*r, char*name)
776 parseColor2(name, &color);
777 return swf_ShapeAddSolidFillStyle(s, &color);
778 } else if ((texture = dictionary_lookup(&textures, name))) {
779 return swf_ShapeAddFillStyle2(s, &texture->fs);
780 } else if((image = dictionary_lookup(&images, name))) {
782 swf_GetMatrix(0, &m);
783 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
784 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
787 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
788 } else if ((gradient = dictionary_lookup(&gradients, name))) {
792 swf_GetMatrix(0, &rot);
793 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
794 csin = sin(-gradient->rotate*2*3.14159265358979/360);
796 rot.r1 = -csin*65536;
799 r2 = swf_TurnRect(*r, &rot);
800 swf_GetMatrix(0, &m);
801 m.sx = (r2.xmax - r2.xmin)*2*ccos;
802 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
803 m.r0 = (r2.ymax - r2.ymin)*2*csin;
804 m.sy = (r2.ymax - r2.ymin)*2*ccos;
805 m.tx = r->xmin + (r->xmax - r->xmin)/2;
806 m.ty = r->ymin + (r->ymax - r->ymin)/2;
807 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
808 } else if (parseColor2(name, &color)) {
809 return swf_ShapeAddSolidFillStyle(s, &color);
811 syntaxerror("not a color/fillstyle: %s", name);
816 RGBA black={r:0,g:0,b:0,a:0};
817 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
826 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
829 linewidth = linewidth>=20?linewidth-20:0;
830 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
833 fs1 = addFillStyle(s, &r2, texture);
836 r.xmin = r2.xmin-linewidth/2;
837 r.ymin = r2.ymin-linewidth/2;
838 r.xmax = r2.xmax+linewidth/2;
839 r.ymax = r2.ymax+linewidth/2;
841 swf_SetShapeHeader(tag,s);
842 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
843 swf_ShapeSetLine(tag,s,width,0);
844 swf_ShapeSetLine(tag,s,0,height);
845 swf_ShapeSetLine(tag,s,-width,0);
846 swf_ShapeSetLine(tag,s,0,-height);
847 swf_ShapeSetEnd(tag);
850 s_addcharacter(name, id, tag, r);
854 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
860 outline = dictionary_lookup(&outlines, outlinename);
862 syntaxerror("outline %s not defined", outlinename);
866 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
869 linewidth = linewidth>=20?linewidth-20:0;
870 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
873 fs1 = addFillStyle(s, &r2, texture);
876 rect.xmin = r2.xmin-linewidth/2;
877 rect.ymin = r2.ymin-linewidth/2;
878 rect.xmax = r2.xmax+linewidth/2;
879 rect.ymax = r2.ymax+linewidth/2;
881 swf_SetRect(tag,&rect);
882 swf_SetShapeStyles(tag, s);
883 swf_ShapeCountBits(s,0,0);
884 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
885 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
886 swf_SetShapeBits(tag, s);
887 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
890 s_addcharacter(name, id, tag, rect);
894 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
899 r2.xmin = r2.ymin = 0;
903 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
906 linewidth = linewidth>=20?linewidth-20:0;
907 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
910 fs1 = addFillStyle(s, &r2, texture);
912 rect.xmin = r2.xmin-linewidth/2;
913 rect.ymin = r2.ymin-linewidth/2;
914 rect.xmax = r2.xmax+linewidth/2;
915 rect.ymax = r2.ymax+linewidth/2;
917 swf_SetRect(tag,&rect);
918 swf_SetShapeHeader(tag,s);
919 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
920 swf_ShapeSetCircle(tag, s, r,r,r,r);
921 swf_ShapeSetEnd(tag);
924 s_addcharacter(name, id, tag, rect);
928 void s_textshape(char*name, char*fontname, float size, char*_text)
931 U8*text = (U8*)_text;
935 font = dictionary_lookup(&fonts, fontname);
937 syntaxerror("font \"%s\" not known!", fontname);
939 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
940 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
941 s_box(name, 0, 0, black, 20, 0);
944 g = font->ascii2glyph[text[0]];
946 outline = malloc(sizeof(outline_t));
947 memset(outline, 0, sizeof(outline_t));
948 outline->shape = font->glyph[g].shape;
949 outline->bbox = font->layout->bounds[g];
953 swf_Shape11DrawerInit(&draw, 0);
954 swf_DrawText(&draw, font, (int)(size*100), _text);
956 outline->shape = swf_ShapeDrawerToShape(&draw);
957 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
961 if(dictionary_lookup(&outlines, name))
962 syntaxerror("outline %s defined twice", name);
963 dictionary_put2(&outlines, name, outline);
966 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
971 font = dictionary_lookup(&fonts, fontname);
973 syntaxerror("font \"%s\" not known!", fontname);
975 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
977 if(!font->numchars) {
978 s_box(name, 0, 0, black, 20, 0);
981 r = swf_SetDefineText(tag, font, &color, text, size);
983 if(stack[0].swf->fileVersion >= 8) {
984 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
986 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
987 swf_SetU32(tag, 0);//thickness
988 swf_SetU32(tag, 0);//sharpness
989 swf_SetU8(tag, 0);//reserved
992 s_addcharacter(name, id, tag, r);
996 void s_quicktime(char*name, char*url)
1001 memset(&r, 0, sizeof(r));
1003 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1004 swf_SetU16(tag, id);
1005 swf_SetString(tag, url);
1007 s_addcharacter(name, id, tag, r);
1011 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)
1014 EditTextLayout layout;
1017 if(fontname && *fontname) {
1018 flags |= ET_USEOUTLINES;
1019 font = dictionary_lookup(&fonts, fontname);
1021 syntaxerror("font \"%s\" not known!", fontname);
1023 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1024 swf_SetU16(tag, id);
1025 layout.align = align;
1026 layout.leftmargin = 0;
1027 layout.rightmargin = 0;
1035 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1037 s_addcharacter(name, id, tag, r);
1041 /* type: either "jpeg" or "png"
1043 void s_image(char*name, char*type, char*filename, int quality)
1045 /* an image is actually two folded: 1st bitmap, 2nd character.
1046 Both of them can be used separately */
1048 /* step 1: the bitmap */
1052 if(!strcmp(type,"jpeg")) {
1053 #ifndef HAVE_JPEGLIB
1054 warning("no jpeg support compiled in");
1055 s_box(name, 0, 0, black, 20, 0);
1058 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1059 swf_SetU16(tag, imageID);
1061 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1062 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1065 swf_GetJPEGSize(filename, &width, &height);
1072 s_addimage(name, id, tag, r);
1075 } else if(!strcmp(type,"png")) {
1077 swf_SetU16(tag, imageID);
1079 getPNG(filename, &width, &height, (unsigned char**)&data);
1082 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1085 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1086 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1087 swf_SetU16(tag, imageID);
1088 swf_SetLosslessImage(tag, data, width, height);
1094 s_addimage(name, id, tag, r);
1097 warning("image type \"%s\" not supported yet!", type);
1098 s_box(name, 0, 0, black, 20, 0);
1102 /* step 2: the character */
1103 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1104 swf_SetU16(tag, id);
1105 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1107 s_addcharacter(name, id, tag, r);
1111 void s_getBitmapSize(char*name, int*width, int*height)
1113 character_t* image = dictionary_lookup(&images, name);
1114 gradient_t* gradient = dictionary_lookup(&gradients,name);
1116 *width = image->size.xmax;
1117 *height = image->size.ymax;
1121 /* internal SWF gradient size */
1122 if(gradient->radial) {
1131 syntaxerror("No such bitmap/gradient: %s", name);
1134 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1136 gradient_t* gradient = dictionary_lookup(&gradients, object);
1137 character_t* bitmap = dictionary_lookup(&images, object);
1138 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1140 FILLSTYLE*fs = &texture->fs;
1142 memset(&p, 0, sizeof(parameters_t));
1145 fs->type = FILL_TILED;
1146 fs->id_bitmap = bitmap->id;
1147 } else if(gradient) {
1148 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1149 fs->gradient = gradient->gradient;
1151 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1152 makeMatrix(&fs->m, &p);
1153 if(gradient && !gradient->radial) {
1160 p2 = swf_TurnPoint(p1, &m);
1170 if(dictionary_lookup(&textures, name))
1171 syntaxerror("texture %s defined twice", name);
1172 dictionary_put2(&textures, name, texture);
1175 void dumpSWF(SWF*swf)
1177 TAG* tag = swf->firstTag;
1178 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1180 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1183 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1186 void s_font(char*name, char*filename)
1189 font = swf_LoadFont(filename);
1192 warning("Couldn't open font file \"%s\"", filename);
1193 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1194 memset(font, 0, sizeof(SWFFONT));
1195 dictionary_put2(&fonts, name, font);
1201 /* fix the layout. Only needed for old fonts */
1203 for(t=0;t<font->numchars;t++) {
1204 font->glyph[t].advance = 0;
1207 swf_FontCreateLayout(font);
1209 /* just in case this thing is used in .edittext later on */
1210 swf_FontPrepareForEditText(font);
1213 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1214 swf_FontSetDefine2(tag, font);
1215 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1217 swf_SetU16(tag, id);
1218 swf_SetString(tag, name);
1221 if(dictionary_lookup(&fonts, name))
1222 syntaxerror("font %s defined twice", name);
1223 dictionary_put2(&fonts, name, font);
1228 typedef struct _sound_t
1234 void s_sound(char*name, char*filename)
1236 struct WAV wav, wav2;
1240 unsigned numsamples;
1241 unsigned blocksize = 1152;
1244 if(wav_read(&wav, filename)) {
1246 wav_convert2mono(&wav, &wav2, 44100);
1247 samples = (U16*)wav2.data;
1248 numsamples = wav2.size/2;
1250 #ifdef WORDS_BIGENDIAN
1252 for(t=0;t<numsamples;t++) {
1253 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1256 } else if(mp3_read(&mp3, filename)) {
1257 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1263 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1268 if(numsamples%blocksize != 0)
1270 // apply padding, so that block is a multiple of blocksize
1271 int numblocks = (numsamples+blocksize-1)/blocksize;
1274 numsamples2 = numblocks * blocksize;
1275 samples2 = malloc(sizeof(U16)*numsamples2);
1276 memcpy(samples2, samples, numsamples*sizeof(U16));
1277 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1278 numsamples = numsamples2;
1282 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1283 swf_SetU16(tag, id); //id
1286 swf_SetSoundDefineMP3(
1287 tag, mp3.data, mp3.size,
1295 swf_SetSoundDefine(tag, samples, numsamples);
1298 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1299 swf_SetU16(tag, id);
1300 swf_SetString(tag, name);
1301 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1303 swf_SetU16(tag, id);
1304 swf_SetString(tag, name);
1306 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1310 if(dictionary_lookup(&sounds, name))
1311 syntaxerror("sound %s defined twice", name);
1312 dictionary_put2(&sounds, name, sound);
1320 static char* gradient_getToken(const char**p)
1324 while(**p && strchr(" \t\n\r", **p)) {
1328 while(**p && !strchr(" \t\n\r", **p)) {
1331 result = malloc((*p)-start+1);
1332 memcpy(result,start,(*p)-start+1);
1333 result[(*p)-start] = 0;
1337 float parsePercent(char*str);
1338 RGBA parseColor(char*str);
1340 GRADIENT parseGradient(const char*str)
1344 const char* p = str;
1345 memset(&gradient, 0, sizeof(GRADIENT));
1346 gradient.ratios = rfx_calloc(16*sizeof(U8));
1347 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1349 char*posstr,*colorstr;
1352 posstr = gradient_getToken(&p);
1355 pos = (int)(parsePercent(posstr)*255.0);
1358 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1359 colorstr = gradient_getToken(&p);
1360 color = parseColor(colorstr);
1361 if(gradient.num == 16) {
1362 warning("gradient record too big- max size is 16, rest ignored");
1365 gradient.ratios[gradient.num] = pos;
1366 gradient.rgba[gradient.num] = color;
1375 void s_gradient(char*name, const char*text, int radial, int rotate)
1377 gradient_t* gradient;
1378 gradient = malloc(sizeof(gradient_t));
1379 memset(gradient, 0, sizeof(gradient_t));
1380 gradient->gradient = parseGradient(text);
1381 gradient->radial = radial;
1382 gradient->rotate = rotate;
1384 if(dictionary_lookup(&gradients, name))
1385 syntaxerror("gradient %s defined twice", name);
1386 dictionary_put2(&gradients, name, gradient);
1389 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1390 float angle, float distance, float strength, char innershadow,
1391 char knockout, char composite, char ontop, int passes)
1393 gradient_t* g = dictionary_lookup(&gradients, gradient);
1398 syntaxerror("unknown gradient %s", gradient);
1399 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1400 filter->type = FILTERTYPE_GRADIENTGLOW;
1401 filter->gradient = &g->gradient;
1402 filter->blurx = blurx;
1403 filter->blury = blury;
1404 filter->strength = strength;
1405 filter->angle = angle;
1406 filter->distance = distance;
1407 filter->innershadow = innershadow;
1408 filter->knockout = knockout;
1409 filter->composite = composite;
1410 filter->ontop = ontop;
1411 filter->passes = passes;
1413 if(dictionary_lookup(&filters, name))
1414 syntaxerror("filter %s defined twice", name);
1415 dictionary_put2(&filters, name, filter);
1418 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)
1421 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1422 filter->type = FILTERTYPE_DROPSHADOW;
1423 filter->color= color;
1424 filter->blurx = blurx;
1425 filter->blury = blury;
1426 filter->strength = strength;
1427 filter->angle = angle;
1428 filter->distance = distance;
1429 filter->innershadow = innershadow;
1430 filter->knockout = knockout;
1431 filter->composite = composite;
1432 filter->passes = passes;
1434 if(dictionary_lookup(&filters, name))
1435 syntaxerror("filter %s defined twice", name);
1436 dictionary_put2(&filters, name, filter);
1439 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)
1442 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1443 filter->type = FILTERTYPE_BEVEL;
1444 filter->shadow = shadow;
1445 filter->highlight = highlight;
1446 filter->blurx = blurx;
1447 filter->blury = blury;
1448 filter->strength = strength;
1449 filter->angle = angle;
1450 filter->distance = distance;
1451 filter->innershadow = innershadow;
1452 filter->knockout = knockout;
1453 filter->composite = composite;
1454 filter->ontop = ontop;
1455 filter->passes = passes;
1457 if(dictionary_lookup(&filters, name))
1458 syntaxerror("filter %s defined twice", name);
1459 dictionary_put2(&filters, name, filter);
1462 void s_blur(char*name, double blurx, double blury, int passes)
1464 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1465 filter->type = FILTERTYPE_BLUR;
1466 filter->blurx = blurx;
1467 filter->blury = blury;
1468 filter->passes = passes;
1470 if(dictionary_lookup(&filters, name))
1471 syntaxerror("filter %s defined twice", name);
1472 dictionary_put2(&filters, name, filter);
1475 void s_action(const char*text)
1478 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1480 syntaxerror("Couldn't compile ActionScript");
1483 tag = swf_InsertTag(tag, ST_DOACTION);
1485 swf_ActionSet(tag, a);
1490 void s_initaction(const char*character, const char*text)
1494 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1496 syntaxerror("Couldn't compile ActionScript");
1499 c = (character_t*)dictionary_lookup(&characters, character);
1501 tag = swf_InsertTag(tag, ST_DOINITACTION);
1502 swf_SetU16(tag, c->id);
1503 swf_ActionSet(tag, a);
1508 int s_swf3action(char*name, char*action)
1511 instance_t* object = 0;
1513 object = (instance_t*)dictionary_lookup(&instances, name);
1514 if(!object && name && *name) {
1515 /* we have a name, but couldn't find it. Abort. */
1518 a = action_SetTarget(0, name);
1519 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1520 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1521 else if(!strcmp(action, "stop")) a = action_Stop(a);
1522 else if(!strcmp(action, "play")) a = action_Play(a);
1523 a = action_SetTarget(a, "");
1526 tag = swf_InsertTag(tag, ST_DOACTION);
1527 swf_ActionSet(tag, a);
1532 void s_outline(char*name, char*format, char*source)
1541 //swf_Shape10DrawerInit(&draw, 0);
1542 swf_Shape11DrawerInit(&draw, 0);
1544 draw_string(&draw, source);
1546 shape = swf_ShapeDrawerToShape(&draw);
1547 bounds = swf_ShapeDrawerGetBBox(&draw);
1548 draw.dealloc(&draw);
1550 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1551 outline->shape = shape;
1552 outline->bbox = bounds;
1554 if(dictionary_lookup(&outlines, name))
1555 syntaxerror("outline %s defined twice", name);
1556 dictionary_put2(&outlines, name, outline);
1559 int s_playsound(char*name, int loops, int nomultiple, int stop)
1565 sound = dictionary_lookup(&sounds, name);
1569 tag = swf_InsertTag(tag, ST_STARTSOUND);
1570 swf_SetU16(tag, sound->id); //id
1571 memset(&info, 0, sizeof(info));
1574 info.nomultiple = nomultiple;
1575 swf_SetSoundInfo(tag, &info);
1579 void s_includeswf(char*name, char*filename)
1587 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1588 f = open(filename,O_RDONLY|O_BINARY);
1590 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1591 s_box(name, 0, 0, black, 20, 0);
1594 if (swf_ReadSWF(f,&swf)<0) {
1595 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1596 s_box(name, 0, 0, black, 20, 0);
1601 /* FIXME: The following sets the bounding Box for the character.
1602 It is wrong for two reasons:
1603 a) It may be too small (in case objects in the movie clip at the borders)
1604 b) it may be too big (because the poor movie never got autocropped)
1608 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1609 swf_SetU16(tag, id);
1610 swf_SetU16(tag, swf.frameCount);
1612 swf_Relocate(&swf, idmap);
1614 ftag = swf.firstTag;
1618 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1619 if(cutout[t] == ftag->id) {
1623 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1625 if(ftag->id == ST_END)
1630 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
1631 /* We simply dump all tags right after the sprite
1632 header, relying on the fact that swf_OptimizeTagOrder() will
1633 sort things out for us later.
1634 We also rely on the fact that the imported SWF is well-formed.
1636 tag = swf_InsertTag(tag, ftag->id);
1637 swf_SetBlock(tag, ftag->data, ftag->len);
1643 syntaxerror("Included file %s contains errors", filename);
1644 tag = swf_InsertTag(tag, ST_END);
1648 s_addcharacter(name, id, tag, r);
1651 SRECT s_getCharBBox(char*name)
1653 character_t* c = dictionary_lookup(&characters, name);
1654 if(!c) syntaxerror("character '%s' unknown(2)", name);
1657 SRECT s_getInstanceBBox(char*name)
1659 instance_t * i = dictionary_lookup(&instances, name);
1661 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1663 if(!c) syntaxerror("internal error(5)");
1666 parameters_t s_getParameters(char*name)
1668 instance_t * i = dictionary_lookup(&instances, name);
1669 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1670 return i->parameters;
1672 void s_startclip(char*instance, char*character, parameters_t p)
1674 character_t* c = dictionary_lookup(&characters, character);
1678 syntaxerror("character %s not known", character);
1680 i = s_addinstance(instance, c, currentdepth);
1682 m = s_instancepos(i->character->size, &p);
1684 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1685 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1686 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1688 i->lastFrame= currentframe;
1690 stack[stackpos].tag = tag;
1691 stack[stackpos].type = 2;
1700 swf_SetTagPos(stack[stackpos].tag, 0);
1701 swf_GetPlaceObject(stack[stackpos].tag, &p);
1702 p.clipdepth = currentdepth;
1704 swf_ClearTag(stack[stackpos].tag);
1705 swf_SetPlaceObject(stack[stackpos].tag, &p);
1709 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
1713 swf_GetPlaceObject(NULL, &po);
1717 po.cxform = p->cxform;
1723 po.blendmode = p->blendmode;
1727 flist.filter[0] = p->filter;
1728 po.filters = &flist;
1730 swf_SetPlaceObject(tag, &po);
1733 void s_put(char*instance, char*character, parameters_t p)
1735 character_t* c = dictionary_lookup(&characters, character);
1739 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1742 i = s_addinstance(instance, c, currentdepth);
1744 m = s_instancepos(i->character->size, &p);
1746 if(p.blendmode || p.filter) {
1747 if(stack[0].swf->fileVersion < 8) {
1748 if(p.blendmode) warning("blendmodes only supported for flash version>=8");
1749 else warning("filters only supported for flash version>=8");
1751 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
1753 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1755 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
1758 i->lastFrame = currentframe;
1763 void s_jump(char*instance, parameters_t p)
1765 instance_t* i = dictionary_lookup(&instances, instance);
1768 syntaxerror("instance %s not known", instance);
1772 m = s_instancepos(i->character->size, &p);
1774 if(p.blendmode || p.filter) {
1775 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
1777 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1779 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
1782 i->lastFrame = currentframe;
1785 RGBA interpolateColor(RGBA c1, RGBA c2, float ratio)
1788 c.r = c1.r * (1-ratio) + c2.r * ratio;
1789 c.g = c1.g * (1-ratio) + c2.g * ratio;
1790 c.b = c1.b * (1-ratio) + c2.b * ratio;
1791 c.a = c1.a * (1-ratio) + c2.a * ratio;
1795 FILTER* interpolateFilter(FILTER*filter1,FILTER*filter2, float ratio)
1797 if(!filter1 && !filter2)
1800 return interpolateFilter(filter2,filter1,1-ratio);
1802 if(filter2 && filter2->type != filter1->type)
1803 syntaxerror("can't interpolate between %s and %s filters yet", filtername[filter1->type], filtername[filter2->type]);
1805 if(filter1->type == FILTERTYPE_BLUR) {
1806 FILTER_BLUR*f1 = (FILTER_BLUR*)filter1;
1807 FILTER_BLUR*f2 = (FILTER_BLUR*)filter2;
1808 if(f2 && f1->blurx == f2->blurx && f1->blury == f2->blury)
1810 FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR);
1811 f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
1812 f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
1813 f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
1815 } else if (filter1->type == FILTERTYPE_DROPSHADOW) {
1816 FILTER_DROPSHADOW*f1 = (FILTER_DROPSHADOW*)filter1;
1817 FILTER_DROPSHADOW*f2 = (FILTER_DROPSHADOW*)filter2;
1818 if(f2 && !memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength &&
1819 f1->blurx == f2->blurx && f1->blury == f2->blury &&
1820 f1->angle == f2->angle && f1->distance == f2->distance)
1822 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW);
1823 memcpy(f, f1, sizeof(FILTER_DROPSHADOW));
1824 f->color = interpolateColor(f1->color, f2->color, ratio);
1825 f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
1826 f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
1827 f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
1828 f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio;
1829 f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio;
1830 f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio;
1832 } else if (filter1->type == FILTERTYPE_BEVEL) {
1833 FILTER_BEVEL*f1 = (FILTER_BEVEL*)filter1;
1834 FILTER_BEVEL*f2 = (FILTER_BEVEL*)filter2;
1835 if(f2 && !memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) &&
1836 !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) &&
1837 f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
1839 FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL);
1840 memcpy(f, f1, sizeof(FILTER_BEVEL));
1841 f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio);
1842 f->highlight = interpolateColor(f1->highlight, f2->highlight, ratio);
1843 f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
1844 f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
1845 f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
1846 f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio;
1847 f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio;
1848 f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio;
1850 } /*else if (filter1->type == FILTERTYPE_GRADIENTGLOW) {
1851 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
1852 // can't interpolate gradients
1853 memcpy(f, filter1, sizeof(FILTER_GRADIENTGLOW));
1856 syntaxerror("can't interpolate %s filters yet", filtername[filter1->type]);
1861 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1865 if(num==0 || num==1)
1867 ratio = (float)pos/(float)num;
1869 p.x = (p2->x-p1->x)*ratio + p1->x;
1870 p.y = (p2->y-p1->y)*ratio + p1->y;
1871 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1872 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1873 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1874 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1876 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1877 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1878 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1879 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1881 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1882 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1883 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1884 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1886 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1887 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1888 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1889 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1891 p.filter = interpolateFilter(p1->filter, p2->filter, ratio);
1895 void s_change(char*instance, parameters_t p2)
1897 instance_t* i = dictionary_lookup(&instances, instance);
1901 int frame, allframes;
1903 syntaxerror("instance %s not known", instance);
1907 allframes = currentframe - i->lastFrame - 1;
1909 warning(".change ignored. can only .put/.change an object once per frame.");
1913 m = s_instancepos(i->character->size, &p2);
1914 if(p2.blendmode || p2.filter) {
1915 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
1917 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1919 setPlacement(tag, 0, i->depth, m, 0, &p2, 1);
1922 /* o.k., we got the start and end point set. Now iterate though all the
1923 tags in between, inserting object changes after each new frame */
1926 if(!t) syntaxerror("internal error(6)");
1928 while(frame < allframes) {
1929 if(t->id == ST_SHOWFRAME) {
1934 p = s_interpolate(&p1, &p2, frame, allframes);
1935 m = s_instancepos(i->character->size, &p); //needed?
1937 i->lastFrame = currentframe;
1938 if(p.blendmode || p.filter) {
1939 lt = swf_InsertTag(t, ST_PLACEOBJECT3);
1941 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1943 setPlacement(lt, 0, i->depth, m, 0, &p, 1);
1945 if(frame == allframes)
1950 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1954 void s_delinstance(char*instance)
1956 instance_t* i = dictionary_lookup(&instances, instance);
1958 syntaxerror("instance %s not known", instance);
1960 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1961 swf_SetU16(tag, i->depth);
1962 dictionary_del(&instances, instance);
1965 void s_qchange(char*instance, parameters_t p)
1972 syntaxerror(".end unexpected");
1973 if(stack[stackpos-1].type == 0)
1975 else if(stack[stackpos-1].type == 1)
1977 else if(stack[stackpos-1].type == 2)
1979 else if(stack[stackpos-1].type == 3)
1981 else syntaxerror("internal error 1");
1984 // ------------------------------------------------------------------------
1986 typedef int command_func_t(map_t*args);
1988 SRECT parseBox(char*str)
1990 SRECT r = {0,0,0,0};
1991 float xmin, xmax, ymin, ymax;
1992 char*x = strchr(str, 'x');
1994 if(!strcmp(str, "autocrop")) {
1995 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1999 d1 = strchr(x+1, ':');
2001 d2 = strchr(d1+1, ':');
2003 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2007 else if(d1 && !d2) {
2008 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2014 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2019 r.xmin = (SCOORD)(xmin*20);
2020 r.ymin = (SCOORD)(ymin*20);
2021 r.xmax = (SCOORD)(xmax*20);
2022 r.ymax = (SCOORD)(ymax*20);
2025 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2028 float parseFloat(char*str)
2032 int parseInt(char*str)
2037 if(str[0]=='+' || str[0]=='-')
2041 if(str[t]<'0' || str[t]>'9')
2042 syntaxerror("Not an Integer: \"%s\"", str);
2045 int parseTwip(char*str)
2049 if(str[0]=='+' || str[0]=='-') {
2054 dot = strchr(str, '.');
2058 return sign*parseInt(str)*20;
2060 char* old = strdup(str);
2061 int l=strlen(dot+1);
2064 for(s=str;s<dot-1;s++)
2065 if(*s<'0' || *s>'9')
2066 syntaxerror("Not a coordinate: \"%s\"", str);
2068 if(*s<'0' || *s>'9')
2069 syntaxerror("Not a coordinate: \"%s\"", str);
2071 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2072 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2075 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2079 return sign*atoi(str)*20;
2081 return sign*atoi(str)*20+atoi(dot)*2;
2083 return sign*atoi(str)*20+atoi(dot)/5;
2088 int isPoint(char*str)
2090 if(strchr(str, '('))
2096 SPOINT parsePoint(char*str)
2100 int l = strlen(str);
2101 char*comma = strchr(str, ',');
2102 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2103 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2104 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2105 p.x = parseTwip(tmp);
2106 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2107 p.y = parseTwip(tmp);
2111 int parseColor2(char*str, RGBA*color)
2113 int l = strlen(str);
2117 struct {unsigned char r,g,b;char*name;} colors[] =
2118 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2119 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2120 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2121 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2122 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2123 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2124 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2125 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2126 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2127 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2128 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2129 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2133 if(str[0]=='#' && (l==7 || l==9)) {
2134 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2136 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2138 color->r = r; color->g = g; color->b = b; color->a = a;
2141 int len=strlen(str);
2143 if(strchr(str, '/')) {
2144 len = strchr(str, '/')-str;
2145 sscanf(str+len+1,"%02x", &alpha);
2147 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2148 if(!strncmp(str, colors[t].name, len)) {
2153 color->r = r; color->g = g; color->b = b; color->a = a;
2159 RGBA parseColor(char*str)
2162 if(!parseColor2(str, &c))
2163 syntaxerror("Expression '%s' is not a color", str);
2167 typedef struct _muladd {
2172 MULADD parseMulAdd(char*str)
2175 char* str2 = (char*)malloc(strlen(str)+5);
2182 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2183 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2184 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2185 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2186 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2187 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2188 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2189 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2190 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2191 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2193 syntaxerror("'%s' is not a valid color transform expression", str);
2195 m.add = (int)(add*256);
2196 m.mul = (int)(mul*256);
2201 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2203 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2204 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2206 if(a<-32768) a=-32768;
2207 if(a>32767) a=32767;
2208 if(m<-32768) m=-32768;
2209 if(m>32767) m=32767;
2215 float parsePxOrPercent(char*fontname, char*str)
2217 int l = strlen(str);
2218 if(strchr(str, '%'))
2219 return parsePercent(str);
2220 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2221 float p = atof(str);
2222 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2224 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2228 float parsePercent(char*str)
2230 int l = strlen(str);
2234 return atoi(str)/100.0;
2236 syntaxerror("Expression '%s' is not a percentage", str);
2239 int isPercent(char*str)
2241 return str[strlen(str)-1]=='%';
2243 int parseNewSize(char*str, int size)
2246 return parsePercent(str)*size;
2248 return (int)(atof(str)*20);
2251 int isColor(char*str)
2254 return parseColor2(str, &c);
2257 static char* lu(map_t* args, char*name)
2259 char* value = map_lookup(args, name);
2261 map_dump(args, stdout, "");
2262 syntaxerror("internal error 2: value %s should be set", name);
2267 static int c_flash(map_t*args)
2269 char* filename = map_lookup(args, "filename");
2270 char* compressstr = lu(args, "compress");
2271 SRECT bbox = parseBox(lu(args, "bbox"));
2272 int version = parseInt(lu(args, "version"));
2273 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2275 RGBA color = parseColor(lu(args, "background"));
2277 if(!filename || !*filename) {
2278 /* for compatibility */
2279 filename = map_lookup(args, "name");
2280 if(!filename || !*filename) {
2283 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2284 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2288 if(!filename || override_outputname)
2289 filename = outputname;
2291 if(!strcmp(compressstr, "default"))
2292 compress = version>=6;
2293 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2295 else if(!strcmp(compressstr, "no"))
2297 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2299 s_swf(filename, bbox, version, fps, compress, color);
2302 int isRelative(char*str)
2304 return !strncmp(str, "<plus>", 6) ||
2305 !strncmp(str, "<minus>", 7);
2307 char* getOffset(char*str)
2309 if(!strncmp(str, "<plus>", 6))
2311 if(!strncmp(str, "<minus>", 7))
2313 syntaxerror("internal error (347)");
2316 int getSign(char*str)
2318 if(!strncmp(str, "<plus>", 6))
2320 if(!strncmp(str, "<minus>", 7))
2322 syntaxerror("internal error (348)");
2325 static dictionary_t points;
2326 static mem_t mpoints;
2327 int points_initialized = 0;
2329 SPOINT getPoint(SRECT r, char*name)
2332 if(!strcmp(name, "center")) {
2334 p.x = (r.xmin + r.xmax)/2;
2335 p.y = (r.ymin + r.ymax)/2;
2339 if(points_initialized)
2340 l = (int)dictionary_lookup(&points, name);
2342 syntaxerror("Invalid point: \"%s\".", name);
2345 return *(SPOINT*)&mpoints.buffer[l];
2348 static int texture2(char*name, char*object, map_t*args, int errors)
2351 char*xstr = map_lookup(args, "x");
2352 char*ystr = map_lookup(args, "y");
2353 char*widthstr = map_lookup(args, "width");
2354 char*heightstr = map_lookup(args, "height");
2355 char*scalestr = map_lookup(args, "scale");
2356 char*scalexstr = map_lookup(args, "scalex");
2357 char*scaleystr = map_lookup(args, "scaley");
2358 char*rotatestr = map_lookup(args, "rotate");
2359 char* shearstr = map_lookup(args, "shear");
2360 char* radiusstr = map_lookup(args, "r");
2362 float scalex = 1.0, scaley = 1.0;
2363 float rotate=0, shear=0;
2365 if(!*xstr && !*ystr) {
2367 syntaxerror("x and y must be set");
2370 if(*scalestr && (*scalexstr || *scaleystr)) {
2371 syntaxerror("scale and scalex/scaley can't both be set");
2374 if((*widthstr || *heightstr) && *radiusstr) {
2375 syntaxerror("width/height and radius can't both be set");
2378 widthstr = radiusstr;
2379 heightstr = radiusstr;
2381 if(!*xstr) xstr="0";
2382 if(!*ystr) ystr="0";
2383 if(!*rotatestr) rotatestr="0";
2384 if(!*shearstr) shearstr="0";
2387 scalex = scaley = parsePercent(scalestr);
2388 } else if(*scalexstr || *scaleystr) {
2389 if(scalexstr) scalex = parsePercent(scalexstr);
2390 if(scaleystr) scaley = parsePercent(scaleystr);
2391 } else if(*widthstr || *heightstr) {
2394 s_getBitmapSize(object, &width, &height);
2396 scalex = (float)parseTwip(widthstr)/(float)width;
2398 scaley = (float)parseTwip(heightstr)/(float)height;
2400 x = parseTwip(xstr);
2401 y = parseTwip(ystr);
2402 rotate = parseFloat(rotatestr);
2403 shear = parseFloat(shearstr);
2405 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2410 static int c_texture(map_t*args)
2412 char*name = lu(args, "instance");
2413 char*object = lu(args, "character");
2414 return texture2(name, object, args, 1);
2417 static int c_gradient(map_t*args)
2419 char*name = lu(args, "name");
2420 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2421 int rotate = parseInt(lu(args, "rotate"));
2425 syntaxerror("colon (:) expected");
2427 s_gradient(name, text, radial, rotate);
2429 /* check whether we also have placement information,
2430 which would make this a positioned gradient.
2431 If there is placement information, texture2() will
2432 add a texture, which has priority over the gradient.
2434 texture2(name, name, args, 0);
2438 static int c_blur(map_t*args)
2440 char*name = lu(args, "name");
2441 char*blurstr = lu(args, "blur");
2442 char*blurxstr = lu(args, "blurx");
2443 char*blurystr = lu(args, "blury");
2444 float blurx=1.0, blury=1.0;
2446 blurx = parseFloat(blurstr);
2447 blury = parseFloat(blurstr);
2450 blurx = parseFloat(blurxstr);
2452 blury = parseFloat(blurystr);
2453 int passes = parseInt(lu(args, "passes"));
2454 s_blur(name, blurx, blury, passes);
2458 static int c_gradientglow(map_t*args)
2460 char*name = lu(args, "name");
2461 char*gradient = lu(args, "gradient");
2462 char*blurstr = lu(args, "blur");
2463 char*blurxstr = lu(args, "blurx");
2464 char*blurystr = lu(args, "blury");
2465 float blurx=1.0, blury=1.0;
2467 blurx = parseFloat(blurstr);
2468 blury = parseFloat(blurstr);
2471 blurx = parseFloat(blurxstr);
2473 blury = parseFloat(blurystr);
2475 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2476 float distance = parseFloat(lu(args, "distance"));
2477 float strength = parseFloat(lu(args, "strength"));
2478 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2479 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2480 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2481 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2482 int passes = parseInt(lu(args, "passes"));
2484 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2488 static int c_dropshadow(map_t*args)
2490 char*name = lu(args, "name");
2491 RGBA color = parseColor(lu(args, "color"));
2492 char*blurstr = lu(args, "blur");
2493 char*blurxstr = lu(args, "blurx");
2494 char*blurystr = lu(args, "blury");
2495 float blurx=1.0, blury=1.0;
2497 blurx = parseFloat(blurstr);
2498 blury = parseFloat(blurstr);
2501 blurx = parseFloat(blurxstr);
2503 blury = parseFloat(blurystr);
2505 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2506 float distance = parseFloat(lu(args, "distance"));
2507 float strength = parseFloat(lu(args, "strength"));
2508 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2509 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2510 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2511 int passes = parseInt(lu(args, "passes"));
2513 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2517 static int c_bevel(map_t*args)
2519 char*name = lu(args, "name");
2520 RGBA shadow = parseColor(lu(args, "shadow"));
2521 RGBA highlight = parseColor(lu(args, "highlight"));
2522 char*blurstr = lu(args, "blur");
2523 char*blurxstr = lu(args, "blurx");
2524 char*blurystr = lu(args, "blury");
2525 float blurx=1.0, blury=1.0;
2527 blurx = parseFloat(blurstr);
2528 blury = parseFloat(blurstr);
2531 blurx = parseFloat(blurxstr);
2533 blury = parseFloat(blurystr);
2535 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2536 float distance = parseFloat(lu(args, "distance"));
2537 float strength = parseFloat(lu(args, "strength"));
2538 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2539 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2540 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2541 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2542 int passes = parseInt(lu(args, "passes"));
2544 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2548 static int c_point(map_t*args)
2550 char*name = lu(args, "name");
2554 if(!points_initialized) {
2555 dictionary_init(&points);
2557 points_initialized = 1;
2559 p.x = parseTwip(lu(args, "x"));
2560 p.y = parseTwip(lu(args, "y"));
2561 pos = mem_put(&mpoints, &p, sizeof(p));
2562 string_set(&s1, name);
2564 dictionary_put(&points, s1, (void*)pos);
2567 static int c_play(map_t*args)
2569 char*name = lu(args, "name");
2570 char*loop = lu(args, "loop");
2571 char*nomultiple = lu(args, "nomultiple");
2573 if(!strcmp(nomultiple, "nomultiple"))
2576 nm = parseInt(nomultiple);
2578 if(s_playsound(name, parseInt(loop), nm, 0)) {
2580 } else if(s_swf3action(name, "play")) {
2586 static int c_stop(map_t*args)
2588 char*name = map_lookup(args, "name");
2590 if(s_playsound(name, 0,0,1)) {
2592 } else if(s_swf3action(name, "stop")) {
2595 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2599 static int c_nextframe(map_t*args)
2601 char*name = lu(args, "name");
2603 if(s_swf3action(name, "nextframe")) {
2606 syntaxerror("I don't know anything about movie \"%s\"", name);
2610 static int c_previousframe(map_t*args)
2612 char*name = lu(args, "name");
2614 if(s_swf3action(name, "previousframe")) {
2617 syntaxerror("I don't know anything about movie \"%s\"", name);
2621 static int c_placement(map_t*args, int type)
2623 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2626 char* luminancestr = lu(args, "luminance");
2627 char* scalestr = lu(args, "scale");
2628 char* scalexstr = lu(args, "scalex");
2629 char* scaleystr = lu(args, "scaley");
2630 char* rotatestr = lu(args, "rotate");
2631 char* shearstr = lu(args, "shear");
2632 char* xstr="", *pivotstr="";
2633 char* ystr="", *anglestr="";
2634 char*above = lu(args, "above"); /*FIXME*/
2635 char*below = lu(args, "below");
2636 char* rstr = lu(args, "red");
2637 char* gstr = lu(args, "green");
2638 char* bstr = lu(args, "blue");
2639 char* astr = lu(args, "alpha");
2640 char* pinstr = lu(args, "pin");
2641 char* as = map_lookup(args, "as");
2642 char* blendmode = lu(args, "blend");
2643 char*filterstr = lu(args, "filter");
2652 if(type==9) { // (?) .rotate or .arcchange
2653 pivotstr = lu(args, "pivot");
2654 anglestr = lu(args, "angle");
2656 xstr = lu(args, "x");
2657 ystr = lu(args, "y");
2660 luminance = parseMulAdd(luminancestr);
2663 luminance.mul = 256;
2667 if(scalexstr[0]||scaleystr[0])
2668 syntaxerror("scalex/scaley and scale cannot both be set");
2669 scalexstr = scaleystr = scalestr;
2672 if(type == 0 || type == 4) {
2674 character = lu(args, "character");
2675 parameters_clear(&p);
2676 } else if (type == 5) {
2677 character = lu(args, "name");
2678 parameters_clear(&p);
2681 p = s_getParameters(instance);
2686 if(isRelative(xstr)) {
2687 if(type == 0 || type == 4)
2688 syntaxerror("relative x values not allowed for initial put or startclip");
2689 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2691 p.x = parseTwip(xstr);
2695 if(isRelative(ystr)) {
2696 if(type == 0 || type == 4)
2697 syntaxerror("relative y values not allowed for initial put or startclip");
2698 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2700 p.y = parseTwip(ystr);
2704 /* scale, scalex, scaley */
2706 oldbbox = s_getCharBBox(character);
2708 oldbbox = s_getInstanceBBox(instance);
2710 oldwidth = oldbbox.xmax - oldbbox.xmin;
2711 oldheight = oldbbox.ymax - oldbbox.ymin;
2713 if(oldwidth==0) p.scalex = 1.0;
2716 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2720 if(oldheight==0) p.scaley = 1.0;
2723 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2729 if(isRelative(rotatestr)) {
2730 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2732 p.rotate = parseFloat(rotatestr);
2738 if(isRelative(shearstr)) {
2739 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2741 p.shear = parseFloat(shearstr);
2746 if(isPoint(pivotstr))
2747 p.pivot = parsePoint(pivotstr);
2749 p.pivot = getPoint(oldbbox, pivotstr);
2753 p.pin = parsePoint(pinstr);
2755 p.pin = getPoint(oldbbox, pinstr);
2758 /* color transform */
2760 if(rstr[0] || luminancestr[0]) {
2763 r = parseMulAdd(rstr);
2765 r.add = p.cxform.r0;
2766 r.mul = p.cxform.r1;
2768 r = mergeMulAdd(r, luminance);
2769 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2771 if(gstr[0] || luminancestr[0]) {
2774 g = parseMulAdd(gstr);
2776 g.add = p.cxform.g0;
2777 g.mul = p.cxform.g1;
2779 g = mergeMulAdd(g, luminance);
2780 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2782 if(bstr[0] || luminancestr[0]) {
2785 b = parseMulAdd(bstr);
2787 b.add = p.cxform.b0;
2788 b.mul = p.cxform.b1;
2790 b = mergeMulAdd(b, luminance);
2791 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2794 MULADD a = parseMulAdd(astr);
2795 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2801 for(t=0;blendModeNames[t];t++) {
2802 if(!strcmp(blendModeNames[t], blendmode)) {
2808 syntaxerror("unknown blend mode: '%s'", blendmode);
2810 p.blendmode = blend;
2814 FILTER*f = dictionary_lookup(&filters, filterstr);
2816 syntaxerror("Unknown filter %s", filterstr);
2822 s_put(instance, character, p);
2824 s_change(instance, p);
2826 s_qchange(instance, p);
2828 s_jump(instance, p);
2830 s_startclip(instance, character, p);
2831 else if(type == 5) {
2833 s_buttonput(character, as, p);
2835 s_buttonput(character, "shape", p);
2840 static int c_put(map_t*args)
2842 c_placement(args, 0);
2845 static int c_change(map_t*args)
2847 c_placement(args, 1);
2850 static int c_qchange(map_t*args)
2852 c_placement(args, 2);
2855 static int c_arcchange(map_t*args)
2857 c_placement(args, 2);
2860 static int c_jump(map_t*args)
2862 c_placement(args, 3);
2865 static int c_startclip(map_t*args)
2867 c_placement(args, 4);
2870 static int c_show(map_t*args)
2872 c_placement(args, 5);
2875 static int c_del(map_t*args)
2877 char*instance = lu(args, "name");
2878 s_delinstance(instance);
2881 static int c_end(map_t*args)
2886 static int c_sprite(map_t*args)
2888 char* name = lu(args, "name");
2892 static int c_frame(map_t*args)
2894 char*framestr = lu(args, "n");
2895 char*cutstr = lu(args, "cut");
2897 char*name = lu(args, "name");
2898 char*anchor = lu(args, "anchor");
2901 if(!strcmp(anchor, "anchor") && !*name)
2906 if(strcmp(cutstr, "no"))
2908 if(isRelative(framestr)) {
2909 frame = s_getframe();
2910 if(getSign(framestr)<0)
2911 syntaxerror("relative frame expressions must be positive");
2912 frame += parseInt(getOffset(framestr));
2915 frame = parseInt(framestr);
2916 if(s_getframe() >= frame
2917 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2918 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2920 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
2923 static int c_primitive(map_t*args)
2925 char*name = lu(args, "name");
2926 char*command = lu(args, "commandname");
2927 int width=0, height=0, r=0;
2928 int linewidth = parseTwip(lu(args, "line"));
2929 char*colorstr = lu(args, "color");
2930 RGBA color = parseColor(colorstr);
2931 char*fillstr = lu(args, "fill");
2938 if(!strcmp(command, "circle"))
2940 else if(!strcmp(command, "filled"))
2944 width = parseTwip(lu(args, "width"));
2945 height = parseTwip(lu(args, "height"));
2946 } else if (type==1) {
2947 r = parseTwip(lu(args, "r"));
2948 } else if (type==2) {
2949 outline = lu(args, "outline");
2952 if(!strcmp(fillstr, "fill"))
2954 if(!strcmp(fillstr, "none"))
2956 if(width<0 || height<0 || linewidth<0 || r<0)
2957 syntaxerror("values width, height, line, r must be positive");
2959 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2960 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2961 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2965 static int c_textshape(map_t*args)
2967 char*name = lu(args, "name");
2968 char*text = lu(args, "text");
2969 char*font = lu(args, "font");
2970 float size = parsePxOrPercent(font, lu(args, "size"));
2972 s_textshape(name, font, size, text);
2976 static int c_swf(map_t*args)
2978 char*name = lu(args, "name");
2979 char*filename = lu(args, "filename");
2980 char*command = lu(args, "commandname");
2981 if(!strcmp(command, "shape"))
2982 warning("Please use .swf instead of .shape");
2983 s_includeswf(name, filename);
2987 static int c_font(map_t*args)
2989 char*name = lu(args, "name");
2990 char*filename = lu(args, "filename");
2991 s_font(name, filename);
2995 static int c_sound(map_t*args)
2997 char*name = lu(args, "name");
2998 char*filename = lu(args, "filename");
2999 s_sound(name, filename);
3003 static int c_text(map_t*args)
3005 char*name = lu(args, "name");
3006 char*text = lu(args, "text");
3007 char*font = lu(args, "font");
3008 float size = parsePxOrPercent(font, lu(args, "size"));
3009 RGBA color = parseColor(lu(args, "color"));
3010 s_text(name, font, text, (int)(size*100), color);
3014 static int c_soundtrack(map_t*args)
3019 static int c_quicktime(map_t*args)
3021 char*name = lu(args, "name");
3022 char*url = lu(args, "url");
3023 s_quicktime(name, url);
3027 static int c_image(map_t*args)
3029 char*command = lu(args, "commandname");
3030 char*name = lu(args, "name");
3031 char*filename = lu(args, "filename");
3032 if(!strcmp(command,"jpeg")) {
3033 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3034 s_image(name, "jpeg", filename, quality);
3036 s_image(name, "png", filename, 0);
3041 static int c_outline(map_t*args)
3043 char*name = lu(args, "name");
3044 char*format = lu(args, "format");
3048 syntaxerror("colon (:) expected");
3050 s_outline(name, format, text);
3054 int fakechar(map_t*args)
3056 char*name = lu(args, "name");
3057 s_box(name, 0, 0, black, 20, 0);
3061 static int c_egon(map_t*args) {return fakechar(args);}
3062 static int c_button(map_t*args) {
3063 char*name = lu(args, "name");
3067 static int current_button_flags = 0;
3068 static int c_on_press(map_t*args)
3070 char*position = lu(args, "position");
3072 if(!strcmp(position, "inside")) {
3073 current_button_flags |= BC_OVERUP_OVERDOWN;
3074 } else if(!strcmp(position, "outside")) {
3075 //current_button_flags |= BC_IDLE_OUTDOWN;
3076 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3077 } else if(!strcmp(position, "anywhere")) {
3078 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3081 if(type == RAWDATA) {
3083 s_buttonaction(current_button_flags, action);
3084 current_button_flags = 0;
3090 static int c_on_release(map_t*args)
3092 char*position = lu(args, "position");
3094 if(!strcmp(position, "inside")) {
3095 current_button_flags |= BC_OVERDOWN_OVERUP;
3096 } else if(!strcmp(position, "outside")) {
3097 current_button_flags |= BC_OUTDOWN_IDLE;
3098 } else if(!strcmp(position, "anywhere")) {
3099 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3102 if(type == RAWDATA) {
3104 s_buttonaction(current_button_flags, action);
3105 current_button_flags = 0;
3111 static int c_on_move_in(map_t*args)
3113 char*position = lu(args, "state");
3115 if(!strcmp(position, "pressed")) {
3116 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3117 } else if(!strcmp(position, "not_pressed")) {
3118 current_button_flags |= BC_IDLE_OVERUP;
3119 } else if(!strcmp(position, "any")) {
3120 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3123 if(type == RAWDATA) {
3125 s_buttonaction(current_button_flags, action);
3126 current_button_flags = 0;
3132 static int c_on_move_out(map_t*args)
3134 char*position = lu(args, "state");
3136 if(!strcmp(position, "pressed")) {
3137 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3138 } else if(!strcmp(position, "not_pressed")) {
3139 current_button_flags |= BC_OVERUP_IDLE;
3140 } else if(!strcmp(position, "any")) {
3141 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3144 if(type == RAWDATA) {
3146 s_buttonaction(current_button_flags, action);
3147 current_button_flags = 0;
3153 static int c_on_key(map_t*args)
3155 char*key = lu(args, "key");
3157 if(strlen(key)==1) {
3160 current_button_flags |= 0x4000 + (key[0]*0x200);
3162 syntaxerror("invalid character: %c"+key[0]);
3167 <ctrl-x> = 0x200*(x-'a')
3171 syntaxerror("invalid key: %s",key);
3174 if(type == RAWDATA) {
3176 s_buttonaction(current_button_flags, action);
3177 current_button_flags = 0;
3184 static int c_edittext(map_t*args)
3186 //"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"},
3187 char*name = lu(args, "name");
3188 char*font = lu(args, "font");
3189 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3190 int width = parseTwip(lu(args, "width"));
3191 int height = parseTwip(lu(args, "height"));
3192 char*text = lu(args, "text");
3193 RGBA color = parseColor(lu(args, "color"));
3194 int maxlength = parseInt(lu(args, "maxlength"));
3195 char*variable = lu(args, "variable");
3196 char*passwordstr = lu(args, "password");
3197 char*wordwrapstr = lu(args, "wordwrap");
3198 char*multilinestr = lu(args, "multiline");
3199 char*htmlstr = lu(args, "html");
3200 char*noselectstr = lu(args, "noselect");
3201 char*readonlystr = lu(args, "readonly");
3202 char*borderstr = lu(args, "border");
3203 char*autosizestr = lu(args, "autosize");
3204 char*alignstr = lu(args, "align");
3208 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3209 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3210 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3211 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3212 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3213 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3214 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3215 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3216 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3217 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3218 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3219 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3220 else syntaxerror("Unknown alignment: %s", alignstr);
3222 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3226 static int c_morphshape(map_t*args) {return fakechar(args);}
3227 static int c_movie(map_t*args) {return fakechar(args);}
3229 static char* readfile(const char*filename)
3231 FILE*fi = fopen(filename, "rb");
3235 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3236 fseek(fi, 0, SEEK_END);
3238 fseek(fi, 0, SEEK_SET);
3239 text = rfx_alloc(l+1);
3240 fread(text, l, 1, fi);
3246 static int c_action(map_t*args)
3248 char* filename = map_lookup(args, "filename");
3249 if(!filename ||!*filename) {
3251 if(type != RAWDATA) {
3252 syntaxerror("colon (:) expected");
3256 s_action(readfile(filename));
3262 static int c_initaction(map_t*args)
3264 char* character = lu(args, "name");
3265 char* filename = map_lookup(args, "filename");
3266 if(!filename ||!*filename) {
3268 if(type != RAWDATA) {
3269 syntaxerror("colon (:) expected");
3271 s_initaction(character, text);
3273 s_initaction(character, readfile(filename));
3281 command_func_t* func;
3284 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
3285 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3286 // "import" type stuff
3287 {"swf", c_swf, "name filename"},
3288 {"shape", c_swf, "name filename"},
3289 {"jpeg", c_image, "name filename quality=80%"},
3290 {"png", c_image, "name filename"},
3291 {"movie", c_movie, "name filename"},
3292 {"sound", c_sound, "name filename"},
3293 {"font", c_font, "name filename"},
3294 {"soundtrack", c_soundtrack, "filename"},
3295 {"quicktime", c_quicktime, "url"},
3297 // generators of primitives
3299 {"point", c_point, "name x=0 y=0"},
3300 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3301 {"outline", c_outline, "name format=simple"},
3302 {"textshape", c_textshape, "name font size=100% text"},
3305 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3306 {"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"},
3307 {"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"},
3308 {"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"},
3310 // character generators
3311 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3312 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3313 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3315 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3316 {"text", c_text, "name text font size=100% color=white"},
3317 {"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="},
3318 {"morphshape", c_morphshape, "name start end"},
3319 {"button", c_button, "name"},
3320 {"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="},
3321 {"on_press", c_on_press, "position=inside"},
3322 {"on_release", c_on_release, "position=anywhere"},
3323 {"on_move_in", c_on_move_in, "state=not_pressed"},
3324 {"on_move_out", c_on_move_out, "state=not_pressed"},
3325 {"on_key", c_on_key, "key=any"},
3328 {"play", c_play, "name loop=0 @nomultiple=0"},
3329 {"stop", c_stop, "name= "},
3330 {"nextframe", c_nextframe, "name"},
3331 {"previousframe", c_previousframe, "name"},
3333 // object placement tags
3334 {"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="},
3335 {"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="},
3336 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3337 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3338 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3339 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3340 {"del", c_del, "name"},
3341 // virtual object placement
3342 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3344 // commands which start a block
3345 //startclip (see above)
3346 {"sprite", c_sprite, "name"},
3347 {"action", c_action, "filename="},
3348 {"initaction", c_initaction, "name filename="},
3354 static map_t parseArguments(char*command, char*pattern)
3370 string_set(&t1, "commandname");
3371 string_set(&t2, command);
3372 map_put(&result, t1, t2);
3374 if(!pattern || !*pattern)
3381 if(!strncmp("<i> ", x, 3)) {
3383 if(type == COMMAND || type == RAWDATA) {
3385 syntaxerror("character name expected");
3387 name[pos].str = "instance";
3389 value[pos].str = text;
3390 value[pos].len = strlen(text);
3394 if(type == ASSIGNMENT)
3397 name[pos].str = "character";
3399 value[pos].str = text;
3400 value[pos].len = strlen(text);
3408 isboolean[pos] = (x[0] =='@');
3421 name[pos].len = d-x;
3426 name[pos].len = e-x;
3427 value[pos].str = e+1;
3428 value[pos].len = d-e-1;
3436 /* for(t=0;t<len;t++) {
3437 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
3438 isboolean[t]?"(boolean)":"");
3443 if(type == RAWDATA || type == COMMAND) {
3448 // first, search for boolean arguments
3449 for(pos=0;pos<len;pos++)
3451 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
3453 if(type == ASSIGNMENT)
3455 value[pos].str = text;
3456 value[pos].len = strlen(text);
3457 /*printf("setting boolean parameter %s (to %s)\n",
3458 strdup_n(name[pos], namelen[pos]),
3459 strdup_n(value[pos], valuelen[pos]));*/
3464 // second, search for normal arguments
3466 for(pos=0;pos<len;pos++)
3468 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3469 (type != ASSIGNMENT && !set[pos])) {
3471 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3473 if(type == ASSIGNMENT)
3476 value[pos].str = text;
3477 value[pos].len = strlen(text);
3479 printf("setting parameter %s (to %s)\n",
3480 strdup_n(name[pos].str, name[pos].len),
3481 strdup_n(value[pos].str, value[pos].len));
3487 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3491 for(t=0;t<len;t++) {
3492 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3495 for(t=0;t<len;t++) {
3496 if(value[t].str && value[t].str[0] == '*') {
3497 //relative default- take value from some other parameter
3499 for(s=0;s<len;s++) {
3500 if(value[s].len == value[t].len-1 &&
3501 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3502 value[t].str = value[s].str;
3505 if(value[t].str == 0) {
3507 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3511 /* ok, now construct the dictionary from the parameters */
3515 map_put(&result, name[t], value[t]);
3519 static void parseArgumentsForCommand(char*command)
3524 msg("<verbose> parse Command: %s (line %d)", command, line);
3526 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3527 if(!strcmp(arguments[t].command, command)) {
3529 /* ugly hack- will be removed soon (once documentation and .sc generating
3530 utilities have been changed) */
3531 if(!strcmp(command, "swf") && !stackpos) {
3532 warning("Please use .flash instead of .swf- this will be mandatory soon");
3537 args = parseArguments(command, arguments[t].arguments);
3543 syntaxerror("command %s not known", command);
3545 // catch missing .flash directives at the beginning of a file
3546 if(strcmp(command, "flash") && !stackpos)
3548 syntaxerror("No movie defined- use .flash first");
3552 printf(".%s\n", command);fflush(stdout);
3553 map_dump(&args, stdout, "\t");fflush(stdout);
3556 (*arguments[nr].func)(&args);
3558 /*if(!strcmp(command, "button") ||
3559 !strcmp(command, "action")) {
3562 if(type == COMMAND) {
3563 if(!strcmp(text, "end"))
3577 int main (int argc,char ** argv)
3580 processargs(argc, argv);
3581 initLog(0,-1,0,0,-1,verbose);
3584 args_callback_usage(argv[0]);
3588 file = generateTokens(filename);
3590 fprintf(stderr, "parser returned error.\n");
3596 while(!noMoreTokens()) {
3599 syntaxerror("command expected");
3600 parseArgumentsForCommand(text);