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"
40 static char * filename = 0;
41 static char * outputname = "output.swf";
42 static int verbose = 2;
43 static int optimize = 0;
44 static int override_outputname = 0;
46 static struct options_t options[] = {
55 int args_callback_option(char*name,char*val)
57 if(!strcmp(name, "V")) {
58 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
61 else if(!strcmp(name, "o")) {
63 override_outputname = 1;
66 else if(!strcmp(name, "O")) {
70 else if(!strcmp(name, "v")) {
75 printf("Unknown option: -%s\n", name);
80 int args_callback_longoption(char*name,char*val)
82 return args_long2shortoption(options, name, val);
84 void args_callback_usage(char *name)
87 printf("Usage: %s [-o file.swf] file.sc\n", name);
89 printf("-h , --help Print short help message and exit\n");
90 printf("-V , --version Print version info and exit\n");
91 printf("-v , --verbose Increase verbosity. \n");
92 printf("-o , --output <filename> Set output file to <filename>.\n");
95 int args_callback_command(char*name,char*val)
98 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
105 static struct token_t* file;
114 static void syntaxerror(char*format, ...)
118 va_start(arglist, format);
119 vsprintf(buf, format, arglist);
121 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
125 static void warning(char*format, ...)
129 va_start(arglist, format);
130 vsprintf(buf, format, arglist);
132 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
135 static void readToken()
137 type = file[pos].type;
139 syntaxerror("unexpected end of file");
141 text = file[pos].text;
142 textlen = strlen(text);
143 line = file[pos].line;
144 column = file[pos].column;
146 //printf("---> %d(%s) %s\n", type, type_names[type], text);
149 static void pushBack()
152 if(!pos) syntaxerror("internal error 3");
157 textlen = strlen(text);
160 column = file[p].column;
163 static int noMoreTokens()
165 if(file[pos].type == END)
170 // ------------------------------ swf routines ----------------------------
174 int type; //0=swf, 1=sprite, 2=clip, 3=button
180 /* for sprites (1): */
186 dictionary_t oldinstances;
191 static int stackpos = 0;
193 static dictionary_t characters;
194 static dictionary_t images;
195 static dictionary_t outlines;
196 static dictionary_t gradients;
197 static char idmap[65536];
198 static TAG*tag = 0; //current tag
200 static int id; //current character id
201 static int currentframe; //current frame in current level
202 static SRECT currentrect; //current bounding box in current level
203 static U16 currentdepth;
204 static dictionary_t instances;
205 static dictionary_t fonts;
206 static dictionary_t sounds;
208 typedef struct _parameters {
210 float scalex, scaley;
218 typedef struct _character {
224 typedef struct _instance {
225 character_t*character;
227 parameters_t parameters;
228 TAG* lastTag; //last tag which set the object
229 U16 lastFrame; //frame lastTag is in
232 typedef struct _outline {
237 typedef struct _gradient {
243 static void character_init(character_t*c)
245 memset(c, 0, sizeof(character_t));
247 static character_t* character_new()
250 c = (character_t*)malloc(sizeof(character_t));
254 static void instance_init(instance_t*i)
256 memset(i, 0, sizeof(instance_t));
258 static instance_t* instance_new()
261 c = (instance_t*)malloc(sizeof(instance_t));
266 static void incrementid()
270 syntaxerror("Out of character ids.");
275 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
277 character_t* c = character_new();
279 c->definingTag = ctag;
282 if(dictionary_lookup(&characters, name))
283 syntaxerror("character %s defined twice", name);
284 dictionary_put2(&characters, name, c);
286 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
288 swf_SetString(tag, name);
289 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
292 swf_SetString(tag, name);
294 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
296 character_t* c = character_new();
297 c->definingTag = ctag;
301 if(dictionary_lookup(&images, name))
302 syntaxerror("image %s defined twice", name);
303 dictionary_put2(&images, name, c);
305 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
307 instance_t* i = instance_new();
310 //swf_GetMatrix(0, &i->matrix);
311 if(dictionary_lookup(&instances, name))
312 syntaxerror("object %s defined twice", name);
313 dictionary_put2(&instances, name, i);
317 static void parameters_set(parameters_t*p, int x,int y, float scalex, float scaley, float rotate, float shear, SPOINT pivot, SPOINT pin, CXFORM cxform)
320 p->scalex = scalex; p->scaley = scaley;
321 p->pin = pin; p->pivot = pivot;
322 p->rotate = rotate; p->cxform = cxform;
326 static void parameters_clear(parameters_t*p)
329 p->scalex = 1.0; p->scaley = 1.0;
332 p->pivot.x = 0; p->pivot.y = 0;
335 swf_GetCXForm(0, &p->cxform, 1);
338 static void makeMatrix(MATRIX*m, parameters_t*p)
347 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
348 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
349 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
350 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
352 m->sx = (int)(sx*65536+0.5);
353 m->r1 = (int)(r1*65536+0.5);
354 m->r0 = (int)(r0*65536+0.5);
355 m->sy = (int)(sy*65536+0.5);
359 h = swf_TurnPoint(p->pin, m);
364 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
369 r = swf_TurnRect(rect, &m);
370 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
371 currentrect.xmax == 0 && currentrect.ymax == 0)
374 swf_ExpandRect2(¤trect, &r);
378 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
380 SWF*swf = (SWF*)malloc(sizeof(SWF));
383 syntaxerror(".swf blocks can't be nested");
385 memset(swf, 0, sizeof(swf));
386 swf->fileVersion = version;
388 swf->frameRate = fps;
389 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
390 swf->compressed = compress;
391 swf_SetRGB(tag,&background);
393 if(stackpos==sizeof(stack)/sizeof(stack[0]))
394 syntaxerror("too many levels of recursion");
396 dictionary_init(&characters);
397 dictionary_init(&images);
398 dictionary_init(&outlines);
399 dictionary_init(&gradients);
400 dictionary_init(&instances);
401 dictionary_init(&fonts);
402 dictionary_init(&sounds);
404 memset(&stack[stackpos], 0, sizeof(stack[0]));
405 stack[stackpos].type = 0;
406 stack[stackpos].filename = strdup(name);
407 stack[stackpos].swf = swf;
408 stack[stackpos].oldframe = -1;
413 memset(¤trect, 0, sizeof(currentrect));
416 memset(idmap, 0, sizeof(idmap));
420 void s_sprite(char*name)
422 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
423 swf_SetU16(tag, id); //id
424 swf_SetU16(tag, 0); //frames
426 memset(&stack[stackpos], 0, sizeof(stack[0]));
427 stack[stackpos].type = 1;
428 stack[stackpos].oldframe = currentframe;
429 stack[stackpos].olddepth = currentdepth;
430 stack[stackpos].oldrect = currentrect;
431 stack[stackpos].oldinstances = instances;
432 stack[stackpos].tag = tag;
433 stack[stackpos].id = id;
434 stack[stackpos].name = strdup(name);
436 /* FIXME: those four fields should be bundled together */
437 dictionary_init(&instances);
440 memset(¤trect, 0, sizeof(currentrect));
446 typedef struct _buttonrecord
454 typedef struct _button
458 buttonrecord_t records[4];
461 static button_t mybutton;
463 void s_button(char*name)
465 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
466 swf_SetU16(tag, id); //id
467 swf_ButtonSetFlags(tag, 0); //menu=no
469 memset(&mybutton, 0, sizeof(mybutton));
471 memset(&stack[stackpos], 0, sizeof(stack[0]));
472 stack[stackpos].type = 3;
473 stack[stackpos].tag = tag;
474 stack[stackpos].id = id;
475 stack[stackpos].name = strdup(name);
476 stack[stackpos].oldrect = currentrect;
477 memset(¤trect, 0, sizeof(currentrect));
482 void s_buttonput(char*character, char*as, parameters_t p)
484 character_t* c = dictionary_lookup(&characters, character);
489 if(!stackpos || (stack[stackpos-1].type != 3)) {
490 syntaxerror(".show may only appear in .button");
493 syntaxerror("character %s not known (in .shape %s)", character, character);
495 if(mybutton.endofshapes) {
496 syntaxerror("a .do may not precede a .show", character, character);
499 m = s_instancepos(c->size, &p);
507 if(*s==',' || *s==0) {
508 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
509 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
510 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
511 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
512 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
513 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
520 static void setbuttonrecords(TAG*tag)
522 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
523 if(!mybutton.endofshapes) {
526 if(!mybutton.records[3].set) {
527 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
531 if(mybutton.records[t].set) {
532 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
535 swf_SetU8(tag,0); // end of button records
536 mybutton.endofshapes = 1;
540 void s_buttonaction(int flags, char*action)
546 setbuttonrecords(stack[stackpos-1].tag);
548 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
550 syntaxerror("Couldn't compile ActionScript");
553 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
554 swf_ActionSet(stack[stackpos-1].tag, a);
555 mybutton.nr_actions++;
560 static void setactionend(TAG*tag)
562 if(!mybutton.nr_actions) {
563 /* no actions means we didn't have an actionoffset,
564 which means we can't signal the end of the
565 buttonaction records, so, *sigh*, we have
566 to insert a dummy record */
567 swf_SetU16(tag, 0); //offset
568 swf_SetU16(tag, 0); //condition
569 swf_SetU8(tag, 0); //action
573 static void s_endButton()
576 setbuttonrecords(stack[stackpos-1].tag);
577 setactionend(stack[stackpos-1].tag);
580 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
584 tag = stack[stackpos].tag;
585 currentrect = stack[stackpos].oldrect;
587 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
588 free(stack[stackpos].name);
591 TAG* removeFromTo(TAG*from, TAG*to)
593 TAG*save = from->prev;
595 TAG*next = from->next;
603 static void s_endSprite()
605 SRECT r = currentrect;
607 if(stack[stackpos].cut)
608 tag = removeFromTo(stack[stackpos].cut, tag);
612 /* TODO: before clearing, prepend "<spritename>." to names and
613 copy into old instances dict */
614 dictionary_clear(&instances);
616 currentframe = stack[stackpos].oldframe;
617 currentrect = stack[stackpos].oldrect;
618 currentdepth = stack[stackpos].olddepth;
619 instances = stack[stackpos].oldinstances;
621 tag = swf_InsertTag(tag, ST_SHOWFRAME);
622 tag = swf_InsertTag(tag, ST_END);
624 tag = stack[stackpos].tag;
627 syntaxerror("internal error(7)");
629 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
630 free(stack[stackpos].name);
633 static void s_endSWF()
639 if(stack[stackpos].cut)
640 tag = removeFromTo(stack[stackpos].cut, tag);
644 swf = stack[stackpos].swf;
645 filename = stack[stackpos].filename;
647 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
648 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
649 tag = swf_InsertTag(tag, ST_SHOWFRAME);
651 tag = swf_InsertTag(tag, ST_END);
653 swf_OptimizeTagOrder(swf);
659 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
660 swf->movieSize = currentrect; /* "autocrop" */
663 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
664 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
665 swf->movieSize.ymax += 20;
668 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
670 syntaxerror("couldn't create output file %s", filename);
673 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
675 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
679 dictionary_clear(&instances);
680 dictionary_clear(&characters);
681 dictionary_clear(&images);
682 dictionary_clear(&outlines);
683 dictionary_clear(&gradients);
684 dictionary_clear(&fonts);
685 dictionary_clear(&sounds);
695 if(stack[stackpos-1].type == 0)
696 syntaxerror("End of file encountered in .flash block");
697 if(stack[stackpos-1].type == 1)
698 syntaxerror("End of file encountered in .sprite block");
699 if(stack[stackpos-1].type == 2)
700 syntaxerror("End of file encountered in .clip block");
706 return currentframe+1;
709 void s_frame(int nr, int cut, char*name)
715 syntaxerror("Illegal frame number");
716 nr--; // internally, frame 1 is frame 0
718 for(t=currentframe;t<nr;t++) {
719 tag = swf_InsertTag(tag, ST_SHOWFRAME);
720 if(t==nr-1 && name && *name) {
721 tag = swf_InsertTag(tag, ST_FRAMELABEL);
722 swf_SetString(tag, name);
725 if(nr == 0 && currentframe == 0 && name) {
726 tag = swf_InsertTag(tag, ST_FRAMELABEL);
727 swf_SetString(tag, name);
732 syntaxerror("Can't cut, frame empty");
734 stack[stackpos].cut = tag;
740 int parseColor2(char*str, RGBA*color);
742 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
747 if(texture[0] == '#') {
748 parseColor2(texture, &color);
749 return swf_ShapeAddSolidFillStyle(s, &color);
750 } else if((image = dictionary_lookup(&images, texture))) {
752 swf_GetMatrix(0, &m);
753 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
754 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
757 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
758 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
759 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
763 swf_GetMatrix(0, &rot);
764 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
765 csin = sin(-gradient->rotate*2*3.14159265358979/360);
767 rot.r1 = -csin*65536;
770 r2 = swf_TurnRect(*r, &rot);
771 swf_GetMatrix(0, &m);
772 m.sx = (r2.xmax - r2.xmin)*2*ccos;
773 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
774 m.r0 = (r2.ymax - r2.ymin)*2*csin;
775 m.sy = (r2.ymax - r2.ymin)*2*ccos;
776 m.tx = r->xmin + (r->xmax - r->xmin)/2;
777 m.ty = r->ymin + (r->ymax - r->ymin)/2;
778 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
779 } else if (parseColor2(texture, &color)) {
780 return swf_ShapeAddSolidFillStyle(s, &color);
782 syntaxerror("not a color/fillstyle: %s", texture);
787 RGBA black={r:0,g:0,b:0,a:0};
788 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
797 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
800 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
802 fs1 = addFillStyle(s, &r2, texture);
805 r.xmin = r2.xmin-linewidth-linewidth/2;
806 r.ymin = r2.ymin-linewidth-linewidth/2;
807 r.xmax = r2.xmax+linewidth+linewidth/2;
808 r.ymax = r2.ymax+linewidth+linewidth/2;
810 swf_SetShapeHeader(tag,s);
811 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
812 swf_ShapeSetLine(tag,s,width,0);
813 swf_ShapeSetLine(tag,s,0,height);
814 swf_ShapeSetLine(tag,s,-width,0);
815 swf_ShapeSetLine(tag,s,0,-height);
816 swf_ShapeSetEnd(tag);
819 s_addcharacter(name, id, tag, r);
823 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
829 outline = dictionary_lookup(&outlines, outlinename);
831 syntaxerror("outline %s not defined", outlinename);
835 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
838 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
840 fs1 = addFillStyle(s, &r2, texture);
843 rect.xmin = r2.xmin-linewidth-linewidth/2;
844 rect.ymin = r2.ymin-linewidth-linewidth/2;
845 rect.xmax = r2.xmax+linewidth+linewidth/2;
846 rect.ymax = r2.ymax+linewidth+linewidth/2;
848 swf_SetRect(tag,&rect);
849 swf_SetShapeStyles(tag, s);
850 swf_ShapeCountBits(s,0,0);
851 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, 1, 1,
852 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
853 swf_SetShapeBits(tag, s);
854 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
857 s_addcharacter(name, id, tag, rect);
861 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
866 r2.xmin = r2.ymin = 0;
870 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
873 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
875 fs1 = addFillStyle(s, &r2, texture);
877 rect.xmin = r2.xmin-linewidth-linewidth/2;
878 rect.ymin = r2.ymin-linewidth-linewidth/2;
879 rect.xmax = r2.xmax+linewidth+linewidth/2;
880 rect.ymax = r2.ymax+linewidth+linewidth/2;
882 swf_SetRect(tag,&rect);
883 swf_SetShapeHeader(tag,s);
884 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
885 swf_ShapeSetCircle(tag, s, r,r,r,r);
886 swf_ShapeSetEnd(tag);
889 s_addcharacter(name, id, tag, rect);
893 void s_textshape(char*name, char*fontname, float size, char*_text)
896 U8*text = (U8*)_text;
900 font = dictionary_lookup(&fonts, fontname);
902 syntaxerror("font \"%s\" not known!", fontname);
904 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
905 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
906 s_box(name, 0, 0, black, 20, 0);
909 g = font->ascii2glyph[text[0]];
911 outline = malloc(sizeof(outline_t));
912 memset(outline, 0, sizeof(outline_t));
913 outline->shape = font->glyph[g].shape;
914 outline->bbox = font->layout->bounds[g];
918 swf_Shape11DrawerInit(&draw, 0);
919 swf_DrawText(&draw, font, (int)(size*100), _text);
921 outline->shape = swf_ShapeDrawerToShape(&draw);
922 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
926 if(dictionary_lookup(&outlines, name))
927 syntaxerror("outline %s defined twice", name);
928 dictionary_put2(&outlines, name, outline);
931 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
936 font = dictionary_lookup(&fonts, fontname);
938 syntaxerror("font \"%s\" not known!", fontname);
940 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
942 if(!font->numchars) {
943 s_box(name, 0, 0, black, 20, 0);
946 r = swf_SetDefineText(tag, font, &color, text, size);
948 s_addcharacter(name, id, tag, r);
952 void s_quicktime(char*name, char*url)
957 memset(&r, 0, sizeof(r));
959 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
961 swf_SetString(tag, url);
963 s_addcharacter(name, id, tag, r);
967 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
970 EditTextLayout layout;
973 font = dictionary_lookup(&fonts, fontname);
975 syntaxerror("font \"%s\" not known!", fontname);
976 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
979 layout.leftmargin = 0;
980 layout.rightmargin = 0;
987 swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable);
989 s_addcharacter(name, id, tag, r);
993 /* type: either "jpeg" or "png"
995 void s_image(char*name, char*type, char*filename, int quality)
997 /* an image is actually two folded: 1st bitmap, 2nd character.
998 Both of them can be used separately */
1000 /* step 1: the bitmap */
1005 warning("image type \"png\" not supported yet!");
1006 s_box(name, 0, 0, black, 20, 0);
1010 #ifndef HAVE_LIBJPEG
1011 warning("no jpeg support compiled in");
1012 s_box(name, 0, 0, black, 20, 0);
1015 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1016 swf_SetU16(tag, imageID);
1018 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1019 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1022 swf_GetJPEGSize(filename, &width, &height);
1029 s_addimage(name, id, tag, r);
1034 /* step 2: the character */
1035 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1036 swf_SetU16(tag, id);
1037 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1039 s_addcharacter(name, id, tag, r);
1043 void dumpSWF(SWF*swf)
1045 TAG* tag = swf->firstTag;
1046 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1048 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1051 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1054 void s_font(char*name, char*filename)
1057 font = swf_LoadFont(filename);
1060 warning("Couldn't open font file \"%s\"", filename);
1061 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1062 memset(font, 0, sizeof(SWFFONT));
1063 dictionary_put2(&fonts, name, font);
1069 /* fix the layout. Only needed for old fonts */
1071 for(t=0;t<font->numchars;t++) {
1072 font->glyph[t].advance = 0;
1075 swf_FontCreateLayout(font);
1077 /* just in case this thing is used in .edittext later on */
1078 swf_FontPrepareForEditText(font);
1081 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1082 swf_FontSetDefine2(tag, font);
1085 if(dictionary_lookup(&fonts, name))
1086 syntaxerror("font %s defined twice", name);
1087 dictionary_put2(&fonts, name, font);
1092 typedef struct _sound_t
1098 void s_sound(char*name, char*filename)
1100 struct WAV wav, wav2;
1105 if(!readWAV(filename, &wav)) {
1106 warning("Couldn't read wav file \"%s\"", filename);
1110 convertWAV2mono(&wav, &wav2, 44100);
1111 samples = (U16*)wav2.data;
1112 numsamples = wav2.size/2;
1114 #ifdef WORDS_BIGENDIAN
1116 for(t=0;t<numsamples;t++) {
1117 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1122 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1123 swf_SetU16(tag, id); //id
1124 swf_SetSoundDefine(tag, samples, numsamples);
1126 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1130 if(dictionary_lookup(&sounds, name))
1131 syntaxerror("sound %s defined twice", name);
1132 dictionary_put2(&sounds, name, sound);
1140 static char* gradient_getToken(const char**p)
1144 while(**p && strchr(" \t\n\r", **p)) {
1148 while(**p && !strchr(" \t\n\r", **p)) {
1151 result = malloc((*p)-start+1);
1152 memcpy(result,start,(*p)-start+1);
1153 result[(*p)-start] = 0;
1157 float parsePercent(char*str);
1158 RGBA parseColor(char*str);
1160 GRADIENT parseGradient(const char*str)
1163 const char* p = str;
1164 memset(&gradient, 0, sizeof(GRADIENT));
1166 char*posstr,*colorstr;
1169 posstr = gradient_getToken(&p);
1172 pos = parsePercent(posstr);
1173 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1174 colorstr = gradient_getToken(&p);
1175 color = parseColor(colorstr);
1176 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1177 warning("gradient record too big- max size is 8, rest ignored");
1180 gradient.ratios[gradient.num] = (int)(pos*255.0);
1181 gradient.rgba[gradient.num] = color;
1189 void s_gradient(char*name, const char*text, int radial, int rotate)
1191 gradient_t* gradient;
1192 gradient = malloc(sizeof(gradient_t));
1193 memset(gradient, 0, sizeof(gradient_t));
1194 gradient->gradient = parseGradient(text);
1195 gradient->radial = radial;
1196 gradient->rotate = rotate;
1198 if(dictionary_lookup(&gradients, name))
1199 syntaxerror("gradient %s defined twice", name);
1200 dictionary_put2(&gradients, name, gradient);
1203 void s_action(const char*text)
1206 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1208 syntaxerror("Couldn't compile ActionScript");
1211 tag = swf_InsertTag(tag, ST_DOACTION);
1213 swf_ActionSet(tag, a);
1218 int s_swf3action(char*name, char*action)
1221 instance_t* object = 0;
1223 dictionary_lookup(&instances, name);
1224 if(!object && name && *name) {
1225 /* we have a name, but couldn't find it. Abort. */
1228 a = action_SetTarget(0, name);
1229 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1230 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1231 else if(!strcmp(action, "stop")) a = action_Stop(a);
1232 else if(!strcmp(action, "play")) a = action_Play(a);
1233 a = action_SetTarget(a, "");
1236 tag = swf_InsertTag(tag, ST_DOACTION);
1237 swf_ActionSet(tag, a);
1242 void s_outline(char*name, char*format, char*source)
1251 swf_Shape11DrawerInit(&draw, 0);
1252 draw_string(&draw, source);
1254 shape = swf_ShapeDrawerToShape(&draw);
1255 bounds = swf_ShapeDrawerGetBBox(&draw);
1256 draw.dealloc(&draw);
1258 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1259 outline->shape = shape;
1260 outline->bbox = bounds;
1262 if(dictionary_lookup(&outlines, name))
1263 syntaxerror("outline %s defined twice", name);
1264 dictionary_put2(&outlines, name, outline);
1267 int s_playsound(char*name, int loops, int nomultiple, int stop)
1272 sound = dictionary_lookup(&sounds, name);
1277 tag = swf_InsertTag(tag, ST_STARTSOUND);
1278 swf_SetU16(tag, sound->id); //id
1279 memset(&info, 0, sizeof(info));
1282 info.nomultiple = nomultiple;
1283 swf_SetSoundInfo(tag, &info);
1287 void s_includeswf(char*name, char*filename)
1295 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1296 f = open(filename,O_RDONLY|O_BINARY);
1298 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1299 s_box(name, 0, 0, black, 20, 0);
1302 if (swf_ReadSWF(f,&swf)<0) {
1303 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1304 s_box(name, 0, 0, black, 20, 0);
1309 /* FIXME: The following sets the bounding Box for the character.
1310 It is wrong for two reasons:
1311 a) It may be too small (in case objects in the movie clip at the borders)
1312 b) it may be too big (because the poor movie never got autocropped)
1316 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1317 swf_SetU16(tag, id);
1320 swf_Relocate(&swf, idmap);
1322 ftag = swf.firstTag;
1326 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1327 if(cutout[t] == ftag->id) {
1331 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1333 if(ftag->id == ST_END)
1337 /* We simply dump all tags right after the sprite
1338 header, relying on the fact that swf_OptimizeTagOrder() will
1339 sort things out for us later.
1340 We also rely on the fact that the imported SWF is well-formed.
1342 tag = swf_InsertTag(tag, ftag->id);
1343 swf_SetBlock(tag, ftag->data, ftag->len);
1347 syntaxerror("Included file %s contains errors", filename);
1348 tag = swf_InsertTag(tag, ST_END);
1352 s_addcharacter(name, id, tag, r);
1355 SRECT s_getCharBBox(char*name)
1357 character_t* c = dictionary_lookup(&characters, name);
1358 if(!c) syntaxerror("character '%s' unknown(2)", name);
1361 SRECT s_getInstanceBBox(char*name)
1363 instance_t * i = dictionary_lookup(&instances, name);
1365 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1367 if(!c) syntaxerror("internal error(5)");
1370 parameters_t s_getParameters(char*name)
1372 instance_t * i = dictionary_lookup(&instances, name);
1373 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1374 return i->parameters;
1376 void s_startclip(char*instance, char*character, parameters_t p)
1378 character_t* c = dictionary_lookup(&characters, character);
1382 syntaxerror("character %s not known", character);
1384 i = s_addinstance(instance, c, currentdepth);
1386 m = s_instancepos(i->character->size, &p);
1388 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1389 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1390 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1392 i->lastFrame= currentframe;
1394 stack[stackpos].tag = tag;
1395 stack[stackpos].type = 2;
1404 swf_SetTagPos(stack[stackpos].tag, 0);
1405 swf_GetPlaceObject(stack[stackpos].tag, &p);
1406 p.clipdepth = currentdepth;
1408 swf_ClearTag(stack[stackpos].tag);
1409 swf_SetPlaceObject(stack[stackpos].tag, &p);
1413 void s_put(char*instance, char*character, parameters_t p)
1415 character_t* c = dictionary_lookup(&characters, character);
1419 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1422 i = s_addinstance(instance, c, currentdepth);
1424 m = s_instancepos(i->character->size, &p);
1426 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1427 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1429 i->lastFrame = currentframe;
1433 void s_jump(char*instance, parameters_t p)
1435 instance_t* i = dictionary_lookup(&instances, instance);
1438 syntaxerror("instance %s not known", instance);
1442 m = s_instancepos(i->character->size, &p);
1444 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1445 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1447 i->lastFrame = currentframe;
1450 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1454 if(num==0 || num==1)
1456 ratio = (float)pos/(float)num;
1458 p.x = (p2->x-p1->x)*ratio + p1->x;
1459 p.y = (p2->y-p1->y)*ratio + p1->y;
1460 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1461 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1462 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1463 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1465 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1466 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1467 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1468 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1470 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1471 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1472 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1473 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1475 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1476 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1477 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1478 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1482 void s_change(char*instance, parameters_t p2)
1484 instance_t* i = dictionary_lookup(&instances, instance);
1488 int frame, allframes;
1490 syntaxerror("instance %s not known", instance);
1494 allframes = currentframe - i->lastFrame - 1;
1496 warning(".change ignored. can only .put/.change an object once per frame.");
1500 m = s_instancepos(i->character->size, &p2);
1501 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1502 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1505 /* o.k., we got the start and end point set. Now iterate though all the
1506 tags in between, inserting object changes after each new frame */
1509 if(!t) syntaxerror("internal error(6)");
1511 while(frame < allframes) {
1512 if(t->id == ST_SHOWFRAME) {
1517 p = s_interpolate(&p1, &p2, frame, allframes);
1518 m = s_instancepos(i->character->size, &p); //needed?
1519 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1520 i->lastFrame = currentframe;
1521 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1523 if(frame == allframes)
1528 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1532 void s_delinstance(char*instance)
1534 instance_t* i = dictionary_lookup(&instances, instance);
1536 syntaxerror("instance %s not known", instance);
1538 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1539 swf_SetU16(tag, i->depth);
1540 dictionary_del(&instances, instance);
1543 void s_qchange(char*instance, parameters_t p)
1550 syntaxerror(".end unexpected");
1551 if(stack[stackpos-1].type == 0)
1553 else if(stack[stackpos-1].type == 1)
1555 else if(stack[stackpos-1].type == 2)
1557 else if(stack[stackpos-1].type == 3)
1559 else syntaxerror("internal error 1");
1562 // ------------------------------------------------------------------------
1564 typedef int command_func_t(map_t*args);
1566 SRECT parseBox(char*str)
1569 float xmin, xmax, ymin, ymax;
1570 char*x = strchr(str, 'x');
1572 if(!strcmp(str, "autocrop")) {
1573 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1577 d1 = strchr(x+1, ':');
1579 d2 = strchr(d1+1, ':');
1581 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1585 else if(d1 && !d2) {
1586 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1592 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1597 r.xmin = (SCOORD)(xmin*20);
1598 r.ymin = (SCOORD)(ymin*20);
1599 r.xmax = (SCOORD)(xmax*20);
1600 r.ymax = (SCOORD)(ymax*20);
1603 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1606 float parseFloat(char*str)
1610 int parseInt(char*str)
1615 if(str[0]=='+' || str[0]=='-')
1619 if(str[t]<'0' || str[t]>'9')
1620 syntaxerror("Not an Integer: \"%s\"", str);
1623 int parseTwip(char*str)
1627 if(str[0]=='+' || str[0]=='-') {
1632 dot = strchr(str, '.');
1636 return sign*parseInt(str)*20;
1638 int l=strlen(++dot);
1640 for(s=str;s<dot-1;s++)
1641 if(*s<'0' || *s>'9')
1642 syntaxerror("Not a coordinate: \"%s\"", str);
1644 if(*s<'0' || *s>'9')
1645 syntaxerror("Not a coordinate: \"%s\"", str);
1647 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1648 warning("precision loss: %s converted to twip: %s", str, dot);
1653 return sign*atoi(str)*20;
1655 return sign*atoi(str)*20+atoi(dot)*2;
1657 return sign*atoi(str)*20+atoi(dot)/5;
1662 int isPoint(char*str)
1664 if(strchr(str, '('))
1670 SPOINT parsePoint(char*str)
1674 int l = strlen(str);
1675 char*comma = strchr(str, ',');
1676 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1677 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1678 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1679 p.x = parseTwip(tmp);
1680 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1681 p.y = parseTwip(tmp);
1685 int parseColor2(char*str, RGBA*color)
1687 int l = strlen(str);
1691 struct {unsigned char r,g,b;char*name;} colors[] =
1692 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1693 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1694 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1695 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1696 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1697 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1698 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1699 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1700 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1701 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1702 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1703 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1707 if(str[0]=='#' && (l==7 || l==9)) {
1708 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1710 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1712 color->r = r; color->g = g; color->b = b; color->a = a;
1715 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1716 if(!strcmp(str, colors[t].name)) {
1721 color->r = r; color->g = g; color->b = b; color->a = a;
1727 RGBA parseColor(char*str)
1730 if(!parseColor2(str, &c))
1731 syntaxerror("Expression '%s' is not a color", str);
1735 typedef struct _muladd {
1740 MULADD parseMulAdd(char*str)
1743 char* str2 = (char*)malloc(strlen(str)+5);
1750 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1751 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1752 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1753 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1754 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1755 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1756 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1757 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1758 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1759 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1761 syntaxerror("'%s' is not a valid color transform expression", str);
1763 m.add = (int)(add*256);
1764 m.mul = (int)(mul*256);
1769 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1771 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1772 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1774 if(a<-32768) a=-32768;
1775 if(a>32767) a=32767;
1776 if(m<-32768) m=-32768;
1777 if(m>32767) m=32767;
1783 float parsePercent(char*str)
1785 int l = strlen(str);
1789 return atoi(str)/100.0;
1791 syntaxerror("Expression '%s' is not a percentage", str);
1794 int isPercent(char*str)
1796 return str[strlen(str)-1]=='%';
1798 int parseNewSize(char*str, int size)
1801 return parsePercent(str)*size;
1803 return (int)(atof(str)*20);
1806 int isColor(char*str)
1809 return parseColor2(str, &c);
1812 static char* lu(map_t* args, char*name)
1814 char* value = map_lookup(args, name);
1816 map_dump(args, stdout, "");
1817 syntaxerror("internal error 2: value %s should be set", name);
1822 static int c_flash(map_t*args)
1824 char* name = lu(args, "name");
1825 char* compressstr = lu(args, "compress");
1826 SRECT bbox = parseBox(lu(args, "bbox"));
1827 int version = parseInt(lu(args, "version"));
1828 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1830 RGBA color = parseColor(lu(args, "background"));
1831 if(!strcmp(name, "!default!") || override_outputname)
1834 if(!strcmp(compressstr, "default"))
1835 compress = version==6;
1836 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1838 else if(!strcmp(compressstr, "no"))
1840 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1842 s_swf(name, bbox, version, fps, compress, color);
1845 int isRelative(char*str)
1847 return !strncmp(str, "<plus>", 6) ||
1848 !strncmp(str, "<minus>", 7);
1850 char* getOffset(char*str)
1852 if(!strncmp(str, "<plus>", 6))
1854 if(!strncmp(str, "<minus>", 7))
1856 syntaxerror("internal error (347)");
1859 int getSign(char*str)
1861 if(!strncmp(str, "<plus>", 6))
1863 if(!strncmp(str, "<minus>", 7))
1865 syntaxerror("internal error (348)");
1868 static dictionary_t points;
1869 static mem_t mpoints;
1870 int points_initialized = 0;
1872 SPOINT getPoint(SRECT r, char*name)
1875 if(!strcmp(name, "center")) {
1877 p.x = (r.xmin + r.xmax)/2;
1878 p.y = (r.ymin + r.ymax)/2;
1882 if(points_initialized)
1883 l = (int)dictionary_lookup(&points, name);
1885 syntaxerror("Invalid point: \"%s\".", name);
1888 return *(SPOINT*)&mpoints.buffer[l];
1890 static int c_gradient(map_t*args)
1892 char*name = lu(args, "name");
1893 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1894 int rotate = parseInt(lu(args, "rotate"));
1898 syntaxerror("colon (:) expected");
1900 s_gradient(name, text, radial,rotate);
1903 static int c_point(map_t*args)
1905 char*name = lu(args, "name");
1909 if(!points_initialized) {
1910 dictionary_init(&points);
1912 points_initialized = 1;
1914 p.x = parseTwip(lu(args, "x"));
1915 p.y = parseTwip(lu(args, "y"));
1916 pos = mem_put(&mpoints, &p, sizeof(p));
1917 string_set(&s1, name);
1919 dictionary_put(&points, s1, (void*)pos);
1922 static int c_play(map_t*args)
1924 char*name = lu(args, "name");
1925 char*loop = lu(args, "loop");
1926 char*nomultiple = lu(args, "nomultiple");
1928 if(!strcmp(nomultiple, "nomultiple"))
1931 nm = parseInt(nomultiple);
1933 if(s_playsound(name, parseInt(loop), nm, 0)) {
1935 } else if(s_swf3action(name, "play")) {
1941 static int c_stop(map_t*args)
1943 char*name = map_lookup(args, "name");
1945 if(s_playsound(name, 0,0,1)) {
1947 } else if(s_swf3action(name, "stop")) {
1950 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1954 static int c_nextframe(map_t*args)
1956 char*name = lu(args, "name");
1958 if(s_swf3action(name, "nextframe")) {
1961 syntaxerror("I don't know anything about movie \"%s\"", name);
1965 static int c_previousframe(map_t*args)
1967 char*name = lu(args, "name");
1969 if(s_swf3action(name, "previousframe")) {
1972 syntaxerror("I don't know anything about movie \"%s\"", name);
1976 static int c_placement(map_t*args, int type)
1978 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1981 char* luminancestr = lu(args, "luminance");
1982 char* scalestr = lu(args, "scale");
1983 char* scalexstr = lu(args, "scalex");
1984 char* scaleystr = lu(args, "scaley");
1985 char* rotatestr = lu(args, "rotate");
1986 char* shearstr = lu(args, "shear");
1987 char* xstr="", *pivotstr="";
1988 char* ystr="", *anglestr="";
1989 char*above = lu(args, "above"); /*FIXME*/
1990 char*below = lu(args, "below");
1991 char* rstr = lu(args, "red");
1992 char* gstr = lu(args, "green");
1993 char* bstr = lu(args, "blue");
1994 char* astr = lu(args, "alpha");
1995 char* pinstr = lu(args, "pin");
1996 char* as = map_lookup(args, "as");
2004 if(type==9) { // (?) .rotate or .arcchange
2005 pivotstr = lu(args, "pivot");
2006 anglestr = lu(args, "angle");
2008 xstr = lu(args, "x");
2009 ystr = lu(args, "y");
2012 luminance = parseMulAdd(luminancestr);
2015 luminance.mul = 256;
2019 if(scalexstr[0]||scaleystr[0])
2020 syntaxerror("scalex/scaley and scale cannot both be set");
2021 scalexstr = scaleystr = scalestr;
2024 if(type == 0 || type == 4) {
2026 character = lu(args, "character");
2027 parameters_clear(&p);
2028 } else if (type == 5) {
2029 character = lu(args, "name");
2030 parameters_clear(&p);
2033 p = s_getParameters(instance);
2038 if(isRelative(xstr)) {
2039 if(type == 0 || type == 4)
2040 syntaxerror("relative x values not allowed for initial put or startclip");
2041 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2043 p.x = parseTwip(xstr);
2047 if(isRelative(ystr)) {
2048 if(type == 0 || type == 4)
2049 syntaxerror("relative y values not allowed for initial put or startclip");
2050 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2052 p.y = parseTwip(ystr);
2056 /* scale, scalex, scaley */
2058 oldbbox = s_getCharBBox(character);
2060 oldbbox = s_getInstanceBBox(instance);
2062 oldwidth = oldbbox.xmax - oldbbox.xmin;
2063 oldheight = oldbbox.ymax - oldbbox.ymin;
2065 if(oldwidth==0) p.scalex = 1.0;
2068 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2072 if(oldheight==0) p.scaley = 1.0;
2075 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2081 if(isRelative(rotatestr)) {
2082 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2084 p.rotate = parseFloat(rotatestr);
2090 if(isRelative(shearstr)) {
2091 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2093 p.shear = parseFloat(shearstr);
2098 if(isPoint(pivotstr))
2099 p.pivot = parsePoint(pivotstr);
2101 p.pivot = getPoint(oldbbox, pivotstr);
2105 p.pin = parsePoint(pinstr);
2107 p.pin = getPoint(oldbbox, pinstr);
2110 /* color transform */
2112 if(rstr[0] || luminancestr[0]) {
2115 r = parseMulAdd(rstr);
2117 r.add = p.cxform.r0;
2118 r.mul = p.cxform.r1;
2120 r = mergeMulAdd(r, luminance);
2121 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2123 if(gstr[0] || luminancestr[0]) {
2126 g = parseMulAdd(gstr);
2128 g.add = p.cxform.g0;
2129 g.mul = p.cxform.g1;
2131 g = mergeMulAdd(g, luminance);
2132 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2134 if(bstr[0] || luminancestr[0]) {
2137 b = parseMulAdd(bstr);
2139 b.add = p.cxform.b0;
2140 b.mul = p.cxform.b1;
2142 b = mergeMulAdd(b, luminance);
2143 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2146 MULADD a = parseMulAdd(astr);
2147 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2151 s_put(instance, character, p);
2153 s_change(instance, p);
2155 s_qchange(instance, p);
2157 s_jump(instance, p);
2159 s_startclip(instance, character, p);
2160 else if(type == 5) {
2162 s_buttonput(character, as, p);
2164 s_buttonput(character, "shape", p);
2169 static int c_put(map_t*args)
2171 c_placement(args, 0);
2174 static int c_change(map_t*args)
2176 c_placement(args, 1);
2179 static int c_qchange(map_t*args)
2181 c_placement(args, 2);
2184 static int c_arcchange(map_t*args)
2186 c_placement(args, 2);
2189 static int c_jump(map_t*args)
2191 c_placement(args, 3);
2194 static int c_startclip(map_t*args)
2196 c_placement(args, 4);
2199 static int c_show(map_t*args)
2201 c_placement(args, 5);
2204 static int c_del(map_t*args)
2206 char*instance = lu(args, "name");
2207 s_delinstance(instance);
2210 static int c_end(map_t*args)
2215 static int c_sprite(map_t*args)
2217 char* name = lu(args, "name");
2221 static int c_frame(map_t*args)
2223 char*framestr = lu(args, "n");
2224 char*cutstr = lu(args, "cut");
2225 char*name = lu(args, "name");
2228 if(strcmp(cutstr, "no"))
2230 if(isRelative(framestr)) {
2231 frame = s_getframe();
2232 if(getSign(framestr)<0)
2233 syntaxerror("relative frame expressions must be positive");
2234 frame += parseInt(getOffset(framestr));
2237 frame = parseInt(framestr);
2238 if(s_getframe() >= frame
2239 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2240 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2242 s_frame(frame, cut, name);
2245 static int c_primitive(map_t*args)
2247 char*name = lu(args, "name");
2248 char*command = lu(args, "commandname");
2249 int width=0, height=0, r=0;
2250 int linewidth = parseTwip(lu(args, "line"));
2251 char*colorstr = lu(args, "color");
2252 RGBA color = parseColor(colorstr);
2253 char*fillstr = lu(args, "fill");
2260 if(!strcmp(command, "circle"))
2262 else if(!strcmp(command, "filled"))
2266 width = parseTwip(lu(args, "width"));
2267 height = parseTwip(lu(args, "height"));
2268 } else if (type==1) {
2269 r = parseTwip(lu(args, "r"));
2270 } else if (type==2) {
2271 outline = lu(args, "outline");
2274 if(!strcmp(fillstr, "fill"))
2276 if(!strcmp(fillstr, "none"))
2278 if(width<0 || height<0 || linewidth<0 || r<0)
2279 syntaxerror("values width, height, line, r must be positive");
2281 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2282 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2283 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2287 static int c_textshape(map_t*args)
2289 char*name = lu(args, "name");
2290 char*text = lu(args, "text");
2291 char*font = lu(args, "font");
2292 float size = parsePercent(lu(args, "size"));
2294 s_textshape(name, font, size, text);
2298 static int c_swf(map_t*args)
2300 char*name = lu(args, "name");
2301 char*filename = lu(args, "filename");
2302 char*command = lu(args, "commandname");
2303 if(!strcmp(command, "shape"))
2304 warning("Please use .swf instead of .shape");
2305 s_includeswf(name, filename);
2309 static int c_font(map_t*args)
2311 char*name = lu(args, "name");
2312 char*filename = lu(args, "filename");
2313 s_font(name, filename);
2317 static int c_sound(map_t*args)
2319 char*name = lu(args, "name");
2320 char*filename = lu(args, "filename");
2321 s_sound(name, filename);
2325 static int c_text(map_t*args)
2327 char*name = lu(args, "name");
2328 char*text = lu(args, "text");
2329 char*font = lu(args, "font");
2330 float size = parsePercent(lu(args, "size"));
2331 RGBA color = parseColor(lu(args, "color"));
2332 s_text(name, font, text, (int)(size*100), color);
2336 static int c_soundtrack(map_t*args)
2341 static int c_quicktime(map_t*args)
2343 char*name = lu(args, "name");
2344 char*url = lu(args, "url");
2345 s_quicktime(name, url);
2349 static int c_image(map_t*args)
2351 char*command = lu(args, "commandname");
2352 char*name = lu(args, "name");
2353 char*filename = lu(args, "filename");
2354 if(!strcmp(command,"jpeg")) {
2355 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2356 s_image(name, "jpeg", filename, quality);
2358 s_image(name, "png", filename, 0);
2363 static int c_outline(map_t*args)
2365 char*name = lu(args, "name");
2366 char*format = lu(args, "format");
2370 syntaxerror("colon (:) expected");
2372 s_outline(name, format, text);
2376 int fakechar(map_t*args)
2378 char*name = lu(args, "name");
2379 s_box(name, 0, 0, black, 20, 0);
2383 static int c_egon(map_t*args) {return fakechar(args);}
2384 static int c_button(map_t*args) {
2385 char*name = lu(args, "name");
2389 static int current_button_flags = 0;
2390 static int c_on_press(map_t*args)
2392 char*position = lu(args, "position");
2394 if(!strcmp(position, "inside")) {
2395 current_button_flags |= BC_OVERUP_OVERDOWN;
2396 } else if(!strcmp(position, "outside")) {
2397 //current_button_flags |= BC_IDLE_OUTDOWN;
2398 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2399 } else if(!strcmp(position, "anywhere")) {
2400 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2403 if(type == RAWDATA) {
2405 s_buttonaction(current_button_flags, action);
2406 current_button_flags = 0;
2412 static int c_on_release(map_t*args)
2414 char*position = lu(args, "position");
2416 if(!strcmp(position, "inside")) {
2417 current_button_flags |= BC_OVERDOWN_OVERUP;
2418 } else if(!strcmp(position, "outside")) {
2419 current_button_flags |= BC_OUTDOWN_IDLE;
2420 } else if(!strcmp(position, "anywhere")) {
2421 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2424 if(type == RAWDATA) {
2426 s_buttonaction(current_button_flags, action);
2427 current_button_flags = 0;
2433 static int c_on_move_in(map_t*args)
2435 char*position = lu(args, "state");
2437 if(!strcmp(position, "pressed")) {
2438 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2439 } else if(!strcmp(position, "not_pressed")) {
2440 current_button_flags |= BC_IDLE_OVERUP;
2441 } else if(!strcmp(position, "any")) {
2442 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2445 if(type == RAWDATA) {
2447 s_buttonaction(current_button_flags, action);
2448 current_button_flags = 0;
2454 static int c_on_move_out(map_t*args)
2456 char*position = lu(args, "state");
2458 if(!strcmp(position, "pressed")) {
2459 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2460 } else if(!strcmp(position, "not_pressed")) {
2461 current_button_flags |= BC_OVERUP_IDLE;
2462 } else if(!strcmp(position, "any")) {
2463 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2466 if(type == RAWDATA) {
2468 s_buttonaction(current_button_flags, action);
2469 current_button_flags = 0;
2475 static int c_on_key(map_t*args)
2477 char*key = lu(args, "key");
2479 if(strlen(key)==1) {
2482 current_button_flags |= 0x4000 + (key[0]*0x200);
2484 syntaxerror("invalid character: %c"+key[0]);
2489 <ctrl-x> = 0x200*(x-'a')
2493 syntaxerror("invalid key: %s",key);
2496 if(type == RAWDATA) {
2498 s_buttonaction(current_button_flags, action);
2499 current_button_flags = 0;
2506 static int c_edittext(map_t*args)
2508 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2509 char*name = lu(args, "name");
2510 char*font = lu(args, "font");
2511 int size = (int)(1024*parsePercent(lu(args, "size")));
2512 int width = parseTwip(lu(args, "width"));
2513 int height = parseTwip(lu(args, "height"));
2514 char*text = lu(args, "text");
2515 RGBA color = parseColor(lu(args, "color"));
2516 int maxlength = parseInt(lu(args, "maxlength"));
2517 char*variable = lu(args, "variable");
2518 char*passwordstr = lu(args, "password");
2519 char*wordwrapstr = lu(args, "wordwrap");
2520 char*multilinestr = lu(args, "multiline");
2521 char*htmlstr = lu(args, "html");
2522 char*noselectstr = lu(args, "noselect");
2523 char*readonlystr = lu(args, "readonly");
2524 char*borderstr = lu(args, "border");
2527 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2528 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2529 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2530 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2531 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2532 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2533 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2535 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2539 static int c_morphshape(map_t*args) {return fakechar(args);}
2540 static int c_movie(map_t*args) {return fakechar(args);}
2542 static int c_texture(map_t*args) {return 0;}
2544 static int c_action(map_t*args)
2547 if(type != RAWDATA) {
2548 syntaxerror("colon (:) expected");
2558 command_func_t* func;
2561 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2562 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2563 // "import" type stuff
2564 {"swf", c_swf, "name filename"},
2565 {"shape", c_swf, "name filename"},
2566 {"jpeg", c_image, "name filename quality=80%"},
2567 {"png", c_image, "name filename"},
2568 {"movie", c_movie, "name filename"},
2569 {"sound", c_sound, "name filename"},
2570 {"font", c_font, "name filename"},
2571 {"soundtrack", c_soundtrack, "filename"},
2572 {"quicktime", c_quicktime, "url"},
2574 // generators of primitives
2576 {"point", c_point, "name x=0 y=0"},
2577 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2578 {"outline", c_outline, "name format=simple"},
2579 {"textshape", c_textshape, "name font size=100% text"},
2581 // character generators
2582 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2583 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2584 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2586 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2587 {"text", c_text, "name text font size=100% color=white"},
2588 {"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"},
2589 {"morphshape", c_morphshape, "name start end"},
2590 {"button", c_button, "name"},
2591 {"show", c_show, "name x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below= as="},
2592 {"on_press", c_on_press, "position=inside"},
2593 {"on_release", c_on_release, "position=anywhere"},
2594 {"on_move_in", c_on_move_in, "state=not_pressed"},
2595 {"on_move_out", c_on_move_out, "state=not_pressed"},
2596 {"on_key", c_on_key, "key=any"},
2599 {"play", c_play, "name loop=0 @nomultiple=0"},
2600 {"stop", c_stop, "name= "},
2601 {"nextframe", c_nextframe, "name"},
2602 {"previousframe", c_previousframe, "name"},
2604 // object placement tags
2605 {"put", c_put, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2606 {"startclip", c_startclip, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2607 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2608 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2609 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2610 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2611 {"del", c_del, "name"},
2612 // virtual object placement
2613 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2615 // commands which start a block
2616 //startclip (see above)
2617 {"sprite", c_sprite, "name"},
2618 {"action", c_action, ""},
2624 static map_t parseArguments(char*command, char*pattern)
2640 string_set(&t1, "commandname");
2641 string_set(&t2, command);
2642 map_put(&result, t1, t2);
2644 if(!pattern || !*pattern)
2651 if(!strncmp("<i> ", x, 3)) {
2653 if(type == COMMAND || type == RAWDATA) {
2655 syntaxerror("character name expected");
2657 name[pos].str = "instance";
2659 value[pos].str = text;
2660 value[pos].len = strlen(text);
2664 if(type == ASSIGNMENT)
2667 name[pos].str = "character";
2669 value[pos].str = text;
2670 value[pos].len = strlen(text);
2678 isboolean[pos] = (x[0] =='@');
2691 name[pos].len = d-x;
2696 name[pos].len = e-x;
2697 value[pos].str = e+1;
2698 value[pos].len = d-e-1;
2706 /* for(t=0;t<len;t++) {
2707 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2708 isboolean[t]?"(boolean)":"");
2713 if(type == RAWDATA || type == COMMAND) {
2718 // first, search for boolean arguments
2719 for(pos=0;pos<len;pos++)
2721 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2723 if(type == ASSIGNMENT)
2725 value[pos].str = text;
2726 value[pos].len = strlen(text);
2727 /*printf("setting boolean parameter %s (to %s)\n",
2728 strdup_n(name[pos], namelen[pos]),
2729 strdup_n(value[pos], valuelen[pos]));*/
2734 // second, search for normal arguments
2736 for(pos=0;pos<len;pos++)
2738 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2739 (type != ASSIGNMENT && !set[pos])) {
2741 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2743 if(type == ASSIGNMENT)
2746 value[pos].str = text;
2747 value[pos].len = strlen(text);
2749 printf("setting parameter %s (to %s)\n",
2750 strdup_n(name[pos].str, name[pos].len),
2751 strdup_n(value[pos].str, value[pos].len));
2757 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
2761 for(t=0;t<len;t++) {
2762 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2765 for(t=0;t<len;t++) {
2766 if(value[t].str && value[t].str[0] == '*') {
2767 //relative default- take value from some other parameter
2769 for(s=0;s<len;s++) {
2770 if(value[s].len == value[t].len-1 &&
2771 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2772 value[t].str = value[s].str;
2775 if(value[t].str == 0) {
2777 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2781 /* ok, now construct the dictionary from the parameters */
2785 map_put(&result, name[t], value[t]);
2789 static void parseArgumentsForCommand(char*command)
2794 msg("<verbose> parse Command: %s (line %d)", command, line);
2796 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2797 if(!strcmp(arguments[t].command, command)) {
2799 /* ugly hack- will be removed soon (once documentation and .sc generating
2800 utilities have been changed) */
2801 if(!strcmp(command, "swf") && !stackpos) {
2802 warning("Please use .flash instead of .swf- this will be mandatory soon");
2807 args = parseArguments(command, arguments[t].arguments);
2813 syntaxerror("command %s not known", command);
2815 // catch missing .flash directives at the beginning of a file
2816 if(strcmp(command, "flash") && !stackpos)
2818 syntaxerror("No movie defined- use .flash first");
2822 printf(".%s\n", command);fflush(stdout);
2823 map_dump(&args, stdout, "\t");fflush(stdout);
2826 (*arguments[nr].func)(&args);
2828 /*if(!strcmp(command, "button") ||
2829 !strcmp(command, "action")) {
2832 if(type == COMMAND) {
2833 if(!strcmp(text, "end"))
2847 int main (int argc,char ** argv)
2850 processargs(argc, argv);
2851 initLog(0,-1,0,0,-1,verbose);
2854 args_callback_usage(argv[0]);
2858 file = generateTokens(filename);
2860 printf("parser returned error.\n");
2866 while(!noMoreTokens()) {
2869 syntaxerror("command expected");
2870 parseArgumentsForCommand(text);