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);
1156 if(dictionary_lookup(&textures, name))
1157 syntaxerror("texture %s defined twice", name);
1158 dictionary_put2(&textures, name, texture);
1161 void dumpSWF(SWF*swf)
1163 TAG* tag = swf->firstTag;
1164 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1166 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1169 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1172 void s_font(char*name, char*filename)
1175 font = swf_LoadFont(filename);
1178 warning("Couldn't open font file \"%s\"", filename);
1179 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1180 memset(font, 0, sizeof(SWFFONT));
1181 dictionary_put2(&fonts, name, font);
1187 /* fix the layout. Only needed for old fonts */
1189 for(t=0;t<font->numchars;t++) {
1190 font->glyph[t].advance = 0;
1193 swf_FontCreateLayout(font);
1195 /* just in case this thing is used in .edittext later on */
1196 swf_FontPrepareForEditText(font);
1199 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1200 swf_FontSetDefine2(tag, font);
1201 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1203 swf_SetU16(tag, id);
1204 swf_SetString(tag, name);
1207 if(dictionary_lookup(&fonts, name))
1208 syntaxerror("font %s defined twice", name);
1209 dictionary_put2(&fonts, name, font);
1214 typedef struct _sound_t
1220 void s_sound(char*name, char*filename)
1222 struct WAV wav, wav2;
1226 unsigned numsamples;
1227 unsigned blocksize = 1152;
1230 if(wav_read(&wav, filename)) {
1232 wav_convert2mono(&wav, &wav2, 44100);
1233 samples = (U16*)wav2.data;
1234 numsamples = wav2.size/2;
1236 #ifdef WORDS_BIGENDIAN
1238 for(t=0;t<numsamples;t++) {
1239 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1242 } else if(mp3_read(&mp3, filename)) {
1243 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1249 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1254 if(numsamples%blocksize != 0)
1256 // apply padding, so that block is a multiple of blocksize
1257 int numblocks = (numsamples+blocksize-1)/blocksize;
1260 numsamples2 = numblocks * blocksize;
1261 samples2 = malloc(sizeof(U16)*numsamples2);
1262 memcpy(samples2, samples, numsamples*sizeof(U16));
1263 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1264 numsamples = numsamples2;
1268 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1269 swf_SetU16(tag, id); //id
1272 swf_SetSoundDefineMP3(
1273 tag, mp3.data, mp3.size,
1281 swf_SetSoundDefine(tag, samples, numsamples);
1284 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1285 swf_SetU16(tag, id);
1286 swf_SetString(tag, name);
1287 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1289 swf_SetU16(tag, id);
1290 swf_SetString(tag, name);
1292 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1296 if(dictionary_lookup(&sounds, name))
1297 syntaxerror("sound %s defined twice", name);
1298 dictionary_put2(&sounds, name, sound);
1306 static char* gradient_getToken(const char**p)
1310 while(**p && strchr(" \t\n\r", **p)) {
1314 while(**p && !strchr(" \t\n\r", **p)) {
1317 result = malloc((*p)-start+1);
1318 memcpy(result,start,(*p)-start+1);
1319 result[(*p)-start] = 0;
1323 float parsePercent(char*str);
1324 RGBA parseColor(char*str);
1326 GRADIENT parseGradient(const char*str)
1330 const char* p = str;
1331 memset(&gradient, 0, sizeof(GRADIENT));
1332 gradient.ratios = rfx_calloc(16*sizeof(U8));
1333 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1335 char*posstr,*colorstr;
1338 posstr = gradient_getToken(&p);
1341 pos = (int)(parsePercent(posstr)*255.0);
1344 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1345 colorstr = gradient_getToken(&p);
1346 color = parseColor(colorstr);
1347 if(gradient.num == 16) {
1348 warning("gradient record too big- max size is 16, rest ignored");
1351 gradient.ratios[gradient.num] = pos;
1352 gradient.rgba[gradient.num] = color;
1361 void s_gradient(char*name, const char*text, int radial, int rotate)
1363 gradient_t* gradient;
1364 gradient = malloc(sizeof(gradient_t));
1365 memset(gradient, 0, sizeof(gradient_t));
1366 gradient->gradient = parseGradient(text);
1367 gradient->radial = radial;
1368 gradient->rotate = rotate;
1370 if(dictionary_lookup(&gradients, name))
1371 syntaxerror("gradient %s defined twice", name);
1372 dictionary_put2(&gradients, name, gradient);
1375 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1376 float angle, float distance, float strength, char innershadow,
1377 char knockout, char composite, char ontop, int passes)
1379 gradient_t* g = dictionary_lookup(&gradients, gradient);
1384 syntaxerror("unknown gradient %s", gradient);
1385 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1386 filter->type = FILTERTYPE_GRADIENTGLOW;
1387 filter->gradient = &g->gradient;
1388 filter->blurx = blurx;
1389 filter->blury = blury;
1390 filter->strength = strength;
1391 filter->angle = angle;
1392 filter->distance = distance;
1393 filter->innershadow = innershadow;
1394 filter->knockout = knockout;
1395 filter->composite = composite;
1396 filter->ontop = ontop;
1397 filter->passes = passes;
1399 if(dictionary_lookup(&filters, name))
1400 syntaxerror("filter %s defined twice", name);
1401 dictionary_put2(&filters, name, filter);
1404 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)
1407 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1408 filter->type = FILTERTYPE_DROPSHADOW;
1409 filter->color= color;
1410 filter->blurx = blurx;
1411 filter->blury = blury;
1412 filter->strength = strength;
1413 filter->angle = angle;
1414 filter->distance = distance;
1415 filter->innershadow = innershadow;
1416 filter->knockout = knockout;
1417 filter->composite = composite;
1418 filter->passes = passes;
1420 if(dictionary_lookup(&filters, name))
1421 syntaxerror("filter %s defined twice", name);
1422 dictionary_put2(&filters, name, filter);
1425 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)
1428 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1429 filter->type = FILTERTYPE_BEVEL;
1430 filter->shadow = shadow;
1431 filter->highlight = highlight;
1432 filter->blurx = blurx;
1433 filter->blury = blury;
1434 filter->strength = strength;
1435 filter->angle = angle;
1436 filter->distance = distance;
1437 filter->innershadow = innershadow;
1438 filter->knockout = knockout;
1439 filter->composite = composite;
1440 filter->ontop = ontop;
1441 filter->passes = passes;
1443 if(dictionary_lookup(&filters, name))
1444 syntaxerror("filter %s defined twice", name);
1445 dictionary_put2(&filters, name, filter);
1448 void s_blur(char*name, double blurx, double blury, int passes)
1450 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1451 filter->type = FILTERTYPE_BLUR;
1452 filter->blurx = blurx;
1453 filter->blury = blury;
1454 filter->passes = passes;
1456 if(dictionary_lookup(&filters, name))
1457 syntaxerror("filter %s defined twice", name);
1458 dictionary_put2(&filters, name, filter);
1461 void s_action(const char*text)
1464 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1466 syntaxerror("Couldn't compile ActionScript");
1469 tag = swf_InsertTag(tag, ST_DOACTION);
1471 swf_ActionSet(tag, a);
1476 void s_initaction(const char*character, const char*text)
1480 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1482 syntaxerror("Couldn't compile ActionScript");
1485 c = (character_t*)dictionary_lookup(&characters, character);
1487 tag = swf_InsertTag(tag, ST_DOINITACTION);
1488 swf_SetU16(tag, c->id);
1489 swf_ActionSet(tag, a);
1494 int s_swf3action(char*name, char*action)
1497 instance_t* object = 0;
1499 object = (instance_t*)dictionary_lookup(&instances, name);
1500 if(!object && name && *name) {
1501 /* we have a name, but couldn't find it. Abort. */
1504 a = action_SetTarget(0, name);
1505 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1506 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1507 else if(!strcmp(action, "stop")) a = action_Stop(a);
1508 else if(!strcmp(action, "play")) a = action_Play(a);
1509 a = action_SetTarget(a, "");
1512 tag = swf_InsertTag(tag, ST_DOACTION);
1513 swf_ActionSet(tag, a);
1518 void s_outline(char*name, char*format, char*source)
1527 //swf_Shape10DrawerInit(&draw, 0);
1528 swf_Shape11DrawerInit(&draw, 0);
1530 draw_string(&draw, source);
1532 shape = swf_ShapeDrawerToShape(&draw);
1533 bounds = swf_ShapeDrawerGetBBox(&draw);
1534 draw.dealloc(&draw);
1536 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1537 outline->shape = shape;
1538 outline->bbox = bounds;
1540 if(dictionary_lookup(&outlines, name))
1541 syntaxerror("outline %s defined twice", name);
1542 dictionary_put2(&outlines, name, outline);
1545 int s_playsound(char*name, int loops, int nomultiple, int stop)
1551 sound = dictionary_lookup(&sounds, name);
1555 tag = swf_InsertTag(tag, ST_STARTSOUND);
1556 swf_SetU16(tag, sound->id); //id
1557 memset(&info, 0, sizeof(info));
1560 info.nomultiple = nomultiple;
1561 swf_SetSoundInfo(tag, &info);
1565 void s_includeswf(char*name, char*filename)
1573 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1574 f = open(filename,O_RDONLY|O_BINARY);
1576 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1577 s_box(name, 0, 0, black, 20, 0);
1580 if (swf_ReadSWF(f,&swf)<0) {
1581 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1582 s_box(name, 0, 0, black, 20, 0);
1587 /* FIXME: The following sets the bounding Box for the character.
1588 It is wrong for two reasons:
1589 a) It may be too small (in case objects in the movie clip at the borders)
1590 b) it may be too big (because the poor movie never got autocropped)
1594 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1595 swf_SetU16(tag, id);
1596 swf_SetU16(tag, swf.frameCount);
1598 swf_Relocate(&swf, idmap);
1600 ftag = swf.firstTag;
1604 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1605 if(cutout[t] == ftag->id) {
1609 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1611 if(ftag->id == ST_END)
1616 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
1617 /* We simply dump all tags right after the sprite
1618 header, relying on the fact that swf_OptimizeTagOrder() will
1619 sort things out for us later.
1620 We also rely on the fact that the imported SWF is well-formed.
1622 tag = swf_InsertTag(tag, ftag->id);
1623 swf_SetBlock(tag, ftag->data, ftag->len);
1629 syntaxerror("Included file %s contains errors", filename);
1630 tag = swf_InsertTag(tag, ST_END);
1634 s_addcharacter(name, id, tag, r);
1637 SRECT s_getCharBBox(char*name)
1639 character_t* c = dictionary_lookup(&characters, name);
1640 if(!c) syntaxerror("character '%s' unknown(2)", name);
1643 SRECT s_getInstanceBBox(char*name)
1645 instance_t * i = dictionary_lookup(&instances, name);
1647 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1649 if(!c) syntaxerror("internal error(5)");
1652 parameters_t s_getParameters(char*name)
1654 instance_t * i = dictionary_lookup(&instances, name);
1655 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1656 return i->parameters;
1658 void s_startclip(char*instance, char*character, parameters_t p)
1660 character_t* c = dictionary_lookup(&characters, character);
1664 syntaxerror("character %s not known", character);
1666 i = s_addinstance(instance, c, currentdepth);
1668 m = s_instancepos(i->character->size, &p);
1670 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1671 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1672 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1674 i->lastFrame= currentframe;
1676 stack[stackpos].tag = tag;
1677 stack[stackpos].type = 2;
1686 swf_SetTagPos(stack[stackpos].tag, 0);
1687 swf_GetPlaceObject(stack[stackpos].tag, &p);
1688 p.clipdepth = currentdepth;
1690 swf_ClearTag(stack[stackpos].tag);
1691 swf_SetPlaceObject(stack[stackpos].tag, &p);
1695 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
1699 swf_GetPlaceObject(NULL, &po);
1703 po.cxform = p->cxform;
1709 po.blendmode = p->blendmode;
1713 flist.filter[0] = p->filter;
1714 po.filters = &flist;
1716 swf_SetPlaceObject(tag, &po);
1719 void s_put(char*instance, char*character, parameters_t p)
1721 character_t* c = dictionary_lookup(&characters, character);
1725 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1728 i = s_addinstance(instance, c, currentdepth);
1730 m = s_instancepos(i->character->size, &p);
1732 if(p.blendmode || p.filter) {
1733 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
1735 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1737 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
1740 i->lastFrame = currentframe;
1745 void s_jump(char*instance, parameters_t p)
1747 instance_t* i = dictionary_lookup(&instances, instance);
1750 syntaxerror("instance %s not known", instance);
1754 m = s_instancepos(i->character->size, &p);
1756 if(p.blendmode || p.filter) {
1757 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
1759 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1761 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
1764 i->lastFrame = currentframe;
1767 RGBA interpolateColor(RGBA c1, RGBA c2, float ratio)
1770 c.r = c1.r * (1-ratio) + c2.r * ratio;
1771 c.g = c1.g * (1-ratio) + c2.g * ratio;
1772 c.b = c1.b * (1-ratio) + c2.b * ratio;
1773 c.a = c1.a * (1-ratio) + c2.a * ratio;
1777 FILTER* interpolateFilter(FILTER*filter1,FILTER*filter2, float ratio)
1779 if(!filter1 && !filter2)
1782 return interpolateFilter(filter2,filter1,1-ratio);
1784 if(filter2 && filter2->type != filter1->type)
1785 syntaxerror("can't interpolate between %s and %s filters yet", filtername[filter1->type], filtername[filter2->type]);
1787 if(filter1->type == FILTERTYPE_BLUR) {
1788 FILTER_BLUR*f1 = (FILTER_BLUR*)filter1;
1789 FILTER_BLUR*f2 = (FILTER_BLUR*)filter2;
1790 if(f2 && f1->blurx == f2->blurx && f1->blury == f2->blury)
1792 FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR);
1793 f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
1794 f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
1795 f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
1797 } else if (filter1->type == FILTERTYPE_DROPSHADOW) {
1798 FILTER_DROPSHADOW*f1 = (FILTER_DROPSHADOW*)filter1;
1799 FILTER_DROPSHADOW*f2 = (FILTER_DROPSHADOW*)filter2;
1800 if(f2 && !memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength &&
1801 f1->blurx == f2->blurx && f1->blury == f2->blury &&
1802 f1->angle == f2->angle && f1->distance == f2->distance)
1804 FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW);
1805 memcpy(f, f1, sizeof(FILTER_DROPSHADOW));
1806 f->color = interpolateColor(f1->color, f2->color, ratio);
1807 f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
1808 f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
1809 f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
1810 f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio;
1811 f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio;
1812 f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio;
1814 } else if (filter1->type == FILTERTYPE_BEVEL) {
1815 FILTER_BEVEL*f1 = (FILTER_BEVEL*)filter1;
1816 FILTER_BEVEL*f2 = (FILTER_BEVEL*)filter2;
1817 if(f2 && !memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) &&
1818 !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) &&
1819 f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
1821 FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL);
1822 memcpy(f, f1, sizeof(FILTER_BEVEL));
1823 f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio);
1824 f->highlight = interpolateColor(f1->highlight, f2->highlight, 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_GRADIENTGLOW) {
1833 FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
1834 // can't interpolate gradients
1835 memcpy(f, filter1, sizeof(FILTER_GRADIENTGLOW));
1838 syntaxerror("can't interpolate %s filters yet", filtername[filter1->type]);
1843 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1847 if(num==0 || num==1)
1849 ratio = (float)pos/(float)num;
1851 p.x = (p2->x-p1->x)*ratio + p1->x;
1852 p.y = (p2->y-p1->y)*ratio + p1->y;
1853 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1854 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1855 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1856 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1858 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1859 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1860 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1861 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1863 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1864 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1865 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1866 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1868 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1869 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1870 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1871 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1873 p.filter = interpolateFilter(p1->filter, p2->filter, ratio);
1877 void s_change(char*instance, parameters_t p2)
1879 instance_t* i = dictionary_lookup(&instances, instance);
1883 int frame, allframes;
1885 syntaxerror("instance %s not known", instance);
1889 allframes = currentframe - i->lastFrame - 1;
1891 warning(".change ignored. can only .put/.change an object once per frame.");
1895 m = s_instancepos(i->character->size, &p2);
1896 if(p2.blendmode || p2.filter) {
1897 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
1899 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1901 setPlacement(tag, 0, i->depth, m, 0, &p2, 1);
1904 /* o.k., we got the start and end point set. Now iterate though all the
1905 tags in between, inserting object changes after each new frame */
1908 if(!t) syntaxerror("internal error(6)");
1910 while(frame < allframes) {
1911 if(t->id == ST_SHOWFRAME) {
1916 p = s_interpolate(&p1, &p2, frame, allframes);
1917 m = s_instancepos(i->character->size, &p); //needed?
1919 i->lastFrame = currentframe;
1920 if(p.blendmode || p.filter) {
1921 lt = swf_InsertTag(t, ST_PLACEOBJECT3);
1923 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1925 setPlacement(lt, 0, i->depth, m, 0, &p, 1);
1927 if(frame == allframes)
1932 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1936 void s_delinstance(char*instance)
1938 instance_t* i = dictionary_lookup(&instances, instance);
1940 syntaxerror("instance %s not known", instance);
1942 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1943 swf_SetU16(tag, i->depth);
1944 dictionary_del(&instances, instance);
1947 void s_qchange(char*instance, parameters_t p)
1954 syntaxerror(".end unexpected");
1955 if(stack[stackpos-1].type == 0)
1957 else if(stack[stackpos-1].type == 1)
1959 else if(stack[stackpos-1].type == 2)
1961 else if(stack[stackpos-1].type == 3)
1963 else syntaxerror("internal error 1");
1966 // ------------------------------------------------------------------------
1968 typedef int command_func_t(map_t*args);
1970 SRECT parseBox(char*str)
1972 SRECT r = {0,0,0,0};
1973 float xmin, xmax, ymin, ymax;
1974 char*x = strchr(str, 'x');
1976 if(!strcmp(str, "autocrop")) {
1977 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1981 d1 = strchr(x+1, ':');
1983 d2 = strchr(d1+1, ':');
1985 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1989 else if(d1 && !d2) {
1990 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1996 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2001 r.xmin = (SCOORD)(xmin*20);
2002 r.ymin = (SCOORD)(ymin*20);
2003 r.xmax = (SCOORD)(xmax*20);
2004 r.ymax = (SCOORD)(ymax*20);
2007 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2010 float parseFloat(char*str)
2014 int parseInt(char*str)
2019 if(str[0]=='+' || str[0]=='-')
2023 if(str[t]<'0' || str[t]>'9')
2024 syntaxerror("Not an Integer: \"%s\"", str);
2027 int parseTwip(char*str)
2031 if(str[0]=='+' || str[0]=='-') {
2036 dot = strchr(str, '.');
2040 return sign*parseInt(str)*20;
2042 char* old = strdup(str);
2043 int l=strlen(dot+1);
2046 for(s=str;s<dot-1;s++)
2047 if(*s<'0' || *s>'9')
2048 syntaxerror("Not a coordinate: \"%s\"", str);
2050 if(*s<'0' || *s>'9')
2051 syntaxerror("Not a coordinate: \"%s\"", str);
2053 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2054 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2057 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2061 return sign*atoi(str)*20;
2063 return sign*atoi(str)*20+atoi(dot)*2;
2065 return sign*atoi(str)*20+atoi(dot)/5;
2070 int isPoint(char*str)
2072 if(strchr(str, '('))
2078 SPOINT parsePoint(char*str)
2082 int l = strlen(str);
2083 char*comma = strchr(str, ',');
2084 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2085 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2086 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2087 p.x = parseTwip(tmp);
2088 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2089 p.y = parseTwip(tmp);
2093 int parseColor2(char*str, RGBA*color)
2095 int l = strlen(str);
2099 struct {unsigned char r,g,b;char*name;} colors[] =
2100 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2101 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2102 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2103 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2104 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2105 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2106 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2107 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2108 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2109 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2110 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2111 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2115 if(str[0]=='#' && (l==7 || l==9)) {
2116 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2118 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2120 color->r = r; color->g = g; color->b = b; color->a = a;
2123 int len=strlen(str);
2125 if(strchr(str, '/')) {
2126 len = strchr(str, '/')-str;
2127 sscanf(str+len+1,"%02x", &alpha);
2129 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2130 if(!strncmp(str, colors[t].name, len)) {
2135 color->r = r; color->g = g; color->b = b; color->a = a;
2141 RGBA parseColor(char*str)
2144 if(!parseColor2(str, &c))
2145 syntaxerror("Expression '%s' is not a color", str);
2149 typedef struct _muladd {
2154 MULADD parseMulAdd(char*str)
2157 char* str2 = (char*)malloc(strlen(str)+5);
2164 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2165 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2166 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2167 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2168 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2169 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2170 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2171 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2172 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2173 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2175 syntaxerror("'%s' is not a valid color transform expression", str);
2177 m.add = (int)(add*256);
2178 m.mul = (int)(mul*256);
2183 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2185 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2186 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2188 if(a<-32768) a=-32768;
2189 if(a>32767) a=32767;
2190 if(m<-32768) m=-32768;
2191 if(m>32767) m=32767;
2197 float parsePxOrPercent(char*fontname, char*str)
2199 int l = strlen(str);
2200 if(strchr(str, '%'))
2201 return parsePercent(str);
2202 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2203 float p = atof(str);
2204 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2206 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2210 float parsePercent(char*str)
2212 int l = strlen(str);
2216 return atoi(str)/100.0;
2218 syntaxerror("Expression '%s' is not a percentage", str);
2221 int isPercent(char*str)
2223 return str[strlen(str)-1]=='%';
2225 int parseNewSize(char*str, int size)
2228 return parsePercent(str)*size;
2230 return (int)(atof(str)*20);
2233 int isColor(char*str)
2236 return parseColor2(str, &c);
2239 static char* lu(map_t* args, char*name)
2241 char* value = map_lookup(args, name);
2243 map_dump(args, stdout, "");
2244 syntaxerror("internal error 2: value %s should be set", name);
2249 static int c_flash(map_t*args)
2251 char* filename = map_lookup(args, "filename");
2252 char* compressstr = lu(args, "compress");
2253 SRECT bbox = parseBox(lu(args, "bbox"));
2254 int version = parseInt(lu(args, "version"));
2255 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2257 RGBA color = parseColor(lu(args, "background"));
2259 if(!filename || !*filename) {
2260 /* for compatibility */
2261 filename = map_lookup(args, "name");
2262 if(!filename || !*filename) {
2265 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2266 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2270 if(!filename || override_outputname)
2271 filename = outputname;
2273 if(!strcmp(compressstr, "default"))
2274 compress = version>=6;
2275 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2277 else if(!strcmp(compressstr, "no"))
2279 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2281 s_swf(filename, bbox, version, fps, compress, color);
2284 int isRelative(char*str)
2286 return !strncmp(str, "<plus>", 6) ||
2287 !strncmp(str, "<minus>", 7);
2289 char* getOffset(char*str)
2291 if(!strncmp(str, "<plus>", 6))
2293 if(!strncmp(str, "<minus>", 7))
2295 syntaxerror("internal error (347)");
2298 int getSign(char*str)
2300 if(!strncmp(str, "<plus>", 6))
2302 if(!strncmp(str, "<minus>", 7))
2304 syntaxerror("internal error (348)");
2307 static dictionary_t points;
2308 static mem_t mpoints;
2309 int points_initialized = 0;
2311 SPOINT getPoint(SRECT r, char*name)
2314 if(!strcmp(name, "center")) {
2316 p.x = (r.xmin + r.xmax)/2;
2317 p.y = (r.ymin + r.ymax)/2;
2321 if(points_initialized)
2322 l = (int)dictionary_lookup(&points, name);
2324 syntaxerror("Invalid point: \"%s\".", name);
2327 return *(SPOINT*)&mpoints.buffer[l];
2330 static int texture2(char*name, char*object, map_t*args, int errors)
2333 char*xstr = map_lookup(args, "x");
2334 char*ystr = map_lookup(args, "y");
2335 char*widthstr = map_lookup(args, "width");
2336 char*heightstr = map_lookup(args, "height");
2337 char*scalestr = map_lookup(args, "scale");
2338 char*scalexstr = map_lookup(args, "scalex");
2339 char*scaleystr = map_lookup(args, "scaley");
2340 char*rotatestr = map_lookup(args, "rotate");
2341 char* shearstr = map_lookup(args, "shear");
2342 char* radiusstr = map_lookup(args, "r");
2344 float scalex = 1.0, scaley = 1.0;
2345 float rotate=0, shear=0;
2347 if(!*xstr && !*ystr) {
2349 syntaxerror("x and y must be set");
2352 if(*scalestr && (*scalexstr || *scaleystr)) {
2353 syntaxerror("scale and scalex/scaley can't both be set");
2356 if((*widthstr || *heightstr) && *radiusstr) {
2357 syntaxerror("width/height and radius can't both be set");
2360 widthstr = radiusstr;
2361 heightstr = radiusstr;
2363 if(!*xstr) xstr="0";
2364 if(!*ystr) ystr="0";
2365 if(!*rotatestr) rotatestr="0";
2366 if(!*shearstr) shearstr="0";
2369 scalex = scaley = parsePercent(scalestr);
2370 } else if(*scalexstr || *scaleystr) {
2371 if(scalexstr) scalex = parsePercent(scalexstr);
2372 if(scaleystr) scaley = parsePercent(scaleystr);
2373 } else if(*widthstr || *heightstr) {
2376 s_getBitmapSize(object, &width, &height);
2378 scalex = (float)parseTwip(widthstr)/(float)width;
2380 scaley = (float)parseTwip(heightstr)/(float)height;
2382 x = parseTwip(xstr);
2383 y = parseTwip(ystr);
2384 rotate = parseFloat(rotatestr);
2385 shear = parseFloat(shearstr);
2387 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2392 static int c_texture(map_t*args)
2394 char*name = lu(args, "instance");
2395 char*object = lu(args, "character");
2396 return texture2(name, object, args, 1);
2399 static int c_gradient(map_t*args)
2401 char*name = lu(args, "name");
2402 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2403 int rotate = parseInt(lu(args, "rotate"));
2407 syntaxerror("colon (:) expected");
2409 s_gradient(name, text, radial, rotate);
2411 /* check whether we also have placement information,
2412 which would make this a positioned gradient.
2413 If there is placement information, texture2() will
2414 add a texture, which has priority over the gradient.
2416 texture2(name, name, args, 0);
2420 static int c_blur(map_t*args)
2422 char*name = lu(args, "name");
2423 char*blurstr = lu(args, "blur");
2424 char*blurxstr = lu(args, "blurx");
2425 char*blurystr = lu(args, "blury");
2426 float blurx=1.0, blury=1.0;
2428 blurx = parseFloat(blurstr);
2429 blury = parseFloat(blurstr);
2432 blurx = parseFloat(blurxstr);
2434 blury = parseFloat(blurystr);
2435 int passes = parseInt(lu(args, "passes"));
2436 s_blur(name, blurx, blury, passes);
2440 static int c_gradientglow(map_t*args)
2442 char*name = lu(args, "name");
2443 char*gradient = lu(args, "gradient");
2444 char*blurstr = lu(args, "blur");
2445 char*blurxstr = lu(args, "blurx");
2446 char*blurystr = lu(args, "blury");
2447 float blurx=1.0, blury=1.0;
2449 blurx = parseFloat(blurstr);
2450 blury = parseFloat(blurstr);
2453 blurx = parseFloat(blurxstr);
2455 blury = parseFloat(blurystr);
2457 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2458 float distance = parseFloat(lu(args, "distance"));
2459 float strength = parseFloat(lu(args, "strength"));
2460 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2461 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2462 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2463 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2464 int passes = parseInt(lu(args, "passes"));
2466 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2470 static int c_dropshadow(map_t*args)
2472 char*name = lu(args, "name");
2473 RGBA color = parseColor(lu(args, "color"));
2474 char*blurstr = lu(args, "blur");
2475 char*blurxstr = lu(args, "blurx");
2476 char*blurystr = lu(args, "blury");
2477 float blurx=1.0, blury=1.0;
2479 blurx = parseFloat(blurstr);
2480 blury = parseFloat(blurstr);
2483 blurx = parseFloat(blurxstr);
2485 blury = parseFloat(blurystr);
2487 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2488 float distance = parseFloat(lu(args, "distance"));
2489 float strength = parseFloat(lu(args, "strength"));
2490 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2491 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2492 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2493 int passes = parseInt(lu(args, "passes"));
2495 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2499 static int c_bevel(map_t*args)
2501 char*name = lu(args, "name");
2502 RGBA shadow = parseColor(lu(args, "shadow"));
2503 RGBA highlight = parseColor(lu(args, "highlight"));
2504 char*blurstr = lu(args, "blur");
2505 char*blurxstr = lu(args, "blurx");
2506 char*blurystr = lu(args, "blury");
2507 float blurx=1.0, blury=1.0;
2509 blurx = parseFloat(blurstr);
2510 blury = parseFloat(blurstr);
2513 blurx = parseFloat(blurxstr);
2515 blury = parseFloat(blurystr);
2517 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2518 float distance = parseFloat(lu(args, "distance"));
2519 float strength = parseFloat(lu(args, "strength"));
2520 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2521 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2522 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2523 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2524 int passes = parseInt(lu(args, "passes"));
2526 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2530 static int c_point(map_t*args)
2532 char*name = lu(args, "name");
2536 if(!points_initialized) {
2537 dictionary_init(&points);
2539 points_initialized = 1;
2541 p.x = parseTwip(lu(args, "x"));
2542 p.y = parseTwip(lu(args, "y"));
2543 pos = mem_put(&mpoints, &p, sizeof(p));
2544 string_set(&s1, name);
2546 dictionary_put(&points, s1, (void*)pos);
2549 static int c_play(map_t*args)
2551 char*name = lu(args, "name");
2552 char*loop = lu(args, "loop");
2553 char*nomultiple = lu(args, "nomultiple");
2555 if(!strcmp(nomultiple, "nomultiple"))
2558 nm = parseInt(nomultiple);
2560 if(s_playsound(name, parseInt(loop), nm, 0)) {
2562 } else if(s_swf3action(name, "play")) {
2568 static int c_stop(map_t*args)
2570 char*name = map_lookup(args, "name");
2572 if(s_playsound(name, 0,0,1)) {
2574 } else if(s_swf3action(name, "stop")) {
2577 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2581 static int c_nextframe(map_t*args)
2583 char*name = lu(args, "name");
2585 if(s_swf3action(name, "nextframe")) {
2588 syntaxerror("I don't know anything about movie \"%s\"", name);
2592 static int c_previousframe(map_t*args)
2594 char*name = lu(args, "name");
2596 if(s_swf3action(name, "previousframe")) {
2599 syntaxerror("I don't know anything about movie \"%s\"", name);
2603 static int c_placement(map_t*args, int type)
2605 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2608 char* luminancestr = lu(args, "luminance");
2609 char* scalestr = lu(args, "scale");
2610 char* scalexstr = lu(args, "scalex");
2611 char* scaleystr = lu(args, "scaley");
2612 char* rotatestr = lu(args, "rotate");
2613 char* shearstr = lu(args, "shear");
2614 char* xstr="", *pivotstr="";
2615 char* ystr="", *anglestr="";
2616 char*above = lu(args, "above"); /*FIXME*/
2617 char*below = lu(args, "below");
2618 char* rstr = lu(args, "red");
2619 char* gstr = lu(args, "green");
2620 char* bstr = lu(args, "blue");
2621 char* astr = lu(args, "alpha");
2622 char* pinstr = lu(args, "pin");
2623 char* as = map_lookup(args, "as");
2624 char* blendmode = lu(args, "blend");
2625 char*filterstr = lu(args, "filter");
2634 if(type==9) { // (?) .rotate or .arcchange
2635 pivotstr = lu(args, "pivot");
2636 anglestr = lu(args, "angle");
2638 xstr = lu(args, "x");
2639 ystr = lu(args, "y");
2642 luminance = parseMulAdd(luminancestr);
2645 luminance.mul = 256;
2649 if(scalexstr[0]||scaleystr[0])
2650 syntaxerror("scalex/scaley and scale cannot both be set");
2651 scalexstr = scaleystr = scalestr;
2654 if(type == 0 || type == 4) {
2656 character = lu(args, "character");
2657 parameters_clear(&p);
2658 } else if (type == 5) {
2659 character = lu(args, "name");
2660 parameters_clear(&p);
2663 p = s_getParameters(instance);
2668 if(isRelative(xstr)) {
2669 if(type == 0 || type == 4)
2670 syntaxerror("relative x values not allowed for initial put or startclip");
2671 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2673 p.x = parseTwip(xstr);
2677 if(isRelative(ystr)) {
2678 if(type == 0 || type == 4)
2679 syntaxerror("relative y values not allowed for initial put or startclip");
2680 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2682 p.y = parseTwip(ystr);
2686 /* scale, scalex, scaley */
2688 oldbbox = s_getCharBBox(character);
2690 oldbbox = s_getInstanceBBox(instance);
2692 oldwidth = oldbbox.xmax - oldbbox.xmin;
2693 oldheight = oldbbox.ymax - oldbbox.ymin;
2695 if(oldwidth==0) p.scalex = 1.0;
2698 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2702 if(oldheight==0) p.scaley = 1.0;
2705 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2711 if(isRelative(rotatestr)) {
2712 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2714 p.rotate = parseFloat(rotatestr);
2720 if(isRelative(shearstr)) {
2721 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2723 p.shear = parseFloat(shearstr);
2728 if(isPoint(pivotstr))
2729 p.pivot = parsePoint(pivotstr);
2731 p.pivot = getPoint(oldbbox, pivotstr);
2735 p.pin = parsePoint(pinstr);
2737 p.pin = getPoint(oldbbox, pinstr);
2740 /* color transform */
2742 if(rstr[0] || luminancestr[0]) {
2745 r = parseMulAdd(rstr);
2747 r.add = p.cxform.r0;
2748 r.mul = p.cxform.r1;
2750 r = mergeMulAdd(r, luminance);
2751 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2753 if(gstr[0] || luminancestr[0]) {
2756 g = parseMulAdd(gstr);
2758 g.add = p.cxform.g0;
2759 g.mul = p.cxform.g1;
2761 g = mergeMulAdd(g, luminance);
2762 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2764 if(bstr[0] || luminancestr[0]) {
2767 b = parseMulAdd(bstr);
2769 b.add = p.cxform.b0;
2770 b.mul = p.cxform.b1;
2772 b = mergeMulAdd(b, luminance);
2773 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2776 MULADD a = parseMulAdd(astr);
2777 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2783 for(t=0;blendModeNames[t];t++) {
2784 if(!strcmp(blendModeNames[t], blendmode)) {
2790 syntaxerror("unknown blend mode: '%s'", blendmode);
2792 p.blendmode = blend;
2796 FILTER*f = dictionary_lookup(&filters, filterstr);
2798 syntaxerror("Unknown filter %s", filterstr);
2804 s_put(instance, character, p);
2806 s_change(instance, p);
2808 s_qchange(instance, p);
2810 s_jump(instance, p);
2812 s_startclip(instance, character, p);
2813 else if(type == 5) {
2815 s_buttonput(character, as, p);
2817 s_buttonput(character, "shape", p);
2822 static int c_put(map_t*args)
2824 c_placement(args, 0);
2827 static int c_change(map_t*args)
2829 c_placement(args, 1);
2832 static int c_qchange(map_t*args)
2834 c_placement(args, 2);
2837 static int c_arcchange(map_t*args)
2839 c_placement(args, 2);
2842 static int c_jump(map_t*args)
2844 c_placement(args, 3);
2847 static int c_startclip(map_t*args)
2849 c_placement(args, 4);
2852 static int c_show(map_t*args)
2854 c_placement(args, 5);
2857 static int c_del(map_t*args)
2859 char*instance = lu(args, "name");
2860 s_delinstance(instance);
2863 static int c_end(map_t*args)
2868 static int c_sprite(map_t*args)
2870 char* name = lu(args, "name");
2874 static int c_frame(map_t*args)
2876 char*framestr = lu(args, "n");
2877 char*cutstr = lu(args, "cut");
2879 char*name = lu(args, "name");
2880 char*anchor = lu(args, "anchor");
2883 if(!strcmp(anchor, "anchor") && !*name)
2888 if(strcmp(cutstr, "no"))
2890 if(isRelative(framestr)) {
2891 frame = s_getframe();
2892 if(getSign(framestr)<0)
2893 syntaxerror("relative frame expressions must be positive");
2894 frame += parseInt(getOffset(framestr));
2897 frame = parseInt(framestr);
2898 if(s_getframe() >= frame
2899 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2900 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2902 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
2905 static int c_primitive(map_t*args)
2907 char*name = lu(args, "name");
2908 char*command = lu(args, "commandname");
2909 int width=0, height=0, r=0;
2910 int linewidth = parseTwip(lu(args, "line"));
2911 char*colorstr = lu(args, "color");
2912 RGBA color = parseColor(colorstr);
2913 char*fillstr = lu(args, "fill");
2920 if(!strcmp(command, "circle"))
2922 else if(!strcmp(command, "filled"))
2926 width = parseTwip(lu(args, "width"));
2927 height = parseTwip(lu(args, "height"));
2928 } else if (type==1) {
2929 r = parseTwip(lu(args, "r"));
2930 } else if (type==2) {
2931 outline = lu(args, "outline");
2934 if(!strcmp(fillstr, "fill"))
2936 if(!strcmp(fillstr, "none"))
2938 if(width<0 || height<0 || linewidth<0 || r<0)
2939 syntaxerror("values width, height, line, r must be positive");
2941 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2942 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2943 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2947 static int c_textshape(map_t*args)
2949 char*name = lu(args, "name");
2950 char*text = lu(args, "text");
2951 char*font = lu(args, "font");
2952 float size = parsePxOrPercent(font, lu(args, "size"));
2954 s_textshape(name, font, size, text);
2958 static int c_swf(map_t*args)
2960 char*name = lu(args, "name");
2961 char*filename = lu(args, "filename");
2962 char*command = lu(args, "commandname");
2963 if(!strcmp(command, "shape"))
2964 warning("Please use .swf instead of .shape");
2965 s_includeswf(name, filename);
2969 static int c_font(map_t*args)
2971 char*name = lu(args, "name");
2972 char*filename = lu(args, "filename");
2973 s_font(name, filename);
2977 static int c_sound(map_t*args)
2979 char*name = lu(args, "name");
2980 char*filename = lu(args, "filename");
2981 s_sound(name, filename);
2985 static int c_text(map_t*args)
2987 char*name = lu(args, "name");
2988 char*text = lu(args, "text");
2989 char*font = lu(args, "font");
2990 float size = parsePxOrPercent(font, lu(args, "size"));
2991 RGBA color = parseColor(lu(args, "color"));
2992 s_text(name, font, text, (int)(size*100), color);
2996 static int c_soundtrack(map_t*args)
3001 static int c_quicktime(map_t*args)
3003 char*name = lu(args, "name");
3004 char*url = lu(args, "url");
3005 s_quicktime(name, url);
3009 static int c_image(map_t*args)
3011 char*command = lu(args, "commandname");
3012 char*name = lu(args, "name");
3013 char*filename = lu(args, "filename");
3014 if(!strcmp(command,"jpeg")) {
3015 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3016 s_image(name, "jpeg", filename, quality);
3018 s_image(name, "png", filename, 0);
3023 static int c_outline(map_t*args)
3025 char*name = lu(args, "name");
3026 char*format = lu(args, "format");
3030 syntaxerror("colon (:) expected");
3032 s_outline(name, format, text);
3036 int fakechar(map_t*args)
3038 char*name = lu(args, "name");
3039 s_box(name, 0, 0, black, 20, 0);
3043 static int c_egon(map_t*args) {return fakechar(args);}
3044 static int c_button(map_t*args) {
3045 char*name = lu(args, "name");
3049 static int current_button_flags = 0;
3050 static int c_on_press(map_t*args)
3052 char*position = lu(args, "position");
3054 if(!strcmp(position, "inside")) {
3055 current_button_flags |= BC_OVERUP_OVERDOWN;
3056 } else if(!strcmp(position, "outside")) {
3057 //current_button_flags |= BC_IDLE_OUTDOWN;
3058 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3059 } else if(!strcmp(position, "anywhere")) {
3060 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3063 if(type == RAWDATA) {
3065 s_buttonaction(current_button_flags, action);
3066 current_button_flags = 0;
3072 static int c_on_release(map_t*args)
3074 char*position = lu(args, "position");
3076 if(!strcmp(position, "inside")) {
3077 current_button_flags |= BC_OVERDOWN_OVERUP;
3078 } else if(!strcmp(position, "outside")) {
3079 current_button_flags |= BC_OUTDOWN_IDLE;
3080 } else if(!strcmp(position, "anywhere")) {
3081 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3084 if(type == RAWDATA) {
3086 s_buttonaction(current_button_flags, action);
3087 current_button_flags = 0;
3093 static int c_on_move_in(map_t*args)
3095 char*position = lu(args, "state");
3097 if(!strcmp(position, "pressed")) {
3098 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3099 } else if(!strcmp(position, "not_pressed")) {
3100 current_button_flags |= BC_IDLE_OVERUP;
3101 } else if(!strcmp(position, "any")) {
3102 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3105 if(type == RAWDATA) {
3107 s_buttonaction(current_button_flags, action);
3108 current_button_flags = 0;
3114 static int c_on_move_out(map_t*args)
3116 char*position = lu(args, "state");
3118 if(!strcmp(position, "pressed")) {
3119 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3120 } else if(!strcmp(position, "not_pressed")) {
3121 current_button_flags |= BC_OVERUP_IDLE;
3122 } else if(!strcmp(position, "any")) {
3123 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3126 if(type == RAWDATA) {
3128 s_buttonaction(current_button_flags, action);
3129 current_button_flags = 0;
3135 static int c_on_key(map_t*args)
3137 char*key = lu(args, "key");
3139 if(strlen(key)==1) {
3142 current_button_flags |= 0x4000 + (key[0]*0x200);
3144 syntaxerror("invalid character: %c"+key[0]);
3149 <ctrl-x> = 0x200*(x-'a')
3153 syntaxerror("invalid key: %s",key);
3156 if(type == RAWDATA) {
3158 s_buttonaction(current_button_flags, action);
3159 current_button_flags = 0;
3166 static int c_edittext(map_t*args)
3168 //"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"},
3169 char*name = lu(args, "name");
3170 char*font = lu(args, "font");
3171 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3172 int width = parseTwip(lu(args, "width"));
3173 int height = parseTwip(lu(args, "height"));
3174 char*text = lu(args, "text");
3175 RGBA color = parseColor(lu(args, "color"));
3176 int maxlength = parseInt(lu(args, "maxlength"));
3177 char*variable = lu(args, "variable");
3178 char*passwordstr = lu(args, "password");
3179 char*wordwrapstr = lu(args, "wordwrap");
3180 char*multilinestr = lu(args, "multiline");
3181 char*htmlstr = lu(args, "html");
3182 char*noselectstr = lu(args, "noselect");
3183 char*readonlystr = lu(args, "readonly");
3184 char*borderstr = lu(args, "border");
3185 char*autosizestr = lu(args, "autosize");
3186 char*alignstr = lu(args, "align");
3190 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3191 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3192 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3193 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3194 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3195 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3196 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3197 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3198 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3199 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3200 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3201 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3202 else syntaxerror("Unknown alignment: %s", alignstr);
3204 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3208 static int c_morphshape(map_t*args) {return fakechar(args);}
3209 static int c_movie(map_t*args) {return fakechar(args);}
3211 static char* readfile(const char*filename)
3213 FILE*fi = fopen(filename, "rb");
3217 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3218 fseek(fi, 0, SEEK_END);
3220 fseek(fi, 0, SEEK_SET);
3221 text = rfx_alloc(l+1);
3222 fread(text, l, 1, fi);
3228 static int c_action(map_t*args)
3230 char* filename = map_lookup(args, "filename");
3231 if(!filename ||!*filename) {
3233 if(type != RAWDATA) {
3234 syntaxerror("colon (:) expected");
3238 s_action(readfile(filename));
3244 static int c_initaction(map_t*args)
3246 char* character = lu(args, "name");
3247 char* filename = map_lookup(args, "filename");
3248 if(!filename ||!*filename) {
3250 if(type != RAWDATA) {
3251 syntaxerror("colon (:) expected");
3253 s_initaction(character, text);
3255 s_initaction(character, readfile(filename));
3263 command_func_t* func;
3266 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
3267 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3268 // "import" type stuff
3269 {"swf", c_swf, "name filename"},
3270 {"shape", c_swf, "name filename"},
3271 {"jpeg", c_image, "name filename quality=80%"},
3272 {"png", c_image, "name filename"},
3273 {"movie", c_movie, "name filename"},
3274 {"sound", c_sound, "name filename"},
3275 {"font", c_font, "name filename"},
3276 {"soundtrack", c_soundtrack, "filename"},
3277 {"quicktime", c_quicktime, "url"},
3279 // generators of primitives
3281 {"point", c_point, "name x=0 y=0"},
3282 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3283 {"outline", c_outline, "name format=simple"},
3284 {"textshape", c_textshape, "name font size=100% text"},
3287 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3288 {"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"},
3289 {"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"},
3290 {"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"},
3292 // character generators
3293 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3294 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3295 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3297 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3298 {"text", c_text, "name text font size=100% color=white"},
3299 {"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="},
3300 {"morphshape", c_morphshape, "name start end"},
3301 {"button", c_button, "name"},
3302 {"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="},
3303 {"on_press", c_on_press, "position=inside"},
3304 {"on_release", c_on_release, "position=anywhere"},
3305 {"on_move_in", c_on_move_in, "state=not_pressed"},
3306 {"on_move_out", c_on_move_out, "state=not_pressed"},
3307 {"on_key", c_on_key, "key=any"},
3310 {"play", c_play, "name loop=0 @nomultiple=0"},
3311 {"stop", c_stop, "name= "},
3312 {"nextframe", c_nextframe, "name"},
3313 {"previousframe", c_previousframe, "name"},
3315 // object placement tags
3316 {"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="},
3317 {"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="},
3318 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3319 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3320 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3321 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3322 {"del", c_del, "name"},
3323 // virtual object placement
3324 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3326 // commands which start a block
3327 //startclip (see above)
3328 {"sprite", c_sprite, "name"},
3329 {"action", c_action, "filename="},
3330 {"initaction", c_initaction, "name filename="},
3336 static map_t parseArguments(char*command, char*pattern)
3352 string_set(&t1, "commandname");
3353 string_set(&t2, command);
3354 map_put(&result, t1, t2);
3356 if(!pattern || !*pattern)
3363 if(!strncmp("<i> ", x, 3)) {
3365 if(type == COMMAND || type == RAWDATA) {
3367 syntaxerror("character name expected");
3369 name[pos].str = "instance";
3371 value[pos].str = text;
3372 value[pos].len = strlen(text);
3376 if(type == ASSIGNMENT)
3379 name[pos].str = "character";
3381 value[pos].str = text;
3382 value[pos].len = strlen(text);
3390 isboolean[pos] = (x[0] =='@');
3403 name[pos].len = d-x;
3408 name[pos].len = e-x;
3409 value[pos].str = e+1;
3410 value[pos].len = d-e-1;
3418 /* for(t=0;t<len;t++) {
3419 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
3420 isboolean[t]?"(boolean)":"");
3425 if(type == RAWDATA || type == COMMAND) {
3430 // first, search for boolean arguments
3431 for(pos=0;pos<len;pos++)
3433 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
3435 if(type == ASSIGNMENT)
3437 value[pos].str = text;
3438 value[pos].len = strlen(text);
3439 /*printf("setting boolean parameter %s (to %s)\n",
3440 strdup_n(name[pos], namelen[pos]),
3441 strdup_n(value[pos], valuelen[pos]));*/
3446 // second, search for normal arguments
3448 for(pos=0;pos<len;pos++)
3450 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3451 (type != ASSIGNMENT && !set[pos])) {
3453 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3455 if(type == ASSIGNMENT)
3458 value[pos].str = text;
3459 value[pos].len = strlen(text);
3461 printf("setting parameter %s (to %s)\n",
3462 strdup_n(name[pos].str, name[pos].len),
3463 strdup_n(value[pos].str, value[pos].len));
3469 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3473 for(t=0;t<len;t++) {
3474 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3477 for(t=0;t<len;t++) {
3478 if(value[t].str && value[t].str[0] == '*') {
3479 //relative default- take value from some other parameter
3481 for(s=0;s<len;s++) {
3482 if(value[s].len == value[t].len-1 &&
3483 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3484 value[t].str = value[s].str;
3487 if(value[t].str == 0) {
3489 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3493 /* ok, now construct the dictionary from the parameters */
3497 map_put(&result, name[t], value[t]);
3501 static void parseArgumentsForCommand(char*command)
3506 msg("<verbose> parse Command: %s (line %d)", command, line);
3508 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3509 if(!strcmp(arguments[t].command, command)) {
3511 /* ugly hack- will be removed soon (once documentation and .sc generating
3512 utilities have been changed) */
3513 if(!strcmp(command, "swf") && !stackpos) {
3514 warning("Please use .flash instead of .swf- this will be mandatory soon");
3519 args = parseArguments(command, arguments[t].arguments);
3525 syntaxerror("command %s not known", command);
3527 // catch missing .flash directives at the beginning of a file
3528 if(strcmp(command, "flash") && !stackpos)
3530 syntaxerror("No movie defined- use .flash first");
3534 printf(".%s\n", command);fflush(stdout);
3535 map_dump(&args, stdout, "\t");fflush(stdout);
3538 (*arguments[nr].func)(&args);
3540 /*if(!strcmp(command, "button") ||
3541 !strcmp(command, "action")) {
3544 if(type == COMMAND) {
3545 if(!strcmp(text, "end"))
3559 int main (int argc,char ** argv)
3562 processargs(argc, argv);
3563 initLog(0,-1,0,0,-1,verbose);
3566 args_callback_usage(argv[0]);
3570 file = generateTokens(filename);
3572 fprintf(stderr, "parser returned error.\n");
3578 while(!noMoreTokens()) {
3581 syntaxerror("command expected");
3582 parseArgumentsForCommand(text);