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"
35 #include "../lib/mp3.h"
36 #include "../lib/wav.h"
38 #include "../lib/png.h"
42 static char * filename = 0;
43 static char * outputname = "output.swf";
44 static int verbose = 2;
45 static int optimize = 0;
46 static int override_outputname = 0;
47 static int do_cgi = 0;
49 static struct options_t options[] = {
58 int args_callback_option(char*name,char*val)
60 if(!strcmp(name, "V")) {
61 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
64 else if(!strcmp(name, "o")) {
66 override_outputname = 1;
69 else if(!strcmp(name, "O")) {
73 else if(!strcmp(name, "C")) {
77 else if(!strcmp(name, "v")) {
82 printf("Unknown option: -%s\n", name);
87 int args_callback_longoption(char*name,char*val)
89 return args_long2shortoption(options, name, val);
91 void args_callback_usage(char *name)
94 printf("Usage: %s [-o file.swf] file.sc\n", name);
96 printf("-h , --help Print short help message and exit\n");
97 printf("-V , --version Print version info and exit\n");
98 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
99 printf("-v , --verbose Increase verbosity. \n");
100 printf("-o , --output <filename> Set output file to <filename>.\n");
103 int args_callback_command(char*name,char*val)
106 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
113 static struct token_t* file;
122 static void syntaxerror(char*format, ...)
126 va_start(arglist, format);
127 vsprintf(buf, format, arglist);
129 fprintf(stderr, "\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
133 static void warning(char*format, ...)
137 va_start(arglist, format);
138 vsprintf(buf, format, arglist);
140 fprintf(stderr, "\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
143 static void readToken()
145 type = file[pos].type;
147 syntaxerror("unexpected end of file");
149 text = file[pos].text;
150 textlen = strlen(text);
151 line = file[pos].line;
152 column = file[pos].column;
154 //printf("---> %d(%s) %s\n", type, type_names[type], text);
157 static void pushBack()
160 if(!pos) syntaxerror("internal error 3");
165 textlen = strlen(text);
168 column = file[p].column;
171 static int noMoreTokens()
173 if(file[pos].type == END)
178 // ------------------------------ swf routines ----------------------------
182 int type; //0=swf, 1=sprite, 2=clip, 3=button
188 /* for sprites (1): */
194 dictionary_t oldinstances;
199 static int stackpos = 0;
201 static dictionary_t characters;
202 static dictionary_t images;
203 static dictionary_t textures;
204 static dictionary_t outlines;
205 static dictionary_t gradients;
206 static char idmap[65536];
207 static TAG*tag = 0; //current tag
209 static int id; //current character id
210 static int currentframe; //current frame in current level
211 static SRECT currentrect; //current bounding box in current level
212 static U16 currentdepth;
213 static dictionary_t instances;
214 static dictionary_t fonts;
215 static dictionary_t sounds;
217 typedef struct _parameters {
219 float scalex, scaley;
227 typedef struct _character {
233 typedef struct _instance {
234 character_t*character;
236 parameters_t parameters;
237 TAG* lastTag; //last tag which set the object
238 U16 lastFrame; //frame lastTag is in
241 typedef struct _outline {
246 typedef struct _gradient {
252 typedef struct _texture {
256 static void character_init(character_t*c)
258 memset(c, 0, sizeof(character_t));
260 static character_t* character_new()
263 c = (character_t*)malloc(sizeof(character_t));
267 static void instance_init(instance_t*i)
269 memset(i, 0, sizeof(instance_t));
271 static instance_t* instance_new()
274 c = (instance_t*)malloc(sizeof(instance_t));
279 static void incrementid()
283 syntaxerror("Out of character ids.");
288 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
290 character_t* c = character_new();
292 c->definingTag = ctag;
295 if(dictionary_lookup(&characters, name))
296 syntaxerror("character %s defined twice", name);
297 dictionary_put2(&characters, name, c);
299 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
301 swf_SetString(tag, name);
302 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
305 swf_SetString(tag, name);
307 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
309 character_t* c = character_new();
310 c->definingTag = ctag;
314 if(dictionary_lookup(&images, name))
315 syntaxerror("image %s defined twice", name);
316 dictionary_put2(&images, name, c);
318 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
320 instance_t* i = instance_new();
323 //swf_GetMatrix(0, &i->matrix);
324 if(dictionary_lookup(&instances, name))
325 syntaxerror("object %s defined twice", name);
326 dictionary_put2(&instances, name, i);
330 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)
333 p->scalex = scalex; p->scaley = scaley;
334 p->pin = pin; p->pivot = pivot;
335 p->rotate = rotate; p->cxform = cxform;
339 static void parameters_clear(parameters_t*p)
342 p->scalex = 1.0; p->scaley = 1.0;
345 p->pivot.x = 0; p->pivot.y = 0;
348 swf_GetCXForm(0, &p->cxform, 1);
351 static void makeMatrix(MATRIX*m, parameters_t*p)
360 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
361 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
362 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
363 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
365 m->sx = (int)(sx*65536+0.5);
366 m->r1 = (int)(r1*65536+0.5);
367 m->r0 = (int)(r0*65536+0.5);
368 m->sy = (int)(sy*65536+0.5);
372 h = swf_TurnPoint(p->pin, m);
377 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
382 r = swf_TurnRect(rect, &m);
383 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
384 currentrect.xmax == 0 && currentrect.ymax == 0)
387 swf_ExpandRect2(¤trect, &r);
391 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
393 SWF*swf = (SWF*)malloc(sizeof(SWF));
396 syntaxerror(".swf blocks can't be nested");
398 memset(swf, 0, sizeof(swf));
399 swf->fileVersion = version;
401 swf->frameRate = fps;
402 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
403 swf->compressed = compress;
404 swf_SetRGB(tag,&background);
406 if(stackpos==sizeof(stack)/sizeof(stack[0]))
407 syntaxerror("too many levels of recursion");
409 dictionary_init(&characters);
410 dictionary_init(&images);
411 dictionary_init(&textures);
412 dictionary_init(&outlines);
413 dictionary_init(&gradients);
414 dictionary_init(&instances);
415 dictionary_init(&fonts);
416 dictionary_init(&sounds);
418 memset(&stack[stackpos], 0, sizeof(stack[0]));
419 stack[stackpos].type = 0;
420 stack[stackpos].filename = strdup(name);
421 stack[stackpos].swf = swf;
422 stack[stackpos].oldframe = -1;
427 memset(¤trect, 0, sizeof(currentrect));
430 memset(idmap, 0, sizeof(idmap));
434 void s_sprite(char*name)
436 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
437 swf_SetU16(tag, id); //id
438 swf_SetU16(tag, 0); //frames
440 memset(&stack[stackpos], 0, sizeof(stack[0]));
441 stack[stackpos].type = 1;
442 stack[stackpos].oldframe = currentframe;
443 stack[stackpos].olddepth = currentdepth;
444 stack[stackpos].oldrect = currentrect;
445 stack[stackpos].oldinstances = instances;
446 stack[stackpos].tag = tag;
447 stack[stackpos].id = id;
448 stack[stackpos].name = strdup(name);
450 /* FIXME: those four fields should be bundled together */
451 dictionary_init(&instances);
454 memset(¤trect, 0, sizeof(currentrect));
460 typedef struct _buttonrecord
468 typedef struct _button
472 buttonrecord_t records[4];
475 static button_t mybutton;
477 void s_button(char*name)
479 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
480 swf_SetU16(tag, id); //id
481 swf_ButtonSetFlags(tag, 0); //menu=no
483 memset(&mybutton, 0, sizeof(mybutton));
485 memset(&stack[stackpos], 0, sizeof(stack[0]));
486 stack[stackpos].type = 3;
487 stack[stackpos].tag = tag;
488 stack[stackpos].id = id;
489 stack[stackpos].name = strdup(name);
490 stack[stackpos].oldrect = currentrect;
491 memset(¤trect, 0, sizeof(currentrect));
496 void s_buttonput(char*character, char*as, parameters_t p)
498 character_t* c = dictionary_lookup(&characters, character);
503 if(!stackpos || (stack[stackpos-1].type != 3)) {
504 syntaxerror(".show may only appear in .button");
507 syntaxerror("character %s not known (in .shape %s)", character, character);
509 if(mybutton.endofshapes) {
510 syntaxerror("a .do may not precede a .show", character, character);
513 m = s_instancepos(c->size, &p);
521 if(*s==',' || *s==0) {
522 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
523 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
524 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
525 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
526 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
527 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
534 static void setbuttonrecords(TAG*tag)
536 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
537 if(!mybutton.endofshapes) {
540 if(!mybutton.records[3].set) {
541 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
545 if(mybutton.records[t].set) {
546 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
549 swf_SetU8(tag,0); // end of button records
550 mybutton.endofshapes = 1;
554 void s_buttonaction(int flags, char*action)
560 setbuttonrecords(stack[stackpos-1].tag);
562 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
564 syntaxerror("Couldn't compile ActionScript");
567 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
568 swf_ActionSet(stack[stackpos-1].tag, a);
569 mybutton.nr_actions++;
574 static void setactionend(TAG*tag)
576 if(!mybutton.nr_actions) {
577 /* no actions means we didn't have an actionoffset,
578 which means we can't signal the end of the
579 buttonaction records, so, *sigh*, we have
580 to insert a dummy record */
581 swf_SetU16(tag, 0); //offset
582 swf_SetU16(tag, 0); //condition
583 swf_SetU8(tag, 0); //action
587 static void s_endButton()
590 setbuttonrecords(stack[stackpos-1].tag);
591 setactionend(stack[stackpos-1].tag);
594 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
598 tag = stack[stackpos].tag;
599 currentrect = stack[stackpos].oldrect;
601 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
602 free(stack[stackpos].name);
605 TAG* removeFromTo(TAG*from, TAG*to)
607 TAG*save = from->prev;
609 TAG*next = from->next;
617 static void s_endSprite()
619 SRECT r = currentrect;
621 if(stack[stackpos].cut)
622 tag = removeFromTo(stack[stackpos].cut, tag);
626 /* TODO: before clearing, prepend "<spritename>." to names and
627 copy into old instances dict */
628 dictionary_clear(&instances);
630 currentframe = stack[stackpos].oldframe;
631 currentrect = stack[stackpos].oldrect;
632 currentdepth = stack[stackpos].olddepth;
633 instances = stack[stackpos].oldinstances;
635 tag = swf_InsertTag(tag, ST_SHOWFRAME);
636 tag = swf_InsertTag(tag, ST_END);
638 tag = stack[stackpos].tag;
641 syntaxerror("internal error(7)");
643 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
644 free(stack[stackpos].name);
647 static void s_endSWF()
653 if(stack[stackpos].cut)
654 tag = removeFromTo(stack[stackpos].cut, tag);
658 swf = stack[stackpos].swf;
659 filename = stack[stackpos].filename;
661 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
662 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
663 tag = swf_InsertTag(tag, ST_SHOWFRAME);
665 tag = swf_InsertTag(tag, ST_END);
667 swf_OptimizeTagOrder(swf);
673 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
674 swf->movieSize = currentrect; /* "autocrop" */
677 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
678 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
679 swf->movieSize.ymax += 20;
680 warning("Empty bounding box for movie");
686 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
688 syntaxerror("couldn't create output file %s", filename);
691 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
692 else if(swf->compressed)
693 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
695 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
699 dictionary_clear(&instances);
700 dictionary_clear(&characters);
701 dictionary_clear(&images);
702 dictionary_clear(&textures);
703 dictionary_clear(&outlines);
704 dictionary_clear(&gradients);
705 dictionary_clear(&fonts);
706 dictionary_clear(&sounds);
716 if(stack[stackpos-1].type == 0)
717 syntaxerror("End of file encountered in .flash block");
718 if(stack[stackpos-1].type == 1)
719 syntaxerror("End of file encountered in .sprite block");
720 if(stack[stackpos-1].type == 2)
721 syntaxerror("End of file encountered in .clip block");
727 return currentframe+1;
730 void s_frame(int nr, int cut, char*name, char anchor)
736 syntaxerror("Illegal frame number");
737 nr--; // internally, frame 1 is frame 0
739 for(t=currentframe;t<nr;t++) {
740 tag = swf_InsertTag(tag, ST_SHOWFRAME);
741 if(t==nr-1 && name && *name) {
742 tag = swf_InsertTag(tag, ST_FRAMELABEL);
743 swf_SetString(tag, name);
745 swf_SetU8(tag, 1); //make this an anchor
748 if(nr == 0 && currentframe == 0 && name && *name) {
749 tag = swf_InsertTag(tag, ST_FRAMELABEL);
750 swf_SetString(tag, name);
752 swf_SetU8(tag, 1); //make this an anchor
757 syntaxerror("Can't cut, frame empty");
759 stack[stackpos].cut = tag;
765 int parseColor2(char*str, RGBA*color);
767 int addFillStyle(SHAPE*s, SRECT*r, char*name)
774 parseColor2(name, &color);
775 return swf_ShapeAddSolidFillStyle(s, &color);
776 } else if ((texture = dictionary_lookup(&textures, name))) {
777 return swf_ShapeAddFillStyle2(s, &texture->fs);
778 } else if((image = dictionary_lookup(&images, name))) {
780 swf_GetMatrix(0, &m);
781 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
782 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
785 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
786 } else if ((gradient = dictionary_lookup(&gradients, name))) {
790 swf_GetMatrix(0, &rot);
791 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
792 csin = sin(-gradient->rotate*2*3.14159265358979/360);
794 rot.r1 = -csin*65536;
797 r2 = swf_TurnRect(*r, &rot);
798 swf_GetMatrix(0, &m);
799 m.sx = (r2.xmax - r2.xmin)*2*ccos;
800 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
801 m.r0 = (r2.ymax - r2.ymin)*2*csin;
802 m.sy = (r2.ymax - r2.ymin)*2*ccos;
803 m.tx = r->xmin + (r->xmax - r->xmin)/2;
804 m.ty = r->ymin + (r->ymax - r->ymin)/2;
805 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
806 } else if (parseColor2(name, &color)) {
807 return swf_ShapeAddSolidFillStyle(s, &color);
809 syntaxerror("not a color/fillstyle: %s", name);
814 RGBA black={r:0,g:0,b:0,a:0};
815 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
824 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
827 linewidth = linewidth>=20?linewidth-20:0;
828 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
831 fs1 = addFillStyle(s, &r2, texture);
834 r.xmin = r2.xmin-linewidth/2;
835 r.ymin = r2.ymin-linewidth/2;
836 r.xmax = r2.xmax+linewidth/2;
837 r.ymax = r2.ymax+linewidth/2;
839 swf_SetShapeHeader(tag,s);
840 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
841 swf_ShapeSetLine(tag,s,width,0);
842 swf_ShapeSetLine(tag,s,0,height);
843 swf_ShapeSetLine(tag,s,-width,0);
844 swf_ShapeSetLine(tag,s,0,-height);
845 swf_ShapeSetEnd(tag);
848 s_addcharacter(name, id, tag, r);
852 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
858 outline = dictionary_lookup(&outlines, outlinename);
860 syntaxerror("outline %s not defined", outlinename);
864 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
867 linewidth = linewidth>=20?linewidth-20:0;
868 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
871 fs1 = addFillStyle(s, &r2, texture);
874 rect.xmin = r2.xmin-linewidth/2;
875 rect.ymin = r2.ymin-linewidth/2;
876 rect.xmax = r2.xmax+linewidth/2;
877 rect.ymax = r2.ymax+linewidth/2;
879 swf_SetRect(tag,&rect);
880 swf_SetShapeStyles(tag, s);
881 swf_ShapeCountBits(s,0,0);
882 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
883 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
884 swf_SetShapeBits(tag, s);
885 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
888 s_addcharacter(name, id, tag, rect);
892 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
897 r2.xmin = r2.ymin = 0;
901 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
904 linewidth = linewidth>=20?linewidth-20:0;
905 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
908 fs1 = addFillStyle(s, &r2, texture);
910 rect.xmin = r2.xmin-linewidth/2;
911 rect.ymin = r2.ymin-linewidth/2;
912 rect.xmax = r2.xmax+linewidth/2;
913 rect.ymax = r2.ymax+linewidth/2;
915 swf_SetRect(tag,&rect);
916 swf_SetShapeHeader(tag,s);
917 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
918 swf_ShapeSetCircle(tag, s, r,r,r,r);
919 swf_ShapeSetEnd(tag);
922 s_addcharacter(name, id, tag, rect);
926 void s_textshape(char*name, char*fontname, float size, char*_text)
929 U8*text = (U8*)_text;
933 font = dictionary_lookup(&fonts, fontname);
935 syntaxerror("font \"%s\" not known!", fontname);
937 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
938 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
939 s_box(name, 0, 0, black, 20, 0);
942 g = font->ascii2glyph[text[0]];
944 outline = malloc(sizeof(outline_t));
945 memset(outline, 0, sizeof(outline_t));
946 outline->shape = font->glyph[g].shape;
947 outline->bbox = font->layout->bounds[g];
951 swf_Shape11DrawerInit(&draw, 0);
952 swf_DrawText(&draw, font, (int)(size*100), _text);
954 outline->shape = swf_ShapeDrawerToShape(&draw);
955 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
959 if(dictionary_lookup(&outlines, name))
960 syntaxerror("outline %s defined twice", name);
961 dictionary_put2(&outlines, name, outline);
964 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
969 font = dictionary_lookup(&fonts, fontname);
971 syntaxerror("font \"%s\" not known!", fontname);
973 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
975 if(!font->numchars) {
976 s_box(name, 0, 0, black, 20, 0);
979 r = swf_SetDefineText(tag, font, &color, text, size);
981 s_addcharacter(name, id, tag, r);
985 void s_quicktime(char*name, char*url)
990 memset(&r, 0, sizeof(r));
992 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
994 swf_SetString(tag, url);
996 s_addcharacter(name, id, tag, r);
1000 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)
1003 EditTextLayout layout;
1006 if(fontname && *fontname) {
1007 flags |= ET_USEOUTLINES;
1008 font = dictionary_lookup(&fonts, fontname);
1010 syntaxerror("font \"%s\" not known!", fontname);
1012 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1013 swf_SetU16(tag, id);
1014 layout.align = align;
1015 layout.leftmargin = 0;
1016 layout.rightmargin = 0;
1024 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1026 s_addcharacter(name, id, tag, r);
1030 /* type: either "jpeg" or "png"
1032 void s_image(char*name, char*type, char*filename, int quality)
1034 /* an image is actually two folded: 1st bitmap, 2nd character.
1035 Both of them can be used separately */
1037 /* step 1: the bitmap */
1041 if(!strcmp(type,"jpeg")) {
1042 #ifndef HAVE_JPEGLIB
1043 warning("no jpeg support compiled in");
1044 s_box(name, 0, 0, black, 20, 0);
1047 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1048 swf_SetU16(tag, imageID);
1050 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1051 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1054 swf_GetJPEGSize(filename, &width, &height);
1061 s_addimage(name, id, tag, r);
1064 } else if(!strcmp(type,"png")) {
1066 swf_SetU16(tag, imageID);
1068 getPNG(filename, &width, &height, (unsigned char**)&data);
1071 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1074 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1075 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1076 swf_SetU16(tag, imageID);
1077 swf_SetLosslessImage(tag, data, width, height);
1083 s_addimage(name, id, tag, r);
1086 warning("image type \"%s\" not supported yet!", type);
1087 s_box(name, 0, 0, black, 20, 0);
1091 /* step 2: the character */
1092 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1093 swf_SetU16(tag, id);
1094 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1096 s_addcharacter(name, id, tag, r);
1100 void s_getBitmapSize(char*name, int*width, int*height)
1102 character_t* image = dictionary_lookup(&images, name);
1103 gradient_t* gradient = dictionary_lookup(&gradients,name);
1105 *width = image->size.xmax;
1106 *height = image->size.ymax;
1110 /* internal SWF gradient size */
1111 if(gradient->radial) {
1120 syntaxerror("No such bitmap/gradient: %s", name);
1123 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1125 gradient_t* gradient = dictionary_lookup(&gradients, object);
1126 character_t* bitmap = dictionary_lookup(&images, object);
1127 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1129 FILLSTYLE*fs = &texture->fs;
1131 memset(&p, 0, sizeof(parameters_t));
1134 fs->type = FILL_TILED;
1135 fs->id_bitmap = bitmap->id;
1136 } else if(gradient) {
1137 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1138 fs->gradient = gradient->gradient;
1140 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1141 makeMatrix(&fs->m, &p);
1142 if(gradient && !gradient->radial) {
1149 p2 = swf_TurnPoint(p1, &m);
1154 if(dictionary_lookup(&textures, name))
1155 syntaxerror("texture %s defined twice", name);
1156 dictionary_put2(&textures, name, texture);
1159 void dumpSWF(SWF*swf)
1161 TAG* tag = swf->firstTag;
1162 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1164 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1167 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1170 void s_font(char*name, char*filename)
1173 font = swf_LoadFont(filename);
1176 warning("Couldn't open font file \"%s\"", filename);
1177 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1178 memset(font, 0, sizeof(SWFFONT));
1179 dictionary_put2(&fonts, name, font);
1185 /* fix the layout. Only needed for old fonts */
1187 for(t=0;t<font->numchars;t++) {
1188 font->glyph[t].advance = 0;
1191 swf_FontCreateLayout(font);
1193 /* just in case this thing is used in .edittext later on */
1194 swf_FontPrepareForEditText(font);
1197 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1198 swf_FontSetDefine2(tag, font);
1199 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1201 swf_SetU16(tag, id);
1202 swf_SetString(tag, name);
1205 if(dictionary_lookup(&fonts, name))
1206 syntaxerror("font %s defined twice", name);
1207 dictionary_put2(&fonts, name, font);
1212 typedef struct _sound_t
1218 void s_sound(char*name, char*filename)
1220 struct WAV wav, wav2;
1224 unsigned numsamples;
1225 unsigned blocksize = 1152;
1228 if(wav_read(&wav, filename)) {
1230 wav_convert2mono(&wav, &wav2, 44100);
1231 samples = (U16*)wav2.data;
1232 numsamples = wav2.size/2;
1234 #ifdef WORDS_BIGENDIAN
1236 for(t=0;t<numsamples;t++) {
1237 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1240 } else if(mp3_read(&mp3, filename)) {
1241 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1247 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1252 if(numsamples%blocksize != 0)
1254 // apply padding, so that block is a multiple of blocksize
1255 int numblocks = (numsamples+blocksize-1)/blocksize;
1258 numsamples2 = numblocks * blocksize;
1259 samples2 = malloc(sizeof(U16)*numsamples2);
1260 memcpy(samples2, samples, numsamples*sizeof(U16));
1261 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1262 numsamples = numsamples2;
1266 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1267 swf_SetU16(tag, id); //id
1270 swf_SetSoundDefineMP3(
1271 tag, mp3.data, mp3.size,
1279 swf_SetSoundDefine(tag, samples, numsamples);
1282 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1283 swf_SetU16(tag, id);
1284 swf_SetString(tag, name);
1285 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1287 swf_SetU16(tag, id);
1288 swf_SetString(tag, name);
1290 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1294 if(dictionary_lookup(&sounds, name))
1295 syntaxerror("sound %s defined twice", name);
1296 dictionary_put2(&sounds, name, sound);
1304 static char* gradient_getToken(const char**p)
1308 while(**p && strchr(" \t\n\r", **p)) {
1312 while(**p && !strchr(" \t\n\r", **p)) {
1315 result = malloc((*p)-start+1);
1316 memcpy(result,start,(*p)-start+1);
1317 result[(*p)-start] = 0;
1321 float parsePercent(char*str);
1322 RGBA parseColor(char*str);
1324 GRADIENT parseGradient(const char*str)
1328 const char* p = str;
1329 memset(&gradient, 0, sizeof(GRADIENT));
1331 char*posstr,*colorstr;
1334 posstr = gradient_getToken(&p);
1337 pos = (int)(parsePercent(posstr)*255.0);
1340 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1341 colorstr = gradient_getToken(&p);
1342 color = parseColor(colorstr);
1343 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1344 warning("gradient record too big- max size is 8, rest ignored");
1347 gradient.ratios[gradient.num] = pos;
1348 gradient.rgba[gradient.num] = color;
1357 void s_gradient(char*name, const char*text, int radial, int rotate)
1359 gradient_t* gradient;
1360 gradient = malloc(sizeof(gradient_t));
1361 memset(gradient, 0, sizeof(gradient_t));
1362 gradient->gradient = parseGradient(text);
1363 gradient->radial = radial;
1364 gradient->rotate = rotate;
1366 if(dictionary_lookup(&gradients, name))
1367 syntaxerror("gradient %s defined twice", name);
1368 dictionary_put2(&gradients, name, gradient);
1371 void s_action(const char*text)
1374 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1376 syntaxerror("Couldn't compile ActionScript");
1379 tag = swf_InsertTag(tag, ST_DOACTION);
1381 swf_ActionSet(tag, a);
1386 void s_initaction(const char*character, const char*text)
1390 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1392 syntaxerror("Couldn't compile ActionScript");
1395 c = (character_t*)dictionary_lookup(&characters, character);
1397 tag = swf_InsertTag(tag, ST_DOINITACTION);
1398 swf_SetU16(tag, c->id);
1399 swf_ActionSet(tag, a);
1404 int s_swf3action(char*name, char*action)
1407 instance_t* object = 0;
1409 object = (instance_t*)dictionary_lookup(&instances, name);
1410 if(!object && name && *name) {
1411 /* we have a name, but couldn't find it. Abort. */
1414 a = action_SetTarget(0, name);
1415 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1416 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1417 else if(!strcmp(action, "stop")) a = action_Stop(a);
1418 else if(!strcmp(action, "play")) a = action_Play(a);
1419 a = action_SetTarget(a, "");
1422 tag = swf_InsertTag(tag, ST_DOACTION);
1423 swf_ActionSet(tag, a);
1428 void s_outline(char*name, char*format, char*source)
1437 //swf_Shape10DrawerInit(&draw, 0);
1438 swf_Shape11DrawerInit(&draw, 0);
1440 draw_string(&draw, source);
1442 shape = swf_ShapeDrawerToShape(&draw);
1443 bounds = swf_ShapeDrawerGetBBox(&draw);
1444 draw.dealloc(&draw);
1446 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1447 outline->shape = shape;
1448 outline->bbox = bounds;
1450 if(dictionary_lookup(&outlines, name))
1451 syntaxerror("outline %s defined twice", name);
1452 dictionary_put2(&outlines, name, outline);
1455 int s_playsound(char*name, int loops, int nomultiple, int stop)
1461 sound = dictionary_lookup(&sounds, name);
1465 tag = swf_InsertTag(tag, ST_STARTSOUND);
1466 swf_SetU16(tag, sound->id); //id
1467 memset(&info, 0, sizeof(info));
1470 info.nomultiple = nomultiple;
1471 swf_SetSoundInfo(tag, &info);
1475 void s_includeswf(char*name, char*filename)
1483 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1484 f = open(filename,O_RDONLY|O_BINARY);
1486 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1487 s_box(name, 0, 0, black, 20, 0);
1490 if (swf_ReadSWF(f,&swf)<0) {
1491 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1492 s_box(name, 0, 0, black, 20, 0);
1497 /* FIXME: The following sets the bounding Box for the character.
1498 It is wrong for two reasons:
1499 a) It may be too small (in case objects in the movie clip at the borders)
1500 b) it may be too big (because the poor movie never got autocropped)
1504 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1505 swf_SetU16(tag, id);
1506 swf_SetU16(tag, swf.frameCount);
1508 swf_Relocate(&swf, idmap);
1510 ftag = swf.firstTag;
1514 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1515 if(cutout[t] == ftag->id) {
1519 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1521 if(ftag->id == ST_END)
1526 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
1527 /* We simply dump all tags right after the sprite
1528 header, relying on the fact that swf_OptimizeTagOrder() will
1529 sort things out for us later.
1530 We also rely on the fact that the imported SWF is well-formed.
1532 tag = swf_InsertTag(tag, ftag->id);
1533 swf_SetBlock(tag, ftag->data, ftag->len);
1539 syntaxerror("Included file %s contains errors", filename);
1540 tag = swf_InsertTag(tag, ST_END);
1544 s_addcharacter(name, id, tag, r);
1547 SRECT s_getCharBBox(char*name)
1549 character_t* c = dictionary_lookup(&characters, name);
1550 if(!c) syntaxerror("character '%s' unknown(2)", name);
1553 SRECT s_getInstanceBBox(char*name)
1555 instance_t * i = dictionary_lookup(&instances, name);
1557 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1559 if(!c) syntaxerror("internal error(5)");
1562 parameters_t s_getParameters(char*name)
1564 instance_t * i = dictionary_lookup(&instances, name);
1565 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1566 return i->parameters;
1568 void s_startclip(char*instance, char*character, parameters_t p)
1570 character_t* c = dictionary_lookup(&characters, character);
1574 syntaxerror("character %s not known", character);
1576 i = s_addinstance(instance, c, currentdepth);
1578 m = s_instancepos(i->character->size, &p);
1580 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1581 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1582 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1584 i->lastFrame= currentframe;
1586 stack[stackpos].tag = tag;
1587 stack[stackpos].type = 2;
1596 swf_SetTagPos(stack[stackpos].tag, 0);
1597 swf_GetPlaceObject(stack[stackpos].tag, &p);
1598 p.clipdepth = currentdepth;
1600 swf_ClearTag(stack[stackpos].tag);
1601 swf_SetPlaceObject(stack[stackpos].tag, &p);
1605 void s_put(char*instance, char*character, parameters_t p)
1607 character_t* c = dictionary_lookup(&characters, character);
1611 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1614 i = s_addinstance(instance, c, currentdepth);
1616 m = s_instancepos(i->character->size, &p);
1618 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1619 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1621 i->lastFrame = currentframe;
1625 void s_jump(char*instance, parameters_t p)
1627 instance_t* i = dictionary_lookup(&instances, instance);
1630 syntaxerror("instance %s not known", instance);
1634 m = s_instancepos(i->character->size, &p);
1636 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1637 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1639 i->lastFrame = currentframe;
1642 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1646 if(num==0 || num==1)
1648 ratio = (float)pos/(float)num;
1650 p.x = (p2->x-p1->x)*ratio + p1->x;
1651 p.y = (p2->y-p1->y)*ratio + p1->y;
1652 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1653 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1654 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1655 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1657 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1658 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1659 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1660 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1662 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1663 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1664 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1665 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1667 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1668 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1669 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1670 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1674 void s_change(char*instance, parameters_t p2)
1676 instance_t* i = dictionary_lookup(&instances, instance);
1680 int frame, allframes;
1682 syntaxerror("instance %s not known", instance);
1686 allframes = currentframe - i->lastFrame - 1;
1688 warning(".change ignored. can only .put/.change an object once per frame.");
1692 m = s_instancepos(i->character->size, &p2);
1693 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1694 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1697 /* o.k., we got the start and end point set. Now iterate though all the
1698 tags in between, inserting object changes after each new frame */
1701 if(!t) syntaxerror("internal error(6)");
1703 while(frame < allframes) {
1704 if(t->id == ST_SHOWFRAME) {
1709 p = s_interpolate(&p1, &p2, frame, allframes);
1710 m = s_instancepos(i->character->size, &p); //needed?
1711 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1712 i->lastFrame = currentframe;
1713 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1715 if(frame == allframes)
1720 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1724 void s_delinstance(char*instance)
1726 instance_t* i = dictionary_lookup(&instances, instance);
1728 syntaxerror("instance %s not known", instance);
1730 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1731 swf_SetU16(tag, i->depth);
1732 dictionary_del(&instances, instance);
1735 void s_qchange(char*instance, parameters_t p)
1742 syntaxerror(".end unexpected");
1743 if(stack[stackpos-1].type == 0)
1745 else if(stack[stackpos-1].type == 1)
1747 else if(stack[stackpos-1].type == 2)
1749 else if(stack[stackpos-1].type == 3)
1751 else syntaxerror("internal error 1");
1754 // ------------------------------------------------------------------------
1756 typedef int command_func_t(map_t*args);
1758 SRECT parseBox(char*str)
1760 SRECT r = {0,0,0,0};
1761 float xmin, xmax, ymin, ymax;
1762 char*x = strchr(str, 'x');
1764 if(!strcmp(str, "autocrop")) {
1765 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1769 d1 = strchr(x+1, ':');
1771 d2 = strchr(d1+1, ':');
1773 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1777 else if(d1 && !d2) {
1778 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1784 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1789 r.xmin = (SCOORD)(xmin*20);
1790 r.ymin = (SCOORD)(ymin*20);
1791 r.xmax = (SCOORD)(xmax*20);
1792 r.ymax = (SCOORD)(ymax*20);
1795 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1798 float parseFloat(char*str)
1802 int parseInt(char*str)
1807 if(str[0]=='+' || str[0]=='-')
1811 if(str[t]<'0' || str[t]>'9')
1812 syntaxerror("Not an Integer: \"%s\"", str);
1815 int parseTwip(char*str)
1819 if(str[0]=='+' || str[0]=='-') {
1824 dot = strchr(str, '.');
1828 return sign*parseInt(str)*20;
1830 char* old = strdup(str);
1831 int l=strlen(dot+1);
1834 for(s=str;s<dot-1;s++)
1835 if(*s<'0' || *s>'9')
1836 syntaxerror("Not a coordinate: \"%s\"", str);
1838 if(*s<'0' || *s>'9')
1839 syntaxerror("Not a coordinate: \"%s\"", str);
1841 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1842 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
1845 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
1849 return sign*atoi(str)*20;
1851 return sign*atoi(str)*20+atoi(dot)*2;
1853 return sign*atoi(str)*20+atoi(dot)/5;
1858 int isPoint(char*str)
1860 if(strchr(str, '('))
1866 SPOINT parsePoint(char*str)
1870 int l = strlen(str);
1871 char*comma = strchr(str, ',');
1872 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1873 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1874 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1875 p.x = parseTwip(tmp);
1876 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1877 p.y = parseTwip(tmp);
1881 int parseColor2(char*str, RGBA*color)
1883 int l = strlen(str);
1887 struct {unsigned char r,g,b;char*name;} colors[] =
1888 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1889 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1890 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1891 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1892 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1893 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1894 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1895 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1896 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1897 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1898 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1899 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1903 if(str[0]=='#' && (l==7 || l==9)) {
1904 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1906 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1908 color->r = r; color->g = g; color->b = b; color->a = a;
1911 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1912 if(!strcmp(str, colors[t].name)) {
1917 color->r = r; color->g = g; color->b = b; color->a = a;
1923 RGBA parseColor(char*str)
1926 if(!parseColor2(str, &c))
1927 syntaxerror("Expression '%s' is not a color", str);
1931 typedef struct _muladd {
1936 MULADD parseMulAdd(char*str)
1939 char* str2 = (char*)malloc(strlen(str)+5);
1946 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1947 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1948 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1949 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1950 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1951 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1952 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1953 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1954 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1955 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1957 syntaxerror("'%s' is not a valid color transform expression", str);
1959 m.add = (int)(add*256);
1960 m.mul = (int)(mul*256);
1965 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1967 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1968 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1970 if(a<-32768) a=-32768;
1971 if(a>32767) a=32767;
1972 if(m<-32768) m=-32768;
1973 if(m>32767) m=32767;
1979 float parsePxOrPercent(char*fontname, char*str)
1981 int l = strlen(str);
1982 if(strchr(str, '%'))
1983 return parsePercent(str);
1984 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
1985 float p = atof(str);
1986 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
1988 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
1992 float parsePercent(char*str)
1994 int l = strlen(str);
1998 return atoi(str)/100.0;
2000 syntaxerror("Expression '%s' is not a percentage", str);
2003 int isPercent(char*str)
2005 return str[strlen(str)-1]=='%';
2007 int parseNewSize(char*str, int size)
2010 return parsePercent(str)*size;
2012 return (int)(atof(str)*20);
2015 int isColor(char*str)
2018 return parseColor2(str, &c);
2021 static char* lu(map_t* args, char*name)
2023 char* value = map_lookup(args, name);
2025 map_dump(args, stdout, "");
2026 syntaxerror("internal error 2: value %s should be set", name);
2031 static int c_flash(map_t*args)
2033 char* filename = map_lookup(args, "filename");
2034 char* compressstr = lu(args, "compress");
2035 SRECT bbox = parseBox(lu(args, "bbox"));
2036 int version = parseInt(lu(args, "version"));
2037 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2039 RGBA color = parseColor(lu(args, "background"));
2041 if(!filename || !*filename) {
2042 /* for compatibility */
2043 filename = map_lookup(args, "name");
2044 if(!filename || !*filename) {
2047 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2048 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2052 if(!filename || override_outputname)
2053 filename = outputname;
2055 if(!strcmp(compressstr, "default"))
2056 compress = version==6;
2057 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2059 else if(!strcmp(compressstr, "no"))
2061 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2063 s_swf(filename, bbox, version, fps, compress, color);
2066 int isRelative(char*str)
2068 return !strncmp(str, "<plus>", 6) ||
2069 !strncmp(str, "<minus>", 7);
2071 char* getOffset(char*str)
2073 if(!strncmp(str, "<plus>", 6))
2075 if(!strncmp(str, "<minus>", 7))
2077 syntaxerror("internal error (347)");
2080 int getSign(char*str)
2082 if(!strncmp(str, "<plus>", 6))
2084 if(!strncmp(str, "<minus>", 7))
2086 syntaxerror("internal error (348)");
2089 static dictionary_t points;
2090 static mem_t mpoints;
2091 int points_initialized = 0;
2093 SPOINT getPoint(SRECT r, char*name)
2096 if(!strcmp(name, "center")) {
2098 p.x = (r.xmin + r.xmax)/2;
2099 p.y = (r.ymin + r.ymax)/2;
2103 if(points_initialized)
2104 l = (int)dictionary_lookup(&points, name);
2106 syntaxerror("Invalid point: \"%s\".", name);
2109 return *(SPOINT*)&mpoints.buffer[l];
2112 static int texture2(char*name, char*object, map_t*args, int errors)
2115 char*xstr = map_lookup(args, "x");
2116 char*ystr = map_lookup(args, "y");
2117 char*widthstr = map_lookup(args, "width");
2118 char*heightstr = map_lookup(args, "height");
2119 char*scalestr = map_lookup(args, "scale");
2120 char*scalexstr = map_lookup(args, "scalex");
2121 char*scaleystr = map_lookup(args, "scaley");
2122 char*rotatestr = map_lookup(args, "rotate");
2123 char* shearstr = map_lookup(args, "shear");
2124 char* radiusstr = map_lookup(args, "r");
2126 float scalex = 1.0, scaley = 1.0;
2127 float rotate=0, shear=0;
2129 if(!*xstr && !*ystr) {
2131 syntaxerror("x and y must be set");
2134 if(*scalestr && (*scalexstr || *scaleystr)) {
2135 syntaxerror("scale and scalex/scaley can't both be set");
2138 if((*widthstr || *heightstr) && *radiusstr) {
2139 syntaxerror("width/height and radius can't both be set");
2142 widthstr = radiusstr;
2143 heightstr = radiusstr;
2145 if(!*xstr) xstr="0";
2146 if(!*ystr) ystr="0";
2147 if(!*rotatestr) rotatestr="0";
2148 if(!*shearstr) shearstr="0";
2151 scalex = scaley = parsePercent(scalestr);
2152 } else if(*scalexstr || *scaleystr) {
2153 if(scalexstr) scalex = parsePercent(scalexstr);
2154 if(scaleystr) scaley = parsePercent(scaleystr);
2155 } else if(*widthstr || *heightstr) {
2158 s_getBitmapSize(object, &width, &height);
2160 scalex = (float)parseTwip(widthstr)/(float)width;
2162 scaley = (float)parseTwip(heightstr)/(float)height;
2164 x = parseTwip(xstr);
2165 y = parseTwip(ystr);
2166 rotate = parseFloat(rotatestr);
2167 shear = parseFloat(shearstr);
2169 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2174 static int c_texture(map_t*args)
2176 char*name = lu(args, "instance");
2177 char*object = lu(args, "character");
2178 return texture2(name, object, args, 1);
2181 static int c_gradient(map_t*args)
2183 char*name = lu(args, "name");
2184 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2185 int rotate = parseInt(lu(args, "rotate"));
2189 syntaxerror("colon (:) expected");
2191 s_gradient(name, text, radial, rotate);
2193 /* check whether we also have placement information,
2194 which would make this a positioned gradient.
2195 If there is placement information, texture2() will
2196 add a texture, which has priority over the gradient.
2198 texture2(name, name, args, 0);
2201 static int c_point(map_t*args)
2203 char*name = lu(args, "name");
2207 if(!points_initialized) {
2208 dictionary_init(&points);
2210 points_initialized = 1;
2212 p.x = parseTwip(lu(args, "x"));
2213 p.y = parseTwip(lu(args, "y"));
2214 pos = mem_put(&mpoints, &p, sizeof(p));
2215 string_set(&s1, name);
2217 dictionary_put(&points, s1, (void*)pos);
2220 static int c_play(map_t*args)
2222 char*name = lu(args, "name");
2223 char*loop = lu(args, "loop");
2224 char*nomultiple = lu(args, "nomultiple");
2226 if(!strcmp(nomultiple, "nomultiple"))
2229 nm = parseInt(nomultiple);
2231 if(s_playsound(name, parseInt(loop), nm, 0)) {
2233 } else if(s_swf3action(name, "play")) {
2239 static int c_stop(map_t*args)
2241 char*name = map_lookup(args, "name");
2243 if(s_playsound(name, 0,0,1)) {
2245 } else if(s_swf3action(name, "stop")) {
2248 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2252 static int c_nextframe(map_t*args)
2254 char*name = lu(args, "name");
2256 if(s_swf3action(name, "nextframe")) {
2259 syntaxerror("I don't know anything about movie \"%s\"", name);
2263 static int c_previousframe(map_t*args)
2265 char*name = lu(args, "name");
2267 if(s_swf3action(name, "previousframe")) {
2270 syntaxerror("I don't know anything about movie \"%s\"", name);
2274 static int c_placement(map_t*args, int type)
2276 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2279 char* luminancestr = lu(args, "luminance");
2280 char* scalestr = lu(args, "scale");
2281 char* scalexstr = lu(args, "scalex");
2282 char* scaleystr = lu(args, "scaley");
2283 char* rotatestr = lu(args, "rotate");
2284 char* shearstr = lu(args, "shear");
2285 char* xstr="", *pivotstr="";
2286 char* ystr="", *anglestr="";
2287 char*above = lu(args, "above"); /*FIXME*/
2288 char*below = lu(args, "below");
2289 char* rstr = lu(args, "red");
2290 char* gstr = lu(args, "green");
2291 char* bstr = lu(args, "blue");
2292 char* astr = lu(args, "alpha");
2293 char* pinstr = lu(args, "pin");
2294 char* as = map_lookup(args, "as");
2302 if(type==9) { // (?) .rotate or .arcchange
2303 pivotstr = lu(args, "pivot");
2304 anglestr = lu(args, "angle");
2306 xstr = lu(args, "x");
2307 ystr = lu(args, "y");
2310 luminance = parseMulAdd(luminancestr);
2313 luminance.mul = 256;
2317 if(scalexstr[0]||scaleystr[0])
2318 syntaxerror("scalex/scaley and scale cannot both be set");
2319 scalexstr = scaleystr = scalestr;
2322 if(type == 0 || type == 4) {
2324 character = lu(args, "character");
2325 parameters_clear(&p);
2326 } else if (type == 5) {
2327 character = lu(args, "name");
2328 parameters_clear(&p);
2331 p = s_getParameters(instance);
2336 if(isRelative(xstr)) {
2337 if(type == 0 || type == 4)
2338 syntaxerror("relative x values not allowed for initial put or startclip");
2339 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2341 p.x = parseTwip(xstr);
2345 if(isRelative(ystr)) {
2346 if(type == 0 || type == 4)
2347 syntaxerror("relative y values not allowed for initial put or startclip");
2348 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2350 p.y = parseTwip(ystr);
2354 /* scale, scalex, scaley */
2356 oldbbox = s_getCharBBox(character);
2358 oldbbox = s_getInstanceBBox(instance);
2360 oldwidth = oldbbox.xmax - oldbbox.xmin;
2361 oldheight = oldbbox.ymax - oldbbox.ymin;
2363 if(oldwidth==0) p.scalex = 1.0;
2366 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2370 if(oldheight==0) p.scaley = 1.0;
2373 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2379 if(isRelative(rotatestr)) {
2380 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2382 p.rotate = parseFloat(rotatestr);
2388 if(isRelative(shearstr)) {
2389 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2391 p.shear = parseFloat(shearstr);
2396 if(isPoint(pivotstr))
2397 p.pivot = parsePoint(pivotstr);
2399 p.pivot = getPoint(oldbbox, pivotstr);
2403 p.pin = parsePoint(pinstr);
2405 p.pin = getPoint(oldbbox, pinstr);
2408 /* color transform */
2410 if(rstr[0] || luminancestr[0]) {
2413 r = parseMulAdd(rstr);
2415 r.add = p.cxform.r0;
2416 r.mul = p.cxform.r1;
2418 r = mergeMulAdd(r, luminance);
2419 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2421 if(gstr[0] || luminancestr[0]) {
2424 g = parseMulAdd(gstr);
2426 g.add = p.cxform.g0;
2427 g.mul = p.cxform.g1;
2429 g = mergeMulAdd(g, luminance);
2430 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2432 if(bstr[0] || luminancestr[0]) {
2435 b = parseMulAdd(bstr);
2437 b.add = p.cxform.b0;
2438 b.mul = p.cxform.b1;
2440 b = mergeMulAdd(b, luminance);
2441 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2444 MULADD a = parseMulAdd(astr);
2445 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2449 s_put(instance, character, p);
2451 s_change(instance, p);
2453 s_qchange(instance, p);
2455 s_jump(instance, p);
2457 s_startclip(instance, character, p);
2458 else if(type == 5) {
2460 s_buttonput(character, as, p);
2462 s_buttonput(character, "shape", p);
2467 static int c_put(map_t*args)
2469 c_placement(args, 0);
2472 static int c_change(map_t*args)
2474 c_placement(args, 1);
2477 static int c_qchange(map_t*args)
2479 c_placement(args, 2);
2482 static int c_arcchange(map_t*args)
2484 c_placement(args, 2);
2487 static int c_jump(map_t*args)
2489 c_placement(args, 3);
2492 static int c_startclip(map_t*args)
2494 c_placement(args, 4);
2497 static int c_show(map_t*args)
2499 c_placement(args, 5);
2502 static int c_del(map_t*args)
2504 char*instance = lu(args, "name");
2505 s_delinstance(instance);
2508 static int c_end(map_t*args)
2513 static int c_sprite(map_t*args)
2515 char* name = lu(args, "name");
2519 static int c_frame(map_t*args)
2521 char*framestr = lu(args, "n");
2522 char*cutstr = lu(args, "cut");
2524 char*name = lu(args, "name");
2525 char*anchor = lu(args, "anchor");
2528 if(!strcmp(anchor, "anchor") && !*name)
2533 if(strcmp(cutstr, "no"))
2535 if(isRelative(framestr)) {
2536 frame = s_getframe();
2537 if(getSign(framestr)<0)
2538 syntaxerror("relative frame expressions must be positive");
2539 frame += parseInt(getOffset(framestr));
2542 frame = parseInt(framestr);
2543 if(s_getframe() >= frame
2544 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2545 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2547 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
2550 static int c_primitive(map_t*args)
2552 char*name = lu(args, "name");
2553 char*command = lu(args, "commandname");
2554 int width=0, height=0, r=0;
2555 int linewidth = parseTwip(lu(args, "line"));
2556 char*colorstr = lu(args, "color");
2557 RGBA color = parseColor(colorstr);
2558 char*fillstr = lu(args, "fill");
2565 if(!strcmp(command, "circle"))
2567 else if(!strcmp(command, "filled"))
2571 width = parseTwip(lu(args, "width"));
2572 height = parseTwip(lu(args, "height"));
2573 } else if (type==1) {
2574 r = parseTwip(lu(args, "r"));
2575 } else if (type==2) {
2576 outline = lu(args, "outline");
2579 if(!strcmp(fillstr, "fill"))
2581 if(!strcmp(fillstr, "none"))
2583 if(width<0 || height<0 || linewidth<0 || r<0)
2584 syntaxerror("values width, height, line, r must be positive");
2586 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2587 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2588 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2592 static int c_textshape(map_t*args)
2594 char*name = lu(args, "name");
2595 char*text = lu(args, "text");
2596 char*font = lu(args, "font");
2597 float size = parsePxOrPercent(font, lu(args, "size"));
2599 s_textshape(name, font, size, text);
2603 static int c_swf(map_t*args)
2605 char*name = lu(args, "name");
2606 char*filename = lu(args, "filename");
2607 char*command = lu(args, "commandname");
2608 if(!strcmp(command, "shape"))
2609 warning("Please use .swf instead of .shape");
2610 s_includeswf(name, filename);
2614 static int c_font(map_t*args)
2616 char*name = lu(args, "name");
2617 char*filename = lu(args, "filename");
2618 s_font(name, filename);
2622 static int c_sound(map_t*args)
2624 char*name = lu(args, "name");
2625 char*filename = lu(args, "filename");
2626 s_sound(name, filename);
2630 static int c_text(map_t*args)
2632 char*name = lu(args, "name");
2633 char*text = lu(args, "text");
2634 char*font = lu(args, "font");
2635 float size = parsePxOrPercent(font, lu(args, "size"));
2636 RGBA color = parseColor(lu(args, "color"));
2637 s_text(name, font, text, (int)(size*100), color);
2641 static int c_soundtrack(map_t*args)
2646 static int c_quicktime(map_t*args)
2648 char*name = lu(args, "name");
2649 char*url = lu(args, "url");
2650 s_quicktime(name, url);
2654 static int c_image(map_t*args)
2656 char*command = lu(args, "commandname");
2657 char*name = lu(args, "name");
2658 char*filename = lu(args, "filename");
2659 if(!strcmp(command,"jpeg")) {
2660 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2661 s_image(name, "jpeg", filename, quality);
2663 s_image(name, "png", filename, 0);
2668 static int c_outline(map_t*args)
2670 char*name = lu(args, "name");
2671 char*format = lu(args, "format");
2675 syntaxerror("colon (:) expected");
2677 s_outline(name, format, text);
2681 int fakechar(map_t*args)
2683 char*name = lu(args, "name");
2684 s_box(name, 0, 0, black, 20, 0);
2688 static int c_egon(map_t*args) {return fakechar(args);}
2689 static int c_button(map_t*args) {
2690 char*name = lu(args, "name");
2694 static int current_button_flags = 0;
2695 static int c_on_press(map_t*args)
2697 char*position = lu(args, "position");
2699 if(!strcmp(position, "inside")) {
2700 current_button_flags |= BC_OVERUP_OVERDOWN;
2701 } else if(!strcmp(position, "outside")) {
2702 //current_button_flags |= BC_IDLE_OUTDOWN;
2703 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2704 } else if(!strcmp(position, "anywhere")) {
2705 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2708 if(type == RAWDATA) {
2710 s_buttonaction(current_button_flags, action);
2711 current_button_flags = 0;
2717 static int c_on_release(map_t*args)
2719 char*position = lu(args, "position");
2721 if(!strcmp(position, "inside")) {
2722 current_button_flags |= BC_OVERDOWN_OVERUP;
2723 } else if(!strcmp(position, "outside")) {
2724 current_button_flags |= BC_OUTDOWN_IDLE;
2725 } else if(!strcmp(position, "anywhere")) {
2726 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2729 if(type == RAWDATA) {
2731 s_buttonaction(current_button_flags, action);
2732 current_button_flags = 0;
2738 static int c_on_move_in(map_t*args)
2740 char*position = lu(args, "state");
2742 if(!strcmp(position, "pressed")) {
2743 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2744 } else if(!strcmp(position, "not_pressed")) {
2745 current_button_flags |= BC_IDLE_OVERUP;
2746 } else if(!strcmp(position, "any")) {
2747 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2750 if(type == RAWDATA) {
2752 s_buttonaction(current_button_flags, action);
2753 current_button_flags = 0;
2759 static int c_on_move_out(map_t*args)
2761 char*position = lu(args, "state");
2763 if(!strcmp(position, "pressed")) {
2764 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2765 } else if(!strcmp(position, "not_pressed")) {
2766 current_button_flags |= BC_OVERUP_IDLE;
2767 } else if(!strcmp(position, "any")) {
2768 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2771 if(type == RAWDATA) {
2773 s_buttonaction(current_button_flags, action);
2774 current_button_flags = 0;
2780 static int c_on_key(map_t*args)
2782 char*key = lu(args, "key");
2784 if(strlen(key)==1) {
2787 current_button_flags |= 0x4000 + (key[0]*0x200);
2789 syntaxerror("invalid character: %c"+key[0]);
2794 <ctrl-x> = 0x200*(x-'a')
2798 syntaxerror("invalid key: %s",key);
2801 if(type == RAWDATA) {
2803 s_buttonaction(current_button_flags, action);
2804 current_button_flags = 0;
2811 static int c_edittext(map_t*args)
2813 //"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"},
2814 char*name = lu(args, "name");
2815 char*font = lu(args, "font");
2816 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
2817 int width = parseTwip(lu(args, "width"));
2818 int height = parseTwip(lu(args, "height"));
2819 char*text = lu(args, "text");
2820 RGBA color = parseColor(lu(args, "color"));
2821 int maxlength = parseInt(lu(args, "maxlength"));
2822 char*variable = lu(args, "variable");
2823 char*passwordstr = lu(args, "password");
2824 char*wordwrapstr = lu(args, "wordwrap");
2825 char*multilinestr = lu(args, "multiline");
2826 char*htmlstr = lu(args, "html");
2827 char*noselectstr = lu(args, "noselect");
2828 char*readonlystr = lu(args, "readonly");
2829 char*borderstr = lu(args, "border");
2830 char*autosizestr = lu(args, "autosize");
2831 char*alignstr = lu(args, "align");
2835 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2836 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2837 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2838 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2839 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2840 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2841 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2842 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
2843 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
2844 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
2845 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
2846 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
2847 else syntaxerror("Unknown alignment: %s", alignstr);
2849 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
2853 static int c_morphshape(map_t*args) {return fakechar(args);}
2854 static int c_movie(map_t*args) {return fakechar(args);}
2856 static char* readfile(const char*filename)
2858 FILE*fi = fopen(filename, "rb");
2862 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
2863 fseek(fi, 0, SEEK_END);
2865 fseek(fi, 0, SEEK_SET);
2866 text = rfx_alloc(l+1);
2867 fread(text, l, 1, fi);
2873 static int c_action(map_t*args)
2875 char* filename = map_lookup(args, "filename");
2876 if(!filename ||!*filename) {
2878 if(type != RAWDATA) {
2879 syntaxerror("colon (:) expected");
2883 s_action(readfile(filename));
2889 static int c_initaction(map_t*args)
2891 char* character = lu(args, "name");
2892 char* filename = map_lookup(args, "filename");
2893 if(!filename ||!*filename) {
2895 if(type != RAWDATA) {
2896 syntaxerror("colon (:) expected");
2898 s_initaction(character, text);
2900 s_initaction(character, readfile(filename));
2908 command_func_t* func;
2911 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
2912 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
2913 // "import" type stuff
2914 {"swf", c_swf, "name filename"},
2915 {"shape", c_swf, "name filename"},
2916 {"jpeg", c_image, "name filename quality=80%"},
2917 {"png", c_image, "name filename"},
2918 {"movie", c_movie, "name filename"},
2919 {"sound", c_sound, "name filename"},
2920 {"font", c_font, "name filename"},
2921 {"soundtrack", c_soundtrack, "filename"},
2922 {"quicktime", c_quicktime, "url"},
2924 // generators of primitives
2926 {"point", c_point, "name x=0 y=0"},
2927 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
2928 {"outline", c_outline, "name format=simple"},
2929 {"textshape", c_textshape, "name font size=100% text"},
2931 // character generators
2932 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2933 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2934 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2936 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2937 {"text", c_text, "name text font size=100% color=white"},
2938 {"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="},
2939 {"morphshape", c_morphshape, "name start end"},
2940 {"button", c_button, "name"},
2941 {"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="},
2942 {"on_press", c_on_press, "position=inside"},
2943 {"on_release", c_on_release, "position=anywhere"},
2944 {"on_move_in", c_on_move_in, "state=not_pressed"},
2945 {"on_move_out", c_on_move_out, "state=not_pressed"},
2946 {"on_key", c_on_key, "key=any"},
2949 {"play", c_play, "name loop=0 @nomultiple=0"},
2950 {"stop", c_stop, "name= "},
2951 {"nextframe", c_nextframe, "name"},
2952 {"previousframe", c_previousframe, "name"},
2954 // object placement tags
2955 {"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="},
2956 {"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="},
2957 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2958 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2959 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2960 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2961 {"del", c_del, "name"},
2962 // virtual object placement
2963 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
2965 // commands which start a block
2966 //startclip (see above)
2967 {"sprite", c_sprite, "name"},
2968 {"action", c_action, "filename="},
2969 {"initaction", c_initaction, "name filename="},
2975 static map_t parseArguments(char*command, char*pattern)
2991 string_set(&t1, "commandname");
2992 string_set(&t2, command);
2993 map_put(&result, t1, t2);
2995 if(!pattern || !*pattern)
3002 if(!strncmp("<i> ", x, 3)) {
3004 if(type == COMMAND || type == RAWDATA) {
3006 syntaxerror("character name expected");
3008 name[pos].str = "instance";
3010 value[pos].str = text;
3011 value[pos].len = strlen(text);
3015 if(type == ASSIGNMENT)
3018 name[pos].str = "character";
3020 value[pos].str = text;
3021 value[pos].len = strlen(text);
3029 isboolean[pos] = (x[0] =='@');
3042 name[pos].len = d-x;
3047 name[pos].len = e-x;
3048 value[pos].str = e+1;
3049 value[pos].len = d-e-1;
3057 /* for(t=0;t<len;t++) {
3058 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
3059 isboolean[t]?"(boolean)":"");
3064 if(type == RAWDATA || type == COMMAND) {
3069 // first, search for boolean arguments
3070 for(pos=0;pos<len;pos++)
3072 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
3074 if(type == ASSIGNMENT)
3076 value[pos].str = text;
3077 value[pos].len = strlen(text);
3078 /*printf("setting boolean parameter %s (to %s)\n",
3079 strdup_n(name[pos], namelen[pos]),
3080 strdup_n(value[pos], valuelen[pos]));*/
3085 // second, search for normal arguments
3087 for(pos=0;pos<len;pos++)
3089 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3090 (type != ASSIGNMENT && !set[pos])) {
3092 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3094 if(type == ASSIGNMENT)
3097 value[pos].str = text;
3098 value[pos].len = strlen(text);
3100 printf("setting parameter %s (to %s)\n",
3101 strdup_n(name[pos].str, name[pos].len),
3102 strdup_n(value[pos].str, value[pos].len));
3108 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3112 for(t=0;t<len;t++) {
3113 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3116 for(t=0;t<len;t++) {
3117 if(value[t].str && value[t].str[0] == '*') {
3118 //relative default- take value from some other parameter
3120 for(s=0;s<len;s++) {
3121 if(value[s].len == value[t].len-1 &&
3122 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3123 value[t].str = value[s].str;
3126 if(value[t].str == 0) {
3128 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3132 /* ok, now construct the dictionary from the parameters */
3136 map_put(&result, name[t], value[t]);
3140 static void parseArgumentsForCommand(char*command)
3145 msg("<verbose> parse Command: %s (line %d)", command, line);
3147 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3148 if(!strcmp(arguments[t].command, command)) {
3150 /* ugly hack- will be removed soon (once documentation and .sc generating
3151 utilities have been changed) */
3152 if(!strcmp(command, "swf") && !stackpos) {
3153 warning("Please use .flash instead of .swf- this will be mandatory soon");
3158 args = parseArguments(command, arguments[t].arguments);
3164 syntaxerror("command %s not known", command);
3166 // catch missing .flash directives at the beginning of a file
3167 if(strcmp(command, "flash") && !stackpos)
3169 syntaxerror("No movie defined- use .flash first");
3173 printf(".%s\n", command);fflush(stdout);
3174 map_dump(&args, stdout, "\t");fflush(stdout);
3177 (*arguments[nr].func)(&args);
3179 /*if(!strcmp(command, "button") ||
3180 !strcmp(command, "action")) {
3183 if(type == COMMAND) {
3184 if(!strcmp(text, "end"))
3198 int main (int argc,char ** argv)
3201 processargs(argc, argv);
3202 initLog(0,-1,0,0,-1,verbose);
3205 args_callback_usage(argv[0]);
3209 file = generateTokens(filename);
3211 fprintf(stderr, "parser returned error.\n");
3217 while(!noMoreTokens()) {
3220 syntaxerror("command expected");
3221 parseArgumentsForCommand(text);