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);
1159 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1161 swf_SetU16(tag, id);
1162 swf_SetString(tag, name);
1165 if(dictionary_lookup(&fonts, name))
1166 syntaxerror("font %s defined twice", name);
1167 dictionary_put2(&fonts, name, font);
1172 typedef struct _sound_t
1178 void s_sound(char*name, char*filename)
1180 struct WAV wav, wav2;
1185 int blocksize = 1152;
1187 if(!readWAV(filename, &wav)) {
1188 warning("Couldn't read wav file \"%s\"", filename);
1192 convertWAV2mono(&wav, &wav2, 44100);
1193 samples = (U16*)wav2.data;
1194 numsamples = wav2.size/2;
1196 #ifdef WORDS_BIGENDIAN
1198 for(t=0;t<numsamples;t++) {
1199 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1204 if(numsamples%blocksize != 0)
1206 // apply padding, so that block is a multiple of blocksize
1207 int numblocks = (numsamples+blocksize-1)/blocksize;
1210 numsamples2 = numblocks * blocksize;
1211 samples2 = malloc(sizeof(U16)*numsamples2);
1212 memcpy(samples2, samples, numsamples*sizeof(U16));
1213 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1214 numsamples = numsamples2;
1218 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1219 swf_SetU16(tag, id); //id
1220 swf_SetSoundDefine(tag, samples, numsamples);
1222 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1226 if(dictionary_lookup(&sounds, name))
1227 syntaxerror("sound %s defined twice", name);
1228 dictionary_put2(&sounds, name, sound);
1236 static char* gradient_getToken(const char**p)
1240 while(**p && strchr(" \t\n\r", **p)) {
1244 while(**p && !strchr(" \t\n\r", **p)) {
1247 result = malloc((*p)-start+1);
1248 memcpy(result,start,(*p)-start+1);
1249 result[(*p)-start] = 0;
1253 float parsePercent(char*str);
1254 RGBA parseColor(char*str);
1256 GRADIENT parseGradient(const char*str)
1260 const char* p = str;
1261 memset(&gradient, 0, sizeof(GRADIENT));
1263 char*posstr,*colorstr;
1266 posstr = gradient_getToken(&p);
1269 pos = (int)(parsePercent(posstr)*255.0);
1272 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1273 colorstr = gradient_getToken(&p);
1274 color = parseColor(colorstr);
1275 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1276 warning("gradient record too big- max size is 8, rest ignored");
1279 gradient.ratios[gradient.num] = pos;
1280 gradient.rgba[gradient.num] = color;
1289 void s_gradient(char*name, const char*text, int radial, int rotate)
1291 gradient_t* gradient;
1292 gradient = malloc(sizeof(gradient_t));
1293 memset(gradient, 0, sizeof(gradient_t));
1294 gradient->gradient = parseGradient(text);
1295 gradient->radial = radial;
1296 gradient->rotate = rotate;
1298 if(dictionary_lookup(&gradients, name))
1299 syntaxerror("gradient %s defined twice", name);
1300 dictionary_put2(&gradients, name, gradient);
1303 void s_action(const char*text)
1306 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1308 syntaxerror("Couldn't compile ActionScript");
1311 tag = swf_InsertTag(tag, ST_DOACTION);
1313 swf_ActionSet(tag, a);
1318 void s_initaction(const char*character, const char*text)
1322 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1324 syntaxerror("Couldn't compile ActionScript");
1327 c = (character_t*)dictionary_lookup(&characters, character);
1329 tag = swf_InsertTag(tag, ST_DOINITACTION);
1330 swf_SetU16(tag, c->id);
1331 swf_ActionSet(tag, a);
1336 int s_swf3action(char*name, char*action)
1339 instance_t* object = 0;
1341 dictionary_lookup(&instances, name);
1342 if(!object && name && *name) {
1343 /* we have a name, but couldn't find it. Abort. */
1346 a = action_SetTarget(0, name);
1347 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1348 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1349 else if(!strcmp(action, "stop")) a = action_Stop(a);
1350 else if(!strcmp(action, "play")) a = action_Play(a);
1351 a = action_SetTarget(a, "");
1354 tag = swf_InsertTag(tag, ST_DOACTION);
1355 swf_ActionSet(tag, a);
1360 void s_outline(char*name, char*format, char*source)
1369 //swf_Shape10DrawerInit(&draw, 0);
1370 swf_Shape11DrawerInit(&draw, 0);
1372 draw_string(&draw, source);
1374 shape = swf_ShapeDrawerToShape(&draw);
1375 bounds = swf_ShapeDrawerGetBBox(&draw);
1376 draw.dealloc(&draw);
1378 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1379 outline->shape = shape;
1380 outline->bbox = bounds;
1382 if(dictionary_lookup(&outlines, name))
1383 syntaxerror("outline %s defined twice", name);
1384 dictionary_put2(&outlines, name, outline);
1387 int s_playsound(char*name, int loops, int nomultiple, int stop)
1393 sound = dictionary_lookup(&sounds, name);
1397 tag = swf_InsertTag(tag, ST_STARTSOUND);
1398 swf_SetU16(tag, sound->id); //id
1399 memset(&info, 0, sizeof(info));
1402 info.nomultiple = nomultiple;
1403 swf_SetSoundInfo(tag, &info);
1407 void s_includeswf(char*name, char*filename)
1415 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1416 f = open(filename,O_RDONLY|O_BINARY);
1418 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1419 s_box(name, 0, 0, black, 20, 0);
1422 if (swf_ReadSWF(f,&swf)<0) {
1423 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1424 s_box(name, 0, 0, black, 20, 0);
1429 /* FIXME: The following sets the bounding Box for the character.
1430 It is wrong for two reasons:
1431 a) It may be too small (in case objects in the movie clip at the borders)
1432 b) it may be too big (because the poor movie never got autocropped)
1436 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1437 swf_SetU16(tag, id);
1438 swf_SetU16(tag, swf.frameCount);
1440 swf_Relocate(&swf, idmap);
1442 ftag = swf.firstTag;
1446 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1447 if(cutout[t] == ftag->id) {
1451 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1453 if(ftag->id == ST_END)
1457 /* We simply dump all tags right after the sprite
1458 header, relying on the fact that swf_OptimizeTagOrder() will
1459 sort things out for us later.
1460 We also rely on the fact that the imported SWF is well-formed.
1462 tag = swf_InsertTag(tag, ftag->id);
1463 swf_SetBlock(tag, ftag->data, ftag->len);
1467 syntaxerror("Included file %s contains errors", filename);
1468 tag = swf_InsertTag(tag, ST_END);
1472 s_addcharacter(name, id, tag, r);
1475 SRECT s_getCharBBox(char*name)
1477 character_t* c = dictionary_lookup(&characters, name);
1478 if(!c) syntaxerror("character '%s' unknown(2)", name);
1481 SRECT s_getInstanceBBox(char*name)
1483 instance_t * i = dictionary_lookup(&instances, name);
1485 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1487 if(!c) syntaxerror("internal error(5)");
1490 parameters_t s_getParameters(char*name)
1492 instance_t * i = dictionary_lookup(&instances, name);
1493 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1494 return i->parameters;
1496 void s_startclip(char*instance, char*character, parameters_t p)
1498 character_t* c = dictionary_lookup(&characters, character);
1502 syntaxerror("character %s not known", character);
1504 i = s_addinstance(instance, c, currentdepth);
1506 m = s_instancepos(i->character->size, &p);
1508 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1509 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1510 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1512 i->lastFrame= currentframe;
1514 stack[stackpos].tag = tag;
1515 stack[stackpos].type = 2;
1524 swf_SetTagPos(stack[stackpos].tag, 0);
1525 swf_GetPlaceObject(stack[stackpos].tag, &p);
1526 p.clipdepth = currentdepth;
1528 swf_ClearTag(stack[stackpos].tag);
1529 swf_SetPlaceObject(stack[stackpos].tag, &p);
1533 void s_put(char*instance, char*character, parameters_t p)
1535 character_t* c = dictionary_lookup(&characters, character);
1539 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1542 i = s_addinstance(instance, c, currentdepth);
1544 m = s_instancepos(i->character->size, &p);
1546 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1547 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1549 i->lastFrame = currentframe;
1553 void s_jump(char*instance, parameters_t p)
1555 instance_t* i = dictionary_lookup(&instances, instance);
1558 syntaxerror("instance %s not known", instance);
1562 m = s_instancepos(i->character->size, &p);
1564 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1565 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1567 i->lastFrame = currentframe;
1570 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1574 if(num==0 || num==1)
1576 ratio = (float)pos/(float)num;
1578 p.x = (p2->x-p1->x)*ratio + p1->x;
1579 p.y = (p2->y-p1->y)*ratio + p1->y;
1580 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1581 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1582 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1583 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1585 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1586 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1587 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1588 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1590 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1591 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1592 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1593 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1595 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1596 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1597 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1598 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1602 void s_change(char*instance, parameters_t p2)
1604 instance_t* i = dictionary_lookup(&instances, instance);
1608 int frame, allframes;
1610 syntaxerror("instance %s not known", instance);
1614 allframes = currentframe - i->lastFrame - 1;
1616 warning(".change ignored. can only .put/.change an object once per frame.");
1620 m = s_instancepos(i->character->size, &p2);
1621 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1622 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1625 /* o.k., we got the start and end point set. Now iterate though all the
1626 tags in between, inserting object changes after each new frame */
1629 if(!t) syntaxerror("internal error(6)");
1631 while(frame < allframes) {
1632 if(t->id == ST_SHOWFRAME) {
1637 p = s_interpolate(&p1, &p2, frame, allframes);
1638 m = s_instancepos(i->character->size, &p); //needed?
1639 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1640 i->lastFrame = currentframe;
1641 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1643 if(frame == allframes)
1648 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1652 void s_delinstance(char*instance)
1654 instance_t* i = dictionary_lookup(&instances, instance);
1656 syntaxerror("instance %s not known", instance);
1658 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1659 swf_SetU16(tag, i->depth);
1660 dictionary_del(&instances, instance);
1663 void s_qchange(char*instance, parameters_t p)
1670 syntaxerror(".end unexpected");
1671 if(stack[stackpos-1].type == 0)
1673 else if(stack[stackpos-1].type == 1)
1675 else if(stack[stackpos-1].type == 2)
1677 else if(stack[stackpos-1].type == 3)
1679 else syntaxerror("internal error 1");
1682 // ------------------------------------------------------------------------
1684 typedef int command_func_t(map_t*args);
1686 SRECT parseBox(char*str)
1689 float xmin, xmax, ymin, ymax;
1690 char*x = strchr(str, 'x');
1692 if(!strcmp(str, "autocrop")) {
1693 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1697 d1 = strchr(x+1, ':');
1699 d2 = strchr(d1+1, ':');
1701 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1705 else if(d1 && !d2) {
1706 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1712 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1717 r.xmin = (SCOORD)(xmin*20);
1718 r.ymin = (SCOORD)(ymin*20);
1719 r.xmax = (SCOORD)(xmax*20);
1720 r.ymax = (SCOORD)(ymax*20);
1723 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1726 float parseFloat(char*str)
1730 int parseInt(char*str)
1735 if(str[0]=='+' || str[0]=='-')
1739 if(str[t]<'0' || str[t]>'9')
1740 syntaxerror("Not an Integer: \"%s\"", str);
1743 int parseTwip(char*str)
1747 if(str[0]=='+' || str[0]=='-') {
1752 dot = strchr(str, '.');
1756 return sign*parseInt(str)*20;
1758 int l=strlen(++dot);
1760 for(s=str;s<dot-1;s++)
1761 if(*s<'0' || *s>'9')
1762 syntaxerror("Not a coordinate: \"%s\"", str);
1764 if(*s<'0' || *s>'9')
1765 syntaxerror("Not a coordinate: \"%s\"", str);
1767 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1768 warning("precision loss: %s converted to twip: %s", str, dot);
1773 return sign*atoi(str)*20;
1775 return sign*atoi(str)*20+atoi(dot)*2;
1777 return sign*atoi(str)*20+atoi(dot)/5;
1782 int isPoint(char*str)
1784 if(strchr(str, '('))
1790 SPOINT parsePoint(char*str)
1794 int l = strlen(str);
1795 char*comma = strchr(str, ',');
1796 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1797 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1798 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1799 p.x = parseTwip(tmp);
1800 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1801 p.y = parseTwip(tmp);
1805 int parseColor2(char*str, RGBA*color)
1807 int l = strlen(str);
1811 struct {unsigned char r,g,b;char*name;} colors[] =
1812 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1813 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1814 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1815 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1816 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1817 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1818 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1819 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1820 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1821 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1822 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1823 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1827 if(str[0]=='#' && (l==7 || l==9)) {
1828 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1830 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1832 color->r = r; color->g = g; color->b = b; color->a = a;
1835 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1836 if(!strcmp(str, colors[t].name)) {
1841 color->r = r; color->g = g; color->b = b; color->a = a;
1847 RGBA parseColor(char*str)
1850 if(!parseColor2(str, &c))
1851 syntaxerror("Expression '%s' is not a color", str);
1855 typedef struct _muladd {
1860 MULADD parseMulAdd(char*str)
1863 char* str2 = (char*)malloc(strlen(str)+5);
1870 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1871 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1872 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1873 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1874 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1875 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1876 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1877 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1878 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1879 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1881 syntaxerror("'%s' is not a valid color transform expression", str);
1883 m.add = (int)(add*256);
1884 m.mul = (int)(mul*256);
1889 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1891 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1892 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1894 if(a<-32768) a=-32768;
1895 if(a>32767) a=32767;
1896 if(m<-32768) m=-32768;
1897 if(m>32767) m=32767;
1903 float parsePxOrPercent(char*fontname, char*str)
1905 int l = strlen(str);
1906 if(strchr(str, '%'))
1907 return parsePercent(str);
1908 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
1909 float p = atof(str);
1910 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
1912 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
1916 float parsePercent(char*str)
1918 int l = strlen(str);
1922 return atoi(str)/100.0;
1924 syntaxerror("Expression '%s' is not a percentage", str);
1927 int isPercent(char*str)
1929 return str[strlen(str)-1]=='%';
1931 int parseNewSize(char*str, int size)
1934 return parsePercent(str)*size;
1936 return (int)(atof(str)*20);
1939 int isColor(char*str)
1942 return parseColor2(str, &c);
1945 static char* lu(map_t* args, char*name)
1947 char* value = map_lookup(args, name);
1949 map_dump(args, stdout, "");
1950 syntaxerror("internal error 2: value %s should be set", name);
1955 static int c_flash(map_t*args)
1957 char* filename = map_lookup(args, "filename");
1958 char* compressstr = lu(args, "compress");
1959 SRECT bbox = parseBox(lu(args, "bbox"));
1960 int version = parseInt(lu(args, "version"));
1961 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1963 RGBA color = parseColor(lu(args, "background"));
1965 if(!filename || !*filename) {
1966 /* for compatibility */
1967 filename = map_lookup(args, "name");
1968 if(!filename || !*filename) {
1971 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1972 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1976 if(!filename || override_outputname)
1977 filename = outputname;
1979 if(!strcmp(compressstr, "default"))
1980 compress = version==6;
1981 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1983 else if(!strcmp(compressstr, "no"))
1985 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1987 s_swf(filename, bbox, version, fps, compress, color);
1990 int isRelative(char*str)
1992 return !strncmp(str, "<plus>", 6) ||
1993 !strncmp(str, "<minus>", 7);
1995 char* getOffset(char*str)
1997 if(!strncmp(str, "<plus>", 6))
1999 if(!strncmp(str, "<minus>", 7))
2001 syntaxerror("internal error (347)");
2004 int getSign(char*str)
2006 if(!strncmp(str, "<plus>", 6))
2008 if(!strncmp(str, "<minus>", 7))
2010 syntaxerror("internal error (348)");
2013 static dictionary_t points;
2014 static mem_t mpoints;
2015 int points_initialized = 0;
2017 SPOINT getPoint(SRECT r, char*name)
2020 if(!strcmp(name, "center")) {
2022 p.x = (r.xmin + r.xmax)/2;
2023 p.y = (r.ymin + r.ymax)/2;
2027 if(points_initialized)
2028 l = (int)dictionary_lookup(&points, name);
2030 syntaxerror("Invalid point: \"%s\".", name);
2033 return *(SPOINT*)&mpoints.buffer[l];
2036 static int texture2(char*name, char*object, map_t*args, int errors)
2039 char*xstr = map_lookup(args, "x");
2040 char*ystr = map_lookup(args, "y");
2041 char*widthstr = map_lookup(args, "width");
2042 char*heightstr = map_lookup(args, "height");
2043 char*scalestr = map_lookup(args, "scale");
2044 char*scalexstr = map_lookup(args, "scalex");
2045 char*scaleystr = map_lookup(args, "scaley");
2046 char*rotatestr = map_lookup(args, "rotate");
2047 char* shearstr = map_lookup(args, "shear");
2048 char* radiusstr = map_lookup(args, "r");
2050 float scalex = 1.0, scaley = 1.0;
2051 float rotate=0, shear=0;
2053 if(!*xstr && !*ystr) {
2055 syntaxerror("x and y must be set");
2058 if(*scalestr && (*scalexstr || *scaleystr)) {
2059 syntaxerror("scale and scalex/scaley can't both be set");
2062 if((*widthstr || *heightstr) && *radiusstr) {
2063 syntaxerror("width/height and radius can't both be set");
2066 widthstr = radiusstr;
2067 heightstr = radiusstr;
2069 if(!*xstr) xstr="0";
2070 if(!*ystr) ystr="0";
2071 if(!*rotatestr) rotatestr="0";
2072 if(!*shearstr) shearstr="0";
2075 scalex = scaley = parsePercent(scalestr);
2076 } else if(*scalexstr || *scaleystr) {
2077 if(scalexstr) scalex = parsePercent(scalexstr);
2078 if(scaleystr) scaley = parsePercent(scaleystr);
2079 } else if(*widthstr || *heightstr) {
2082 s_getBitmapSize(object, &width, &height);
2084 scalex = (float)parseTwip(widthstr)/(float)width;
2086 scaley = (float)parseTwip(heightstr)/(float)height;
2088 x = parseTwip(xstr);
2089 y = parseTwip(ystr);
2090 rotate = parseFloat(rotatestr);
2091 shear = parseFloat(shearstr);
2093 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2098 static int c_texture(map_t*args)
2100 char*name = lu(args, "instance");
2101 char*object = lu(args, "character");
2102 return texture2(name, object, args, 1);
2105 static int c_gradient(map_t*args)
2107 char*name = lu(args, "name");
2108 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2109 int rotate = parseInt(lu(args, "rotate"));
2113 syntaxerror("colon (:) expected");
2115 s_gradient(name, text, radial, rotate);
2117 /* check whether we also have placement information,
2118 which would make this a positioned gradient.
2119 If there is placement information, texture2() will
2120 add a texture, which has priority over the gradient.
2122 texture2(name, name, args, 0);
2125 static int c_point(map_t*args)
2127 char*name = lu(args, "name");
2131 if(!points_initialized) {
2132 dictionary_init(&points);
2134 points_initialized = 1;
2136 p.x = parseTwip(lu(args, "x"));
2137 p.y = parseTwip(lu(args, "y"));
2138 pos = mem_put(&mpoints, &p, sizeof(p));
2139 string_set(&s1, name);
2141 dictionary_put(&points, s1, (void*)pos);
2144 static int c_play(map_t*args)
2146 char*name = lu(args, "name");
2147 char*loop = lu(args, "loop");
2148 char*nomultiple = lu(args, "nomultiple");
2150 if(!strcmp(nomultiple, "nomultiple"))
2153 nm = parseInt(nomultiple);
2155 if(s_playsound(name, parseInt(loop), nm, 0)) {
2157 } else if(s_swf3action(name, "play")) {
2163 static int c_stop(map_t*args)
2165 char*name = map_lookup(args, "name");
2167 if(s_playsound(name, 0,0,1)) {
2169 } else if(s_swf3action(name, "stop")) {
2172 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2176 static int c_nextframe(map_t*args)
2178 char*name = lu(args, "name");
2180 if(s_swf3action(name, "nextframe")) {
2183 syntaxerror("I don't know anything about movie \"%s\"", name);
2187 static int c_previousframe(map_t*args)
2189 char*name = lu(args, "name");
2191 if(s_swf3action(name, "previousframe")) {
2194 syntaxerror("I don't know anything about movie \"%s\"", name);
2198 static int c_placement(map_t*args, int type)
2200 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2203 char* luminancestr = lu(args, "luminance");
2204 char* scalestr = lu(args, "scale");
2205 char* scalexstr = lu(args, "scalex");
2206 char* scaleystr = lu(args, "scaley");
2207 char* rotatestr = lu(args, "rotate");
2208 char* shearstr = lu(args, "shear");
2209 char* xstr="", *pivotstr="";
2210 char* ystr="", *anglestr="";
2211 char*above = lu(args, "above"); /*FIXME*/
2212 char*below = lu(args, "below");
2213 char* rstr = lu(args, "red");
2214 char* gstr = lu(args, "green");
2215 char* bstr = lu(args, "blue");
2216 char* astr = lu(args, "alpha");
2217 char* pinstr = lu(args, "pin");
2218 char* as = map_lookup(args, "as");
2226 if(type==9) { // (?) .rotate or .arcchange
2227 pivotstr = lu(args, "pivot");
2228 anglestr = lu(args, "angle");
2230 xstr = lu(args, "x");
2231 ystr = lu(args, "y");
2234 luminance = parseMulAdd(luminancestr);
2237 luminance.mul = 256;
2241 if(scalexstr[0]||scaleystr[0])
2242 syntaxerror("scalex/scaley and scale cannot both be set");
2243 scalexstr = scaleystr = scalestr;
2246 if(type == 0 || type == 4) {
2248 character = lu(args, "character");
2249 parameters_clear(&p);
2250 } else if (type == 5) {
2251 character = lu(args, "name");
2252 parameters_clear(&p);
2255 p = s_getParameters(instance);
2260 if(isRelative(xstr)) {
2261 if(type == 0 || type == 4)
2262 syntaxerror("relative x values not allowed for initial put or startclip");
2263 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2265 p.x = parseTwip(xstr);
2269 if(isRelative(ystr)) {
2270 if(type == 0 || type == 4)
2271 syntaxerror("relative y values not allowed for initial put or startclip");
2272 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2274 p.y = parseTwip(ystr);
2278 /* scale, scalex, scaley */
2280 oldbbox = s_getCharBBox(character);
2282 oldbbox = s_getInstanceBBox(instance);
2284 oldwidth = oldbbox.xmax - oldbbox.xmin;
2285 oldheight = oldbbox.ymax - oldbbox.ymin;
2287 if(oldwidth==0) p.scalex = 1.0;
2290 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2294 if(oldheight==0) p.scaley = 1.0;
2297 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2303 if(isRelative(rotatestr)) {
2304 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2306 p.rotate = parseFloat(rotatestr);
2312 if(isRelative(shearstr)) {
2313 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2315 p.shear = parseFloat(shearstr);
2320 if(isPoint(pivotstr))
2321 p.pivot = parsePoint(pivotstr);
2323 p.pivot = getPoint(oldbbox, pivotstr);
2327 p.pin = parsePoint(pinstr);
2329 p.pin = getPoint(oldbbox, pinstr);
2332 /* color transform */
2334 if(rstr[0] || luminancestr[0]) {
2337 r = parseMulAdd(rstr);
2339 r.add = p.cxform.r0;
2340 r.mul = p.cxform.r1;
2342 r = mergeMulAdd(r, luminance);
2343 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2345 if(gstr[0] || luminancestr[0]) {
2348 g = parseMulAdd(gstr);
2350 g.add = p.cxform.g0;
2351 g.mul = p.cxform.g1;
2353 g = mergeMulAdd(g, luminance);
2354 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2356 if(bstr[0] || luminancestr[0]) {
2359 b = parseMulAdd(bstr);
2361 b.add = p.cxform.b0;
2362 b.mul = p.cxform.b1;
2364 b = mergeMulAdd(b, luminance);
2365 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2368 MULADD a = parseMulAdd(astr);
2369 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2373 s_put(instance, character, p);
2375 s_change(instance, p);
2377 s_qchange(instance, p);
2379 s_jump(instance, p);
2381 s_startclip(instance, character, p);
2382 else if(type == 5) {
2384 s_buttonput(character, as, p);
2386 s_buttonput(character, "shape", p);
2391 static int c_put(map_t*args)
2393 c_placement(args, 0);
2396 static int c_change(map_t*args)
2398 c_placement(args, 1);
2401 static int c_qchange(map_t*args)
2403 c_placement(args, 2);
2406 static int c_arcchange(map_t*args)
2408 c_placement(args, 2);
2411 static int c_jump(map_t*args)
2413 c_placement(args, 3);
2416 static int c_startclip(map_t*args)
2418 c_placement(args, 4);
2421 static int c_show(map_t*args)
2423 c_placement(args, 5);
2426 static int c_del(map_t*args)
2428 char*instance = lu(args, "name");
2429 s_delinstance(instance);
2432 static int c_end(map_t*args)
2437 static int c_sprite(map_t*args)
2439 char* name = lu(args, "name");
2443 static int c_frame(map_t*args)
2445 char*framestr = lu(args, "n");
2446 char*cutstr = lu(args, "cut");
2447 char*name = lu(args, "name");
2450 if(strcmp(cutstr, "no"))
2452 if(isRelative(framestr)) {
2453 frame = s_getframe();
2454 if(getSign(framestr)<0)
2455 syntaxerror("relative frame expressions must be positive");
2456 frame += parseInt(getOffset(framestr));
2459 frame = parseInt(framestr);
2460 if(s_getframe() >= frame
2461 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2462 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2464 s_frame(frame, cut, name);
2467 static int c_primitive(map_t*args)
2469 char*name = lu(args, "name");
2470 char*command = lu(args, "commandname");
2471 int width=0, height=0, r=0;
2472 int linewidth = parseTwip(lu(args, "line"));
2473 char*colorstr = lu(args, "color");
2474 RGBA color = parseColor(colorstr);
2475 char*fillstr = lu(args, "fill");
2482 if(!strcmp(command, "circle"))
2484 else if(!strcmp(command, "filled"))
2488 width = parseTwip(lu(args, "width"));
2489 height = parseTwip(lu(args, "height"));
2490 } else if (type==1) {
2491 r = parseTwip(lu(args, "r"));
2492 } else if (type==2) {
2493 outline = lu(args, "outline");
2496 if(!strcmp(fillstr, "fill"))
2498 if(!strcmp(fillstr, "none"))
2500 if(width<0 || height<0 || linewidth<0 || r<0)
2501 syntaxerror("values width, height, line, r must be positive");
2503 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2504 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2505 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2509 static int c_textshape(map_t*args)
2511 char*name = lu(args, "name");
2512 char*text = lu(args, "text");
2513 char*font = lu(args, "font");
2514 float size = parsePxOrPercent(font, lu(args, "size"));
2516 s_textshape(name, font, size, text);
2520 static int c_swf(map_t*args)
2522 char*name = lu(args, "name");
2523 char*filename = lu(args, "filename");
2524 char*command = lu(args, "commandname");
2525 if(!strcmp(command, "shape"))
2526 warning("Please use .swf instead of .shape");
2527 s_includeswf(name, filename);
2531 static int c_font(map_t*args)
2533 char*name = lu(args, "name");
2534 char*filename = lu(args, "filename");
2535 s_font(name, filename);
2539 static int c_sound(map_t*args)
2541 char*name = lu(args, "name");
2542 char*filename = lu(args, "filename");
2543 s_sound(name, filename);
2547 static int c_text(map_t*args)
2549 char*name = lu(args, "name");
2550 char*text = lu(args, "text");
2551 char*font = lu(args, "font");
2552 float size = parsePxOrPercent(font, lu(args, "size"));
2553 RGBA color = parseColor(lu(args, "color"));
2554 s_text(name, font, text, (int)(size*100), color);
2558 static int c_soundtrack(map_t*args)
2563 static int c_quicktime(map_t*args)
2565 char*name = lu(args, "name");
2566 char*url = lu(args, "url");
2567 s_quicktime(name, url);
2571 static int c_image(map_t*args)
2573 char*command = lu(args, "commandname");
2574 char*name = lu(args, "name");
2575 char*filename = lu(args, "filename");
2576 if(!strcmp(command,"jpeg")) {
2577 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2578 s_image(name, "jpeg", filename, quality);
2580 s_image(name, "png", filename, 0);
2585 static int c_outline(map_t*args)
2587 char*name = lu(args, "name");
2588 char*format = lu(args, "format");
2592 syntaxerror("colon (:) expected");
2594 s_outline(name, format, text);
2598 int fakechar(map_t*args)
2600 char*name = lu(args, "name");
2601 s_box(name, 0, 0, black, 20, 0);
2605 static int c_egon(map_t*args) {return fakechar(args);}
2606 static int c_button(map_t*args) {
2607 char*name = lu(args, "name");
2611 static int current_button_flags = 0;
2612 static int c_on_press(map_t*args)
2614 char*position = lu(args, "position");
2616 if(!strcmp(position, "inside")) {
2617 current_button_flags |= BC_OVERUP_OVERDOWN;
2618 } else if(!strcmp(position, "outside")) {
2619 //current_button_flags |= BC_IDLE_OUTDOWN;
2620 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2621 } else if(!strcmp(position, "anywhere")) {
2622 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2625 if(type == RAWDATA) {
2627 s_buttonaction(current_button_flags, action);
2628 current_button_flags = 0;
2634 static int c_on_release(map_t*args)
2636 char*position = lu(args, "position");
2638 if(!strcmp(position, "inside")) {
2639 current_button_flags |= BC_OVERDOWN_OVERUP;
2640 } else if(!strcmp(position, "outside")) {
2641 current_button_flags |= BC_OUTDOWN_IDLE;
2642 } else if(!strcmp(position, "anywhere")) {
2643 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2646 if(type == RAWDATA) {
2648 s_buttonaction(current_button_flags, action);
2649 current_button_flags = 0;
2655 static int c_on_move_in(map_t*args)
2657 char*position = lu(args, "state");
2659 if(!strcmp(position, "pressed")) {
2660 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2661 } else if(!strcmp(position, "not_pressed")) {
2662 current_button_flags |= BC_IDLE_OVERUP;
2663 } else if(!strcmp(position, "any")) {
2664 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2667 if(type == RAWDATA) {
2669 s_buttonaction(current_button_flags, action);
2670 current_button_flags = 0;
2676 static int c_on_move_out(map_t*args)
2678 char*position = lu(args, "state");
2680 if(!strcmp(position, "pressed")) {
2681 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2682 } else if(!strcmp(position, "not_pressed")) {
2683 current_button_flags |= BC_OVERUP_IDLE;
2684 } else if(!strcmp(position, "any")) {
2685 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2688 if(type == RAWDATA) {
2690 s_buttonaction(current_button_flags, action);
2691 current_button_flags = 0;
2697 static int c_on_key(map_t*args)
2699 char*key = lu(args, "key");
2701 if(strlen(key)==1) {
2704 current_button_flags |= 0x4000 + (key[0]*0x200);
2706 syntaxerror("invalid character: %c"+key[0]);
2711 <ctrl-x> = 0x200*(x-'a')
2715 syntaxerror("invalid key: %s",key);
2718 if(type == RAWDATA) {
2720 s_buttonaction(current_button_flags, action);
2721 current_button_flags = 0;
2728 static int c_edittext(map_t*args)
2730 //"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"},
2731 char*name = lu(args, "name");
2732 char*font = lu(args, "font");
2733 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
2734 int width = parseTwip(lu(args, "width"));
2735 int height = parseTwip(lu(args, "height"));
2736 char*text = lu(args, "text");
2737 RGBA color = parseColor(lu(args, "color"));
2738 int maxlength = parseInt(lu(args, "maxlength"));
2739 char*variable = lu(args, "variable");
2740 char*passwordstr = lu(args, "password");
2741 char*wordwrapstr = lu(args, "wordwrap");
2742 char*multilinestr = lu(args, "multiline");
2743 char*htmlstr = lu(args, "html");
2744 char*noselectstr = lu(args, "noselect");
2745 char*readonlystr = lu(args, "readonly");
2746 char*borderstr = lu(args, "border");
2747 char*autosizestr = lu(args, "autosize");
2748 char*alignstr = lu(args, "align");
2752 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2753 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2754 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2755 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2756 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2757 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2758 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2759 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
2760 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
2761 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
2762 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
2763 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
2764 else syntaxerror("Unknown alignment: %s", alignstr);
2766 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
2770 static int c_morphshape(map_t*args) {return fakechar(args);}
2771 static int c_movie(map_t*args) {return fakechar(args);}
2773 static char* readfile(const char*filename)
2775 FILE*fi = fopen(filename, "rb");
2779 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
2780 fseek(fi, 0, SEEK_END);
2782 fseek(fi, 0, SEEK_SET);
2783 text = rfx_alloc(l+1);
2784 fread(text, l, 1, fi);
2790 static int c_action(map_t*args)
2792 char* filename = map_lookup(args, "filename");
2793 if(!filename ||!*filename) {
2795 if(type != RAWDATA) {
2796 syntaxerror("colon (:) expected");
2800 s_action(readfile(filename));
2806 static int c_initaction(map_t*args)
2808 char* character = lu(args, "name");
2809 char* filename = map_lookup(args, "filename");
2810 if(!filename ||!*filename) {
2812 if(type != RAWDATA) {
2813 syntaxerror("colon (:) expected");
2815 s_initaction(character, text);
2817 s_initaction(character, readfile(filename));
2825 command_func_t* func;
2828 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
2829 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2830 // "import" type stuff
2831 {"swf", c_swf, "name filename"},
2832 {"shape", c_swf, "name filename"},
2833 {"jpeg", c_image, "name filename quality=80%"},
2834 {"png", c_image, "name filename"},
2835 {"movie", c_movie, "name filename"},
2836 {"sound", c_sound, "name filename"},
2837 {"font", c_font, "name filename"},
2838 {"soundtrack", c_soundtrack, "filename"},
2839 {"quicktime", c_quicktime, "url"},
2841 // generators of primitives
2843 {"point", c_point, "name x=0 y=0"},
2844 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
2845 {"outline", c_outline, "name format=simple"},
2846 {"textshape", c_textshape, "name font size=100% text"},
2848 // character generators
2849 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2850 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2851 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2853 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2854 {"text", c_text, "name text font size=100% color=white"},
2855 {"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="},
2856 {"morphshape", c_morphshape, "name start end"},
2857 {"button", c_button, "name"},
2858 {"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="},
2859 {"on_press", c_on_press, "position=inside"},
2860 {"on_release", c_on_release, "position=anywhere"},
2861 {"on_move_in", c_on_move_in, "state=not_pressed"},
2862 {"on_move_out", c_on_move_out, "state=not_pressed"},
2863 {"on_key", c_on_key, "key=any"},
2866 {"play", c_play, "name loop=0 @nomultiple=0"},
2867 {"stop", c_stop, "name= "},
2868 {"nextframe", c_nextframe, "name"},
2869 {"previousframe", c_previousframe, "name"},
2871 // object placement tags
2872 {"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="},
2873 {"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="},
2874 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2875 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2876 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2877 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2878 {"del", c_del, "name"},
2879 // virtual object placement
2880 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
2882 // commands which start a block
2883 //startclip (see above)
2884 {"sprite", c_sprite, "name"},
2885 {"action", c_action, "filename="},
2886 {"initaction", c_initaction, "name filename="},
2892 static map_t parseArguments(char*command, char*pattern)
2908 string_set(&t1, "commandname");
2909 string_set(&t2, command);
2910 map_put(&result, t1, t2);
2912 if(!pattern || !*pattern)
2919 if(!strncmp("<i> ", x, 3)) {
2921 if(type == COMMAND || type == RAWDATA) {
2923 syntaxerror("character name expected");
2925 name[pos].str = "instance";
2927 value[pos].str = text;
2928 value[pos].len = strlen(text);
2932 if(type == ASSIGNMENT)
2935 name[pos].str = "character";
2937 value[pos].str = text;
2938 value[pos].len = strlen(text);
2946 isboolean[pos] = (x[0] =='@');
2959 name[pos].len = d-x;
2964 name[pos].len = e-x;
2965 value[pos].str = e+1;
2966 value[pos].len = d-e-1;
2974 /* for(t=0;t<len;t++) {
2975 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2976 isboolean[t]?"(boolean)":"");
2981 if(type == RAWDATA || type == COMMAND) {
2986 // first, search for boolean arguments
2987 for(pos=0;pos<len;pos++)
2989 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2991 if(type == ASSIGNMENT)
2993 value[pos].str = text;
2994 value[pos].len = strlen(text);
2995 /*printf("setting boolean parameter %s (to %s)\n",
2996 strdup_n(name[pos], namelen[pos]),
2997 strdup_n(value[pos], valuelen[pos]));*/
3002 // second, search for normal arguments
3004 for(pos=0;pos<len;pos++)
3006 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3007 (type != ASSIGNMENT && !set[pos])) {
3009 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3011 if(type == ASSIGNMENT)
3014 value[pos].str = text;
3015 value[pos].len = strlen(text);
3017 printf("setting parameter %s (to %s)\n",
3018 strdup_n(name[pos].str, name[pos].len),
3019 strdup_n(value[pos].str, value[pos].len));
3025 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3029 for(t=0;t<len;t++) {
3030 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3033 for(t=0;t<len;t++) {
3034 if(value[t].str && value[t].str[0] == '*') {
3035 //relative default- take value from some other parameter
3037 for(s=0;s<len;s++) {
3038 if(value[s].len == value[t].len-1 &&
3039 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3040 value[t].str = value[s].str;
3043 if(value[t].str == 0) {
3045 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3049 /* ok, now construct the dictionary from the parameters */
3053 map_put(&result, name[t], value[t]);
3057 static void parseArgumentsForCommand(char*command)
3062 msg("<verbose> parse Command: %s (line %d)", command, line);
3064 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3065 if(!strcmp(arguments[t].command, command)) {
3067 /* ugly hack- will be removed soon (once documentation and .sc generating
3068 utilities have been changed) */
3069 if(!strcmp(command, "swf") && !stackpos) {
3070 warning("Please use .flash instead of .swf- this will be mandatory soon");
3075 args = parseArguments(command, arguments[t].arguments);
3081 syntaxerror("command %s not known", command);
3083 // catch missing .flash directives at the beginning of a file
3084 if(strcmp(command, "flash") && !stackpos)
3086 syntaxerror("No movie defined- use .flash first");
3090 printf(".%s\n", command);fflush(stdout);
3091 map_dump(&args, stdout, "\t");fflush(stdout);
3094 (*arguments[nr].func)(&args);
3096 /*if(!strcmp(command, "button") ||
3097 !strcmp(command, "action")) {
3100 if(type == COMMAND) {
3101 if(!strcmp(text, "end"))
3115 int main (int argc,char ** argv)
3118 processargs(argc, argv);
3119 initLog(0,-1,0,0,-1,verbose);
3122 args_callback_usage(argv[0]);
3126 file = generateTokens(filename);
3128 printf("parser returned error.\n");
3134 while(!noMoreTokens()) {
3137 syntaxerror("command expected");
3138 parseArgumentsForCommand(text);