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[] = {
54 int args_callback_option(char*name,char*val)
56 if(!strcmp(name, "V")) {
57 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
60 else if(!strcmp(name, "o")) {
62 override_outputname = 1;
65 else if(!strcmp(name, "O")) {
69 else if(!strcmp(name, "v")) {
74 printf("Unknown option: -%s\n", name);
79 int args_callback_longoption(char*name,char*val)
81 return args_long2shortoption(options, name, val);
83 void args_callback_usage(char *name)
86 printf("Usage: %s [-o file.swf] file.sc\n", name);
88 printf("-h , --help Print short help message and exit\n");
89 printf("-V , --version Print version info and exit\n");
90 printf("-v , --verbose Increase verbosity. \n");
91 printf("-o , --output <filename> Set output file to <filename>.\n");
94 int args_callback_command(char*name,char*val)
97 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
104 static struct token_t* file;
113 static void syntaxerror(char*format, ...)
117 va_start(arglist, format);
118 vsprintf(buf, format, arglist);
120 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
124 static void warning(char*format, ...)
128 va_start(arglist, format);
129 vsprintf(buf, format, arglist);
131 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
134 static void readToken()
136 type = file[pos].type;
138 syntaxerror("unexpected end of file");
140 text = file[pos].text;
141 textlen = strlen(text);
142 line = file[pos].line;
143 column = file[pos].column;
145 //printf("---> %d(%s) %s\n", type, type_names[type], text);
148 static void pushBack()
151 if(!pos) syntaxerror("internal error 3");
156 textlen = strlen(text);
159 column = file[p].column;
162 static int noMoreTokens()
164 if(file[pos].type == END)
169 // ------------------------------ swf routines ----------------------------
173 int type; //0=swf, 1=sprite, 2=clip, 3=button
179 /* for sprites (1): */
185 dictionary_t oldinstances;
190 static int stackpos = 0;
192 static dictionary_t characters;
193 static dictionary_t images;
194 static dictionary_t textures;
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 typedef struct _texture {
247 static void character_init(character_t*c)
249 memset(c, 0, sizeof(character_t));
251 static character_t* character_new()
254 c = (character_t*)malloc(sizeof(character_t));
258 static void instance_init(instance_t*i)
260 memset(i, 0, sizeof(instance_t));
262 static instance_t* instance_new()
265 c = (instance_t*)malloc(sizeof(instance_t));
270 static void incrementid()
274 syntaxerror("Out of character ids.");
279 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
281 character_t* c = character_new();
283 c->definingTag = ctag;
286 if(dictionary_lookup(&characters, name))
287 syntaxerror("character %s defined twice", name);
288 dictionary_put2(&characters, name, c);
290 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
292 swf_SetString(tag, name);
293 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
296 swf_SetString(tag, name);
298 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
300 character_t* c = character_new();
301 c->definingTag = ctag;
305 if(dictionary_lookup(&images, name))
306 syntaxerror("image %s defined twice", name);
307 dictionary_put2(&images, name, c);
309 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
311 instance_t* i = instance_new();
314 //swf_GetMatrix(0, &i->matrix);
315 if(dictionary_lookup(&instances, name))
316 syntaxerror("object %s defined twice", name);
317 dictionary_put2(&instances, name, i);
321 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)
324 p->scalex = scalex; p->scaley = scaley;
325 p->pin = pin; p->pivot = pivot;
326 p->rotate = rotate; p->cxform = cxform;
330 static void parameters_clear(parameters_t*p)
333 p->scalex = 1.0; p->scaley = 1.0;
336 p->pivot.x = 0; p->pivot.y = 0;
339 swf_GetCXForm(0, &p->cxform, 1);
342 static void makeMatrix(MATRIX*m, parameters_t*p)
351 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
352 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
353 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
354 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
356 m->sx = (int)(sx*65536+0.5);
357 m->r1 = (int)(r1*65536+0.5);
358 m->r0 = (int)(r0*65536+0.5);
359 m->sy = (int)(sy*65536+0.5);
363 h = swf_TurnPoint(p->pin, m);
368 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
373 r = swf_TurnRect(rect, &m);
374 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
375 currentrect.xmax == 0 && currentrect.ymax == 0)
378 swf_ExpandRect2(¤trect, &r);
382 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
384 SWF*swf = (SWF*)malloc(sizeof(SWF));
387 syntaxerror(".swf blocks can't be nested");
389 memset(swf, 0, sizeof(swf));
390 swf->fileVersion = version;
392 swf->frameRate = fps;
393 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
394 swf->compressed = compress;
395 swf_SetRGB(tag,&background);
397 if(stackpos==sizeof(stack)/sizeof(stack[0]))
398 syntaxerror("too many levels of recursion");
400 dictionary_init(&characters);
401 dictionary_init(&images);
402 dictionary_init(&textures);
403 dictionary_init(&outlines);
404 dictionary_init(&gradients);
405 dictionary_init(&instances);
406 dictionary_init(&fonts);
407 dictionary_init(&sounds);
409 memset(&stack[stackpos], 0, sizeof(stack[0]));
410 stack[stackpos].type = 0;
411 stack[stackpos].filename = strdup(name);
412 stack[stackpos].swf = swf;
413 stack[stackpos].oldframe = -1;
418 memset(¤trect, 0, sizeof(currentrect));
421 memset(idmap, 0, sizeof(idmap));
425 void s_sprite(char*name)
427 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
428 swf_SetU16(tag, id); //id
429 swf_SetU16(tag, 0); //frames
431 memset(&stack[stackpos], 0, sizeof(stack[0]));
432 stack[stackpos].type = 1;
433 stack[stackpos].oldframe = currentframe;
434 stack[stackpos].olddepth = currentdepth;
435 stack[stackpos].oldrect = currentrect;
436 stack[stackpos].oldinstances = instances;
437 stack[stackpos].tag = tag;
438 stack[stackpos].id = id;
439 stack[stackpos].name = strdup(name);
441 /* FIXME: those four fields should be bundled together */
442 dictionary_init(&instances);
445 memset(¤trect, 0, sizeof(currentrect));
451 typedef struct _buttonrecord
459 typedef struct _button
463 buttonrecord_t records[4];
466 static button_t mybutton;
468 void s_button(char*name)
470 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
471 swf_SetU16(tag, id); //id
472 swf_ButtonSetFlags(tag, 0); //menu=no
474 memset(&mybutton, 0, sizeof(mybutton));
476 memset(&stack[stackpos], 0, sizeof(stack[0]));
477 stack[stackpos].type = 3;
478 stack[stackpos].tag = tag;
479 stack[stackpos].id = id;
480 stack[stackpos].name = strdup(name);
481 stack[stackpos].oldrect = currentrect;
482 memset(¤trect, 0, sizeof(currentrect));
487 void s_buttonput(char*character, char*as, parameters_t p)
489 character_t* c = dictionary_lookup(&characters, character);
494 if(!stackpos || (stack[stackpos-1].type != 3)) {
495 syntaxerror(".show may only appear in .button");
498 syntaxerror("character %s not known (in .shape %s)", character, character);
500 if(mybutton.endofshapes) {
501 syntaxerror("a .do may not precede a .show", character, character);
504 m = s_instancepos(c->size, &p);
512 if(*s==',' || *s==0) {
513 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
514 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
515 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
516 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
517 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
518 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
525 static void setbuttonrecords(TAG*tag)
527 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
528 if(!mybutton.endofshapes) {
531 if(!mybutton.records[3].set) {
532 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
536 if(mybutton.records[t].set) {
537 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
540 swf_SetU8(tag,0); // end of button records
541 mybutton.endofshapes = 1;
545 void s_buttonaction(int flags, char*action)
551 setbuttonrecords(stack[stackpos-1].tag);
553 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
555 syntaxerror("Couldn't compile ActionScript");
558 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
559 swf_ActionSet(stack[stackpos-1].tag, a);
560 mybutton.nr_actions++;
565 static void setactionend(TAG*tag)
567 if(!mybutton.nr_actions) {
568 /* no actions means we didn't have an actionoffset,
569 which means we can't signal the end of the
570 buttonaction records, so, *sigh*, we have
571 to insert a dummy record */
572 swf_SetU16(tag, 0); //offset
573 swf_SetU16(tag, 0); //condition
574 swf_SetU8(tag, 0); //action
578 static void s_endButton()
581 setbuttonrecords(stack[stackpos-1].tag);
582 setactionend(stack[stackpos-1].tag);
585 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
589 tag = stack[stackpos].tag;
590 currentrect = stack[stackpos].oldrect;
592 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
593 free(stack[stackpos].name);
596 TAG* removeFromTo(TAG*from, TAG*to)
598 TAG*save = from->prev;
600 TAG*next = from->next;
608 static void s_endSprite()
610 SRECT r = currentrect;
612 if(stack[stackpos].cut)
613 tag = removeFromTo(stack[stackpos].cut, tag);
617 /* TODO: before clearing, prepend "<spritename>." to names and
618 copy into old instances dict */
619 dictionary_clear(&instances);
621 currentframe = stack[stackpos].oldframe;
622 currentrect = stack[stackpos].oldrect;
623 currentdepth = stack[stackpos].olddepth;
624 instances = stack[stackpos].oldinstances;
626 tag = swf_InsertTag(tag, ST_SHOWFRAME);
627 tag = swf_InsertTag(tag, ST_END);
629 tag = stack[stackpos].tag;
632 syntaxerror("internal error(7)");
634 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
635 free(stack[stackpos].name);
638 static void s_endSWF()
644 if(stack[stackpos].cut)
645 tag = removeFromTo(stack[stackpos].cut, tag);
649 swf = stack[stackpos].swf;
650 filename = stack[stackpos].filename;
652 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
653 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
654 tag = swf_InsertTag(tag, ST_SHOWFRAME);
656 tag = swf_InsertTag(tag, ST_END);
658 swf_OptimizeTagOrder(swf);
664 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
665 swf->movieSize = currentrect; /* "autocrop" */
668 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
669 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
670 swf->movieSize.ymax += 20;
671 warning("Empty bounding box for movie");
674 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
676 syntaxerror("couldn't create output file %s", filename);
679 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
681 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
685 dictionary_clear(&instances);
686 dictionary_clear(&characters);
687 dictionary_clear(&images);
688 dictionary_clear(&textures);
689 dictionary_clear(&outlines);
690 dictionary_clear(&gradients);
691 dictionary_clear(&fonts);
692 dictionary_clear(&sounds);
702 if(stack[stackpos-1].type == 0)
703 syntaxerror("End of file encountered in .flash block");
704 if(stack[stackpos-1].type == 1)
705 syntaxerror("End of file encountered in .sprite block");
706 if(stack[stackpos-1].type == 2)
707 syntaxerror("End of file encountered in .clip block");
713 return currentframe+1;
716 void s_frame(int nr, int cut, char*name)
722 syntaxerror("Illegal frame number");
723 nr--; // internally, frame 1 is frame 0
725 for(t=currentframe;t<nr;t++) {
726 tag = swf_InsertTag(tag, ST_SHOWFRAME);
727 if(t==nr-1 && name && *name) {
728 tag = swf_InsertTag(tag, ST_FRAMELABEL);
729 swf_SetString(tag, name);
732 if(nr == 0 && currentframe == 0 && name) {
733 tag = swf_InsertTag(tag, ST_FRAMELABEL);
734 swf_SetString(tag, name);
739 syntaxerror("Can't cut, frame empty");
741 stack[stackpos].cut = tag;
747 int parseColor2(char*str, RGBA*color);
749 int addFillStyle(SHAPE*s, SRECT*r, char*name)
756 parseColor2(name, &color);
757 return swf_ShapeAddSolidFillStyle(s, &color);
758 } else if ((texture = dictionary_lookup(&textures, name))) {
759 return swf_ShapeAddFillStyle2(s, &texture->fs);
760 } else if((image = dictionary_lookup(&images, name))) {
762 swf_GetMatrix(0, &m);
763 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
764 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
767 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
768 } else if ((gradient = dictionary_lookup(&gradients, name))) {
772 swf_GetMatrix(0, &rot);
773 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
774 csin = sin(-gradient->rotate*2*3.14159265358979/360);
776 rot.r1 = -csin*65536;
779 r2 = swf_TurnRect(*r, &rot);
780 swf_GetMatrix(0, &m);
781 m.sx = (r2.xmax - r2.xmin)*2*ccos;
782 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
783 m.r0 = (r2.ymax - r2.ymin)*2*csin;
784 m.sy = (r2.ymax - r2.ymin)*2*ccos;
785 m.tx = r->xmin + (r->xmax - r->xmin)/2;
786 m.ty = r->ymin + (r->ymax - r->ymin)/2;
787 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
788 } else if (parseColor2(name, &color)) {
789 return swf_ShapeAddSolidFillStyle(s, &color);
791 syntaxerror("not a color/fillstyle: %s", name);
796 RGBA black={r:0,g:0,b:0,a:0};
797 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
806 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
809 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
811 fs1 = addFillStyle(s, &r2, texture);
814 r.xmin = r2.xmin-linewidth-linewidth/2;
815 r.ymin = r2.ymin-linewidth-linewidth/2;
816 r.xmax = r2.xmax+linewidth+linewidth/2;
817 r.ymax = r2.ymax+linewidth+linewidth/2;
819 swf_SetShapeHeader(tag,s);
820 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
821 swf_ShapeSetLine(tag,s,width,0);
822 swf_ShapeSetLine(tag,s,0,height);
823 swf_ShapeSetLine(tag,s,-width,0);
824 swf_ShapeSetLine(tag,s,0,-height);
825 swf_ShapeSetEnd(tag);
828 s_addcharacter(name, id, tag, r);
832 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
838 outline = dictionary_lookup(&outlines, outlinename);
840 syntaxerror("outline %s not defined", outlinename);
844 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
847 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
849 fs1 = addFillStyle(s, &r2, texture);
852 rect.xmin = r2.xmin-linewidth-linewidth/2;
853 rect.ymin = r2.ymin-linewidth-linewidth/2;
854 rect.xmax = r2.xmax+linewidth+linewidth/2;
855 rect.ymax = r2.ymax+linewidth+linewidth/2;
857 swf_SetRect(tag,&rect);
858 swf_SetShapeStyles(tag, s);
859 swf_ShapeCountBits(s,0,0);
860 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, 1, 1,
861 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
862 swf_SetShapeBits(tag, s);
863 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
866 s_addcharacter(name, id, tag, rect);
870 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
875 r2.xmin = r2.ymin = 0;
879 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
882 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
884 fs1 = addFillStyle(s, &r2, texture);
886 rect.xmin = r2.xmin-linewidth-linewidth/2;
887 rect.ymin = r2.ymin-linewidth-linewidth/2;
888 rect.xmax = r2.xmax+linewidth+linewidth/2;
889 rect.ymax = r2.ymax+linewidth+linewidth/2;
891 swf_SetRect(tag,&rect);
892 swf_SetShapeHeader(tag,s);
893 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
894 swf_ShapeSetCircle(tag, s, r,r,r,r);
895 swf_ShapeSetEnd(tag);
898 s_addcharacter(name, id, tag, rect);
902 void s_textshape(char*name, char*fontname, float size, char*_text)
905 U8*text = (U8*)_text;
909 font = dictionary_lookup(&fonts, fontname);
911 syntaxerror("font \"%s\" not known!", fontname);
913 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
914 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
915 s_box(name, 0, 0, black, 20, 0);
918 g = font->ascii2glyph[text[0]];
920 outline = malloc(sizeof(outline_t));
921 memset(outline, 0, sizeof(outline_t));
922 outline->shape = font->glyph[g].shape;
923 outline->bbox = font->layout->bounds[g];
927 swf_Shape11DrawerInit(&draw, 0);
928 swf_DrawText(&draw, font, (int)(size*100), _text);
930 outline->shape = swf_ShapeDrawerToShape(&draw);
931 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
935 if(dictionary_lookup(&outlines, name))
936 syntaxerror("outline %s defined twice", name);
937 dictionary_put2(&outlines, name, outline);
940 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
945 font = dictionary_lookup(&fonts, fontname);
947 syntaxerror("font \"%s\" not known!", fontname);
949 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
951 if(!font->numchars) {
952 s_box(name, 0, 0, black, 20, 0);
955 r = swf_SetDefineText(tag, font, &color, text, size);
957 s_addcharacter(name, id, tag, r);
961 void s_quicktime(char*name, char*url)
966 memset(&r, 0, sizeof(r));
968 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
970 swf_SetString(tag, url);
972 s_addcharacter(name, id, tag, r);
976 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
979 EditTextLayout layout;
982 if(fontname && *fontname) {
983 flags |= ET_USEOUTLINES;
984 font = dictionary_lookup(&fonts, fontname);
986 syntaxerror("font \"%s\" not known!", fontname);
988 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
991 layout.leftmargin = 0;
992 layout.rightmargin = 0;
1000 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1002 s_addcharacter(name, id, tag, r);
1006 /* type: either "jpeg" or "png"
1008 void s_image(char*name, char*type, char*filename, int quality)
1010 /* an image is actually two folded: 1st bitmap, 2nd character.
1011 Both of them can be used separately */
1013 /* step 1: the bitmap */
1018 warning("image type \"png\" not supported yet!");
1019 s_box(name, 0, 0, black, 20, 0);
1023 #ifndef HAVE_LIBJPEG
1024 warning("no jpeg support compiled in");
1025 s_box(name, 0, 0, black, 20, 0);
1028 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1029 swf_SetU16(tag, imageID);
1031 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1032 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1035 swf_GetJPEGSize(filename, &width, &height);
1042 s_addimage(name, id, tag, r);
1047 /* step 2: the character */
1048 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1049 swf_SetU16(tag, id);
1050 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1052 s_addcharacter(name, id, tag, r);
1056 void s_getBitmapSize(char*name, int*width, int*height)
1058 character_t* image = dictionary_lookup(&images, name);
1059 gradient_t* gradient = dictionary_lookup(&gradients,name);
1061 *width = image->size.xmax;
1062 *height = image->size.ymax;
1066 /* internal SWF gradient size */
1067 if(gradient->radial) {
1076 syntaxerror("No such bitmap/gradient: %s", name);
1079 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1081 gradient_t* gradient = dictionary_lookup(&gradients, object);
1082 character_t* bitmap = dictionary_lookup(&images, object);
1083 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1085 FILLSTYLE*fs = &texture->fs;
1088 fs->type = FILL_TILED;
1089 fs->id_bitmap = bitmap->id;
1090 } else if(gradient) {
1091 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1092 fs->gradient = gradient->gradient;
1094 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1095 makeMatrix(&fs->m, &p);
1096 if(gradient && !gradient->radial) {
1103 p2 = swf_TurnPoint(p1, &m);
1108 if(dictionary_lookup(&textures, name))
1109 syntaxerror("texture %s defined twice", name);
1110 dictionary_put2(&textures, name, texture);
1113 void dumpSWF(SWF*swf)
1115 TAG* tag = swf->firstTag;
1116 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1118 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1121 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1124 void s_font(char*name, char*filename)
1127 font = swf_LoadFont(filename);
1130 warning("Couldn't open font file \"%s\"", filename);
1131 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1132 memset(font, 0, sizeof(SWFFONT));
1133 dictionary_put2(&fonts, name, font);
1139 /* fix the layout. Only needed for old fonts */
1141 for(t=0;t<font->numchars;t++) {
1142 font->glyph[t].advance = 0;
1145 swf_FontCreateLayout(font);
1147 /* just in case this thing is used in .edittext later on */
1148 swf_FontPrepareForEditText(font);
1151 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1152 swf_FontSetDefine2(tag, font);
1155 if(dictionary_lookup(&fonts, name))
1156 syntaxerror("font %s defined twice", name);
1157 dictionary_put2(&fonts, name, font);
1162 typedef struct _sound_t
1168 void s_sound(char*name, char*filename)
1170 struct WAV wav, wav2;
1176 if(!readWAV(filename, &wav)) {
1177 warning("Couldn't read wav file \"%s\"", filename);
1181 convertWAV2mono(&wav, &wav2, 44100);
1182 samples = (U16*)wav2.data;
1183 numsamples = wav2.size/2;
1185 #ifdef WORDS_BIGENDIAN
1187 for(t=0;t<numsamples;t++) {
1188 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1193 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1194 swf_SetU16(tag, id); //id
1195 swf_SetSoundDefine(tag, samples, numsamples);
1197 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1201 if(dictionary_lookup(&sounds, name))
1202 syntaxerror("sound %s defined twice", name);
1203 dictionary_put2(&sounds, name, sound);
1211 static char* gradient_getToken(const char**p)
1215 while(**p && strchr(" \t\n\r", **p)) {
1219 while(**p && !strchr(" \t\n\r", **p)) {
1222 result = malloc((*p)-start+1);
1223 memcpy(result,start,(*p)-start+1);
1224 result[(*p)-start] = 0;
1228 float parsePercent(char*str);
1229 RGBA parseColor(char*str);
1231 GRADIENT parseGradient(const char*str)
1235 const char* p = str;
1236 memset(&gradient, 0, sizeof(GRADIENT));
1238 char*posstr,*colorstr;
1241 posstr = gradient_getToken(&p);
1244 pos = (int)(parsePercent(posstr)*255.0);
1247 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1248 colorstr = gradient_getToken(&p);
1249 color = parseColor(colorstr);
1250 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1251 warning("gradient record too big- max size is 8, rest ignored");
1254 gradient.ratios[gradient.num] = pos;
1255 gradient.rgba[gradient.num] = color;
1264 void s_gradient(char*name, const char*text, int radial, int rotate)
1266 gradient_t* gradient;
1267 gradient = malloc(sizeof(gradient_t));
1268 memset(gradient, 0, sizeof(gradient_t));
1269 gradient->gradient = parseGradient(text);
1270 gradient->radial = radial;
1271 gradient->rotate = rotate;
1273 if(dictionary_lookup(&gradients, name))
1274 syntaxerror("gradient %s defined twice", name);
1275 dictionary_put2(&gradients, name, gradient);
1278 void s_action(const char*text)
1281 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1283 syntaxerror("Couldn't compile ActionScript");
1286 tag = swf_InsertTag(tag, ST_DOACTION);
1288 swf_ActionSet(tag, a);
1293 void s_initaction(const char*character, const char*text)
1297 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1299 syntaxerror("Couldn't compile ActionScript");
1302 c = (character_t*)dictionary_lookup(&characters, character);
1304 tag = swf_InsertTag(tag, ST_DOINITACTION);
1305 swf_SetU16(tag, c->id);
1306 swf_ActionSet(tag, a);
1311 int s_swf3action(char*name, char*action)
1314 instance_t* object = 0;
1316 dictionary_lookup(&instances, name);
1317 if(!object && name && *name) {
1318 /* we have a name, but couldn't find it. Abort. */
1321 a = action_SetTarget(0, name);
1322 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1323 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1324 else if(!strcmp(action, "stop")) a = action_Stop(a);
1325 else if(!strcmp(action, "play")) a = action_Play(a);
1326 a = action_SetTarget(a, "");
1329 tag = swf_InsertTag(tag, ST_DOACTION);
1330 swf_ActionSet(tag, a);
1335 void s_outline(char*name, char*format, char*source)
1344 swf_Shape11DrawerInit(&draw, 0);
1345 draw_string(&draw, source);
1347 shape = swf_ShapeDrawerToShape(&draw);
1348 bounds = swf_ShapeDrawerGetBBox(&draw);
1349 draw.dealloc(&draw);
1351 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1352 outline->shape = shape;
1353 outline->bbox = bounds;
1355 if(dictionary_lookup(&outlines, name))
1356 syntaxerror("outline %s defined twice", name);
1357 dictionary_put2(&outlines, name, outline);
1360 int s_playsound(char*name, int loops, int nomultiple, int stop)
1366 sound = dictionary_lookup(&sounds, name);
1370 tag = swf_InsertTag(tag, ST_STARTSOUND);
1371 swf_SetU16(tag, sound->id); //id
1372 memset(&info, 0, sizeof(info));
1375 info.nomultiple = nomultiple;
1376 swf_SetSoundInfo(tag, &info);
1380 void s_includeswf(char*name, char*filename)
1388 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1389 f = open(filename,O_RDONLY|O_BINARY);
1391 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1392 s_box(name, 0, 0, black, 20, 0);
1395 if (swf_ReadSWF(f,&swf)<0) {
1396 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1397 s_box(name, 0, 0, black, 20, 0);
1402 /* FIXME: The following sets the bounding Box for the character.
1403 It is wrong for two reasons:
1404 a) It may be too small (in case objects in the movie clip at the borders)
1405 b) it may be too big (because the poor movie never got autocropped)
1409 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1410 swf_SetU16(tag, id);
1411 swf_SetU16(tag, swf.frameCount);
1413 swf_Relocate(&swf, idmap);
1415 ftag = swf.firstTag;
1419 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1420 if(cutout[t] == ftag->id) {
1424 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1426 if(ftag->id == ST_END)
1430 /* We simply dump all tags right after the sprite
1431 header, relying on the fact that swf_OptimizeTagOrder() will
1432 sort things out for us later.
1433 We also rely on the fact that the imported SWF is well-formed.
1435 tag = swf_InsertTag(tag, ftag->id);
1436 swf_SetBlock(tag, ftag->data, ftag->len);
1440 syntaxerror("Included file %s contains errors", filename);
1441 tag = swf_InsertTag(tag, ST_END);
1445 s_addcharacter(name, id, tag, r);
1448 SRECT s_getCharBBox(char*name)
1450 character_t* c = dictionary_lookup(&characters, name);
1451 if(!c) syntaxerror("character '%s' unknown(2)", name);
1454 SRECT s_getInstanceBBox(char*name)
1456 instance_t * i = dictionary_lookup(&instances, name);
1458 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1460 if(!c) syntaxerror("internal error(5)");
1463 parameters_t s_getParameters(char*name)
1465 instance_t * i = dictionary_lookup(&instances, name);
1466 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1467 return i->parameters;
1469 void s_startclip(char*instance, char*character, parameters_t p)
1471 character_t* c = dictionary_lookup(&characters, character);
1475 syntaxerror("character %s not known", character);
1477 i = s_addinstance(instance, c, currentdepth);
1479 m = s_instancepos(i->character->size, &p);
1481 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1482 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1483 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1485 i->lastFrame= currentframe;
1487 stack[stackpos].tag = tag;
1488 stack[stackpos].type = 2;
1497 swf_SetTagPos(stack[stackpos].tag, 0);
1498 swf_GetPlaceObject(stack[stackpos].tag, &p);
1499 p.clipdepth = currentdepth;
1501 swf_ClearTag(stack[stackpos].tag);
1502 swf_SetPlaceObject(stack[stackpos].tag, &p);
1506 void s_put(char*instance, char*character, parameters_t p)
1508 character_t* c = dictionary_lookup(&characters, character);
1512 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1515 i = s_addinstance(instance, c, currentdepth);
1517 m = s_instancepos(i->character->size, &p);
1519 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1520 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1522 i->lastFrame = currentframe;
1526 void s_jump(char*instance, parameters_t p)
1528 instance_t* i = dictionary_lookup(&instances, instance);
1531 syntaxerror("instance %s not known", instance);
1535 m = s_instancepos(i->character->size, &p);
1537 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1538 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1540 i->lastFrame = currentframe;
1543 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1547 if(num==0 || num==1)
1549 ratio = (float)pos/(float)num;
1551 p.x = (p2->x-p1->x)*ratio + p1->x;
1552 p.y = (p2->y-p1->y)*ratio + p1->y;
1553 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1554 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1555 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1556 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1558 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1559 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1560 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1561 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1563 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1564 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1565 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1566 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1568 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1569 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1570 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1571 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1575 void s_change(char*instance, parameters_t p2)
1577 instance_t* i = dictionary_lookup(&instances, instance);
1581 int frame, allframes;
1583 syntaxerror("instance %s not known", instance);
1587 allframes = currentframe - i->lastFrame - 1;
1589 warning(".change ignored. can only .put/.change an object once per frame.");
1593 m = s_instancepos(i->character->size, &p2);
1594 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1595 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1598 /* o.k., we got the start and end point set. Now iterate though all the
1599 tags in between, inserting object changes after each new frame */
1602 if(!t) syntaxerror("internal error(6)");
1604 while(frame < allframes) {
1605 if(t->id == ST_SHOWFRAME) {
1610 p = s_interpolate(&p1, &p2, frame, allframes);
1611 m = s_instancepos(i->character->size, &p); //needed?
1612 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1613 i->lastFrame = currentframe;
1614 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1616 if(frame == allframes)
1621 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1625 void s_delinstance(char*instance)
1627 instance_t* i = dictionary_lookup(&instances, instance);
1629 syntaxerror("instance %s not known", instance);
1631 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1632 swf_SetU16(tag, i->depth);
1633 dictionary_del(&instances, instance);
1636 void s_qchange(char*instance, parameters_t p)
1643 syntaxerror(".end unexpected");
1644 if(stack[stackpos-1].type == 0)
1646 else if(stack[stackpos-1].type == 1)
1648 else if(stack[stackpos-1].type == 2)
1650 else if(stack[stackpos-1].type == 3)
1652 else syntaxerror("internal error 1");
1655 // ------------------------------------------------------------------------
1657 typedef int command_func_t(map_t*args);
1659 SRECT parseBox(char*str)
1662 float xmin, xmax, ymin, ymax;
1663 char*x = strchr(str, 'x');
1665 if(!strcmp(str, "autocrop")) {
1666 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1670 d1 = strchr(x+1, ':');
1672 d2 = strchr(d1+1, ':');
1674 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1678 else if(d1 && !d2) {
1679 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1685 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1690 r.xmin = (SCOORD)(xmin*20);
1691 r.ymin = (SCOORD)(ymin*20);
1692 r.xmax = (SCOORD)(xmax*20);
1693 r.ymax = (SCOORD)(ymax*20);
1696 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1699 float parseFloat(char*str)
1703 int parseInt(char*str)
1708 if(str[0]=='+' || str[0]=='-')
1712 if(str[t]<'0' || str[t]>'9')
1713 syntaxerror("Not an Integer: \"%s\"", str);
1716 int parseTwip(char*str)
1720 if(str[0]=='+' || str[0]=='-') {
1725 dot = strchr(str, '.');
1729 return sign*parseInt(str)*20;
1731 int l=strlen(++dot);
1733 for(s=str;s<dot-1;s++)
1734 if(*s<'0' || *s>'9')
1735 syntaxerror("Not a coordinate: \"%s\"", str);
1737 if(*s<'0' || *s>'9')
1738 syntaxerror("Not a coordinate: \"%s\"", str);
1740 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1741 warning("precision loss: %s converted to twip: %s", str, dot);
1746 return sign*atoi(str)*20;
1748 return sign*atoi(str)*20+atoi(dot)*2;
1750 return sign*atoi(str)*20+atoi(dot)/5;
1755 int isPoint(char*str)
1757 if(strchr(str, '('))
1763 SPOINT parsePoint(char*str)
1767 int l = strlen(str);
1768 char*comma = strchr(str, ',');
1769 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1770 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1771 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1772 p.x = parseTwip(tmp);
1773 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1774 p.y = parseTwip(tmp);
1778 int parseColor2(char*str, RGBA*color)
1780 int l = strlen(str);
1784 struct {unsigned char r,g,b;char*name;} colors[] =
1785 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1786 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1787 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1788 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1789 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1790 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1791 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1792 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1793 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1794 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1795 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1796 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1800 if(str[0]=='#' && (l==7 || l==9)) {
1801 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1803 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1805 color->r = r; color->g = g; color->b = b; color->a = a;
1808 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1809 if(!strcmp(str, colors[t].name)) {
1814 color->r = r; color->g = g; color->b = b; color->a = a;
1820 RGBA parseColor(char*str)
1823 if(!parseColor2(str, &c))
1824 syntaxerror("Expression '%s' is not a color", str);
1828 typedef struct _muladd {
1833 MULADD parseMulAdd(char*str)
1836 char* str2 = (char*)malloc(strlen(str)+5);
1843 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1844 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1845 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1846 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1847 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1848 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1849 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1850 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1851 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1852 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1854 syntaxerror("'%s' is not a valid color transform expression", str);
1856 m.add = (int)(add*256);
1857 m.mul = (int)(mul*256);
1862 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1864 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1865 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1867 if(a<-32768) a=-32768;
1868 if(a>32767) a=32767;
1869 if(m<-32768) m=-32768;
1870 if(m>32767) m=32767;
1876 float parsePxOrPercent(char*fontname, char*str)
1878 int l = strlen(str);
1879 if(strchr(str, '%'))
1880 return parsePercent(str);
1881 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
1882 float p = atof(str);
1883 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
1885 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
1889 float parsePercent(char*str)
1891 int l = strlen(str);
1895 return atoi(str)/100.0;
1897 syntaxerror("Expression '%s' is not a percentage", str);
1900 int isPercent(char*str)
1902 return str[strlen(str)-1]=='%';
1904 int parseNewSize(char*str, int size)
1907 return parsePercent(str)*size;
1909 return (int)(atof(str)*20);
1912 int isColor(char*str)
1915 return parseColor2(str, &c);
1918 static char* lu(map_t* args, char*name)
1920 char* value = map_lookup(args, name);
1922 map_dump(args, stdout, "");
1923 syntaxerror("internal error 2: value %s should be set", name);
1928 static int c_flash(map_t*args)
1930 char* filename = map_lookup(args, "filename");
1931 char* compressstr = lu(args, "compress");
1932 SRECT bbox = parseBox(lu(args, "bbox"));
1933 int version = parseInt(lu(args, "version"));
1934 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1936 RGBA color = parseColor(lu(args, "background"));
1938 if(!filename || !*filename) {
1939 /* for compatibility */
1940 filename = map_lookup(args, "name");
1941 if(!filename || !*filename) {
1944 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1945 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1949 if(!filename || override_outputname)
1950 filename = outputname;
1952 if(!strcmp(compressstr, "default"))
1953 compress = version==6;
1954 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1956 else if(!strcmp(compressstr, "no"))
1958 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1960 s_swf(filename, bbox, version, fps, compress, color);
1963 int isRelative(char*str)
1965 return !strncmp(str, "<plus>", 6) ||
1966 !strncmp(str, "<minus>", 7);
1968 char* getOffset(char*str)
1970 if(!strncmp(str, "<plus>", 6))
1972 if(!strncmp(str, "<minus>", 7))
1974 syntaxerror("internal error (347)");
1977 int getSign(char*str)
1979 if(!strncmp(str, "<plus>", 6))
1981 if(!strncmp(str, "<minus>", 7))
1983 syntaxerror("internal error (348)");
1986 static dictionary_t points;
1987 static mem_t mpoints;
1988 int points_initialized = 0;
1990 SPOINT getPoint(SRECT r, char*name)
1993 if(!strcmp(name, "center")) {
1995 p.x = (r.xmin + r.xmax)/2;
1996 p.y = (r.ymin + r.ymax)/2;
2000 if(points_initialized)
2001 l = (int)dictionary_lookup(&points, name);
2003 syntaxerror("Invalid point: \"%s\".", name);
2006 return *(SPOINT*)&mpoints.buffer[l];
2009 static int texture2(char*name, char*object, map_t*args, int errors)
2012 char*xstr = map_lookup(args, "x");
2013 char*ystr = map_lookup(args, "y");
2014 char*widthstr = map_lookup(args, "width");
2015 char*heightstr = map_lookup(args, "height");
2016 char*scalestr = map_lookup(args, "scale");
2017 char*scalexstr = map_lookup(args, "scalex");
2018 char*scaleystr = map_lookup(args, "scaley");
2019 char*rotatestr = map_lookup(args, "rotate");
2020 char* shearstr = map_lookup(args, "shear");
2021 char* radiusstr = map_lookup(args, "r");
2023 float scalex = 1.0, scaley = 1.0;
2024 float rotate=0, shear=0;
2026 if(!*xstr && !*ystr) {
2028 syntaxerror("x and y must be set");
2031 if(*scalestr && (*scalexstr || *scaleystr)) {
2032 syntaxerror("scale and scalex/scaley can't both be set");
2035 if((*widthstr || *heightstr) && *radiusstr) {
2036 syntaxerror("width/height and radius can't both be set");
2039 widthstr = radiusstr;
2040 heightstr = radiusstr;
2042 if(!*xstr) xstr="0";
2043 if(!*ystr) ystr="0";
2044 if(!*rotatestr) rotatestr="0";
2045 if(!*shearstr) shearstr="0";
2048 scalex = scaley = parsePercent(scalestr);
2049 } else if(*scalexstr || *scaleystr) {
2050 if(scalexstr) scalex = parsePercent(scalexstr);
2051 if(scaleystr) scaley = parsePercent(scaleystr);
2052 } else if(*widthstr || *heightstr) {
2055 s_getBitmapSize(object, &width, &height);
2057 scalex = (float)parseTwip(widthstr)/(float)width;
2059 scaley = (float)parseTwip(heightstr)/(float)height;
2061 x = parseTwip(xstr);
2062 y = parseTwip(ystr);
2063 rotate = parseFloat(rotatestr);
2064 shear = parseFloat(shearstr);
2066 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2071 static int c_texture(map_t*args)
2073 char*name = lu(args, "instance");
2074 char*object = lu(args, "character");
2075 return texture2(name, object, args, 1);
2078 static int c_gradient(map_t*args)
2080 char*name = lu(args, "name");
2081 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2082 int rotate = parseInt(lu(args, "rotate"));
2086 syntaxerror("colon (:) expected");
2088 s_gradient(name, text, radial, rotate);
2090 /* check whether we also have placement information,
2091 which would make this a positioned gradient.
2092 If there is placement information, texture2() will
2093 add a texture, which has priority over the gradient.
2095 texture2(name, name, args, 0);
2098 static int c_point(map_t*args)
2100 char*name = lu(args, "name");
2104 if(!points_initialized) {
2105 dictionary_init(&points);
2107 points_initialized = 1;
2109 p.x = parseTwip(lu(args, "x"));
2110 p.y = parseTwip(lu(args, "y"));
2111 pos = mem_put(&mpoints, &p, sizeof(p));
2112 string_set(&s1, name);
2114 dictionary_put(&points, s1, (void*)pos);
2117 static int c_play(map_t*args)
2119 char*name = lu(args, "name");
2120 char*loop = lu(args, "loop");
2121 char*nomultiple = lu(args, "nomultiple");
2123 if(!strcmp(nomultiple, "nomultiple"))
2126 nm = parseInt(nomultiple);
2128 if(s_playsound(name, parseInt(loop), nm, 0)) {
2130 } else if(s_swf3action(name, "play")) {
2136 static int c_stop(map_t*args)
2138 char*name = map_lookup(args, "name");
2140 if(s_playsound(name, 0,0,1)) {
2142 } else if(s_swf3action(name, "stop")) {
2145 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2149 static int c_nextframe(map_t*args)
2151 char*name = lu(args, "name");
2153 if(s_swf3action(name, "nextframe")) {
2156 syntaxerror("I don't know anything about movie \"%s\"", name);
2160 static int c_previousframe(map_t*args)
2162 char*name = lu(args, "name");
2164 if(s_swf3action(name, "previousframe")) {
2167 syntaxerror("I don't know anything about movie \"%s\"", name);
2171 static int c_placement(map_t*args, int type)
2173 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2176 char* luminancestr = lu(args, "luminance");
2177 char* scalestr = lu(args, "scale");
2178 char* scalexstr = lu(args, "scalex");
2179 char* scaleystr = lu(args, "scaley");
2180 char* rotatestr = lu(args, "rotate");
2181 char* shearstr = lu(args, "shear");
2182 char* xstr="", *pivotstr="";
2183 char* ystr="", *anglestr="";
2184 char*above = lu(args, "above"); /*FIXME*/
2185 char*below = lu(args, "below");
2186 char* rstr = lu(args, "red");
2187 char* gstr = lu(args, "green");
2188 char* bstr = lu(args, "blue");
2189 char* astr = lu(args, "alpha");
2190 char* pinstr = lu(args, "pin");
2191 char* as = map_lookup(args, "as");
2199 if(type==9) { // (?) .rotate or .arcchange
2200 pivotstr = lu(args, "pivot");
2201 anglestr = lu(args, "angle");
2203 xstr = lu(args, "x");
2204 ystr = lu(args, "y");
2207 luminance = parseMulAdd(luminancestr);
2210 luminance.mul = 256;
2214 if(scalexstr[0]||scaleystr[0])
2215 syntaxerror("scalex/scaley and scale cannot both be set");
2216 scalexstr = scaleystr = scalestr;
2219 if(type == 0 || type == 4) {
2221 character = lu(args, "character");
2222 parameters_clear(&p);
2223 } else if (type == 5) {
2224 character = lu(args, "name");
2225 parameters_clear(&p);
2228 p = s_getParameters(instance);
2233 if(isRelative(xstr)) {
2234 if(type == 0 || type == 4)
2235 syntaxerror("relative x values not allowed for initial put or startclip");
2236 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2238 p.x = parseTwip(xstr);
2242 if(isRelative(ystr)) {
2243 if(type == 0 || type == 4)
2244 syntaxerror("relative y values not allowed for initial put or startclip");
2245 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2247 p.y = parseTwip(ystr);
2251 /* scale, scalex, scaley */
2253 oldbbox = s_getCharBBox(character);
2255 oldbbox = s_getInstanceBBox(instance);
2257 oldwidth = oldbbox.xmax - oldbbox.xmin;
2258 oldheight = oldbbox.ymax - oldbbox.ymin;
2260 if(oldwidth==0) p.scalex = 1.0;
2263 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2267 if(oldheight==0) p.scaley = 1.0;
2270 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2276 if(isRelative(rotatestr)) {
2277 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2279 p.rotate = parseFloat(rotatestr);
2285 if(isRelative(shearstr)) {
2286 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2288 p.shear = parseFloat(shearstr);
2293 if(isPoint(pivotstr))
2294 p.pivot = parsePoint(pivotstr);
2296 p.pivot = getPoint(oldbbox, pivotstr);
2300 p.pin = parsePoint(pinstr);
2302 p.pin = getPoint(oldbbox, pinstr);
2305 /* color transform */
2307 if(rstr[0] || luminancestr[0]) {
2310 r = parseMulAdd(rstr);
2312 r.add = p.cxform.r0;
2313 r.mul = p.cxform.r1;
2315 r = mergeMulAdd(r, luminance);
2316 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2318 if(gstr[0] || luminancestr[0]) {
2321 g = parseMulAdd(gstr);
2323 g.add = p.cxform.g0;
2324 g.mul = p.cxform.g1;
2326 g = mergeMulAdd(g, luminance);
2327 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2329 if(bstr[0] || luminancestr[0]) {
2332 b = parseMulAdd(bstr);
2334 b.add = p.cxform.b0;
2335 b.mul = p.cxform.b1;
2337 b = mergeMulAdd(b, luminance);
2338 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2341 MULADD a = parseMulAdd(astr);
2342 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2346 s_put(instance, character, p);
2348 s_change(instance, p);
2350 s_qchange(instance, p);
2352 s_jump(instance, p);
2354 s_startclip(instance, character, p);
2355 else if(type == 5) {
2357 s_buttonput(character, as, p);
2359 s_buttonput(character, "shape", p);
2364 static int c_put(map_t*args)
2366 c_placement(args, 0);
2369 static int c_change(map_t*args)
2371 c_placement(args, 1);
2374 static int c_qchange(map_t*args)
2376 c_placement(args, 2);
2379 static int c_arcchange(map_t*args)
2381 c_placement(args, 2);
2384 static int c_jump(map_t*args)
2386 c_placement(args, 3);
2389 static int c_startclip(map_t*args)
2391 c_placement(args, 4);
2394 static int c_show(map_t*args)
2396 c_placement(args, 5);
2399 static int c_del(map_t*args)
2401 char*instance = lu(args, "name");
2402 s_delinstance(instance);
2405 static int c_end(map_t*args)
2410 static int c_sprite(map_t*args)
2412 char* name = lu(args, "name");
2416 static int c_frame(map_t*args)
2418 char*framestr = lu(args, "n");
2419 char*cutstr = lu(args, "cut");
2420 char*name = lu(args, "name");
2423 if(strcmp(cutstr, "no"))
2425 if(isRelative(framestr)) {
2426 frame = s_getframe();
2427 if(getSign(framestr)<0)
2428 syntaxerror("relative frame expressions must be positive");
2429 frame += parseInt(getOffset(framestr));
2432 frame = parseInt(framestr);
2433 if(s_getframe() >= frame
2434 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2435 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2437 s_frame(frame, cut, name);
2440 static int c_primitive(map_t*args)
2442 char*name = lu(args, "name");
2443 char*command = lu(args, "commandname");
2444 int width=0, height=0, r=0;
2445 int linewidth = parseTwip(lu(args, "line"));
2446 char*colorstr = lu(args, "color");
2447 RGBA color = parseColor(colorstr);
2448 char*fillstr = lu(args, "fill");
2455 if(!strcmp(command, "circle"))
2457 else if(!strcmp(command, "filled"))
2461 width = parseTwip(lu(args, "width"));
2462 height = parseTwip(lu(args, "height"));
2463 } else if (type==1) {
2464 r = parseTwip(lu(args, "r"));
2465 } else if (type==2) {
2466 outline = lu(args, "outline");
2469 if(!strcmp(fillstr, "fill"))
2471 if(!strcmp(fillstr, "none"))
2473 if(width<0 || height<0 || linewidth<0 || r<0)
2474 syntaxerror("values width, height, line, r must be positive");
2476 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2477 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2478 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2482 static int c_textshape(map_t*args)
2484 char*name = lu(args, "name");
2485 char*text = lu(args, "text");
2486 char*font = lu(args, "font");
2487 float size = parsePxOrPercent(font, lu(args, "size"));
2489 s_textshape(name, font, size, text);
2493 static int c_swf(map_t*args)
2495 char*name = lu(args, "name");
2496 char*filename = lu(args, "filename");
2497 char*command = lu(args, "commandname");
2498 if(!strcmp(command, "shape"))
2499 warning("Please use .swf instead of .shape");
2500 s_includeswf(name, filename);
2504 static int c_font(map_t*args)
2506 char*name = lu(args, "name");
2507 char*filename = lu(args, "filename");
2508 s_font(name, filename);
2512 static int c_sound(map_t*args)
2514 char*name = lu(args, "name");
2515 char*filename = lu(args, "filename");
2516 s_sound(name, filename);
2520 static int c_text(map_t*args)
2522 char*name = lu(args, "name");
2523 char*text = lu(args, "text");
2524 char*font = lu(args, "font");
2525 float size = parsePxOrPercent(font, lu(args, "size"));
2526 RGBA color = parseColor(lu(args, "color"));
2527 s_text(name, font, text, (int)(size*100), color);
2531 static int c_soundtrack(map_t*args)
2536 static int c_quicktime(map_t*args)
2538 char*name = lu(args, "name");
2539 char*url = lu(args, "url");
2540 s_quicktime(name, url);
2544 static int c_image(map_t*args)
2546 char*command = lu(args, "commandname");
2547 char*name = lu(args, "name");
2548 char*filename = lu(args, "filename");
2549 if(!strcmp(command,"jpeg")) {
2550 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2551 s_image(name, "jpeg", filename, quality);
2553 s_image(name, "png", filename, 0);
2558 static int c_outline(map_t*args)
2560 char*name = lu(args, "name");
2561 char*format = lu(args, "format");
2565 syntaxerror("colon (:) expected");
2567 s_outline(name, format, text);
2571 int fakechar(map_t*args)
2573 char*name = lu(args, "name");
2574 s_box(name, 0, 0, black, 20, 0);
2578 static int c_egon(map_t*args) {return fakechar(args);}
2579 static int c_button(map_t*args) {
2580 char*name = lu(args, "name");
2584 static int current_button_flags = 0;
2585 static int c_on_press(map_t*args)
2587 char*position = lu(args, "position");
2589 if(!strcmp(position, "inside")) {
2590 current_button_flags |= BC_OVERUP_OVERDOWN;
2591 } else if(!strcmp(position, "outside")) {
2592 //current_button_flags |= BC_IDLE_OUTDOWN;
2593 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2594 } else if(!strcmp(position, "anywhere")) {
2595 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2598 if(type == RAWDATA) {
2600 s_buttonaction(current_button_flags, action);
2601 current_button_flags = 0;
2607 static int c_on_release(map_t*args)
2609 char*position = lu(args, "position");
2611 if(!strcmp(position, "inside")) {
2612 current_button_flags |= BC_OVERDOWN_OVERUP;
2613 } else if(!strcmp(position, "outside")) {
2614 current_button_flags |= BC_OUTDOWN_IDLE;
2615 } else if(!strcmp(position, "anywhere")) {
2616 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2619 if(type == RAWDATA) {
2621 s_buttonaction(current_button_flags, action);
2622 current_button_flags = 0;
2628 static int c_on_move_in(map_t*args)
2630 char*position = lu(args, "state");
2632 if(!strcmp(position, "pressed")) {
2633 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2634 } else if(!strcmp(position, "not_pressed")) {
2635 current_button_flags |= BC_IDLE_OVERUP;
2636 } else if(!strcmp(position, "any")) {
2637 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2640 if(type == RAWDATA) {
2642 s_buttonaction(current_button_flags, action);
2643 current_button_flags = 0;
2649 static int c_on_move_out(map_t*args)
2651 char*position = lu(args, "state");
2653 if(!strcmp(position, "pressed")) {
2654 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2655 } else if(!strcmp(position, "not_pressed")) {
2656 current_button_flags |= BC_OVERUP_IDLE;
2657 } else if(!strcmp(position, "any")) {
2658 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2661 if(type == RAWDATA) {
2663 s_buttonaction(current_button_flags, action);
2664 current_button_flags = 0;
2670 static int c_on_key(map_t*args)
2672 char*key = lu(args, "key");
2674 if(strlen(key)==1) {
2677 current_button_flags |= 0x4000 + (key[0]*0x200);
2679 syntaxerror("invalid character: %c"+key[0]);
2684 <ctrl-x> = 0x200*(x-'a')
2688 syntaxerror("invalid key: %s",key);
2691 if(type == RAWDATA) {
2693 s_buttonaction(current_button_flags, action);
2694 current_button_flags = 0;
2701 static int c_edittext(map_t*args)
2703 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2704 char*name = lu(args, "name");
2705 char*font = lu(args, "font");
2706 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
2707 int width = parseTwip(lu(args, "width"));
2708 int height = parseTwip(lu(args, "height"));
2709 char*text = lu(args, "text");
2710 RGBA color = parseColor(lu(args, "color"));
2711 int maxlength = parseInt(lu(args, "maxlength"));
2712 char*variable = lu(args, "variable");
2713 char*passwordstr = lu(args, "password");
2714 char*wordwrapstr = lu(args, "wordwrap");
2715 char*multilinestr = lu(args, "multiline");
2716 char*htmlstr = lu(args, "html");
2717 char*noselectstr = lu(args, "noselect");
2718 char*readonlystr = lu(args, "readonly");
2719 char*borderstr = lu(args, "border");
2722 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2723 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2724 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2725 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2726 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2727 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2728 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2730 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2734 static int c_morphshape(map_t*args) {return fakechar(args);}
2735 static int c_movie(map_t*args) {return fakechar(args);}
2737 static char* readfile(const char*filename)
2739 FILE*fi = fopen(filename, "rb");
2743 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
2744 fseek(fi, 0, SEEK_END);
2746 fseek(fi, 0, SEEK_SET);
2747 text = rfx_alloc(l+1);
2748 fread(text, l, 1, fi);
2754 static int c_action(map_t*args)
2756 char* filename = map_lookup(args, "filename");
2757 if(!filename ||!*filename) {
2759 if(type != RAWDATA) {
2760 syntaxerror("colon (:) expected");
2764 s_action(readfile(filename));
2770 static int c_initaction(map_t*args)
2772 char* character = lu(args, "name");
2773 char* filename = map_lookup(args, "filename");
2774 if(!filename ||!*filename) {
2776 if(type != RAWDATA) {
2777 syntaxerror("colon (:) expected");
2779 s_initaction(character, text);
2781 s_initaction(character, readfile(filename));
2789 command_func_t* func;
2792 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
2793 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2794 // "import" type stuff
2795 {"swf", c_swf, "name filename"},
2796 {"shape", c_swf, "name filename"},
2797 {"jpeg", c_image, "name filename quality=80%"},
2798 {"png", c_image, "name filename"},
2799 {"movie", c_movie, "name filename"},
2800 {"sound", c_sound, "name filename"},
2801 {"font", c_font, "name filename"},
2802 {"soundtrack", c_soundtrack, "filename"},
2803 {"quicktime", c_quicktime, "url"},
2805 // generators of primitives
2807 {"point", c_point, "name x=0 y=0"},
2808 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
2809 {"outline", c_outline, "name format=simple"},
2810 {"textshape", c_textshape, "name font size=100% text"},
2812 // character generators
2813 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2814 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2815 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2817 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2818 {"text", c_text, "name text font size=100% color=white"},
2819 {"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"},
2820 {"morphshape", c_morphshape, "name start end"},
2821 {"button", c_button, "name"},
2822 {"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="},
2823 {"on_press", c_on_press, "position=inside"},
2824 {"on_release", c_on_release, "position=anywhere"},
2825 {"on_move_in", c_on_move_in, "state=not_pressed"},
2826 {"on_move_out", c_on_move_out, "state=not_pressed"},
2827 {"on_key", c_on_key, "key=any"},
2830 {"play", c_play, "name loop=0 @nomultiple=0"},
2831 {"stop", c_stop, "name= "},
2832 {"nextframe", c_nextframe, "name"},
2833 {"previousframe", c_previousframe, "name"},
2835 // object placement tags
2836 {"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="},
2837 {"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="},
2838 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2839 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2840 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2841 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2842 {"del", c_del, "name"},
2843 // virtual object placement
2844 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
2846 // commands which start a block
2847 //startclip (see above)
2848 {"sprite", c_sprite, "name"},
2849 {"action", c_action, "filename="},
2850 {"initaction", c_initaction, "name filename="},
2856 static map_t parseArguments(char*command, char*pattern)
2872 string_set(&t1, "commandname");
2873 string_set(&t2, command);
2874 map_put(&result, t1, t2);
2876 if(!pattern || !*pattern)
2883 if(!strncmp("<i> ", x, 3)) {
2885 if(type == COMMAND || type == RAWDATA) {
2887 syntaxerror("character name expected");
2889 name[pos].str = "instance";
2891 value[pos].str = text;
2892 value[pos].len = strlen(text);
2896 if(type == ASSIGNMENT)
2899 name[pos].str = "character";
2901 value[pos].str = text;
2902 value[pos].len = strlen(text);
2910 isboolean[pos] = (x[0] =='@');
2923 name[pos].len = d-x;
2928 name[pos].len = e-x;
2929 value[pos].str = e+1;
2930 value[pos].len = d-e-1;
2938 /* for(t=0;t<len;t++) {
2939 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2940 isboolean[t]?"(boolean)":"");
2945 if(type == RAWDATA || type == COMMAND) {
2950 // first, search for boolean arguments
2951 for(pos=0;pos<len;pos++)
2953 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2955 if(type == ASSIGNMENT)
2957 value[pos].str = text;
2958 value[pos].len = strlen(text);
2959 /*printf("setting boolean parameter %s (to %s)\n",
2960 strdup_n(name[pos], namelen[pos]),
2961 strdup_n(value[pos], valuelen[pos]));*/
2966 // second, search for normal arguments
2968 for(pos=0;pos<len;pos++)
2970 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2971 (type != ASSIGNMENT && !set[pos])) {
2973 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2975 if(type == ASSIGNMENT)
2978 value[pos].str = text;
2979 value[pos].len = strlen(text);
2981 printf("setting parameter %s (to %s)\n",
2982 strdup_n(name[pos].str, name[pos].len),
2983 strdup_n(value[pos].str, value[pos].len));
2989 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
2993 for(t=0;t<len;t++) {
2994 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2997 for(t=0;t<len;t++) {
2998 if(value[t].str && value[t].str[0] == '*') {
2999 //relative default- take value from some other parameter
3001 for(s=0;s<len;s++) {
3002 if(value[s].len == value[t].len-1 &&
3003 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3004 value[t].str = value[s].str;
3007 if(value[t].str == 0) {
3009 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3013 /* ok, now construct the dictionary from the parameters */
3017 map_put(&result, name[t], value[t]);
3021 static void parseArgumentsForCommand(char*command)
3026 msg("<verbose> parse Command: %s (line %d)", command, line);
3028 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3029 if(!strcmp(arguments[t].command, command)) {
3031 /* ugly hack- will be removed soon (once documentation and .sc generating
3032 utilities have been changed) */
3033 if(!strcmp(command, "swf") && !stackpos) {
3034 warning("Please use .flash instead of .swf- this will be mandatory soon");
3039 args = parseArguments(command, arguments[t].arguments);
3045 syntaxerror("command %s not known", command);
3047 // catch missing .flash directives at the beginning of a file
3048 if(strcmp(command, "flash") && !stackpos)
3050 syntaxerror("No movie defined- use .flash first");
3054 printf(".%s\n", command);fflush(stdout);
3055 map_dump(&args, stdout, "\t");fflush(stdout);
3058 (*arguments[nr].func)(&args);
3060 /*if(!strcmp(command, "button") ||
3061 !strcmp(command, "action")) {
3064 if(type == COMMAND) {
3065 if(!strcmp(text, "end"))
3079 int main (int argc,char ** argv)
3082 processargs(argc, argv);
3083 initLog(0,-1,0,0,-1,verbose);
3086 args_callback_usage(argv[0]);
3090 file = generateTokens(filename);
3092 printf("parser returned error.\n");
3098 while(!noMoreTokens()) {
3101 syntaxerror("command expected");
3102 parseArgumentsForCommand(text);