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_END);
623 tag = stack[stackpos].tag;
626 syntaxerror("internal error(7)");
628 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
629 free(stack[stackpos].name);
632 static void s_endSWF()
638 if(stack[stackpos].cut)
639 tag = removeFromTo(stack[stackpos].cut, tag);
643 swf = stack[stackpos].swf;
644 filename = stack[stackpos].filename;
646 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
647 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
648 tag = swf_InsertTag(tag, ST_SHOWFRAME);
650 tag = swf_InsertTag(tag, ST_END);
652 swf_OptimizeTagOrder(swf);
658 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
659 swf->movieSize = currentrect; /* "autocrop" */
662 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
663 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
664 swf->movieSize.ymax += 20;
667 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
669 syntaxerror("couldn't create output file %s", filename);
672 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
674 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
678 dictionary_clear(&instances);
679 dictionary_clear(&characters);
680 dictionary_clear(&images);
681 dictionary_clear(&outlines);
682 dictionary_clear(&gradients);
683 dictionary_clear(&fonts);
684 dictionary_clear(&sounds);
694 if(stack[stackpos-1].type == 0)
695 syntaxerror("End of file encountered in .flash block");
696 if(stack[stackpos-1].type == 1)
697 syntaxerror("End of file encountered in .sprite block");
698 if(stack[stackpos-1].type == 2)
699 syntaxerror("End of file encountered in .clip block");
705 return currentframe+1;
708 void s_frame(int nr, int cut, char*name)
714 syntaxerror("Illegal frame number");
715 nr--; // internally, frame 1 is frame 0
717 for(t=currentframe;t<nr;t++) {
718 tag = swf_InsertTag(tag, ST_SHOWFRAME);
719 if(t==nr-1 && name && *name) {
720 tag = swf_InsertTag(tag, ST_FRAMELABEL);
721 swf_SetString(tag, name);
724 if(nr == 0 && currentframe == 0 && name) {
725 tag = swf_InsertTag(tag, ST_FRAMELABEL);
726 swf_SetString(tag, name);
731 syntaxerror("Can't cut, frame empty");
733 stack[stackpos].cut = tag;
739 int parseColor2(char*str, RGBA*color);
741 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
746 if(texture[0] == '#') {
747 parseColor2(texture, &color);
748 return swf_ShapeAddSolidFillStyle(s, &color);
749 } else if((image = dictionary_lookup(&images, texture))) {
751 swf_GetMatrix(0, &m);
752 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
753 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
756 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
757 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
758 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
762 swf_GetMatrix(0, &rot);
763 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
764 csin = sin(-gradient->rotate*2*3.14159265358979/360);
766 rot.r1 = -csin*65536;
769 r2 = swf_TurnRect(*r, &rot);
770 swf_GetMatrix(0, &m);
771 m.sx = (r2.xmax - r2.xmin)*2*ccos;
772 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
773 m.r0 = (r2.ymax - r2.ymin)*2*csin;
774 m.sy = (r2.ymax - r2.ymin)*2*ccos;
775 m.tx = r->xmin + (r->xmax - r->xmin)/2;
776 m.ty = r->ymin + (r->ymax - r->ymin)/2;
777 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
778 } else if (parseColor2(texture, &color)) {
779 return swf_ShapeAddSolidFillStyle(s, &color);
781 syntaxerror("not a color/fillstyle: %s", texture);
786 RGBA black={r:0,g:0,b:0,a:0};
787 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
796 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
799 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
801 fs1 = addFillStyle(s, &r2, texture);
804 r.xmin = r2.xmin-linewidth-linewidth/2;
805 r.ymin = r2.ymin-linewidth-linewidth/2;
806 r.xmax = r2.xmax+linewidth+linewidth/2;
807 r.ymax = r2.ymax+linewidth+linewidth/2;
809 swf_SetShapeHeader(tag,s);
810 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
811 swf_ShapeSetLine(tag,s,width,0);
812 swf_ShapeSetLine(tag,s,0,height);
813 swf_ShapeSetLine(tag,s,-width,0);
814 swf_ShapeSetLine(tag,s,0,-height);
815 swf_ShapeSetEnd(tag);
818 s_addcharacter(name, id, tag, r);
822 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
828 outline = dictionary_lookup(&outlines, outlinename);
830 syntaxerror("outline %s not defined", outlinename);
834 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
837 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
839 fs1 = addFillStyle(s, &r2, texture);
842 rect.xmin = r2.xmin-linewidth-linewidth/2;
843 rect.ymin = r2.ymin-linewidth-linewidth/2;
844 rect.xmax = r2.xmax+linewidth+linewidth/2;
845 rect.ymax = r2.ymax+linewidth+linewidth/2;
847 swf_SetRect(tag,&rect);
848 swf_SetShapeStyles(tag, s);
849 swf_ShapeCountBits(s,0,0);
850 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, 1, 1,
851 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
852 swf_SetShapeBits(tag, s);
853 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
856 s_addcharacter(name, id, tag, rect);
860 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
865 r2.xmin = r2.ymin = 0;
869 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
872 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
874 fs1 = addFillStyle(s, &r2, texture);
876 rect.xmin = r2.xmin-linewidth-linewidth/2;
877 rect.ymin = r2.ymin-linewidth-linewidth/2;
878 rect.xmax = r2.xmax+linewidth+linewidth/2;
879 rect.ymax = r2.ymax+linewidth+linewidth/2;
881 swf_SetRect(tag,&rect);
882 swf_SetShapeHeader(tag,s);
883 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
884 swf_ShapeSetCircle(tag, s, r,r,r,r);
885 swf_ShapeSetEnd(tag);
888 s_addcharacter(name, id, tag, rect);
892 void s_textshape(char*name, char*fontname, float size, char*_text)
895 U8*text = (U8*)_text;
899 font = dictionary_lookup(&fonts, fontname);
901 syntaxerror("font \"%s\" not known!", fontname);
903 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
904 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
905 s_box(name, 0, 0, black, 20, 0);
908 g = font->ascii2glyph[text[0]];
910 outline = malloc(sizeof(outline_t));
911 memset(outline, 0, sizeof(outline_t));
912 outline->shape = font->glyph[g].shape;
913 outline->bbox = font->layout->bounds[g];
917 swf_Shape11DrawerInit(&draw, 0);
918 swf_DrawText(&draw, font, (int)(size*100), _text);
920 outline->shape = swf_ShapeDrawerToShape(&draw);
921 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
925 if(dictionary_lookup(&outlines, name))
926 syntaxerror("outline %s defined twice", name);
927 dictionary_put2(&outlines, name, outline);
930 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
935 font = dictionary_lookup(&fonts, fontname);
937 syntaxerror("font \"%s\" not known!", fontname);
939 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
941 if(!font->numchars) {
942 s_box(name, 0, 0, black, 20, 0);
945 r = swf_SetDefineText(tag, font, &color, text, size);
947 s_addcharacter(name, id, tag, r);
951 void s_quicktime(char*name, char*url)
956 memset(&r, 0, sizeof(r));
958 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
960 swf_SetString(tag, url);
962 s_addcharacter(name, id, tag, r);
966 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
969 EditTextLayout layout;
972 font = dictionary_lookup(&fonts, fontname);
974 syntaxerror("font \"%s\" not known!", fontname);
975 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
978 layout.leftmargin = 0;
979 layout.rightmargin = 0;
986 swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable);
988 s_addcharacter(name, id, tag, r);
992 /* type: either "jpeg" or "png"
994 void s_image(char*name, char*type, char*filename, int quality)
996 /* an image is actually two folded: 1st bitmap, 2nd character.
997 Both of them can be used separately */
999 /* step 1: the bitmap */
1004 warning("image type \"png\" not supported yet!");
1005 s_box(name, 0, 0, black, 20, 0);
1009 #ifndef HAVE_LIBJPEG
1010 warning("no jpeg support compiled in");
1011 s_box(name, 0, 0, black, 20, 0);
1014 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1015 swf_SetU16(tag, imageID);
1017 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1018 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1021 swf_GetJPEGSize(filename, &width, &height);
1028 s_addimage(name, id, tag, r);
1033 /* step 2: the character */
1034 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1035 swf_SetU16(tag, id);
1036 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1038 s_addcharacter(name, id, tag, r);
1042 void dumpSWF(SWF*swf)
1044 TAG* tag = swf->firstTag;
1045 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1047 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1050 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1053 void s_font(char*name, char*filename)
1056 font = swf_LoadFont(filename);
1059 warning("Couldn't open font file \"%s\"", filename);
1060 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1061 memset(font, 0, sizeof(SWFFONT));
1062 dictionary_put2(&fonts, name, font);
1068 /* fix the layout. Only needed for old fonts */
1070 for(t=0;t<font->numchars;t++) {
1071 font->glyph[t].advance = 0;
1074 swf_FontCreateLayout(font);
1076 /* just in case this thing is used in .edittext later on */
1077 swf_FontPrepareForEditText(font);
1080 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1081 swf_FontSetDefine2(tag, font);
1084 if(dictionary_lookup(&fonts, name))
1085 syntaxerror("font %s defined twice", name);
1086 dictionary_put2(&fonts, name, font);
1091 typedef struct _sound_t
1097 void s_sound(char*name, char*filename)
1099 struct WAV wav, wav2;
1104 if(!readWAV(filename, &wav)) {
1105 warning("Couldn't read wav file \"%s\"", filename);
1109 convertWAV2mono(&wav, &wav2, 44100);
1110 samples = (U16*)wav2.data;
1111 numsamples = wav2.size/2;
1113 #ifdef WORDS_BIGENDIAN
1115 for(t=0;t<numsamples;t++) {
1116 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1121 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1122 swf_SetU16(tag, id); //id
1123 swf_SetSoundDefine(tag, samples, numsamples);
1125 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1129 if(dictionary_lookup(&sounds, name))
1130 syntaxerror("sound %s defined twice", name);
1131 dictionary_put2(&sounds, name, sound);
1139 static char* gradient_getToken(const char**p)
1143 while(**p && strchr(" \t\n\r", **p)) {
1147 while(**p && !strchr(" \t\n\r", **p)) {
1150 result = malloc((*p)-start+1);
1151 memcpy(result,start,(*p)-start+1);
1152 result[(*p)-start] = 0;
1156 float parsePercent(char*str);
1157 RGBA parseColor(char*str);
1159 GRADIENT parseGradient(const char*str)
1162 const char* p = str;
1163 memset(&gradient, 0, sizeof(GRADIENT));
1165 char*posstr,*colorstr;
1168 posstr = gradient_getToken(&p);
1171 pos = parsePercent(posstr);
1172 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1173 colorstr = gradient_getToken(&p);
1174 color = parseColor(colorstr);
1175 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1176 warning("gradient record too big- max size is 8, rest ignored");
1179 gradient.ratios[gradient.num] = (int)(pos*255.0);
1180 gradient.rgba[gradient.num] = color;
1188 void s_gradient(char*name, const char*text, int radial, int rotate)
1190 gradient_t* gradient;
1191 gradient = malloc(sizeof(gradient_t));
1192 memset(gradient, 0, sizeof(gradient_t));
1193 gradient->gradient = parseGradient(text);
1194 gradient->radial = radial;
1195 gradient->rotate = rotate;
1197 if(dictionary_lookup(&gradients, name))
1198 syntaxerror("gradient %s defined twice", name);
1199 dictionary_put2(&gradients, name, gradient);
1202 void s_action(const char*text)
1205 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1207 syntaxerror("Couldn't compile ActionScript");
1210 tag = swf_InsertTag(tag, ST_DOACTION);
1212 swf_ActionSet(tag, a);
1217 int s_swf3action(char*name, char*action)
1220 instance_t* object = 0;
1222 dictionary_lookup(&instances, name);
1223 if(!object && name && *name) {
1224 /* we have a name, but couldn't find it. Abort. */
1227 a = action_SetTarget(0, name);
1228 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1229 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1230 else if(!strcmp(action, "stop")) a = action_Stop(a);
1231 else if(!strcmp(action, "play")) a = action_Play(a);
1232 a = action_SetTarget(a, "");
1235 tag = swf_InsertTag(tag, ST_DOACTION);
1236 swf_ActionSet(tag, a);
1241 void s_outline(char*name, char*format, char*source)
1250 swf_Shape11DrawerInit(&draw, 0);
1251 draw_string(&draw, source);
1253 shape = swf_ShapeDrawerToShape(&draw);
1254 bounds = swf_ShapeDrawerGetBBox(&draw);
1255 draw.dealloc(&draw);
1257 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1258 outline->shape = shape;
1259 outline->bbox = bounds;
1261 if(dictionary_lookup(&outlines, name))
1262 syntaxerror("outline %s defined twice", name);
1263 dictionary_put2(&outlines, name, outline);
1266 int s_playsound(char*name, int loops, int nomultiple, int stop)
1271 sound = dictionary_lookup(&sounds, name);
1276 tag = swf_InsertTag(tag, ST_STARTSOUND);
1277 swf_SetU16(tag, sound->id); //id
1278 memset(&info, 0, sizeof(info));
1281 info.nomultiple = nomultiple;
1282 swf_SetSoundInfo(tag, &info);
1286 void s_includeswf(char*name, char*filename)
1294 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1295 f = open(filename,O_RDONLY|O_BINARY);
1297 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1298 s_box(name, 0, 0, black, 20, 0);
1301 if (swf_ReadSWF(f,&swf)<0) {
1302 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1303 s_box(name, 0, 0, black, 20, 0);
1308 /* FIXME: The following sets the bounding Box for the character.
1309 It is wrong for two reasons:
1310 a) It may be too small (in case objects in the movie clip at the borders)
1311 b) it may be too big (because the poor movie never got autocropped)
1315 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1316 swf_SetU16(tag, id);
1319 swf_Relocate(&swf, idmap);
1321 ftag = swf.firstTag;
1325 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1326 if(cutout[t] == ftag->id) {
1330 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1332 if(ftag->id == ST_END)
1336 /* We simply dump all tags right after the sprite
1337 header, relying on the fact that swf_OptimizeTagOrder() will
1338 sort things out for us later.
1339 We also rely on the fact that the imported SWF is well-formed.
1341 tag = swf_InsertTag(tag, ftag->id);
1342 swf_SetBlock(tag, ftag->data, ftag->len);
1346 syntaxerror("Included file %s contains errors", filename);
1347 tag = swf_InsertTag(tag, ST_END);
1351 s_addcharacter(name, id, tag, r);
1354 SRECT s_getCharBBox(char*name)
1356 character_t* c = dictionary_lookup(&characters, name);
1357 if(!c) syntaxerror("character '%s' unknown(2)", name);
1360 SRECT s_getInstanceBBox(char*name)
1362 instance_t * i = dictionary_lookup(&instances, name);
1364 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1366 if(!c) syntaxerror("internal error(5)");
1369 parameters_t s_getParameters(char*name)
1371 instance_t * i = dictionary_lookup(&instances, name);
1372 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1373 return i->parameters;
1375 void s_startclip(char*instance, char*character, parameters_t p)
1377 character_t* c = dictionary_lookup(&characters, character);
1381 syntaxerror("character %s not known", character);
1383 i = s_addinstance(instance, c, currentdepth);
1385 m = s_instancepos(i->character->size, &p);
1387 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1388 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1389 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1391 i->lastFrame= currentframe;
1393 stack[stackpos].tag = tag;
1394 stack[stackpos].type = 2;
1403 swf_SetTagPos(stack[stackpos].tag, 0);
1404 swf_GetPlaceObject(stack[stackpos].tag, &p);
1405 p.clipdepth = currentdepth;
1407 swf_ClearTag(stack[stackpos].tag);
1408 swf_SetPlaceObject(stack[stackpos].tag, &p);
1412 void s_put(char*instance, char*character, parameters_t p)
1414 character_t* c = dictionary_lookup(&characters, character);
1418 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1421 i = s_addinstance(instance, c, currentdepth);
1423 m = s_instancepos(i->character->size, &p);
1425 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1426 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1428 i->lastFrame = currentframe;
1432 void s_jump(char*instance, parameters_t p)
1434 instance_t* i = dictionary_lookup(&instances, instance);
1437 syntaxerror("instance %s not known", instance);
1441 m = s_instancepos(i->character->size, &p);
1443 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1444 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1446 i->lastFrame = currentframe;
1449 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1453 if(num==0 || num==1)
1455 ratio = (float)pos/(float)num;
1457 p.x = (p2->x-p1->x)*ratio + p1->x;
1458 p.y = (p2->y-p1->y)*ratio + p1->y;
1459 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1460 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1461 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1462 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1464 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1465 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1466 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1467 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1469 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1470 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1471 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1472 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1474 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1475 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1476 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1477 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1481 void s_change(char*instance, parameters_t p2)
1483 instance_t* i = dictionary_lookup(&instances, instance);
1487 int frame, allframes;
1489 syntaxerror("instance %s not known", instance);
1493 allframes = currentframe - i->lastFrame - 1;
1495 warning(".change ignored. can only .put/.change an object once per frame.");
1499 m = s_instancepos(i->character->size, &p2);
1500 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1501 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1504 /* o.k., we got the start and end point set. Now iterate though all the
1505 tags in between, inserting object changes after each new frame */
1508 if(!t) syntaxerror("internal error(6)");
1510 while(frame < allframes) {
1511 if(t->id == ST_SHOWFRAME) {
1516 p = s_interpolate(&p1, &p2, frame, allframes);
1517 m = s_instancepos(i->character->size, &p); //needed?
1518 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1519 i->lastFrame = currentframe;
1520 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1522 if(frame == allframes)
1527 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1531 void s_delinstance(char*instance)
1533 instance_t* i = dictionary_lookup(&instances, instance);
1535 syntaxerror("instance %s not known", instance);
1537 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1538 swf_SetU16(tag, i->depth);
1539 dictionary_del(&instances, instance);
1542 void s_qchange(char*instance, parameters_t p)
1549 syntaxerror(".end unexpected");
1550 if(stack[stackpos-1].type == 0)
1552 else if(stack[stackpos-1].type == 1)
1554 else if(stack[stackpos-1].type == 2)
1556 else if(stack[stackpos-1].type == 3)
1558 else syntaxerror("internal error 1");
1561 // ------------------------------------------------------------------------
1563 typedef int command_func_t(map_t*args);
1565 SRECT parseBox(char*str)
1568 float xmin, xmax, ymin, ymax;
1569 char*x = strchr(str, 'x');
1571 if(!strcmp(str, "autocrop")) {
1572 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1576 d1 = strchr(x+1, ':');
1578 d2 = strchr(d1+1, ':');
1580 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1584 else if(d1 && !d2) {
1585 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1591 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1596 r.xmin = (SCOORD)(xmin*20);
1597 r.ymin = (SCOORD)(ymin*20);
1598 r.xmax = (SCOORD)(xmax*20);
1599 r.ymax = (SCOORD)(ymax*20);
1602 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1605 float parseFloat(char*str)
1609 int parseInt(char*str)
1614 if(str[0]=='+' || str[0]=='-')
1618 if(str[t]<'0' || str[t]>'9')
1619 syntaxerror("Not an Integer: \"%s\"", str);
1622 int parseTwip(char*str)
1626 if(str[0]=='+' || str[0]=='-') {
1631 dot = strchr(str, '.');
1635 return sign*parseInt(str)*20;
1637 int l=strlen(++dot);
1639 for(s=str;s<dot-1;s++)
1640 if(*s<'0' || *s>'9')
1641 syntaxerror("Not a coordinate: \"%s\"", str);
1643 if(*s<'0' || *s>'9')
1644 syntaxerror("Not a coordinate: \"%s\"", str);
1646 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1647 warning("precision loss: %s converted to twip: %s", str, dot);
1652 return sign*atoi(str)*20;
1654 return sign*atoi(str)*20+atoi(dot)*2;
1656 return sign*atoi(str)*20+atoi(dot)/5;
1661 int isPoint(char*str)
1663 if(strchr(str, '('))
1669 SPOINT parsePoint(char*str)
1673 int l = strlen(str);
1674 char*comma = strchr(str, ',');
1675 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1676 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1677 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1678 p.x = parseTwip(tmp);
1679 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1680 p.y = parseTwip(tmp);
1684 int parseColor2(char*str, RGBA*color)
1686 int l = strlen(str);
1690 struct {unsigned char r,g,b;char*name;} colors[] =
1691 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1692 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1693 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1694 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1695 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1696 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1697 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1698 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1699 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1700 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1701 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1702 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1706 if(str[0]=='#' && (l==7 || l==9)) {
1707 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1709 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1711 color->r = r; color->g = g; color->b = b; color->a = a;
1714 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1715 if(!strcmp(str, colors[t].name)) {
1720 color->r = r; color->g = g; color->b = b; color->a = a;
1726 RGBA parseColor(char*str)
1729 if(!parseColor2(str, &c))
1730 syntaxerror("Expression '%s' is not a color", str);
1734 typedef struct _muladd {
1739 MULADD parseMulAdd(char*str)
1742 char* str2 = (char*)malloc(strlen(str)+5);
1749 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1750 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1751 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1752 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1753 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1754 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1755 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1756 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1757 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1758 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1760 syntaxerror("'%s' is not a valid color transform expression", str);
1762 m.add = (int)(add*256);
1763 m.mul = (int)(mul*256);
1768 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1770 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1771 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1773 if(a<-32768) a=-32768;
1774 if(a>32767) a=32767;
1775 if(m<-32768) m=-32768;
1776 if(m>32767) m=32767;
1782 float parsePercent(char*str)
1784 int l = strlen(str);
1788 return atoi(str)/100.0;
1790 syntaxerror("Expression '%s' is not a percentage", str);
1793 int isPercent(char*str)
1795 return str[strlen(str)-1]=='%';
1797 int parseNewSize(char*str, int size)
1800 return parsePercent(str)*size;
1802 return (int)(atof(str)*20);
1805 int isColor(char*str)
1808 return parseColor2(str, &c);
1811 static char* lu(map_t* args, char*name)
1813 char* value = map_lookup(args, name);
1815 map_dump(args, stdout, "");
1816 syntaxerror("internal error 2: value %s should be set", name);
1821 static int c_flash(map_t*args)
1823 char* name = lu(args, "name");
1824 char* compressstr = lu(args, "compress");
1825 SRECT bbox = parseBox(lu(args, "bbox"));
1826 int version = parseInt(lu(args, "version"));
1827 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1829 RGBA color = parseColor(lu(args, "background"));
1830 if(!strcmp(name, "!default!") || override_outputname)
1833 if(!strcmp(compressstr, "default"))
1834 compress = version==6;
1835 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1837 else if(!strcmp(compressstr, "no"))
1839 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1841 s_swf(name, bbox, version, fps, compress, color);
1844 int isRelative(char*str)
1846 return !strncmp(str, "<plus>", 6) ||
1847 !strncmp(str, "<minus>", 7);
1849 char* getOffset(char*str)
1851 if(!strncmp(str, "<plus>", 6))
1853 if(!strncmp(str, "<minus>", 7))
1855 syntaxerror("internal error (347)");
1858 int getSign(char*str)
1860 if(!strncmp(str, "<plus>", 6))
1862 if(!strncmp(str, "<minus>", 7))
1864 syntaxerror("internal error (348)");
1867 static dictionary_t points;
1868 static mem_t mpoints;
1869 int points_initialized = 0;
1871 SPOINT getPoint(SRECT r, char*name)
1874 if(!strcmp(name, "center")) {
1876 p.x = (r.xmin + r.xmax)/2;
1877 p.y = (r.ymin + r.ymax)/2;
1881 if(points_initialized)
1882 l = (int)dictionary_lookup(&points, name);
1884 syntaxerror("Invalid point: \"%s\".", name);
1887 return *(SPOINT*)&mpoints.buffer[l];
1889 static int c_gradient(map_t*args)
1891 char*name = lu(args, "name");
1892 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1893 int rotate = parseInt(lu(args, "rotate"));
1897 syntaxerror("colon (:) expected");
1899 s_gradient(name, text, radial,rotate);
1902 static int c_point(map_t*args)
1904 char*name = lu(args, "name");
1908 if(!points_initialized) {
1909 dictionary_init(&points);
1911 points_initialized = 1;
1913 p.x = parseTwip(lu(args, "x"));
1914 p.y = parseTwip(lu(args, "y"));
1915 pos = mem_put(&mpoints, &p, sizeof(p));
1916 string_set(&s1, name);
1918 dictionary_put(&points, s1, (void*)pos);
1921 static int c_play(map_t*args)
1923 char*name = lu(args, "name");
1924 char*loop = lu(args, "loop");
1925 char*nomultiple = lu(args, "nomultiple");
1927 if(!strcmp(nomultiple, "nomultiple"))
1930 nm = parseInt(nomultiple);
1932 if(s_playsound(name, parseInt(loop), nm, 0)) {
1934 } else if(s_swf3action(name, "play")) {
1940 static int c_stop(map_t*args)
1942 char*name = map_lookup(args, "name");
1944 if(s_playsound(name, 0,0,1)) {
1946 } else if(s_swf3action(name, "stop")) {
1949 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1953 static int c_nextframe(map_t*args)
1955 char*name = lu(args, "name");
1957 if(s_swf3action(name, "nextframe")) {
1960 syntaxerror("I don't know anything about movie \"%s\"", name);
1964 static int c_previousframe(map_t*args)
1966 char*name = lu(args, "name");
1968 if(s_swf3action(name, "previousframe")) {
1971 syntaxerror("I don't know anything about movie \"%s\"", name);
1975 static int c_placement(map_t*args, int type)
1977 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1980 char* luminancestr = lu(args, "luminance");
1981 char* scalestr = lu(args, "scale");
1982 char* scalexstr = lu(args, "scalex");
1983 char* scaleystr = lu(args, "scaley");
1984 char* rotatestr = lu(args, "rotate");
1985 char* shearstr = lu(args, "shear");
1986 char* xstr="", *pivotstr="";
1987 char* ystr="", *anglestr="";
1988 char*above = lu(args, "above"); /*FIXME*/
1989 char*below = lu(args, "below");
1990 char* rstr = lu(args, "red");
1991 char* gstr = lu(args, "green");
1992 char* bstr = lu(args, "blue");
1993 char* astr = lu(args, "alpha");
1994 char* pinstr = lu(args, "pin");
1995 char* as = map_lookup(args, "as");
2003 if(type==9) { // (?) .rotate or .arcchange
2004 pivotstr = lu(args, "pivot");
2005 anglestr = lu(args, "angle");
2007 xstr = lu(args, "x");
2008 ystr = lu(args, "y");
2011 luminance = parseMulAdd(luminancestr);
2014 luminance.mul = 256;
2018 if(scalexstr[0]||scaleystr[0])
2019 syntaxerror("scalex/scaley and scale cannot both be set");
2020 scalexstr = scaleystr = scalestr;
2023 if(type == 0 || type == 4) {
2025 character = lu(args, "character");
2026 parameters_clear(&p);
2027 } else if (type == 5) {
2028 character = lu(args, "name");
2029 parameters_clear(&p);
2032 p = s_getParameters(instance);
2037 if(isRelative(xstr)) {
2038 if(type == 0 || type == 4)
2039 syntaxerror("relative x values not allowed for initial put or startclip");
2040 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2042 p.x = parseTwip(xstr);
2046 if(isRelative(ystr)) {
2047 if(type == 0 || type == 4)
2048 syntaxerror("relative y values not allowed for initial put or startclip");
2049 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2051 p.y = parseTwip(ystr);
2055 /* scale, scalex, scaley */
2057 oldbbox = s_getCharBBox(character);
2059 oldbbox = s_getInstanceBBox(instance);
2061 oldwidth = oldbbox.xmax - oldbbox.xmin;
2062 oldheight = oldbbox.ymax - oldbbox.ymin;
2064 if(oldwidth==0) p.scalex = 1.0;
2067 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2071 if(oldheight==0) p.scaley = 1.0;
2074 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2080 if(isRelative(rotatestr)) {
2081 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2083 p.rotate = parseFloat(rotatestr);
2089 if(isRelative(shearstr)) {
2090 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2092 p.shear = parseFloat(shearstr);
2097 if(isPoint(pivotstr))
2098 p.pivot = parsePoint(pivotstr);
2100 p.pivot = getPoint(oldbbox, pivotstr);
2104 p.pin = parsePoint(pinstr);
2106 p.pin = getPoint(oldbbox, pinstr);
2109 /* color transform */
2111 if(rstr[0] || luminancestr[0]) {
2114 r = parseMulAdd(rstr);
2116 r.add = p.cxform.r0;
2117 r.mul = p.cxform.r1;
2119 r = mergeMulAdd(r, luminance);
2120 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2122 if(gstr[0] || luminancestr[0]) {
2125 g = parseMulAdd(gstr);
2127 g.add = p.cxform.g0;
2128 g.mul = p.cxform.g1;
2130 g = mergeMulAdd(g, luminance);
2131 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2133 if(bstr[0] || luminancestr[0]) {
2136 b = parseMulAdd(bstr);
2138 b.add = p.cxform.b0;
2139 b.mul = p.cxform.b1;
2141 b = mergeMulAdd(b, luminance);
2142 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2145 MULADD a = parseMulAdd(astr);
2146 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2150 s_put(instance, character, p);
2152 s_change(instance, p);
2154 s_qchange(instance, p);
2156 s_jump(instance, p);
2158 s_startclip(instance, character, p);
2159 else if(type == 5) {
2161 s_buttonput(character, as, p);
2163 s_buttonput(character, "shape", p);
2168 static int c_put(map_t*args)
2170 c_placement(args, 0);
2173 static int c_change(map_t*args)
2175 c_placement(args, 1);
2178 static int c_qchange(map_t*args)
2180 c_placement(args, 2);
2183 static int c_arcchange(map_t*args)
2185 c_placement(args, 2);
2188 static int c_jump(map_t*args)
2190 c_placement(args, 3);
2193 static int c_startclip(map_t*args)
2195 c_placement(args, 4);
2198 static int c_show(map_t*args)
2200 c_placement(args, 5);
2203 static int c_del(map_t*args)
2205 char*instance = lu(args, "name");
2206 s_delinstance(instance);
2209 static int c_end(map_t*args)
2214 static int c_sprite(map_t*args)
2216 char* name = lu(args, "name");
2220 static int c_frame(map_t*args)
2222 char*framestr = lu(args, "n");
2223 char*cutstr = lu(args, "cut");
2224 char*name = lu(args, "name");
2227 if(strcmp(cutstr, "no"))
2229 if(isRelative(framestr)) {
2230 frame = s_getframe();
2231 if(getSign(framestr)<0)
2232 syntaxerror("relative frame expressions must be positive");
2233 frame += parseInt(getOffset(framestr));
2236 frame = parseInt(framestr);
2237 if(s_getframe() >= frame
2238 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2239 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2241 s_frame(frame, cut, name);
2244 static int c_primitive(map_t*args)
2246 char*name = lu(args, "name");
2247 char*command = lu(args, "commandname");
2248 int width=0, height=0, r=0;
2249 int linewidth = parseTwip(lu(args, "line"));
2250 char*colorstr = lu(args, "color");
2251 RGBA color = parseColor(colorstr);
2252 char*fillstr = lu(args, "fill");
2259 if(!strcmp(command, "circle"))
2261 else if(!strcmp(command, "filled"))
2265 width = parseTwip(lu(args, "width"));
2266 height = parseTwip(lu(args, "height"));
2267 } else if (type==1) {
2268 r = parseTwip(lu(args, "r"));
2269 } else if (type==2) {
2270 outline = lu(args, "outline");
2273 if(!strcmp(fillstr, "fill"))
2275 if(!strcmp(fillstr, "none"))
2277 if(width<0 || height<0 || linewidth<0 || r<0)
2278 syntaxerror("values width, height, line, r must be positive");
2280 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2281 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2282 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2286 static int c_textshape(map_t*args)
2288 char*name = lu(args, "name");
2289 char*text = lu(args, "text");
2290 char*font = lu(args, "font");
2291 float size = parsePercent(lu(args, "size"));
2293 s_textshape(name, font, size, text);
2297 static int c_swf(map_t*args)
2299 char*name = lu(args, "name");
2300 char*filename = lu(args, "filename");
2301 char*command = lu(args, "commandname");
2302 if(!strcmp(command, "shape"))
2303 warning("Please use .swf instead of .shape");
2304 s_includeswf(name, filename);
2308 static int c_font(map_t*args)
2310 char*name = lu(args, "name");
2311 char*filename = lu(args, "filename");
2312 s_font(name, filename);
2316 static int c_sound(map_t*args)
2318 char*name = lu(args, "name");
2319 char*filename = lu(args, "filename");
2320 s_sound(name, filename);
2324 static int c_text(map_t*args)
2326 char*name = lu(args, "name");
2327 char*text = lu(args, "text");
2328 char*font = lu(args, "font");
2329 float size = parsePercent(lu(args, "size"));
2330 RGBA color = parseColor(lu(args, "color"));
2331 s_text(name, font, text, (int)(size*100), color);
2335 static int c_soundtrack(map_t*args)
2340 static int c_quicktime(map_t*args)
2342 char*name = lu(args, "name");
2343 char*url = lu(args, "url");
2344 s_quicktime(name, url);
2348 static int c_image(map_t*args)
2350 char*command = lu(args, "commandname");
2351 char*name = lu(args, "name");
2352 char*filename = lu(args, "filename");
2353 if(!strcmp(command,"jpeg")) {
2354 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2355 s_image(name, "jpeg", filename, quality);
2357 s_image(name, "png", filename, 0);
2362 static int c_outline(map_t*args)
2364 char*name = lu(args, "name");
2365 char*format = lu(args, "format");
2369 syntaxerror("colon (:) expected");
2371 s_outline(name, format, text);
2375 int fakechar(map_t*args)
2377 char*name = lu(args, "name");
2378 s_box(name, 0, 0, black, 20, 0);
2382 static int c_egon(map_t*args) {return fakechar(args);}
2383 static int c_button(map_t*args) {
2384 char*name = lu(args, "name");
2388 static int current_button_flags = 0;
2389 static int c_on_press(map_t*args)
2391 char*position = lu(args, "position");
2393 if(!strcmp(position, "inside")) {
2394 current_button_flags |= BC_OVERUP_OVERDOWN;
2395 } else if(!strcmp(position, "outside")) {
2396 //current_button_flags |= BC_IDLE_OUTDOWN;
2397 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2398 } else if(!strcmp(position, "anywhere")) {
2399 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2402 if(type == RAWDATA) {
2404 s_buttonaction(current_button_flags, action);
2405 current_button_flags = 0;
2411 static int c_on_release(map_t*args)
2413 char*position = lu(args, "position");
2415 if(!strcmp(position, "inside")) {
2416 current_button_flags |= BC_OVERDOWN_OVERUP;
2417 } else if(!strcmp(position, "outside")) {
2418 current_button_flags |= BC_OUTDOWN_IDLE;
2419 } else if(!strcmp(position, "anywhere")) {
2420 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2423 if(type == RAWDATA) {
2425 s_buttonaction(current_button_flags, action);
2426 current_button_flags = 0;
2432 static int c_on_move_in(map_t*args)
2434 char*position = lu(args, "state");
2436 if(!strcmp(position, "pressed")) {
2437 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2438 } else if(!strcmp(position, "not_pressed")) {
2439 current_button_flags |= BC_IDLE_OVERUP;
2440 } else if(!strcmp(position, "any")) {
2441 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2444 if(type == RAWDATA) {
2446 s_buttonaction(current_button_flags, action);
2447 current_button_flags = 0;
2453 static int c_on_move_out(map_t*args)
2455 char*position = lu(args, "state");
2457 if(!strcmp(position, "pressed")) {
2458 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2459 } else if(!strcmp(position, "not_pressed")) {
2460 current_button_flags |= BC_OVERUP_IDLE;
2461 } else if(!strcmp(position, "any")) {
2462 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2465 if(type == RAWDATA) {
2467 s_buttonaction(current_button_flags, action);
2468 current_button_flags = 0;
2474 static int c_on_key(map_t*args)
2476 char*key = lu(args, "key");
2478 if(strlen(key)==1) {
2481 current_button_flags |= 0x4000 + (key[0]*0x200);
2483 syntaxerror("invalid character: %c"+key[0]);
2488 <ctrl-x> = 0x200*(x-'a')
2492 syntaxerror("invalid key: %s",key);
2495 if(type == RAWDATA) {
2497 s_buttonaction(current_button_flags, action);
2498 current_button_flags = 0;
2505 static int c_edittext(map_t*args)
2507 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2508 char*name = lu(args, "name");
2509 char*font = lu(args, "font");
2510 int size = (int)(1024*parsePercent(lu(args, "size")));
2511 int width = parseTwip(lu(args, "width"));
2512 int height = parseTwip(lu(args, "height"));
2513 char*text = lu(args, "text");
2514 RGBA color = parseColor(lu(args, "color"));
2515 int maxlength = parseInt(lu(args, "maxlength"));
2516 char*variable = lu(args, "variable");
2517 char*passwordstr = lu(args, "password");
2518 char*wordwrapstr = lu(args, "wordwrap");
2519 char*multilinestr = lu(args, "multiline");
2520 char*htmlstr = lu(args, "html");
2521 char*noselectstr = lu(args, "noselect");
2522 char*readonlystr = lu(args, "readonly");
2523 char*borderstr = lu(args, "border");
2526 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2527 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2528 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2529 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2530 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2531 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2532 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2534 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2538 static int c_morphshape(map_t*args) {return fakechar(args);}
2539 static int c_movie(map_t*args) {return fakechar(args);}
2541 static int c_texture(map_t*args) {return 0;}
2543 static int c_action(map_t*args)
2546 if(type != RAWDATA) {
2547 syntaxerror("colon (:) expected");
2557 command_func_t* func;
2560 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2561 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2562 // "import" type stuff
2563 {"swf", c_swf, "name filename"},
2564 {"shape", c_swf, "name filename"},
2565 {"jpeg", c_image, "name filename quality=80%"},
2566 {"png", c_image, "name filename"},
2567 {"movie", c_movie, "name filename"},
2568 {"sound", c_sound, "name filename"},
2569 {"font", c_font, "name filename"},
2570 {"soundtrack", c_soundtrack, "filename"},
2571 {"quicktime", c_quicktime, "url"},
2573 // generators of primitives
2575 {"point", c_point, "name x=0 y=0"},
2576 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2577 {"outline", c_outline, "name format=simple"},
2578 {"textshape", c_textshape, "name font size=100% text"},
2580 // character generators
2581 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2582 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2583 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2585 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2586 {"text", c_text, "name text font size=100% color=white"},
2587 {"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"},
2588 {"morphshape", c_morphshape, "name start end"},
2589 {"button", c_button, "name"},
2590 {"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="},
2591 {"on_press", c_on_press, "position=inside"},
2592 {"on_release", c_on_release, "position=anywhere"},
2593 {"on_move_in", c_on_move_in, "state=not_pressed"},
2594 {"on_move_out", c_on_move_out, "state=not_pressed"},
2595 {"on_key", c_on_key, "key=any"},
2598 {"play", c_play, "name loop=0 @nomultiple=0"},
2599 {"stop", c_stop, "name= "},
2600 {"nextframe", c_nextframe, "name"},
2601 {"previousframe", c_previousframe, "name"},
2603 // object placement tags
2604 {"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="},
2605 {"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="},
2606 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2607 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2608 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2609 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2610 {"del", c_del, "name"},
2611 // virtual object placement
2612 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2614 // commands which start a block
2615 //startclip (see above)
2616 {"sprite", c_sprite, "name"},
2617 {"action", c_action, ""},
2623 static map_t parseArguments(char*command, char*pattern)
2639 string_set(&t1, "commandname");
2640 string_set(&t2, command);
2641 map_put(&result, t1, t2);
2643 if(!pattern || !*pattern)
2650 if(!strncmp("<i> ", x, 3)) {
2652 if(type == COMMAND || type == RAWDATA) {
2654 syntaxerror("character name expected");
2656 name[pos].str = "instance";
2658 value[pos].str = text;
2659 value[pos].len = strlen(text);
2663 if(type == ASSIGNMENT)
2666 name[pos].str = "character";
2668 value[pos].str = text;
2669 value[pos].len = strlen(text);
2677 isboolean[pos] = (x[0] =='@');
2690 name[pos].len = d-x;
2695 name[pos].len = e-x;
2696 value[pos].str = e+1;
2697 value[pos].len = d-e-1;
2705 /* for(t=0;t<len;t++) {
2706 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2707 isboolean[t]?"(boolean)":"");
2712 if(type == RAWDATA || type == COMMAND) {
2717 // first, search for boolean arguments
2718 for(pos=0;pos<len;pos++)
2720 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2722 if(type == ASSIGNMENT)
2724 value[pos].str = text;
2725 value[pos].len = strlen(text);
2726 /*printf("setting boolean parameter %s (to %s)\n",
2727 strdup_n(name[pos], namelen[pos]),
2728 strdup_n(value[pos], valuelen[pos]));*/
2733 // second, search for normal arguments
2735 for(pos=0;pos<len;pos++)
2737 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2738 (type != ASSIGNMENT && !set[pos])) {
2740 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2742 if(type == ASSIGNMENT)
2745 value[pos].str = text;
2746 value[pos].len = strlen(text);
2748 printf("setting parameter %s (to %s)\n",
2749 strdup_n(name[pos].str, name[pos].len),
2750 strdup_n(value[pos].str, value[pos].len));
2756 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
2760 for(t=0;t<len;t++) {
2761 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2764 for(t=0;t<len;t++) {
2765 if(value[t].str && value[t].str[0] == '*') {
2766 //relative default- take value from some other parameter
2768 for(s=0;s<len;s++) {
2769 if(value[s].len == value[t].len-1 &&
2770 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2771 value[t].str = value[s].str;
2774 if(value[t].str == 0) {
2776 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2780 /* ok, now construct the dictionary from the parameters */
2784 map_put(&result, name[t], value[t]);
2788 static void parseArgumentsForCommand(char*command)
2793 msg("<verbose> parse Command: %s (line %d)", command, line);
2795 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2796 if(!strcmp(arguments[t].command, command)) {
2798 /* ugly hack- will be removed soon (once documentation and .sc generating
2799 utilities have been changed) */
2800 if(!strcmp(command, "swf") && !stackpos) {
2801 warning("Please use .flash instead of .swf- this will be mandatory soon");
2806 args = parseArguments(command, arguments[t].arguments);
2812 syntaxerror("command %s not known", command);
2814 // catch missing .flash directives at the beginning of a file
2815 if(strcmp(command, "flash") && !stackpos)
2817 syntaxerror("No movie defined- use .flash first");
2821 printf(".%s\n", command);fflush(stdout);
2822 map_dump(&args, stdout, "\t");fflush(stdout);
2825 (*arguments[nr].func)(&args);
2827 /*if(!strcmp(command, "button") ||
2828 !strcmp(command, "action")) {
2831 if(type == COMMAND) {
2832 if(!strcmp(text, "end"))
2846 int main (int argc,char ** argv)
2849 processargs(argc, argv);
2850 initLog(0,-1,0,0,-1,verbose);
2853 args_callback_usage(argv[0]);
2857 file = generateTokens(filename);
2859 printf("parser returned error.\n");
2865 while(!noMoreTokens()) {
2868 syntaxerror("command expected");
2869 parseArgumentsForCommand(text);