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 s_addcharacter(name, id, tag, r);
987 void s_quicktime(char*name, char*url)
992 memset(&r, 0, sizeof(r));
994 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
996 swf_SetString(tag, url);
998 s_addcharacter(name, id, tag, r);
1002 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)
1005 EditTextLayout layout;
1008 if(fontname && *fontname) {
1009 flags |= ET_USEOUTLINES;
1010 font = dictionary_lookup(&fonts, fontname);
1012 syntaxerror("font \"%s\" not known!", fontname);
1014 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1015 swf_SetU16(tag, id);
1016 layout.align = align;
1017 layout.leftmargin = 0;
1018 layout.rightmargin = 0;
1026 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1028 s_addcharacter(name, id, tag, r);
1032 /* type: either "jpeg" or "png"
1034 void s_image(char*name, char*type, char*filename, int quality)
1036 /* an image is actually two folded: 1st bitmap, 2nd character.
1037 Both of them can be used separately */
1039 /* step 1: the bitmap */
1043 if(!strcmp(type,"jpeg")) {
1044 #ifndef HAVE_JPEGLIB
1045 warning("no jpeg support compiled in");
1046 s_box(name, 0, 0, black, 20, 0);
1049 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1050 swf_SetU16(tag, imageID);
1052 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1053 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1056 swf_GetJPEGSize(filename, &width, &height);
1063 s_addimage(name, id, tag, r);
1066 } else if(!strcmp(type,"png")) {
1068 swf_SetU16(tag, imageID);
1070 getPNG(filename, &width, &height, (unsigned char**)&data);
1073 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1076 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1077 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1078 swf_SetU16(tag, imageID);
1079 swf_SetLosslessImage(tag, data, width, height);
1085 s_addimage(name, id, tag, r);
1088 warning("image type \"%s\" not supported yet!", type);
1089 s_box(name, 0, 0, black, 20, 0);
1093 /* step 2: the character */
1094 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1095 swf_SetU16(tag, id);
1096 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1098 s_addcharacter(name, id, tag, r);
1102 void s_getBitmapSize(char*name, int*width, int*height)
1104 character_t* image = dictionary_lookup(&images, name);
1105 gradient_t* gradient = dictionary_lookup(&gradients,name);
1107 *width = image->size.xmax;
1108 *height = image->size.ymax;
1112 /* internal SWF gradient size */
1113 if(gradient->radial) {
1122 syntaxerror("No such bitmap/gradient: %s", name);
1125 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1127 gradient_t* gradient = dictionary_lookup(&gradients, object);
1128 character_t* bitmap = dictionary_lookup(&images, object);
1129 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1131 FILLSTYLE*fs = &texture->fs;
1133 memset(&p, 0, sizeof(parameters_t));
1136 fs->type = FILL_TILED;
1137 fs->id_bitmap = bitmap->id;
1138 } else if(gradient) {
1139 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1140 fs->gradient = gradient->gradient;
1142 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1143 makeMatrix(&fs->m, &p);
1144 if(gradient && !gradient->radial) {
1151 p2 = swf_TurnPoint(p1, &m);
1161 if(dictionary_lookup(&textures, name))
1162 syntaxerror("texture %s defined twice", name);
1163 dictionary_put2(&textures, name, texture);
1166 void dumpSWF(SWF*swf)
1168 TAG* tag = swf->firstTag;
1169 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1171 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1174 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1177 void s_font(char*name, char*filename)
1180 font = swf_LoadFont(filename);
1183 warning("Couldn't open font file \"%s\"", filename);
1184 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1185 memset(font, 0, sizeof(SWFFONT));
1186 dictionary_put2(&fonts, name, font);
1192 /* fix the layout. Only needed for old fonts */
1194 for(t=0;t<font->numchars;t++) {
1195 font->glyph[t].advance = 0;
1198 swf_FontCreateLayout(font);
1200 /* just in case this thing is used in .edittext later on */
1201 swf_FontPrepareForEditText(font);
1204 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1205 swf_FontSetDefine2(tag, font);
1206 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1208 swf_SetU16(tag, id);
1209 swf_SetString(tag, name);
1212 if(dictionary_lookup(&fonts, name))
1213 syntaxerror("font %s defined twice", name);
1214 dictionary_put2(&fonts, name, font);
1219 typedef struct _sound_t
1225 void s_sound(char*name, char*filename)
1227 struct WAV wav, wav2;
1231 unsigned numsamples;
1232 unsigned blocksize = 1152;
1235 if(wav_read(&wav, filename)) {
1237 wav_convert2mono(&wav, &wav2, 44100);
1238 samples = (U16*)wav2.data;
1239 numsamples = wav2.size/2;
1241 #ifdef WORDS_BIGENDIAN
1243 for(t=0;t<numsamples;t++) {
1244 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1247 } else if(mp3_read(&mp3, filename)) {
1248 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1254 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1259 if(numsamples%blocksize != 0)
1261 // apply padding, so that block is a multiple of blocksize
1262 int numblocks = (numsamples+blocksize-1)/blocksize;
1265 numsamples2 = numblocks * blocksize;
1266 samples2 = malloc(sizeof(U16)*numsamples2);
1267 memcpy(samples2, samples, numsamples*sizeof(U16));
1268 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1269 numsamples = numsamples2;
1273 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1274 swf_SetU16(tag, id); //id
1277 swf_SetSoundDefineMP3(
1278 tag, mp3.data, mp3.size,
1286 swf_SetSoundDefine(tag, samples, numsamples);
1289 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1290 swf_SetU16(tag, id);
1291 swf_SetString(tag, name);
1292 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1294 swf_SetU16(tag, id);
1295 swf_SetString(tag, name);
1297 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1301 if(dictionary_lookup(&sounds, name))
1302 syntaxerror("sound %s defined twice", name);
1303 dictionary_put2(&sounds, name, sound);
1311 static char* gradient_getToken(const char**p)
1315 while(**p && strchr(" \t\n\r", **p)) {
1319 while(**p && !strchr(" \t\n\r", **p)) {
1322 result = malloc((*p)-start+1);
1323 memcpy(result,start,(*p)-start+1);
1324 result[(*p)-start] = 0;
1328 float parsePercent(char*str);
1329 RGBA parseColor(char*str);
1331 GRADIENT parseGradient(const char*str)
1335 const char* p = str;
1336 memset(&gradient, 0, sizeof(GRADIENT));
1337 gradient.ratios = rfx_calloc(16*sizeof(U8));
1338 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1340 char*posstr,*colorstr;
1343 posstr = gradient_getToken(&p);
1346 pos = (int)(parsePercent(posstr)*255.0);
1349 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1350 colorstr = gradient_getToken(&p);
1351 color = parseColor(colorstr);
1352 if(gradient.num == 16) {
1353 warning("gradient record too big- max size is 16, rest ignored");
1356 gradient.ratios[gradient.num] = pos;
1357 gradient.rgba[gradient.num] = color;
1366 void s_gradient(char*name, const char*text, int radial, int rotate)
1368 gradient_t* gradient;
1369 gradient = malloc(sizeof(gradient_t));
1370 memset(gradient, 0, sizeof(gradient_t));
1371 gradient->gradient = parseGradient(text);
1372 gradient->radial = radial;
1373 gradient->rotate = rotate;
1375 if(dictionary_lookup(&gradients, name))
1376 syntaxerror("gradient %s defined twice", name);
1377 dictionary_put2(&gradients, name, gradient);
1380 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1381 float angle, float distance, float strength, char innershadow,
1382 char knockout, char composite, char ontop, int passes)
1384 gradient_t* g = dictionary_lookup(&gradients, gradient);
1389 syntaxerror("unknown gradient %s", gradient);
1390 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1391 filter->type = FILTERTYPE_GRADIENTGLOW;
1392 filter->gradient = &g->gradient;
1393 filter->blurx = blurx;
1394 filter->blury = blury;
1395 filter->strength = strength;
1396 filter->angle = angle;
1397 filter->distance = distance;
1398 filter->innershadow = innershadow;
1399 filter->knockout = knockout;
1400 filter->composite = composite;
1401 filter->ontop = ontop;
1402 filter->passes = passes;
1404 if(dictionary_lookup(&filters, name))
1405 syntaxerror("filter %s defined twice", name);
1406 dictionary_put2(&filters, name, filter);
1409 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)
1412 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1413 filter->type = FILTERTYPE_DROPSHADOW;
1414 filter->color= color;
1415 filter->blurx = blurx;
1416 filter->blury = blury;
1417 filter->strength = strength;
1418 filter->angle = angle;
1419 filter->distance = distance;
1420 filter->innershadow = innershadow;
1421 filter->knockout = knockout;
1422 filter->composite = composite;
1423 filter->passes = passes;
1425 if(dictionary_lookup(&filters, name))
1426 syntaxerror("filter %s defined twice", name);
1427 dictionary_put2(&filters, name, filter);
1430 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)
1433 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1434 filter->type = FILTERTYPE_BEVEL;
1435 filter->shadow = shadow;
1436 filter->highlight = highlight;
1437 filter->blurx = blurx;
1438 filter->blury = blury;
1439 filter->strength = strength;
1440 filter->angle = angle;
1441 filter->distance = distance;
1442 filter->innershadow = innershadow;
1443 filter->knockout = knockout;
1444 filter->composite = composite;
1445 filter->ontop = ontop;
1446 filter->passes = passes;
1448 if(dictionary_lookup(&filters, name))
1449 syntaxerror("filter %s defined twice", name);
1450 dictionary_put2(&filters, name, filter);
1453 void s_blur(char*name, double blurx, double blury, int passes)
1455 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1456 filter->type = FILTERTYPE_BLUR;
1457 filter->blurx = blurx;
1458 filter->blury = blury;
1459 filter->passes = passes;
1461 if(dictionary_lookup(&filters, name))
1462 syntaxerror("filter %s defined twice", name);
1463 dictionary_put2(&filters, name, filter);
1466 void s_action(const char*text)
1469 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1471 syntaxerror("Couldn't compile ActionScript");
1474 tag = swf_InsertTag(tag, ST_DOACTION);
1476 swf_ActionSet(tag, a);
1481 void s_initaction(const char*character, const char*text)
1485 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1487 syntaxerror("Couldn't compile ActionScript");
1490 c = (character_t*)dictionary_lookup(&characters, character);
1492 tag = swf_InsertTag(tag, ST_DOINITACTION);
1493 swf_SetU16(tag, c->id);
1494 swf_ActionSet(tag, a);
1499 int s_swf3action(char*name, char*action)
1502 instance_t* object = 0;
1504 object = (instance_t*)dictionary_lookup(&instances, name);
1505 if(!object && name && *name) {
1506 /* we have a name, but couldn't find it. Abort. */
1509 a = action_SetTarget(0, name);
1510 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1511 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1512 else if(!strcmp(action, "stop")) a = action_Stop(a);
1513 else if(!strcmp(action, "play")) a = action_Play(a);
1514 a = action_SetTarget(a, "");
1517 tag = swf_InsertTag(tag, ST_DOACTION);
1518 swf_ActionSet(tag, a);
1523 void s_outline(char*name, char*format, char*source)
1532 //swf_Shape10DrawerInit(&draw, 0);
1533 swf_Shape11DrawerInit(&draw, 0);
1535 draw_string(&draw, source);
1537 shape = swf_ShapeDrawerToShape(&draw);
1538 bounds = swf_ShapeDrawerGetBBox(&draw);
1539 draw.dealloc(&draw);
1541 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1542 outline->shape = shape;
1543 outline->bbox = bounds;
1545 if(dictionary_lookup(&outlines, name))
1546 syntaxerror("outline %s defined twice", name);
1547 dictionary_put2(&outlines, name, outline);
1550 int s_playsound(char*name, int loops, int nomultiple, int stop)
1556 sound = dictionary_lookup(&sounds, name);
1560 tag = swf_InsertTag(tag, ST_STARTSOUND);
1561 swf_SetU16(tag, sound->id); //id
1562 memset(&info, 0, sizeof(info));
1565 info.nomultiple = nomultiple;
1566 swf_SetSoundInfo(tag, &info);
1570 void s_includeswf(char*name, char*filename)
1578 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1579 f = open(filename,O_RDONLY|O_BINARY);
1581 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1582 s_box(name, 0, 0, black, 20, 0);
1585 if (swf_ReadSWF(f,&swf)<0) {
1586 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1587 s_box(name, 0, 0, black, 20, 0);
1592 /* FIXME: The following sets the bounding Box for the character.
1593 It is wrong for two reasons:
1594 a) It may be too small (in case objects in the movie clip at the borders)
1595 b) it may be too big (because the poor movie never got autocropped)
1599 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1600 swf_SetU16(tag, id);
1601 swf_SetU16(tag, swf.frameCount);
1603 swf_Relocate(&swf, idmap);
1605 ftag = swf.firstTag;
1609 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1610 if(cutout[t] == ftag->id) {
1614 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1616 if(ftag->id == ST_END)
1621 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
1622 /* We simply dump all tags right after the sprite
1623 header, relying on the fact that swf_OptimizeTagOrder() will
1624 sort things out for us later.
1625 We also rely on the fact that the imported SWF is well-formed.
1627 tag = swf_InsertTag(tag, ftag->id);
1628 swf_SetBlock(tag, ftag->data, ftag->len);
1634 syntaxerror("Included file %s contains errors", filename);
1635 tag = swf_InsertTag(tag, ST_END);
1639 s_addcharacter(name, id, tag, r);
1642 SRECT s_getCharBBox(char*name)
1644 character_t* c = dictionary_lookup(&characters, name);
1645 if(!c) syntaxerror("character '%s' unknown(2)", name);
1648 SRECT s_getInstanceBBox(char*name)
1650 instance_t * i = dictionary_lookup(&instances, name);
1652 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1654 if(!c) syntaxerror("internal error(5)");
1657 parameters_t s_getParameters(char*name)
1659 instance_t * i = dictionary_lookup(&instances, name);
1660 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1661 return i->parameters;
1663 void s_startclip(char*instance, char*character, parameters_t p)
1665 character_t* c = dictionary_lookup(&characters, character);
1669 syntaxerror("character %s not known", character);
1671 i = s_addinstance(instance, c, currentdepth);
1673 m = s_instancepos(i->character->size, &p);
1675 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1676 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1677 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1679 i->lastFrame= currentframe;
1681 stack[stackpos].tag = tag;
1682 stack[stackpos].type = 2;
1691 swf_SetTagPos(stack[stackpos].tag, 0);
1692 swf_GetPlaceObject(stack[stackpos].tag, &p);
1693 p.clipdepth = currentdepth;
1695 swf_ClearTag(stack[stackpos].tag);
1696 swf_SetPlaceObject(stack[stackpos].tag, &p);
1700 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
1704 swf_GetPlaceObject(NULL, &po);
1708 po.cxform = p->cxform;
1714 po.blendmode = p->blendmode;
1718 flist.filter[0] = p->filter;
1719 po.filters = &flist;
1721 swf_SetPlaceObject(tag, &po);
1724 void s_put(char*instance, char*character, parameters_t p)
1726 character_t* c = dictionary_lookup(&characters, character);
1730 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1733 i = s_addinstance(instance, c, currentdepth);
1735 m = s_instancepos(i->character->size, &p);
1737 if(p.blendmode || p.filter) {
1738 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
1740 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1742 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
1745 i->lastFrame = currentframe;
1750 void s_jump(char*instance, parameters_t p)
1752 instance_t* i = dictionary_lookup(&instances, instance);
1755 syntaxerror("instance %s not known", instance);
1759 m = s_instancepos(i->character->size, &p);
1761 if(p.blendmode || p.filter) {
1762 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
1764 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1766 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
1769 i->lastFrame = currentframe;
1772 RGBA interpolateColor(RGBA c1, RGBA c2, float ratio)
1775 c.r = c1.r * (1-ratio) + c2.r * ratio;
1776 c.g = c1.g * (1-ratio) + c2.g * ratio;
1777 c.b = c1.b * (1-ratio) + c2.b * ratio;
1778 c.a = c1.a * (1-ratio) + c2.a * ratio;
1782 FILTER* interpolateFilter(FILTER*filter1,FILTER*filter2, float ratio)
1784 if(!filter1 && !filter2)
1787 return interpolateFilter(filter2,filter1,1-ratio);
1789 if(filter2 && filter2->type != filter1->type)
1790 syntaxerror("can't interpolate between %s and %s filters yet", filtername[filter1->type], filtername[filter2->type]);
1792 if(filter1->type == FILTERTYPE_BLUR) {
1793 FILTER_BLUR*f1 = (FILTER_BLUR*)filter1;
1794 FILTER_BLUR*f2 = (FILTER_BLUR*)filter2;
1795 if(f2 && f1->blurx == f2->blurx && f1->blury == f2->blury)
1797 FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR);
1798 f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
1799 f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
1800 f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
1802 } else if (filter1->type == FILTERTYPE_DROPSHADOW) {
1803 FILTER_DROPSHADOW*f1 = (FILTER_DROPSHADOW*)filter1;
1804 FILTER_DROPSHADOW*f2 = (FILTER_DROPSHADOW*)filter2;
1805 if(f2 && !memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength &&
1806 f1->blurx == f2->blurx && f1->blury == f2->blury &&
1807 f1->angle == f2->angle && f1->distance == f2->distance)
1809 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW);
1810 memcpy(f, f1, sizeof(FILTER_DROPSHADOW));
1811 f->color = interpolateColor(f1->color, f2->color, ratio);
1812 f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
1813 f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
1814 f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
1815 f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio;
1816 f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio;
1817 f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio;
1819 } else if (filter1->type == FILTERTYPE_BEVEL) {
1820 FILTER_BEVEL*f1 = (FILTER_BEVEL*)filter1;
1821 FILTER_BEVEL*f2 = (FILTER_BEVEL*)filter2;
1822 if(f2 && !memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) &&
1823 !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) &&
1824 f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
1826 FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL);
1827 memcpy(f, f1, sizeof(FILTER_BEVEL));
1828 f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio);
1829 f->highlight = interpolateColor(f1->highlight, f2->highlight, ratio);
1830 f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
1831 f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
1832 f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
1833 f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio;
1834 f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio;
1835 f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio;
1837 } /*else if (filter1->type == FILTERTYPE_GRADIENTGLOW) {
1838 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
1839 // can't interpolate gradients
1840 memcpy(f, filter1, sizeof(FILTER_GRADIENTGLOW));
1843 syntaxerror("can't interpolate %s filters yet", filtername[filter1->type]);
1848 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1852 if(num==0 || num==1)
1854 ratio = (float)pos/(float)num;
1856 p.x = (p2->x-p1->x)*ratio + p1->x;
1857 p.y = (p2->y-p1->y)*ratio + p1->y;
1858 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1859 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1860 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1861 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1863 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1864 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1865 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1866 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1868 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1869 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1870 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1871 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1873 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1874 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1875 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1876 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1878 p.filter = interpolateFilter(p1->filter, p2->filter, ratio);
1882 void s_change(char*instance, parameters_t p2)
1884 instance_t* i = dictionary_lookup(&instances, instance);
1888 int frame, allframes;
1890 syntaxerror("instance %s not known", instance);
1894 allframes = currentframe - i->lastFrame - 1;
1896 warning(".change ignored. can only .put/.change an object once per frame.");
1900 m = s_instancepos(i->character->size, &p2);
1901 if(p2.blendmode || p2.filter) {
1902 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
1904 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1906 setPlacement(tag, 0, i->depth, m, 0, &p2, 1);
1909 /* o.k., we got the start and end point set. Now iterate though all the
1910 tags in between, inserting object changes after each new frame */
1913 if(!t) syntaxerror("internal error(6)");
1915 while(frame < allframes) {
1916 if(t->id == ST_SHOWFRAME) {
1921 p = s_interpolate(&p1, &p2, frame, allframes);
1922 m = s_instancepos(i->character->size, &p); //needed?
1924 i->lastFrame = currentframe;
1925 if(p.blendmode || p.filter) {
1926 lt = swf_InsertTag(t, ST_PLACEOBJECT3);
1928 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1930 setPlacement(lt, 0, i->depth, m, 0, &p, 1);
1932 if(frame == allframes)
1937 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1941 void s_delinstance(char*instance)
1943 instance_t* i = dictionary_lookup(&instances, instance);
1945 syntaxerror("instance %s not known", instance);
1947 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1948 swf_SetU16(tag, i->depth);
1949 dictionary_del(&instances, instance);
1952 void s_qchange(char*instance, parameters_t p)
1959 syntaxerror(".end unexpected");
1960 if(stack[stackpos-1].type == 0)
1962 else if(stack[stackpos-1].type == 1)
1964 else if(stack[stackpos-1].type == 2)
1966 else if(stack[stackpos-1].type == 3)
1968 else syntaxerror("internal error 1");
1971 // ------------------------------------------------------------------------
1973 typedef int command_func_t(map_t*args);
1975 SRECT parseBox(char*str)
1977 SRECT r = {0,0,0,0};
1978 float xmin, xmax, ymin, ymax;
1979 char*x = strchr(str, 'x');
1981 if(!strcmp(str, "autocrop")) {
1982 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1986 d1 = strchr(x+1, ':');
1988 d2 = strchr(d1+1, ':');
1990 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1994 else if(d1 && !d2) {
1995 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2001 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2006 r.xmin = (SCOORD)(xmin*20);
2007 r.ymin = (SCOORD)(ymin*20);
2008 r.xmax = (SCOORD)(xmax*20);
2009 r.ymax = (SCOORD)(ymax*20);
2012 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2015 float parseFloat(char*str)
2019 int parseInt(char*str)
2024 if(str[0]=='+' || str[0]=='-')
2028 if(str[t]<'0' || str[t]>'9')
2029 syntaxerror("Not an Integer: \"%s\"", str);
2032 int parseTwip(char*str)
2036 if(str[0]=='+' || str[0]=='-') {
2041 dot = strchr(str, '.');
2045 return sign*parseInt(str)*20;
2047 char* old = strdup(str);
2048 int l=strlen(dot+1);
2051 for(s=str;s<dot-1;s++)
2052 if(*s<'0' || *s>'9')
2053 syntaxerror("Not a coordinate: \"%s\"", str);
2055 if(*s<'0' || *s>'9')
2056 syntaxerror("Not a coordinate: \"%s\"", str);
2058 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2059 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2062 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2066 return sign*atoi(str)*20;
2068 return sign*atoi(str)*20+atoi(dot)*2;
2070 return sign*atoi(str)*20+atoi(dot)/5;
2075 int isPoint(char*str)
2077 if(strchr(str, '('))
2083 SPOINT parsePoint(char*str)
2087 int l = strlen(str);
2088 char*comma = strchr(str, ',');
2089 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2090 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2091 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2092 p.x = parseTwip(tmp);
2093 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2094 p.y = parseTwip(tmp);
2098 int parseColor2(char*str, RGBA*color)
2100 int l = strlen(str);
2104 struct {unsigned char r,g,b;char*name;} colors[] =
2105 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2106 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2107 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2108 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2109 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2110 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2111 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2112 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2113 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2114 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2115 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2116 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2120 if(str[0]=='#' && (l==7 || l==9)) {
2121 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2123 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2125 color->r = r; color->g = g; color->b = b; color->a = a;
2128 int len=strlen(str);
2130 if(strchr(str, '/')) {
2131 len = strchr(str, '/')-str;
2132 sscanf(str+len+1,"%02x", &alpha);
2134 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2135 if(!strncmp(str, colors[t].name, len)) {
2140 color->r = r; color->g = g; color->b = b; color->a = a;
2146 RGBA parseColor(char*str)
2149 if(!parseColor2(str, &c))
2150 syntaxerror("Expression '%s' is not a color", str);
2154 typedef struct _muladd {
2159 MULADD parseMulAdd(char*str)
2162 char* str2 = (char*)malloc(strlen(str)+5);
2169 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2170 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2171 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2172 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2173 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2174 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2175 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2176 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2177 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2178 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2180 syntaxerror("'%s' is not a valid color transform expression", str);
2182 m.add = (int)(add*256);
2183 m.mul = (int)(mul*256);
2188 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2190 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2191 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2193 if(a<-32768) a=-32768;
2194 if(a>32767) a=32767;
2195 if(m<-32768) m=-32768;
2196 if(m>32767) m=32767;
2202 float parsePxOrPercent(char*fontname, char*str)
2204 int l = strlen(str);
2205 if(strchr(str, '%'))
2206 return parsePercent(str);
2207 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2208 float p = atof(str);
2209 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2211 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2215 float parsePercent(char*str)
2217 int l = strlen(str);
2221 return atoi(str)/100.0;
2223 syntaxerror("Expression '%s' is not a percentage", str);
2226 int isPercent(char*str)
2228 return str[strlen(str)-1]=='%';
2230 int parseNewSize(char*str, int size)
2233 return parsePercent(str)*size;
2235 return (int)(atof(str)*20);
2238 int isColor(char*str)
2241 return parseColor2(str, &c);
2244 static char* lu(map_t* args, char*name)
2246 char* value = map_lookup(args, name);
2248 map_dump(args, stdout, "");
2249 syntaxerror("internal error 2: value %s should be set", name);
2254 static int c_flash(map_t*args)
2256 char* filename = map_lookup(args, "filename");
2257 char* compressstr = lu(args, "compress");
2258 SRECT bbox = parseBox(lu(args, "bbox"));
2259 int version = parseInt(lu(args, "version"));
2260 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2262 RGBA color = parseColor(lu(args, "background"));
2264 if(!filename || !*filename) {
2265 /* for compatibility */
2266 filename = map_lookup(args, "name");
2267 if(!filename || !*filename) {
2270 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2271 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2275 if(!filename || override_outputname)
2276 filename = outputname;
2278 if(!strcmp(compressstr, "default"))
2279 compress = version>=6;
2280 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2282 else if(!strcmp(compressstr, "no"))
2284 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2286 s_swf(filename, bbox, version, fps, compress, color);
2289 int isRelative(char*str)
2291 return !strncmp(str, "<plus>", 6) ||
2292 !strncmp(str, "<minus>", 7);
2294 char* getOffset(char*str)
2296 if(!strncmp(str, "<plus>", 6))
2298 if(!strncmp(str, "<minus>", 7))
2300 syntaxerror("internal error (347)");
2303 int getSign(char*str)
2305 if(!strncmp(str, "<plus>", 6))
2307 if(!strncmp(str, "<minus>", 7))
2309 syntaxerror("internal error (348)");
2312 static dictionary_t points;
2313 static mem_t mpoints;
2314 int points_initialized = 0;
2316 SPOINT getPoint(SRECT r, char*name)
2319 if(!strcmp(name, "center")) {
2321 p.x = (r.xmin + r.xmax)/2;
2322 p.y = (r.ymin + r.ymax)/2;
2326 if(points_initialized)
2327 l = (int)dictionary_lookup(&points, name);
2329 syntaxerror("Invalid point: \"%s\".", name);
2332 return *(SPOINT*)&mpoints.buffer[l];
2335 static int texture2(char*name, char*object, map_t*args, int errors)
2338 char*xstr = map_lookup(args, "x");
2339 char*ystr = map_lookup(args, "y");
2340 char*widthstr = map_lookup(args, "width");
2341 char*heightstr = map_lookup(args, "height");
2342 char*scalestr = map_lookup(args, "scale");
2343 char*scalexstr = map_lookup(args, "scalex");
2344 char*scaleystr = map_lookup(args, "scaley");
2345 char*rotatestr = map_lookup(args, "rotate");
2346 char* shearstr = map_lookup(args, "shear");
2347 char* radiusstr = map_lookup(args, "r");
2349 float scalex = 1.0, scaley = 1.0;
2350 float rotate=0, shear=0;
2352 if(!*xstr && !*ystr) {
2354 syntaxerror("x and y must be set");
2357 if(*scalestr && (*scalexstr || *scaleystr)) {
2358 syntaxerror("scale and scalex/scaley can't both be set");
2361 if((*widthstr || *heightstr) && *radiusstr) {
2362 syntaxerror("width/height and radius can't both be set");
2365 widthstr = radiusstr;
2366 heightstr = radiusstr;
2368 if(!*xstr) xstr="0";
2369 if(!*ystr) ystr="0";
2370 if(!*rotatestr) rotatestr="0";
2371 if(!*shearstr) shearstr="0";
2374 scalex = scaley = parsePercent(scalestr);
2375 } else if(*scalexstr || *scaleystr) {
2376 if(scalexstr) scalex = parsePercent(scalexstr);
2377 if(scaleystr) scaley = parsePercent(scaleystr);
2378 } else if(*widthstr || *heightstr) {
2381 s_getBitmapSize(object, &width, &height);
2383 scalex = (float)parseTwip(widthstr)/(float)width;
2385 scaley = (float)parseTwip(heightstr)/(float)height;
2387 x = parseTwip(xstr);
2388 y = parseTwip(ystr);
2389 rotate = parseFloat(rotatestr);
2390 shear = parseFloat(shearstr);
2392 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2397 static int c_texture(map_t*args)
2399 char*name = lu(args, "instance");
2400 char*object = lu(args, "character");
2401 return texture2(name, object, args, 1);
2404 static int c_gradient(map_t*args)
2406 char*name = lu(args, "name");
2407 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2408 int rotate = parseInt(lu(args, "rotate"));
2412 syntaxerror("colon (:) expected");
2414 s_gradient(name, text, radial, rotate);
2416 /* check whether we also have placement information,
2417 which would make this a positioned gradient.
2418 If there is placement information, texture2() will
2419 add a texture, which has priority over the gradient.
2421 texture2(name, name, args, 0);
2425 static int c_blur(map_t*args)
2427 char*name = lu(args, "name");
2428 char*blurstr = lu(args, "blur");
2429 char*blurxstr = lu(args, "blurx");
2430 char*blurystr = lu(args, "blury");
2431 float blurx=1.0, blury=1.0;
2433 blurx = parseFloat(blurstr);
2434 blury = parseFloat(blurstr);
2437 blurx = parseFloat(blurxstr);
2439 blury = parseFloat(blurystr);
2440 int passes = parseInt(lu(args, "passes"));
2441 s_blur(name, blurx, blury, passes);
2445 static int c_gradientglow(map_t*args)
2447 char*name = lu(args, "name");
2448 char*gradient = lu(args, "gradient");
2449 char*blurstr = lu(args, "blur");
2450 char*blurxstr = lu(args, "blurx");
2451 char*blurystr = lu(args, "blury");
2452 float blurx=1.0, blury=1.0;
2454 blurx = parseFloat(blurstr);
2455 blury = parseFloat(blurstr);
2458 blurx = parseFloat(blurxstr);
2460 blury = parseFloat(blurystr);
2462 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2463 float distance = parseFloat(lu(args, "distance"));
2464 float strength = parseFloat(lu(args, "strength"));
2465 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2466 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2467 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2468 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2469 int passes = parseInt(lu(args, "passes"));
2471 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2475 static int c_dropshadow(map_t*args)
2477 char*name = lu(args, "name");
2478 RGBA color = parseColor(lu(args, "color"));
2479 char*blurstr = lu(args, "blur");
2480 char*blurxstr = lu(args, "blurx");
2481 char*blurystr = lu(args, "blury");
2482 float blurx=1.0, blury=1.0;
2484 blurx = parseFloat(blurstr);
2485 blury = parseFloat(blurstr);
2488 blurx = parseFloat(blurxstr);
2490 blury = parseFloat(blurystr);
2492 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2493 float distance = parseFloat(lu(args, "distance"));
2494 float strength = parseFloat(lu(args, "strength"));
2495 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2496 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2497 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2498 int passes = parseInt(lu(args, "passes"));
2500 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2504 static int c_bevel(map_t*args)
2506 char*name = lu(args, "name");
2507 RGBA shadow = parseColor(lu(args, "shadow"));
2508 RGBA highlight = parseColor(lu(args, "highlight"));
2509 char*blurstr = lu(args, "blur");
2510 char*blurxstr = lu(args, "blurx");
2511 char*blurystr = lu(args, "blury");
2512 float blurx=1.0, blury=1.0;
2514 blurx = parseFloat(blurstr);
2515 blury = parseFloat(blurstr);
2518 blurx = parseFloat(blurxstr);
2520 blury = parseFloat(blurystr);
2522 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2523 float distance = parseFloat(lu(args, "distance"));
2524 float strength = parseFloat(lu(args, "strength"));
2525 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2526 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2527 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2528 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2529 int passes = parseInt(lu(args, "passes"));
2531 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2535 static int c_point(map_t*args)
2537 char*name = lu(args, "name");
2541 if(!points_initialized) {
2542 dictionary_init(&points);
2544 points_initialized = 1;
2546 p.x = parseTwip(lu(args, "x"));
2547 p.y = parseTwip(lu(args, "y"));
2548 pos = mem_put(&mpoints, &p, sizeof(p));
2549 string_set(&s1, name);
2551 dictionary_put(&points, s1, (void*)pos);
2554 static int c_play(map_t*args)
2556 char*name = lu(args, "name");
2557 char*loop = lu(args, "loop");
2558 char*nomultiple = lu(args, "nomultiple");
2560 if(!strcmp(nomultiple, "nomultiple"))
2563 nm = parseInt(nomultiple);
2565 if(s_playsound(name, parseInt(loop), nm, 0)) {
2567 } else if(s_swf3action(name, "play")) {
2573 static int c_stop(map_t*args)
2575 char*name = map_lookup(args, "name");
2577 if(s_playsound(name, 0,0,1)) {
2579 } else if(s_swf3action(name, "stop")) {
2582 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2586 static int c_nextframe(map_t*args)
2588 char*name = lu(args, "name");
2590 if(s_swf3action(name, "nextframe")) {
2593 syntaxerror("I don't know anything about movie \"%s\"", name);
2597 static int c_previousframe(map_t*args)
2599 char*name = lu(args, "name");
2601 if(s_swf3action(name, "previousframe")) {
2604 syntaxerror("I don't know anything about movie \"%s\"", name);
2608 static int c_placement(map_t*args, int type)
2610 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2613 char* luminancestr = lu(args, "luminance");
2614 char* scalestr = lu(args, "scale");
2615 char* scalexstr = lu(args, "scalex");
2616 char* scaleystr = lu(args, "scaley");
2617 char* rotatestr = lu(args, "rotate");
2618 char* shearstr = lu(args, "shear");
2619 char* xstr="", *pivotstr="";
2620 char* ystr="", *anglestr="";
2621 char*above = lu(args, "above"); /*FIXME*/
2622 char*below = lu(args, "below");
2623 char* rstr = lu(args, "red");
2624 char* gstr = lu(args, "green");
2625 char* bstr = lu(args, "blue");
2626 char* astr = lu(args, "alpha");
2627 char* pinstr = lu(args, "pin");
2628 char* as = map_lookup(args, "as");
2629 char* blendmode = lu(args, "blend");
2630 char*filterstr = lu(args, "filter");
2639 if(type==9) { // (?) .rotate or .arcchange
2640 pivotstr = lu(args, "pivot");
2641 anglestr = lu(args, "angle");
2643 xstr = lu(args, "x");
2644 ystr = lu(args, "y");
2647 luminance = parseMulAdd(luminancestr);
2650 luminance.mul = 256;
2654 if(scalexstr[0]||scaleystr[0])
2655 syntaxerror("scalex/scaley and scale cannot both be set");
2656 scalexstr = scaleystr = scalestr;
2659 if(type == 0 || type == 4) {
2661 character = lu(args, "character");
2662 parameters_clear(&p);
2663 } else if (type == 5) {
2664 character = lu(args, "name");
2665 parameters_clear(&p);
2668 p = s_getParameters(instance);
2673 if(isRelative(xstr)) {
2674 if(type == 0 || type == 4)
2675 syntaxerror("relative x values not allowed for initial put or startclip");
2676 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2678 p.x = parseTwip(xstr);
2682 if(isRelative(ystr)) {
2683 if(type == 0 || type == 4)
2684 syntaxerror("relative y values not allowed for initial put or startclip");
2685 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2687 p.y = parseTwip(ystr);
2691 /* scale, scalex, scaley */
2693 oldbbox = s_getCharBBox(character);
2695 oldbbox = s_getInstanceBBox(instance);
2697 oldwidth = oldbbox.xmax - oldbbox.xmin;
2698 oldheight = oldbbox.ymax - oldbbox.ymin;
2700 if(oldwidth==0) p.scalex = 1.0;
2703 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2707 if(oldheight==0) p.scaley = 1.0;
2710 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2716 if(isRelative(rotatestr)) {
2717 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2719 p.rotate = parseFloat(rotatestr);
2725 if(isRelative(shearstr)) {
2726 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2728 p.shear = parseFloat(shearstr);
2733 if(isPoint(pivotstr))
2734 p.pivot = parsePoint(pivotstr);
2736 p.pivot = getPoint(oldbbox, pivotstr);
2740 p.pin = parsePoint(pinstr);
2742 p.pin = getPoint(oldbbox, pinstr);
2745 /* color transform */
2747 if(rstr[0] || luminancestr[0]) {
2750 r = parseMulAdd(rstr);
2752 r.add = p.cxform.r0;
2753 r.mul = p.cxform.r1;
2755 r = mergeMulAdd(r, luminance);
2756 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2758 if(gstr[0] || luminancestr[0]) {
2761 g = parseMulAdd(gstr);
2763 g.add = p.cxform.g0;
2764 g.mul = p.cxform.g1;
2766 g = mergeMulAdd(g, luminance);
2767 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2769 if(bstr[0] || luminancestr[0]) {
2772 b = parseMulAdd(bstr);
2774 b.add = p.cxform.b0;
2775 b.mul = p.cxform.b1;
2777 b = mergeMulAdd(b, luminance);
2778 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2781 MULADD a = parseMulAdd(astr);
2782 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2788 for(t=0;blendModeNames[t];t++) {
2789 if(!strcmp(blendModeNames[t], blendmode)) {
2795 syntaxerror("unknown blend mode: '%s'", blendmode);
2797 p.blendmode = blend;
2801 FILTER*f = dictionary_lookup(&filters, filterstr);
2803 syntaxerror("Unknown filter %s", filterstr);
2809 s_put(instance, character, p);
2811 s_change(instance, p);
2813 s_qchange(instance, p);
2815 s_jump(instance, p);
2817 s_startclip(instance, character, p);
2818 else if(type == 5) {
2820 s_buttonput(character, as, p);
2822 s_buttonput(character, "shape", p);
2827 static int c_put(map_t*args)
2829 c_placement(args, 0);
2832 static int c_change(map_t*args)
2834 c_placement(args, 1);
2837 static int c_qchange(map_t*args)
2839 c_placement(args, 2);
2842 static int c_arcchange(map_t*args)
2844 c_placement(args, 2);
2847 static int c_jump(map_t*args)
2849 c_placement(args, 3);
2852 static int c_startclip(map_t*args)
2854 c_placement(args, 4);
2857 static int c_show(map_t*args)
2859 c_placement(args, 5);
2862 static int c_del(map_t*args)
2864 char*instance = lu(args, "name");
2865 s_delinstance(instance);
2868 static int c_end(map_t*args)
2873 static int c_sprite(map_t*args)
2875 char* name = lu(args, "name");
2879 static int c_frame(map_t*args)
2881 char*framestr = lu(args, "n");
2882 char*cutstr = lu(args, "cut");
2884 char*name = lu(args, "name");
2885 char*anchor = lu(args, "anchor");
2888 if(!strcmp(anchor, "anchor") && !*name)
2893 if(strcmp(cutstr, "no"))
2895 if(isRelative(framestr)) {
2896 frame = s_getframe();
2897 if(getSign(framestr)<0)
2898 syntaxerror("relative frame expressions must be positive");
2899 frame += parseInt(getOffset(framestr));
2902 frame = parseInt(framestr);
2903 if(s_getframe() >= frame
2904 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2905 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2907 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
2910 static int c_primitive(map_t*args)
2912 char*name = lu(args, "name");
2913 char*command = lu(args, "commandname");
2914 int width=0, height=0, r=0;
2915 int linewidth = parseTwip(lu(args, "line"));
2916 char*colorstr = lu(args, "color");
2917 RGBA color = parseColor(colorstr);
2918 char*fillstr = lu(args, "fill");
2925 if(!strcmp(command, "circle"))
2927 else if(!strcmp(command, "filled"))
2931 width = parseTwip(lu(args, "width"));
2932 height = parseTwip(lu(args, "height"));
2933 } else if (type==1) {
2934 r = parseTwip(lu(args, "r"));
2935 } else if (type==2) {
2936 outline = lu(args, "outline");
2939 if(!strcmp(fillstr, "fill"))
2941 if(!strcmp(fillstr, "none"))
2943 if(width<0 || height<0 || linewidth<0 || r<0)
2944 syntaxerror("values width, height, line, r must be positive");
2946 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2947 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2948 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2952 static int c_textshape(map_t*args)
2954 char*name = lu(args, "name");
2955 char*text = lu(args, "text");
2956 char*font = lu(args, "font");
2957 float size = parsePxOrPercent(font, lu(args, "size"));
2959 s_textshape(name, font, size, text);
2963 static int c_swf(map_t*args)
2965 char*name = lu(args, "name");
2966 char*filename = lu(args, "filename");
2967 char*command = lu(args, "commandname");
2968 if(!strcmp(command, "shape"))
2969 warning("Please use .swf instead of .shape");
2970 s_includeswf(name, filename);
2974 static int c_font(map_t*args)
2976 char*name = lu(args, "name");
2977 char*filename = lu(args, "filename");
2978 s_font(name, filename);
2982 static int c_sound(map_t*args)
2984 char*name = lu(args, "name");
2985 char*filename = lu(args, "filename");
2986 s_sound(name, filename);
2990 static int c_text(map_t*args)
2992 char*name = lu(args, "name");
2993 char*text = lu(args, "text");
2994 char*font = lu(args, "font");
2995 float size = parsePxOrPercent(font, lu(args, "size"));
2996 RGBA color = parseColor(lu(args, "color"));
2997 s_text(name, font, text, (int)(size*100), color);
3001 static int c_soundtrack(map_t*args)
3006 static int c_quicktime(map_t*args)
3008 char*name = lu(args, "name");
3009 char*url = lu(args, "url");
3010 s_quicktime(name, url);
3014 static int c_image(map_t*args)
3016 char*command = lu(args, "commandname");
3017 char*name = lu(args, "name");
3018 char*filename = lu(args, "filename");
3019 if(!strcmp(command,"jpeg")) {
3020 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3021 s_image(name, "jpeg", filename, quality);
3023 s_image(name, "png", filename, 0);
3028 static int c_outline(map_t*args)
3030 char*name = lu(args, "name");
3031 char*format = lu(args, "format");
3035 syntaxerror("colon (:) expected");
3037 s_outline(name, format, text);
3041 int fakechar(map_t*args)
3043 char*name = lu(args, "name");
3044 s_box(name, 0, 0, black, 20, 0);
3048 static int c_egon(map_t*args) {return fakechar(args);}
3049 static int c_button(map_t*args) {
3050 char*name = lu(args, "name");
3054 static int current_button_flags = 0;
3055 static int c_on_press(map_t*args)
3057 char*position = lu(args, "position");
3059 if(!strcmp(position, "inside")) {
3060 current_button_flags |= BC_OVERUP_OVERDOWN;
3061 } else if(!strcmp(position, "outside")) {
3062 //current_button_flags |= BC_IDLE_OUTDOWN;
3063 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3064 } else if(!strcmp(position, "anywhere")) {
3065 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3068 if(type == RAWDATA) {
3070 s_buttonaction(current_button_flags, action);
3071 current_button_flags = 0;
3077 static int c_on_release(map_t*args)
3079 char*position = lu(args, "position");
3081 if(!strcmp(position, "inside")) {
3082 current_button_flags |= BC_OVERDOWN_OVERUP;
3083 } else if(!strcmp(position, "outside")) {
3084 current_button_flags |= BC_OUTDOWN_IDLE;
3085 } else if(!strcmp(position, "anywhere")) {
3086 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3089 if(type == RAWDATA) {
3091 s_buttonaction(current_button_flags, action);
3092 current_button_flags = 0;
3098 static int c_on_move_in(map_t*args)
3100 char*position = lu(args, "state");
3102 if(!strcmp(position, "pressed")) {
3103 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3104 } else if(!strcmp(position, "not_pressed")) {
3105 current_button_flags |= BC_IDLE_OVERUP;
3106 } else if(!strcmp(position, "any")) {
3107 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3110 if(type == RAWDATA) {
3112 s_buttonaction(current_button_flags, action);
3113 current_button_flags = 0;
3119 static int c_on_move_out(map_t*args)
3121 char*position = lu(args, "state");
3123 if(!strcmp(position, "pressed")) {
3124 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3125 } else if(!strcmp(position, "not_pressed")) {
3126 current_button_flags |= BC_OVERUP_IDLE;
3127 } else if(!strcmp(position, "any")) {
3128 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3131 if(type == RAWDATA) {
3133 s_buttonaction(current_button_flags, action);
3134 current_button_flags = 0;
3140 static int c_on_key(map_t*args)
3142 char*key = lu(args, "key");
3144 if(strlen(key)==1) {
3147 current_button_flags |= 0x4000 + (key[0]*0x200);
3149 syntaxerror("invalid character: %c"+key[0]);
3154 <ctrl-x> = 0x200*(x-'a')
3158 syntaxerror("invalid key: %s",key);
3161 if(type == RAWDATA) {
3163 s_buttonaction(current_button_flags, action);
3164 current_button_flags = 0;
3171 static int c_edittext(map_t*args)
3173 //"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"},
3174 char*name = lu(args, "name");
3175 char*font = lu(args, "font");
3176 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3177 int width = parseTwip(lu(args, "width"));
3178 int height = parseTwip(lu(args, "height"));
3179 char*text = lu(args, "text");
3180 RGBA color = parseColor(lu(args, "color"));
3181 int maxlength = parseInt(lu(args, "maxlength"));
3182 char*variable = lu(args, "variable");
3183 char*passwordstr = lu(args, "password");
3184 char*wordwrapstr = lu(args, "wordwrap");
3185 char*multilinestr = lu(args, "multiline");
3186 char*htmlstr = lu(args, "html");
3187 char*noselectstr = lu(args, "noselect");
3188 char*readonlystr = lu(args, "readonly");
3189 char*borderstr = lu(args, "border");
3190 char*autosizestr = lu(args, "autosize");
3191 char*alignstr = lu(args, "align");
3195 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3196 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3197 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3198 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3199 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3200 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3201 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3202 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3203 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3204 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3205 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3206 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3207 else syntaxerror("Unknown alignment: %s", alignstr);
3209 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3213 static int c_morphshape(map_t*args) {return fakechar(args);}
3214 static int c_movie(map_t*args) {return fakechar(args);}
3216 static char* readfile(const char*filename)
3218 FILE*fi = fopen(filename, "rb");
3222 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3223 fseek(fi, 0, SEEK_END);
3225 fseek(fi, 0, SEEK_SET);
3226 text = rfx_alloc(l+1);
3227 fread(text, l, 1, fi);
3233 static int c_action(map_t*args)
3235 char* filename = map_lookup(args, "filename");
3236 if(!filename ||!*filename) {
3238 if(type != RAWDATA) {
3239 syntaxerror("colon (:) expected");
3243 s_action(readfile(filename));
3249 static int c_initaction(map_t*args)
3251 char* character = lu(args, "name");
3252 char* filename = map_lookup(args, "filename");
3253 if(!filename ||!*filename) {
3255 if(type != RAWDATA) {
3256 syntaxerror("colon (:) expected");
3258 s_initaction(character, text);
3260 s_initaction(character, readfile(filename));
3268 command_func_t* func;
3271 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
3272 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3273 // "import" type stuff
3274 {"swf", c_swf, "name filename"},
3275 {"shape", c_swf, "name filename"},
3276 {"jpeg", c_image, "name filename quality=80%"},
3277 {"png", c_image, "name filename"},
3278 {"movie", c_movie, "name filename"},
3279 {"sound", c_sound, "name filename"},
3280 {"font", c_font, "name filename"},
3281 {"soundtrack", c_soundtrack, "filename"},
3282 {"quicktime", c_quicktime, "url"},
3284 // generators of primitives
3286 {"point", c_point, "name x=0 y=0"},
3287 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3288 {"outline", c_outline, "name format=simple"},
3289 {"textshape", c_textshape, "name font size=100% text"},
3292 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3293 {"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"},
3294 {"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"},
3295 {"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"},
3297 // character generators
3298 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3299 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3300 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3302 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3303 {"text", c_text, "name text font size=100% color=white"},
3304 {"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="},
3305 {"morphshape", c_morphshape, "name start end"},
3306 {"button", c_button, "name"},
3307 {"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="},
3308 {"on_press", c_on_press, "position=inside"},
3309 {"on_release", c_on_release, "position=anywhere"},
3310 {"on_move_in", c_on_move_in, "state=not_pressed"},
3311 {"on_move_out", c_on_move_out, "state=not_pressed"},
3312 {"on_key", c_on_key, "key=any"},
3315 {"play", c_play, "name loop=0 @nomultiple=0"},
3316 {"stop", c_stop, "name= "},
3317 {"nextframe", c_nextframe, "name"},
3318 {"previousframe", c_previousframe, "name"},
3320 // object placement tags
3321 {"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="},
3322 {"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="},
3323 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3324 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3325 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3326 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3327 {"del", c_del, "name"},
3328 // virtual object placement
3329 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3331 // commands which start a block
3332 //startclip (see above)
3333 {"sprite", c_sprite, "name"},
3334 {"action", c_action, "filename="},
3335 {"initaction", c_initaction, "name filename="},
3341 static map_t parseArguments(char*command, char*pattern)
3357 string_set(&t1, "commandname");
3358 string_set(&t2, command);
3359 map_put(&result, t1, t2);
3361 if(!pattern || !*pattern)
3368 if(!strncmp("<i> ", x, 3)) {
3370 if(type == COMMAND || type == RAWDATA) {
3372 syntaxerror("character name expected");
3374 name[pos].str = "instance";
3376 value[pos].str = text;
3377 value[pos].len = strlen(text);
3381 if(type == ASSIGNMENT)
3384 name[pos].str = "character";
3386 value[pos].str = text;
3387 value[pos].len = strlen(text);
3395 isboolean[pos] = (x[0] =='@');
3408 name[pos].len = d-x;
3413 name[pos].len = e-x;
3414 value[pos].str = e+1;
3415 value[pos].len = d-e-1;
3423 /* for(t=0;t<len;t++) {
3424 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
3425 isboolean[t]?"(boolean)":"");
3430 if(type == RAWDATA || type == COMMAND) {
3435 // first, search for boolean arguments
3436 for(pos=0;pos<len;pos++)
3438 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
3440 if(type == ASSIGNMENT)
3442 value[pos].str = text;
3443 value[pos].len = strlen(text);
3444 /*printf("setting boolean parameter %s (to %s)\n",
3445 strdup_n(name[pos], namelen[pos]),
3446 strdup_n(value[pos], valuelen[pos]));*/
3451 // second, search for normal arguments
3453 for(pos=0;pos<len;pos++)
3455 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3456 (type != ASSIGNMENT && !set[pos])) {
3458 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3460 if(type == ASSIGNMENT)
3463 value[pos].str = text;
3464 value[pos].len = strlen(text);
3466 printf("setting parameter %s (to %s)\n",
3467 strdup_n(name[pos].str, name[pos].len),
3468 strdup_n(value[pos].str, value[pos].len));
3474 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3478 for(t=0;t<len;t++) {
3479 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3482 for(t=0;t<len;t++) {
3483 if(value[t].str && value[t].str[0] == '*') {
3484 //relative default- take value from some other parameter
3486 for(s=0;s<len;s++) {
3487 if(value[s].len == value[t].len-1 &&
3488 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3489 value[t].str = value[s].str;
3492 if(value[t].str == 0) {
3494 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3498 /* ok, now construct the dictionary from the parameters */
3502 map_put(&result, name[t], value[t]);
3506 static void parseArgumentsForCommand(char*command)
3511 msg("<verbose> parse Command: %s (line %d)", command, line);
3513 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3514 if(!strcmp(arguments[t].command, command)) {
3516 /* ugly hack- will be removed soon (once documentation and .sc generating
3517 utilities have been changed) */
3518 if(!strcmp(command, "swf") && !stackpos) {
3519 warning("Please use .flash instead of .swf- this will be mandatory soon");
3524 args = parseArguments(command, arguments[t].arguments);
3530 syntaxerror("command %s not known", command);
3532 // catch missing .flash directives at the beginning of a file
3533 if(strcmp(command, "flash") && !stackpos)
3535 syntaxerror("No movie defined- use .flash first");
3539 printf(".%s\n", command);fflush(stdout);
3540 map_dump(&args, stdout, "\t");fflush(stdout);
3543 (*arguments[nr].func)(&args);
3545 /*if(!strcmp(command, "button") ||
3546 !strcmp(command, "action")) {
3549 if(type == COMMAND) {
3550 if(!strcmp(text, "end"))
3564 int main (int argc,char ** argv)
3567 processargs(argc, argv);
3568 initLog(0,-1,0,0,-1,verbose);
3571 args_callback_usage(argv[0]);
3575 file = generateTokens(filename);
3577 fprintf(stderr, "parser returned error.\n");
3583 while(!noMoreTokens()) {
3586 syntaxerror("command expected");
3587 parseArgumentsForCommand(text);