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 linewidth = linewidth>=20?linewidth-20:0;
810 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
813 fs1 = addFillStyle(s, &r2, texture);
816 r.xmin = r2.xmin-linewidth/2;
817 r.ymin = r2.ymin-linewidth/2;
818 r.xmax = r2.xmax+linewidth/2;
819 r.ymax = r2.ymax+linewidth/2;
821 swf_SetShapeHeader(tag,s);
822 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
823 swf_ShapeSetLine(tag,s,width,0);
824 swf_ShapeSetLine(tag,s,0,height);
825 swf_ShapeSetLine(tag,s,-width,0);
826 swf_ShapeSetLine(tag,s,0,-height);
827 swf_ShapeSetEnd(tag);
830 s_addcharacter(name, id, tag, r);
834 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
840 outline = dictionary_lookup(&outlines, outlinename);
842 syntaxerror("outline %s not defined", outlinename);
846 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
849 linewidth = linewidth>=20?linewidth-20:0;
850 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
853 fs1 = addFillStyle(s, &r2, texture);
856 rect.xmin = r2.xmin-linewidth/2;
857 rect.ymin = r2.ymin-linewidth/2;
858 rect.xmax = r2.xmax+linewidth/2;
859 rect.ymax = r2.ymax+linewidth/2;
861 swf_SetRect(tag,&rect);
862 swf_SetShapeStyles(tag, s);
863 swf_ShapeCountBits(s,0,0);
864 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
865 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
866 swf_SetShapeBits(tag, s);
867 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
870 s_addcharacter(name, id, tag, rect);
874 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
879 r2.xmin = r2.ymin = 0;
883 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
886 linewidth = linewidth>=20?linewidth-20:0;
887 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
890 fs1 = addFillStyle(s, &r2, texture);
892 rect.xmin = r2.xmin-linewidth/2;
893 rect.ymin = r2.ymin-linewidth/2;
894 rect.xmax = r2.xmax+linewidth/2;
895 rect.ymax = r2.ymax+linewidth/2;
897 swf_SetRect(tag,&rect);
898 swf_SetShapeHeader(tag,s);
899 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
900 swf_ShapeSetCircle(tag, s, r,r,r,r);
901 swf_ShapeSetEnd(tag);
904 s_addcharacter(name, id, tag, rect);
908 void s_textshape(char*name, char*fontname, float size, char*_text)
911 U8*text = (U8*)_text;
915 font = dictionary_lookup(&fonts, fontname);
917 syntaxerror("font \"%s\" not known!", fontname);
919 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
920 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
921 s_box(name, 0, 0, black, 20, 0);
924 g = font->ascii2glyph[text[0]];
926 outline = malloc(sizeof(outline_t));
927 memset(outline, 0, sizeof(outline_t));
928 outline->shape = font->glyph[g].shape;
929 outline->bbox = font->layout->bounds[g];
933 swf_Shape11DrawerInit(&draw, 0);
934 swf_DrawText(&draw, font, (int)(size*100), _text);
936 outline->shape = swf_ShapeDrawerToShape(&draw);
937 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
941 if(dictionary_lookup(&outlines, name))
942 syntaxerror("outline %s defined twice", name);
943 dictionary_put2(&outlines, name, outline);
946 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
951 font = dictionary_lookup(&fonts, fontname);
953 syntaxerror("font \"%s\" not known!", fontname);
955 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
957 if(!font->numchars) {
958 s_box(name, 0, 0, black, 20, 0);
961 r = swf_SetDefineText(tag, font, &color, text, size);
963 s_addcharacter(name, id, tag, r);
967 void s_quicktime(char*name, char*url)
972 memset(&r, 0, sizeof(r));
974 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
976 swf_SetString(tag, url);
978 s_addcharacter(name, id, tag, r);
982 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags, int align)
985 EditTextLayout layout;
988 if(fontname && *fontname) {
989 flags |= ET_USEOUTLINES;
990 font = dictionary_lookup(&fonts, fontname);
992 syntaxerror("font \"%s\" not known!", fontname);
994 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
996 layout.align = align;
997 layout.leftmargin = 0;
998 layout.rightmargin = 0;
1006 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1008 s_addcharacter(name, id, tag, r);
1012 /* type: either "jpeg" or "png"
1014 void s_image(char*name, char*type, char*filename, int quality)
1016 /* an image is actually two folded: 1st bitmap, 2nd character.
1017 Both of them can be used separately */
1019 /* step 1: the bitmap */
1024 warning("image type \"png\" not supported yet!");
1025 s_box(name, 0, 0, black, 20, 0);
1029 #ifndef HAVE_LIBJPEG
1030 warning("no jpeg support compiled in");
1031 s_box(name, 0, 0, black, 20, 0);
1034 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1035 swf_SetU16(tag, imageID);
1037 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1038 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1041 swf_GetJPEGSize(filename, &width, &height);
1048 s_addimage(name, id, tag, r);
1053 /* step 2: the character */
1054 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1055 swf_SetU16(tag, id);
1056 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1058 s_addcharacter(name, id, tag, r);
1062 void s_getBitmapSize(char*name, int*width, int*height)
1064 character_t* image = dictionary_lookup(&images, name);
1065 gradient_t* gradient = dictionary_lookup(&gradients,name);
1067 *width = image->size.xmax;
1068 *height = image->size.ymax;
1072 /* internal SWF gradient size */
1073 if(gradient->radial) {
1082 syntaxerror("No such bitmap/gradient: %s", name);
1085 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1087 gradient_t* gradient = dictionary_lookup(&gradients, object);
1088 character_t* bitmap = dictionary_lookup(&images, object);
1089 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1091 FILLSTYLE*fs = &texture->fs;
1094 fs->type = FILL_TILED;
1095 fs->id_bitmap = bitmap->id;
1096 } else if(gradient) {
1097 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1098 fs->gradient = gradient->gradient;
1100 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1101 makeMatrix(&fs->m, &p);
1102 if(gradient && !gradient->radial) {
1109 p2 = swf_TurnPoint(p1, &m);
1114 if(dictionary_lookup(&textures, name))
1115 syntaxerror("texture %s defined twice", name);
1116 dictionary_put2(&textures, name, texture);
1119 void dumpSWF(SWF*swf)
1121 TAG* tag = swf->firstTag;
1122 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1124 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1127 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1130 void s_font(char*name, char*filename)
1133 font = swf_LoadFont(filename);
1136 warning("Couldn't open font file \"%s\"", filename);
1137 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1138 memset(font, 0, sizeof(SWFFONT));
1139 dictionary_put2(&fonts, name, font);
1145 /* fix the layout. Only needed for old fonts */
1147 for(t=0;t<font->numchars;t++) {
1148 font->glyph[t].advance = 0;
1151 swf_FontCreateLayout(font);
1153 /* just in case this thing is used in .edittext later on */
1154 swf_FontPrepareForEditText(font);
1157 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1158 swf_FontSetDefine2(tag, font);
1161 if(dictionary_lookup(&fonts, name))
1162 syntaxerror("font %s defined twice", name);
1163 dictionary_put2(&fonts, name, font);
1168 typedef struct _sound_t
1174 void s_sound(char*name, char*filename)
1176 struct WAV wav, wav2;
1181 int blocksize = 1152;
1183 if(!readWAV(filename, &wav)) {
1184 warning("Couldn't read wav file \"%s\"", filename);
1188 convertWAV2mono(&wav, &wav2, 44100);
1189 samples = (U16*)wav2.data;
1190 numsamples = wav2.size/2;
1192 #ifdef WORDS_BIGENDIAN
1194 for(t=0;t<numsamples;t++) {
1195 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1200 if(numsamples%blocksize != 0)
1202 // apply padding, so that block is a multiple of blocksize
1203 int numblocks = (numsamples+blocksize-1)/blocksize;
1206 numsamples2 = numblocks * blocksize;
1207 samples2 = malloc(sizeof(U16)*numsamples2);
1208 memcpy(samples2, samples, numsamples*sizeof(U16));
1209 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1210 numsamples = numsamples2;
1214 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1215 swf_SetU16(tag, id); //id
1216 swf_SetSoundDefine(tag, samples, numsamples);
1218 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1222 if(dictionary_lookup(&sounds, name))
1223 syntaxerror("sound %s defined twice", name);
1224 dictionary_put2(&sounds, name, sound);
1232 static char* gradient_getToken(const char**p)
1236 while(**p && strchr(" \t\n\r", **p)) {
1240 while(**p && !strchr(" \t\n\r", **p)) {
1243 result = malloc((*p)-start+1);
1244 memcpy(result,start,(*p)-start+1);
1245 result[(*p)-start] = 0;
1249 float parsePercent(char*str);
1250 RGBA parseColor(char*str);
1252 GRADIENT parseGradient(const char*str)
1256 const char* p = str;
1257 memset(&gradient, 0, sizeof(GRADIENT));
1259 char*posstr,*colorstr;
1262 posstr = gradient_getToken(&p);
1265 pos = (int)(parsePercent(posstr)*255.0);
1268 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1269 colorstr = gradient_getToken(&p);
1270 color = parseColor(colorstr);
1271 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1272 warning("gradient record too big- max size is 8, rest ignored");
1275 gradient.ratios[gradient.num] = pos;
1276 gradient.rgba[gradient.num] = color;
1285 void s_gradient(char*name, const char*text, int radial, int rotate)
1287 gradient_t* gradient;
1288 gradient = malloc(sizeof(gradient_t));
1289 memset(gradient, 0, sizeof(gradient_t));
1290 gradient->gradient = parseGradient(text);
1291 gradient->radial = radial;
1292 gradient->rotate = rotate;
1294 if(dictionary_lookup(&gradients, name))
1295 syntaxerror("gradient %s defined twice", name);
1296 dictionary_put2(&gradients, name, gradient);
1299 void s_action(const char*text)
1302 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1304 syntaxerror("Couldn't compile ActionScript");
1307 tag = swf_InsertTag(tag, ST_DOACTION);
1309 swf_ActionSet(tag, a);
1314 void s_initaction(const char*character, const char*text)
1318 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1320 syntaxerror("Couldn't compile ActionScript");
1323 c = (character_t*)dictionary_lookup(&characters, character);
1325 tag = swf_InsertTag(tag, ST_DOINITACTION);
1326 swf_SetU16(tag, c->id);
1327 swf_ActionSet(tag, a);
1332 int s_swf3action(char*name, char*action)
1335 instance_t* object = 0;
1337 dictionary_lookup(&instances, name);
1338 if(!object && name && *name) {
1339 /* we have a name, but couldn't find it. Abort. */
1342 a = action_SetTarget(0, name);
1343 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1344 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1345 else if(!strcmp(action, "stop")) a = action_Stop(a);
1346 else if(!strcmp(action, "play")) a = action_Play(a);
1347 a = action_SetTarget(a, "");
1350 tag = swf_InsertTag(tag, ST_DOACTION);
1351 swf_ActionSet(tag, a);
1356 void s_outline(char*name, char*format, char*source)
1365 //swf_Shape10DrawerInit(&draw, 0);
1366 swf_Shape11DrawerInit(&draw, 0);
1368 draw_string(&draw, source);
1370 shape = swf_ShapeDrawerToShape(&draw);
1371 bounds = swf_ShapeDrawerGetBBox(&draw);
1372 draw.dealloc(&draw);
1374 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1375 outline->shape = shape;
1376 outline->bbox = bounds;
1378 if(dictionary_lookup(&outlines, name))
1379 syntaxerror("outline %s defined twice", name);
1380 dictionary_put2(&outlines, name, outline);
1383 int s_playsound(char*name, int loops, int nomultiple, int stop)
1389 sound = dictionary_lookup(&sounds, name);
1393 tag = swf_InsertTag(tag, ST_STARTSOUND);
1394 swf_SetU16(tag, sound->id); //id
1395 memset(&info, 0, sizeof(info));
1398 info.nomultiple = nomultiple;
1399 swf_SetSoundInfo(tag, &info);
1403 void s_includeswf(char*name, char*filename)
1411 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1412 f = open(filename,O_RDONLY|O_BINARY);
1414 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1415 s_box(name, 0, 0, black, 20, 0);
1418 if (swf_ReadSWF(f,&swf)<0) {
1419 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1420 s_box(name, 0, 0, black, 20, 0);
1425 /* FIXME: The following sets the bounding Box for the character.
1426 It is wrong for two reasons:
1427 a) It may be too small (in case objects in the movie clip at the borders)
1428 b) it may be too big (because the poor movie never got autocropped)
1432 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1433 swf_SetU16(tag, id);
1434 swf_SetU16(tag, swf.frameCount);
1436 swf_Relocate(&swf, idmap);
1438 ftag = swf.firstTag;
1442 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1443 if(cutout[t] == ftag->id) {
1447 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1449 if(ftag->id == ST_END)
1453 /* We simply dump all tags right after the sprite
1454 header, relying on the fact that swf_OptimizeTagOrder() will
1455 sort things out for us later.
1456 We also rely on the fact that the imported SWF is well-formed.
1458 tag = swf_InsertTag(tag, ftag->id);
1459 swf_SetBlock(tag, ftag->data, ftag->len);
1463 syntaxerror("Included file %s contains errors", filename);
1464 tag = swf_InsertTag(tag, ST_END);
1468 s_addcharacter(name, id, tag, r);
1471 SRECT s_getCharBBox(char*name)
1473 character_t* c = dictionary_lookup(&characters, name);
1474 if(!c) syntaxerror("character '%s' unknown(2)", name);
1477 SRECT s_getInstanceBBox(char*name)
1479 instance_t * i = dictionary_lookup(&instances, name);
1481 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1483 if(!c) syntaxerror("internal error(5)");
1486 parameters_t s_getParameters(char*name)
1488 instance_t * i = dictionary_lookup(&instances, name);
1489 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1490 return i->parameters;
1492 void s_startclip(char*instance, char*character, parameters_t p)
1494 character_t* c = dictionary_lookup(&characters, character);
1498 syntaxerror("character %s not known", character);
1500 i = s_addinstance(instance, c, currentdepth);
1502 m = s_instancepos(i->character->size, &p);
1504 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1505 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1506 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1508 i->lastFrame= currentframe;
1510 stack[stackpos].tag = tag;
1511 stack[stackpos].type = 2;
1520 swf_SetTagPos(stack[stackpos].tag, 0);
1521 swf_GetPlaceObject(stack[stackpos].tag, &p);
1522 p.clipdepth = currentdepth;
1524 swf_ClearTag(stack[stackpos].tag);
1525 swf_SetPlaceObject(stack[stackpos].tag, &p);
1529 void s_put(char*instance, char*character, parameters_t p)
1531 character_t* c = dictionary_lookup(&characters, character);
1535 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1538 i = s_addinstance(instance, c, currentdepth);
1540 m = s_instancepos(i->character->size, &p);
1542 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1543 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1545 i->lastFrame = currentframe;
1549 void s_jump(char*instance, parameters_t p)
1551 instance_t* i = dictionary_lookup(&instances, instance);
1554 syntaxerror("instance %s not known", instance);
1558 m = s_instancepos(i->character->size, &p);
1560 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1561 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1563 i->lastFrame = currentframe;
1566 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1570 if(num==0 || num==1)
1572 ratio = (float)pos/(float)num;
1574 p.x = (p2->x-p1->x)*ratio + p1->x;
1575 p.y = (p2->y-p1->y)*ratio + p1->y;
1576 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1577 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1578 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1579 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1581 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1582 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1583 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1584 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1586 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1587 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1588 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1589 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1591 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1592 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1593 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1594 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1598 void s_change(char*instance, parameters_t p2)
1600 instance_t* i = dictionary_lookup(&instances, instance);
1604 int frame, allframes;
1606 syntaxerror("instance %s not known", instance);
1610 allframes = currentframe - i->lastFrame - 1;
1612 warning(".change ignored. can only .put/.change an object once per frame.");
1616 m = s_instancepos(i->character->size, &p2);
1617 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1618 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1621 /* o.k., we got the start and end point set. Now iterate though all the
1622 tags in between, inserting object changes after each new frame */
1625 if(!t) syntaxerror("internal error(6)");
1627 while(frame < allframes) {
1628 if(t->id == ST_SHOWFRAME) {
1633 p = s_interpolate(&p1, &p2, frame, allframes);
1634 m = s_instancepos(i->character->size, &p); //needed?
1635 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1636 i->lastFrame = currentframe;
1637 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1639 if(frame == allframes)
1644 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1648 void s_delinstance(char*instance)
1650 instance_t* i = dictionary_lookup(&instances, instance);
1652 syntaxerror("instance %s not known", instance);
1654 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1655 swf_SetU16(tag, i->depth);
1656 dictionary_del(&instances, instance);
1659 void s_qchange(char*instance, parameters_t p)
1666 syntaxerror(".end unexpected");
1667 if(stack[stackpos-1].type == 0)
1669 else if(stack[stackpos-1].type == 1)
1671 else if(stack[stackpos-1].type == 2)
1673 else if(stack[stackpos-1].type == 3)
1675 else syntaxerror("internal error 1");
1678 // ------------------------------------------------------------------------
1680 typedef int command_func_t(map_t*args);
1682 SRECT parseBox(char*str)
1685 float xmin, xmax, ymin, ymax;
1686 char*x = strchr(str, 'x');
1688 if(!strcmp(str, "autocrop")) {
1689 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1693 d1 = strchr(x+1, ':');
1695 d2 = strchr(d1+1, ':');
1697 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1701 else if(d1 && !d2) {
1702 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1708 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1713 r.xmin = (SCOORD)(xmin*20);
1714 r.ymin = (SCOORD)(ymin*20);
1715 r.xmax = (SCOORD)(xmax*20);
1716 r.ymax = (SCOORD)(ymax*20);
1719 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1722 float parseFloat(char*str)
1726 int parseInt(char*str)
1731 if(str[0]=='+' || str[0]=='-')
1735 if(str[t]<'0' || str[t]>'9')
1736 syntaxerror("Not an Integer: \"%s\"", str);
1739 int parseTwip(char*str)
1743 if(str[0]=='+' || str[0]=='-') {
1748 dot = strchr(str, '.');
1752 return sign*parseInt(str)*20;
1754 int l=strlen(++dot);
1756 for(s=str;s<dot-1;s++)
1757 if(*s<'0' || *s>'9')
1758 syntaxerror("Not a coordinate: \"%s\"", str);
1760 if(*s<'0' || *s>'9')
1761 syntaxerror("Not a coordinate: \"%s\"", str);
1763 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1764 warning("precision loss: %s converted to twip: %s", str, dot);
1769 return sign*atoi(str)*20;
1771 return sign*atoi(str)*20+atoi(dot)*2;
1773 return sign*atoi(str)*20+atoi(dot)/5;
1778 int isPoint(char*str)
1780 if(strchr(str, '('))
1786 SPOINT parsePoint(char*str)
1790 int l = strlen(str);
1791 char*comma = strchr(str, ',');
1792 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1793 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1794 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1795 p.x = parseTwip(tmp);
1796 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1797 p.y = parseTwip(tmp);
1801 int parseColor2(char*str, RGBA*color)
1803 int l = strlen(str);
1807 struct {unsigned char r,g,b;char*name;} colors[] =
1808 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1809 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1810 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1811 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1812 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1813 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1814 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1815 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1816 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1817 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1818 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1819 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1823 if(str[0]=='#' && (l==7 || l==9)) {
1824 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1826 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1828 color->r = r; color->g = g; color->b = b; color->a = a;
1831 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1832 if(!strcmp(str, colors[t].name)) {
1837 color->r = r; color->g = g; color->b = b; color->a = a;
1843 RGBA parseColor(char*str)
1846 if(!parseColor2(str, &c))
1847 syntaxerror("Expression '%s' is not a color", str);
1851 typedef struct _muladd {
1856 MULADD parseMulAdd(char*str)
1859 char* str2 = (char*)malloc(strlen(str)+5);
1866 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1867 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1868 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1869 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1870 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1871 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1872 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1873 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1874 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1875 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1877 syntaxerror("'%s' is not a valid color transform expression", str);
1879 m.add = (int)(add*256);
1880 m.mul = (int)(mul*256);
1885 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1887 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1888 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1890 if(a<-32768) a=-32768;
1891 if(a>32767) a=32767;
1892 if(m<-32768) m=-32768;
1893 if(m>32767) m=32767;
1899 float parsePxOrPercent(char*fontname, char*str)
1901 int l = strlen(str);
1902 if(strchr(str, '%'))
1903 return parsePercent(str);
1904 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
1905 float p = atof(str);
1906 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
1908 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
1912 float parsePercent(char*str)
1914 int l = strlen(str);
1918 return atoi(str)/100.0;
1920 syntaxerror("Expression '%s' is not a percentage", str);
1923 int isPercent(char*str)
1925 return str[strlen(str)-1]=='%';
1927 int parseNewSize(char*str, int size)
1930 return parsePercent(str)*size;
1932 return (int)(atof(str)*20);
1935 int isColor(char*str)
1938 return parseColor2(str, &c);
1941 static char* lu(map_t* args, char*name)
1943 char* value = map_lookup(args, name);
1945 map_dump(args, stdout, "");
1946 syntaxerror("internal error 2: value %s should be set", name);
1951 static int c_flash(map_t*args)
1953 char* filename = map_lookup(args, "filename");
1954 char* compressstr = lu(args, "compress");
1955 SRECT bbox = parseBox(lu(args, "bbox"));
1956 int version = parseInt(lu(args, "version"));
1957 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1959 RGBA color = parseColor(lu(args, "background"));
1961 if(!filename || !*filename) {
1962 /* for compatibility */
1963 filename = map_lookup(args, "name");
1964 if(!filename || !*filename) {
1967 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1968 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1972 if(!filename || override_outputname)
1973 filename = outputname;
1975 if(!strcmp(compressstr, "default"))
1976 compress = version==6;
1977 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1979 else if(!strcmp(compressstr, "no"))
1981 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1983 s_swf(filename, bbox, version, fps, compress, color);
1986 int isRelative(char*str)
1988 return !strncmp(str, "<plus>", 6) ||
1989 !strncmp(str, "<minus>", 7);
1991 char* getOffset(char*str)
1993 if(!strncmp(str, "<plus>", 6))
1995 if(!strncmp(str, "<minus>", 7))
1997 syntaxerror("internal error (347)");
2000 int getSign(char*str)
2002 if(!strncmp(str, "<plus>", 6))
2004 if(!strncmp(str, "<minus>", 7))
2006 syntaxerror("internal error (348)");
2009 static dictionary_t points;
2010 static mem_t mpoints;
2011 int points_initialized = 0;
2013 SPOINT getPoint(SRECT r, char*name)
2016 if(!strcmp(name, "center")) {
2018 p.x = (r.xmin + r.xmax)/2;
2019 p.y = (r.ymin + r.ymax)/2;
2023 if(points_initialized)
2024 l = (int)dictionary_lookup(&points, name);
2026 syntaxerror("Invalid point: \"%s\".", name);
2029 return *(SPOINT*)&mpoints.buffer[l];
2032 static int texture2(char*name, char*object, map_t*args, int errors)
2035 char*xstr = map_lookup(args, "x");
2036 char*ystr = map_lookup(args, "y");
2037 char*widthstr = map_lookup(args, "width");
2038 char*heightstr = map_lookup(args, "height");
2039 char*scalestr = map_lookup(args, "scale");
2040 char*scalexstr = map_lookup(args, "scalex");
2041 char*scaleystr = map_lookup(args, "scaley");
2042 char*rotatestr = map_lookup(args, "rotate");
2043 char* shearstr = map_lookup(args, "shear");
2044 char* radiusstr = map_lookup(args, "r");
2046 float scalex = 1.0, scaley = 1.0;
2047 float rotate=0, shear=0;
2049 if(!*xstr && !*ystr) {
2051 syntaxerror("x and y must be set");
2054 if(*scalestr && (*scalexstr || *scaleystr)) {
2055 syntaxerror("scale and scalex/scaley can't both be set");
2058 if((*widthstr || *heightstr) && *radiusstr) {
2059 syntaxerror("width/height and radius can't both be set");
2062 widthstr = radiusstr;
2063 heightstr = radiusstr;
2065 if(!*xstr) xstr="0";
2066 if(!*ystr) ystr="0";
2067 if(!*rotatestr) rotatestr="0";
2068 if(!*shearstr) shearstr="0";
2071 scalex = scaley = parsePercent(scalestr);
2072 } else if(*scalexstr || *scaleystr) {
2073 if(scalexstr) scalex = parsePercent(scalexstr);
2074 if(scaleystr) scaley = parsePercent(scaleystr);
2075 } else if(*widthstr || *heightstr) {
2078 s_getBitmapSize(object, &width, &height);
2080 scalex = (float)parseTwip(widthstr)/(float)width;
2082 scaley = (float)parseTwip(heightstr)/(float)height;
2084 x = parseTwip(xstr);
2085 y = parseTwip(ystr);
2086 rotate = parseFloat(rotatestr);
2087 shear = parseFloat(shearstr);
2089 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2094 static int c_texture(map_t*args)
2096 char*name = lu(args, "instance");
2097 char*object = lu(args, "character");
2098 return texture2(name, object, args, 1);
2101 static int c_gradient(map_t*args)
2103 char*name = lu(args, "name");
2104 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2105 int rotate = parseInt(lu(args, "rotate"));
2109 syntaxerror("colon (:) expected");
2111 s_gradient(name, text, radial, rotate);
2113 /* check whether we also have placement information,
2114 which would make this a positioned gradient.
2115 If there is placement information, texture2() will
2116 add a texture, which has priority over the gradient.
2118 texture2(name, name, args, 0);
2121 static int c_point(map_t*args)
2123 char*name = lu(args, "name");
2127 if(!points_initialized) {
2128 dictionary_init(&points);
2130 points_initialized = 1;
2132 p.x = parseTwip(lu(args, "x"));
2133 p.y = parseTwip(lu(args, "y"));
2134 pos = mem_put(&mpoints, &p, sizeof(p));
2135 string_set(&s1, name);
2137 dictionary_put(&points, s1, (void*)pos);
2140 static int c_play(map_t*args)
2142 char*name = lu(args, "name");
2143 char*loop = lu(args, "loop");
2144 char*nomultiple = lu(args, "nomultiple");
2146 if(!strcmp(nomultiple, "nomultiple"))
2149 nm = parseInt(nomultiple);
2151 if(s_playsound(name, parseInt(loop), nm, 0)) {
2153 } else if(s_swf3action(name, "play")) {
2159 static int c_stop(map_t*args)
2161 char*name = map_lookup(args, "name");
2163 if(s_playsound(name, 0,0,1)) {
2165 } else if(s_swf3action(name, "stop")) {
2168 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2172 static int c_nextframe(map_t*args)
2174 char*name = lu(args, "name");
2176 if(s_swf3action(name, "nextframe")) {
2179 syntaxerror("I don't know anything about movie \"%s\"", name);
2183 static int c_previousframe(map_t*args)
2185 char*name = lu(args, "name");
2187 if(s_swf3action(name, "previousframe")) {
2190 syntaxerror("I don't know anything about movie \"%s\"", name);
2194 static int c_placement(map_t*args, int type)
2196 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2199 char* luminancestr = lu(args, "luminance");
2200 char* scalestr = lu(args, "scale");
2201 char* scalexstr = lu(args, "scalex");
2202 char* scaleystr = lu(args, "scaley");
2203 char* rotatestr = lu(args, "rotate");
2204 char* shearstr = lu(args, "shear");
2205 char* xstr="", *pivotstr="";
2206 char* ystr="", *anglestr="";
2207 char*above = lu(args, "above"); /*FIXME*/
2208 char*below = lu(args, "below");
2209 char* rstr = lu(args, "red");
2210 char* gstr = lu(args, "green");
2211 char* bstr = lu(args, "blue");
2212 char* astr = lu(args, "alpha");
2213 char* pinstr = lu(args, "pin");
2214 char* as = map_lookup(args, "as");
2222 if(type==9) { // (?) .rotate or .arcchange
2223 pivotstr = lu(args, "pivot");
2224 anglestr = lu(args, "angle");
2226 xstr = lu(args, "x");
2227 ystr = lu(args, "y");
2230 luminance = parseMulAdd(luminancestr);
2233 luminance.mul = 256;
2237 if(scalexstr[0]||scaleystr[0])
2238 syntaxerror("scalex/scaley and scale cannot both be set");
2239 scalexstr = scaleystr = scalestr;
2242 if(type == 0 || type == 4) {
2244 character = lu(args, "character");
2245 parameters_clear(&p);
2246 } else if (type == 5) {
2247 character = lu(args, "name");
2248 parameters_clear(&p);
2251 p = s_getParameters(instance);
2256 if(isRelative(xstr)) {
2257 if(type == 0 || type == 4)
2258 syntaxerror("relative x values not allowed for initial put or startclip");
2259 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2261 p.x = parseTwip(xstr);
2265 if(isRelative(ystr)) {
2266 if(type == 0 || type == 4)
2267 syntaxerror("relative y values not allowed for initial put or startclip");
2268 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2270 p.y = parseTwip(ystr);
2274 /* scale, scalex, scaley */
2276 oldbbox = s_getCharBBox(character);
2278 oldbbox = s_getInstanceBBox(instance);
2280 oldwidth = oldbbox.xmax - oldbbox.xmin;
2281 oldheight = oldbbox.ymax - oldbbox.ymin;
2283 if(oldwidth==0) p.scalex = 1.0;
2286 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2290 if(oldheight==0) p.scaley = 1.0;
2293 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2299 if(isRelative(rotatestr)) {
2300 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2302 p.rotate = parseFloat(rotatestr);
2308 if(isRelative(shearstr)) {
2309 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2311 p.shear = parseFloat(shearstr);
2316 if(isPoint(pivotstr))
2317 p.pivot = parsePoint(pivotstr);
2319 p.pivot = getPoint(oldbbox, pivotstr);
2323 p.pin = parsePoint(pinstr);
2325 p.pin = getPoint(oldbbox, pinstr);
2328 /* color transform */
2330 if(rstr[0] || luminancestr[0]) {
2333 r = parseMulAdd(rstr);
2335 r.add = p.cxform.r0;
2336 r.mul = p.cxform.r1;
2338 r = mergeMulAdd(r, luminance);
2339 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2341 if(gstr[0] || luminancestr[0]) {
2344 g = parseMulAdd(gstr);
2346 g.add = p.cxform.g0;
2347 g.mul = p.cxform.g1;
2349 g = mergeMulAdd(g, luminance);
2350 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2352 if(bstr[0] || luminancestr[0]) {
2355 b = parseMulAdd(bstr);
2357 b.add = p.cxform.b0;
2358 b.mul = p.cxform.b1;
2360 b = mergeMulAdd(b, luminance);
2361 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2364 MULADD a = parseMulAdd(astr);
2365 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2369 s_put(instance, character, p);
2371 s_change(instance, p);
2373 s_qchange(instance, p);
2375 s_jump(instance, p);
2377 s_startclip(instance, character, p);
2378 else if(type == 5) {
2380 s_buttonput(character, as, p);
2382 s_buttonput(character, "shape", p);
2387 static int c_put(map_t*args)
2389 c_placement(args, 0);
2392 static int c_change(map_t*args)
2394 c_placement(args, 1);
2397 static int c_qchange(map_t*args)
2399 c_placement(args, 2);
2402 static int c_arcchange(map_t*args)
2404 c_placement(args, 2);
2407 static int c_jump(map_t*args)
2409 c_placement(args, 3);
2412 static int c_startclip(map_t*args)
2414 c_placement(args, 4);
2417 static int c_show(map_t*args)
2419 c_placement(args, 5);
2422 static int c_del(map_t*args)
2424 char*instance = lu(args, "name");
2425 s_delinstance(instance);
2428 static int c_end(map_t*args)
2433 static int c_sprite(map_t*args)
2435 char* name = lu(args, "name");
2439 static int c_frame(map_t*args)
2441 char*framestr = lu(args, "n");
2442 char*cutstr = lu(args, "cut");
2443 char*name = lu(args, "name");
2446 if(strcmp(cutstr, "no"))
2448 if(isRelative(framestr)) {
2449 frame = s_getframe();
2450 if(getSign(framestr)<0)
2451 syntaxerror("relative frame expressions must be positive");
2452 frame += parseInt(getOffset(framestr));
2455 frame = parseInt(framestr);
2456 if(s_getframe() >= frame
2457 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2458 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2460 s_frame(frame, cut, name);
2463 static int c_primitive(map_t*args)
2465 char*name = lu(args, "name");
2466 char*command = lu(args, "commandname");
2467 int width=0, height=0, r=0;
2468 int linewidth = parseTwip(lu(args, "line"));
2469 char*colorstr = lu(args, "color");
2470 RGBA color = parseColor(colorstr);
2471 char*fillstr = lu(args, "fill");
2478 if(!strcmp(command, "circle"))
2480 else if(!strcmp(command, "filled"))
2484 width = parseTwip(lu(args, "width"));
2485 height = parseTwip(lu(args, "height"));
2486 } else if (type==1) {
2487 r = parseTwip(lu(args, "r"));
2488 } else if (type==2) {
2489 outline = lu(args, "outline");
2492 if(!strcmp(fillstr, "fill"))
2494 if(!strcmp(fillstr, "none"))
2496 if(width<0 || height<0 || linewidth<0 || r<0)
2497 syntaxerror("values width, height, line, r must be positive");
2499 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2500 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2501 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2505 static int c_textshape(map_t*args)
2507 char*name = lu(args, "name");
2508 char*text = lu(args, "text");
2509 char*font = lu(args, "font");
2510 float size = parsePxOrPercent(font, lu(args, "size"));
2512 s_textshape(name, font, size, text);
2516 static int c_swf(map_t*args)
2518 char*name = lu(args, "name");
2519 char*filename = lu(args, "filename");
2520 char*command = lu(args, "commandname");
2521 if(!strcmp(command, "shape"))
2522 warning("Please use .swf instead of .shape");
2523 s_includeswf(name, filename);
2527 static int c_font(map_t*args)
2529 char*name = lu(args, "name");
2530 char*filename = lu(args, "filename");
2531 s_font(name, filename);
2535 static int c_sound(map_t*args)
2537 char*name = lu(args, "name");
2538 char*filename = lu(args, "filename");
2539 s_sound(name, filename);
2543 static int c_text(map_t*args)
2545 char*name = lu(args, "name");
2546 char*text = lu(args, "text");
2547 char*font = lu(args, "font");
2548 float size = parsePxOrPercent(font, lu(args, "size"));
2549 RGBA color = parseColor(lu(args, "color"));
2550 s_text(name, font, text, (int)(size*100), color);
2554 static int c_soundtrack(map_t*args)
2559 static int c_quicktime(map_t*args)
2561 char*name = lu(args, "name");
2562 char*url = lu(args, "url");
2563 s_quicktime(name, url);
2567 static int c_image(map_t*args)
2569 char*command = lu(args, "commandname");
2570 char*name = lu(args, "name");
2571 char*filename = lu(args, "filename");
2572 if(!strcmp(command,"jpeg")) {
2573 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2574 s_image(name, "jpeg", filename, quality);
2576 s_image(name, "png", filename, 0);
2581 static int c_outline(map_t*args)
2583 char*name = lu(args, "name");
2584 char*format = lu(args, "format");
2588 syntaxerror("colon (:) expected");
2590 s_outline(name, format, text);
2594 int fakechar(map_t*args)
2596 char*name = lu(args, "name");
2597 s_box(name, 0, 0, black, 20, 0);
2601 static int c_egon(map_t*args) {return fakechar(args);}
2602 static int c_button(map_t*args) {
2603 char*name = lu(args, "name");
2607 static int current_button_flags = 0;
2608 static int c_on_press(map_t*args)
2610 char*position = lu(args, "position");
2612 if(!strcmp(position, "inside")) {
2613 current_button_flags |= BC_OVERUP_OVERDOWN;
2614 } else if(!strcmp(position, "outside")) {
2615 //current_button_flags |= BC_IDLE_OUTDOWN;
2616 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2617 } else if(!strcmp(position, "anywhere")) {
2618 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2621 if(type == RAWDATA) {
2623 s_buttonaction(current_button_flags, action);
2624 current_button_flags = 0;
2630 static int c_on_release(map_t*args)
2632 char*position = lu(args, "position");
2634 if(!strcmp(position, "inside")) {
2635 current_button_flags |= BC_OVERDOWN_OVERUP;
2636 } else if(!strcmp(position, "outside")) {
2637 current_button_flags |= BC_OUTDOWN_IDLE;
2638 } else if(!strcmp(position, "anywhere")) {
2639 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2642 if(type == RAWDATA) {
2644 s_buttonaction(current_button_flags, action);
2645 current_button_flags = 0;
2651 static int c_on_move_in(map_t*args)
2653 char*position = lu(args, "state");
2655 if(!strcmp(position, "pressed")) {
2656 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2657 } else if(!strcmp(position, "not_pressed")) {
2658 current_button_flags |= BC_IDLE_OVERUP;
2659 } else if(!strcmp(position, "any")) {
2660 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2663 if(type == RAWDATA) {
2665 s_buttonaction(current_button_flags, action);
2666 current_button_flags = 0;
2672 static int c_on_move_out(map_t*args)
2674 char*position = lu(args, "state");
2676 if(!strcmp(position, "pressed")) {
2677 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2678 } else if(!strcmp(position, "not_pressed")) {
2679 current_button_flags |= BC_OVERUP_IDLE;
2680 } else if(!strcmp(position, "any")) {
2681 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2684 if(type == RAWDATA) {
2686 s_buttonaction(current_button_flags, action);
2687 current_button_flags = 0;
2693 static int c_on_key(map_t*args)
2695 char*key = lu(args, "key");
2697 if(strlen(key)==1) {
2700 current_button_flags |= 0x4000 + (key[0]*0x200);
2702 syntaxerror("invalid character: %c"+key[0]);
2707 <ctrl-x> = 0x200*(x-'a')
2711 syntaxerror("invalid key: %s",key);
2714 if(type == RAWDATA) {
2716 s_buttonaction(current_button_flags, action);
2717 current_button_flags = 0;
2724 static int c_edittext(map_t*args)
2726 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @autosize=0"},
2727 char*name = lu(args, "name");
2728 char*font = lu(args, "font");
2729 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
2730 int width = parseTwip(lu(args, "width"));
2731 int height = parseTwip(lu(args, "height"));
2732 char*text = lu(args, "text");
2733 RGBA color = parseColor(lu(args, "color"));
2734 int maxlength = parseInt(lu(args, "maxlength"));
2735 char*variable = lu(args, "variable");
2736 char*passwordstr = lu(args, "password");
2737 char*wordwrapstr = lu(args, "wordwrap");
2738 char*multilinestr = lu(args, "multiline");
2739 char*htmlstr = lu(args, "html");
2740 char*noselectstr = lu(args, "noselect");
2741 char*readonlystr = lu(args, "readonly");
2742 char*borderstr = lu(args, "border");
2743 char*autosizestr = lu(args, "autosize");
2744 char*alignstr = lu(args, "align");
2748 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2749 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2750 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2751 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2752 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2753 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2754 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2755 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
2756 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
2757 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
2758 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
2759 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
2760 else syntaxerror("Unknown alignment: %s", alignstr);
2762 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
2766 static int c_morphshape(map_t*args) {return fakechar(args);}
2767 static int c_movie(map_t*args) {return fakechar(args);}
2769 static char* readfile(const char*filename)
2771 FILE*fi = fopen(filename, "rb");
2775 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
2776 fseek(fi, 0, SEEK_END);
2778 fseek(fi, 0, SEEK_SET);
2779 text = rfx_alloc(l+1);
2780 fread(text, l, 1, fi);
2786 static int c_action(map_t*args)
2788 char* filename = map_lookup(args, "filename");
2789 if(!filename ||!*filename) {
2791 if(type != RAWDATA) {
2792 syntaxerror("colon (:) expected");
2796 s_action(readfile(filename));
2802 static int c_initaction(map_t*args)
2804 char* character = lu(args, "name");
2805 char* filename = map_lookup(args, "filename");
2806 if(!filename ||!*filename) {
2808 if(type != RAWDATA) {
2809 syntaxerror("colon (:) expected");
2811 s_initaction(character, text);
2813 s_initaction(character, readfile(filename));
2821 command_func_t* func;
2824 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
2825 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2826 // "import" type stuff
2827 {"swf", c_swf, "name filename"},
2828 {"shape", c_swf, "name filename"},
2829 {"jpeg", c_image, "name filename quality=80%"},
2830 {"png", c_image, "name filename"},
2831 {"movie", c_movie, "name filename"},
2832 {"sound", c_sound, "name filename"},
2833 {"font", c_font, "name filename"},
2834 {"soundtrack", c_soundtrack, "filename"},
2835 {"quicktime", c_quicktime, "url"},
2837 // generators of primitives
2839 {"point", c_point, "name x=0 y=0"},
2840 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
2841 {"outline", c_outline, "name format=simple"},
2842 {"textshape", c_textshape, "name font size=100% text"},
2844 // character generators
2845 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2846 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2847 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2849 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2850 {"text", c_text, "name text font size=100% color=white"},
2851 {"edittext", c_edittext, "name font= size=100% width height text="" color=white maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @border=0 @autosize=0 align="},
2852 {"morphshape", c_morphshape, "name start end"},
2853 {"button", c_button, "name"},
2854 {"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="},
2855 {"on_press", c_on_press, "position=inside"},
2856 {"on_release", c_on_release, "position=anywhere"},
2857 {"on_move_in", c_on_move_in, "state=not_pressed"},
2858 {"on_move_out", c_on_move_out, "state=not_pressed"},
2859 {"on_key", c_on_key, "key=any"},
2862 {"play", c_play, "name loop=0 @nomultiple=0"},
2863 {"stop", c_stop, "name= "},
2864 {"nextframe", c_nextframe, "name"},
2865 {"previousframe", c_previousframe, "name"},
2867 // object placement tags
2868 {"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="},
2869 {"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="},
2870 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2871 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2872 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2873 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2874 {"del", c_del, "name"},
2875 // virtual object placement
2876 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
2878 // commands which start a block
2879 //startclip (see above)
2880 {"sprite", c_sprite, "name"},
2881 {"action", c_action, "filename="},
2882 {"initaction", c_initaction, "name filename="},
2888 static map_t parseArguments(char*command, char*pattern)
2904 string_set(&t1, "commandname");
2905 string_set(&t2, command);
2906 map_put(&result, t1, t2);
2908 if(!pattern || !*pattern)
2915 if(!strncmp("<i> ", x, 3)) {
2917 if(type == COMMAND || type == RAWDATA) {
2919 syntaxerror("character name expected");
2921 name[pos].str = "instance";
2923 value[pos].str = text;
2924 value[pos].len = strlen(text);
2928 if(type == ASSIGNMENT)
2931 name[pos].str = "character";
2933 value[pos].str = text;
2934 value[pos].len = strlen(text);
2942 isboolean[pos] = (x[0] =='@');
2955 name[pos].len = d-x;
2960 name[pos].len = e-x;
2961 value[pos].str = e+1;
2962 value[pos].len = d-e-1;
2970 /* for(t=0;t<len;t++) {
2971 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2972 isboolean[t]?"(boolean)":"");
2977 if(type == RAWDATA || type == COMMAND) {
2982 // first, search for boolean arguments
2983 for(pos=0;pos<len;pos++)
2985 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2987 if(type == ASSIGNMENT)
2989 value[pos].str = text;
2990 value[pos].len = strlen(text);
2991 /*printf("setting boolean parameter %s (to %s)\n",
2992 strdup_n(name[pos], namelen[pos]),
2993 strdup_n(value[pos], valuelen[pos]));*/
2998 // second, search for normal arguments
3000 for(pos=0;pos<len;pos++)
3002 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3003 (type != ASSIGNMENT && !set[pos])) {
3005 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3007 if(type == ASSIGNMENT)
3010 value[pos].str = text;
3011 value[pos].len = strlen(text);
3013 printf("setting parameter %s (to %s)\n",
3014 strdup_n(name[pos].str, name[pos].len),
3015 strdup_n(value[pos].str, value[pos].len));
3021 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3025 for(t=0;t<len;t++) {
3026 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3029 for(t=0;t<len;t++) {
3030 if(value[t].str && value[t].str[0] == '*') {
3031 //relative default- take value from some other parameter
3033 for(s=0;s<len;s++) {
3034 if(value[s].len == value[t].len-1 &&
3035 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3036 value[t].str = value[s].str;
3039 if(value[t].str == 0) {
3041 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3045 /* ok, now construct the dictionary from the parameters */
3049 map_put(&result, name[t], value[t]);
3053 static void parseArgumentsForCommand(char*command)
3058 msg("<verbose> parse Command: %s (line %d)", command, line);
3060 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3061 if(!strcmp(arguments[t].command, command)) {
3063 /* ugly hack- will be removed soon (once documentation and .sc generating
3064 utilities have been changed) */
3065 if(!strcmp(command, "swf") && !stackpos) {
3066 warning("Please use .flash instead of .swf- this will be mandatory soon");
3071 args = parseArguments(command, arguments[t].arguments);
3077 syntaxerror("command %s not known", command);
3079 // catch missing .flash directives at the beginning of a file
3080 if(strcmp(command, "flash") && !stackpos)
3082 syntaxerror("No movie defined- use .flash first");
3086 printf(".%s\n", command);fflush(stdout);
3087 map_dump(&args, stdout, "\t");fflush(stdout);
3090 (*arguments[nr].func)(&args);
3092 /*if(!strcmp(command, "button") ||
3093 !strcmp(command, "action")) {
3096 if(type == COMMAND) {
3097 if(!strcmp(text, "end"))
3111 int main (int argc,char ** argv)
3114 processargs(argc, argv);
3115 initLog(0,-1,0,0,-1,verbose);
3118 args_callback_usage(argv[0]);
3122 file = generateTokens(filename);
3124 printf("parser returned error.\n");
3130 while(!noMoreTokens()) {
3133 syntaxerror("command expected");
3134 parseArgumentsForCommand(text);