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/log.h"
32 #include "../lib/args.h"
39 static char * filename = 0;
40 static char * outputname = "output.swf";
41 static int verbose = 2;
42 static int override_outputname = 0;
44 static struct options_t options[] =
52 int args_callback_option(char*name,char*val)
54 if(!strcmp(name, "V")) {
55 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
58 else if(!strcmp(name, "o")) {
60 override_outputname = 1;
63 else if(!strcmp(name, "v")) {
68 printf("Unknown option: -%s\n", name);
73 int args_callback_longoption(char*name,char*val)
75 return args_long2shortoption(options, name, val);
77 void args_callback_usage(char*name)
79 printf("Usage: %s [-o filename] file.wav\n", name);
80 printf("\t-v , --verbose\t\t\t Be more verbose\n");
81 printf("\t-o , --output filename\t\t set output filename (default: output.swf)\n");
82 printf("\t-V , --version\t\t\t Print program version and exit\n");
84 int args_callback_command(char*name,char*val)
87 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
94 static struct token_t* file;
103 static void syntaxerror(char*format, ...)
107 va_start(arglist, format);
108 vsprintf(buf, format, arglist);
110 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
114 static void warning(char*format, ...)
118 va_start(arglist, format);
119 vsprintf(buf, format, arglist);
121 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
124 static void readToken()
126 type = file[pos].type;
128 syntaxerror("unexpected end of file");
130 text = file[pos].text;
131 textlen = strlen(text);
132 line = file[pos].line;
133 column = file[pos].column;
135 //printf("---> %d(%s) %s\n", type, type_names[type], text);
138 static void pushBack()
141 if(!pos) syntaxerror("internal error 3");
146 textlen = strlen(text);
149 column = file[p].column;
152 static int noMoreTokens()
154 if(file[pos].type == END)
159 // ------------------------------ swf routines ----------------------------
163 int type; //0=swf, 1=sprite, 2=clip
169 /* for sprites (1): */
175 dictionary_t oldinstances;
180 static int stackpos = 0;
182 static dictionary_t characters;
183 static dictionary_t images;
184 static dictionary_t outlines;
185 static dictionary_t gradients;
186 static char idmap[65536];
187 static TAG*tag = 0; //current tag
189 static int id; //current character id
190 static int currentframe; //current frame in current level
191 static SRECT currentrect; //current bounding box in current level
192 static U16 currentdepth;
193 static dictionary_t instances;
194 static dictionary_t fonts;
195 static dictionary_t sounds;
197 typedef struct _parameters {
199 float scalex, scaley;
207 typedef struct _character {
213 typedef struct _instance {
214 character_t*character;
216 parameters_t parameters;
217 TAG* lastTag; //last tag which set the object
218 U16 lastFrame; //frame lastTag is in
221 typedef struct _outline {
226 typedef struct _gradient {
231 static void character_init(character_t*c)
233 memset(c, 0, sizeof(character_t));
235 static character_t* character_new()
238 c = (character_t*)malloc(sizeof(character_t));
242 static void instance_init(instance_t*i)
244 memset(i, 0, sizeof(instance_t));
246 static instance_t* instance_new()
249 c = (instance_t*)malloc(sizeof(instance_t));
254 static void incrementid()
258 syntaxerror("Out of character ids.");
263 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
265 character_t* c = character_new();
267 c->definingTag = ctag;
270 if(dictionary_lookup(&characters, name))
271 syntaxerror("character %s defined twice", name);
272 dictionary_put2(&characters, name, c);
274 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
276 swf_SetString(tag, name);
277 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
280 swf_SetString(tag, name);
282 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
284 character_t* c = character_new();
285 c->definingTag = ctag;
289 if(dictionary_lookup(&images, name))
290 syntaxerror("image %s defined twice", name);
291 dictionary_put2(&images, name, c);
293 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
295 instance_t* i = instance_new();
298 //swf_GetMatrix(0, &i->matrix);
299 if(dictionary_lookup(&instances, name))
300 syntaxerror("object %s defined twice", name);
301 dictionary_put2(&instances, name, i);
305 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)
308 p->scalex = scalex; p->scaley = scaley;
309 p->pin = pin; p->pivot = pivot;
310 p->rotate = rotate; p->cxform = cxform;
314 static void parameters_clear(parameters_t*p)
317 p->scalex = 1.0; p->scaley = 1.0;
318 p->pin.x = 1; p->pin.y = 0;
319 p->pivot.x = 0; p->pivot.y = 0;
322 swf_GetCXForm(0, &p->cxform, 1);
325 static void makeMatrix(MATRIX*m, parameters_t*p)
334 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
335 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
336 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
337 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
339 m->sx = (int)(sx*65536+0.5);
340 m->r1 = (int)(r1*65536+0.5);
341 m->r0 = (int)(r0*65536+0.5);
342 m->sy = (int)(sy*65536+0.5);
346 h = swf_TurnPoint(p->pin, m);
351 static MATRIX s_instancepos(instance_t*i, parameters_t*p)
356 r = swf_TurnRect(i->character->size, &m);
357 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
358 currentrect.xmax == 0 && currentrect.ymax == 0)
361 swf_ExpandRect2(¤trect, &r);
365 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
367 SWF*swf = (SWF*)malloc(sizeof(SWF));
370 syntaxerror(".swf blocks can't be nested");
372 memset(swf, 0, sizeof(swf));
373 swf->fileVersion = version;
375 swf->frameRate = fps;
376 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
377 swf->compressed = compress;
378 swf_SetRGB(tag,&background);
380 if(stackpos==sizeof(stack)/sizeof(stack[0]))
381 syntaxerror("too many levels of recursion");
383 dictionary_init(&characters);
384 dictionary_init(&images);
385 dictionary_init(&outlines);
386 dictionary_init(&gradients);
387 dictionary_init(&instances);
388 dictionary_init(&fonts);
389 dictionary_init(&sounds);
391 memset(&stack[stackpos], 0, sizeof(stack[0]));
392 stack[stackpos].type = 0;
393 stack[stackpos].filename = strdup(name);
394 stack[stackpos].swf = swf;
395 stack[stackpos].oldframe = -1;
400 memset(¤trect, 0, sizeof(currentrect));
403 memset(idmap, 0, sizeof(idmap));
407 void s_sprite(char*name)
409 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
410 swf_SetU16(tag, id); //id
411 swf_SetU16(tag, 0); //frames
413 memset(&stack[stackpos], 0, sizeof(stack[0]));
414 stack[stackpos].type = 1;
415 stack[stackpos].oldframe = currentframe;
416 stack[stackpos].olddepth = currentdepth;
417 stack[stackpos].oldrect = currentrect;
418 stack[stackpos].oldinstances = instances;
419 stack[stackpos].tag = tag;
420 stack[stackpos].id = id;
421 stack[stackpos].name = strdup(name);
423 /* FIXME: those four fields should be bundled together */
424 dictionary_init(&instances);
427 memset(¤trect, 0, sizeof(currentrect));
433 TAG* removeFromTo(TAG*from, TAG*to)
435 TAG*save = from->prev;
437 TAG*next = from->next;
445 static void s_endSprite()
447 SRECT r = currentrect;
449 if(stack[stackpos].cut)
450 tag = removeFromTo(stack[stackpos].cut, tag);
454 /* TODO: before clearing, prepend "<spritename>." to names and
455 copy into old instances dict */
456 dictionary_clear(&instances);
458 currentframe = stack[stackpos].oldframe;
459 currentrect = stack[stackpos].oldrect;
460 currentdepth = stack[stackpos].olddepth;
461 instances = stack[stackpos].oldinstances;
463 tag = swf_InsertTag(tag, ST_END);
465 tag = stack[stackpos].tag;
468 syntaxerror("internal error(7)");
470 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
471 free(stack[stackpos].name);
474 static void s_endSWF()
480 if(stack[stackpos].cut)
481 tag = removeFromTo(stack[stackpos].cut, tag);
485 swf = stack[stackpos].swf;
486 filename = stack[stackpos].filename;
488 //tag = swf_InsertTag(tag, ST_SHOWFRAME); //?
490 tag = swf_InsertTag(tag, ST_END);
492 swf_OptimizeTagOrder(swf);
494 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin))
495 swf->movieSize = currentrect; /* "autocrop" */
497 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
498 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
499 swf->movieSize.ymax += 20;
502 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
504 syntaxerror("couldn't create output file %s", filename);
507 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
509 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
513 dictionary_clear(&instances);
514 dictionary_clear(&characters);
515 dictionary_clear(&images);
516 dictionary_clear(&outlines);
517 dictionary_clear(&gradients);
518 dictionary_clear(&fonts);
519 dictionary_clear(&sounds);
529 if(stack[stackpos-1].type == 0)
530 syntaxerror("End of file encountered in .flash block");
531 if(stack[stackpos-1].type == 1)
532 syntaxerror("End of file encountered in .sprite block");
533 if(stack[stackpos-1].type == 2)
534 syntaxerror("End of file encountered in .clip block");
543 void s_frame(int nr, int cut)
548 for(t=currentframe;t<nr;t++) {
549 tag = swf_InsertTag(tag, ST_SHOWFRAME);
554 syntaxerror("Can't cut, frame empty");
556 stack[stackpos].cut = tag;
562 int parseColor2(char*str, RGBA*color);
564 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
569 if(texture[0] == '#') {
570 parseColor2(texture, &color);
571 return swf_ShapeAddSolidFillStyle(s, &color);
572 } else if((image = dictionary_lookup(&images, texture))) {
574 swf_GetMatrix(0, &m);
575 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
576 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
579 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
580 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
581 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
583 swf_GetMatrix(0, &m);
584 m.sx = (r->xmax - r->xmin)*2;
585 m.sy = (r->ymax - r->ymin)*2;
586 m.tx = r->xmin + (r->xmax - r->xmin)/2;
587 m.ty = r->ymin + (r->ymax - r->ymin)/2;
588 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
589 } else if (parseColor2(texture, &color)) {
590 return swf_ShapeAddSolidFillStyle(s, &color);
592 syntaxerror("not a color/fillstyle: %s", texture);
597 RGBA black={r:0,g:0,b:0,a:0};
598 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
607 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
609 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
612 fs1 = addFillStyle(s, &r2, texture);
615 r.xmin = r2.xmin-linewidth-linewidth/2;
616 r.ymin = r2.ymin-linewidth-linewidth/2;
617 r.xmax = r2.xmax+linewidth+linewidth/2;
618 r.ymax = r2.ymax+linewidth+linewidth/2;
620 swf_SetShapeHeader(tag,s);
621 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
622 swf_ShapeSetLine(tag,s,width,0);
623 swf_ShapeSetLine(tag,s,0,height);
624 swf_ShapeSetLine(tag,s,-width,0);
625 swf_ShapeSetLine(tag,s,0,-height);
626 swf_ShapeSetEnd(tag);
629 s_addcharacter(name, id, tag, r);
633 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
639 outline = dictionary_lookup(&outlines, outlinename);
641 syntaxerror("outline %s not defined", outlinename);
645 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
647 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
649 fs1 = addFillStyle(s, &r2, texture);
651 syntaxerror("non filled outlines not yet supported- please supply a fill=<color/texture> argument");
653 rect.xmin = r2.xmin-linewidth-linewidth/2;
654 rect.ymin = r2.ymin-linewidth-linewidth/2;
655 rect.xmax = r2.xmax+linewidth+linewidth/2;
656 rect.ymax = r2.ymax+linewidth+linewidth/2;
658 swf_SetRect(tag,&rect);
659 swf_SetShapeStyles(tag, s);
660 swf_SetShapeBits(tag, outline->shape); //does not count bits!
661 swf_SetBlock(tag, outline->shape->data, (outline->shape->bitlen+7)/8);
664 s_addcharacter(name, id, tag, rect);
668 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
673 r2.xmin = r2.ymin = 0;
677 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
679 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
681 fs1 = addFillStyle(s, &r2, texture);
683 rect.xmin = r2.xmin-linewidth-linewidth/2;
684 rect.ymin = r2.ymin-linewidth-linewidth/2;
685 rect.xmax = r2.xmax+linewidth+linewidth/2;
686 rect.ymax = r2.ymax+linewidth+linewidth/2;
688 swf_SetRect(tag,&rect);
689 swf_SetShapeHeader(tag,s);
690 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
691 swf_ShapeSetCircle(tag, s, r,r,r,r);
692 swf_ShapeSetEnd(tag);
695 s_addcharacter(name, id, tag, rect);
699 void s_textshape(char*name, char*fontname, char*_text)
702 U8*text = (U8*)_text;
706 font = dictionary_lookup(&fonts, fontname);
708 syntaxerror("font \"%s\" not known!", fontname);
710 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
711 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
712 s_box(name, 0, 0, black, 20, 0);
715 g = font->ascii2glyph[text[0]];
717 outline = malloc(sizeof(outline_t));
718 memset(outline, 0, sizeof(outline_t));
719 outline->shape = font->glyph[g].shape;
720 outline->bbox = font->layout->bounds[g];
724 swf_DrawerInit(&draw,0);
725 swf_DrawText(&draw, font, _text);
726 swf_DrawerFinish(&draw);
727 outline->shape = swf_DrawerToShape(&draw);
728 outline->bbox = draw.bbox;
731 if(dictionary_lookup(&outlines, name))
732 syntaxerror("outline %s defined twice", name);
733 dictionary_put2(&outlines, name, outline);
736 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
741 font = dictionary_lookup(&fonts, fontname);
743 syntaxerror("font \"%s\" not known!", fontname);
745 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
747 if(!font->numchars) {
748 s_box(name, 0, 0, black, 20, 0);
751 r = swf_SetDefineText(tag, font, &color, text, size);
753 s_addcharacter(name, id, tag, r);
757 /* type: either "jpeg" or "png"
759 void s_image(char*name, char*type, char*filename, int quality)
761 /* an image is actually two folded: 1st bitmap, 2nd character.
762 Both of them can be used separately */
764 /* step 1: the bitmap */
769 warning("image type \"png\" not supported yet!");
770 s_box(name, 0, 0, black, 20, 0);
773 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
774 swf_SetU16(tag, imageID);
776 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
777 syntaxerror("Image \"%s\" not found, or contains errors", filename);
780 swf_GetJPEGSize(filename, &width, &height);
787 s_addimage(name, id, tag, r);
790 /* step 2: the character */
791 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
793 swf_ShapeSetBitmapRect(tag, imageID, width, height);
795 s_addcharacter(name, id, tag, r);
799 void dumpSWF(SWF*swf)
801 TAG* tag = swf->firstTag;
802 printf("vvvvvvvvvvvvvvvvvvvvv\n");
804 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
807 printf("^^^^^^^^^^^^^^^^^^^^^\n");
810 void s_font(char*name, char*filename)
815 f = open(filename,O_RDONLY|O_BINARY);
817 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
818 font = (SWFFONT*)malloc(sizeof(SWFFONT));
819 memset(font, 0, sizeof(SWFFONT));
820 dictionary_put2(&fonts, name, font);
824 if (swf_ReadSWF(f,&swf)>=0) {
825 swf_FontExtract(&swf, 0x4e46, &font);
830 syntaxerror("File \"%s\" isn't a valid rfxswf font file", filename);
835 /* fix the layout. Only needed for old fonts */
837 for(t=0;t<font->numchars;t++) {
838 font->glyph[t].advance = 0;
841 swf_FontCreateLayout(font);
845 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
846 swf_FontSetDefine2(tag, font);
849 if(dictionary_lookup(&fonts, name))
850 syntaxerror("font %s defined twice", name);
851 dictionary_put2(&fonts, name, font);
856 typedef struct _sound_t
862 void s_sound(char*name, char*filename)
864 struct WAV wav, wav2;
869 if(!readWAV(filename, &wav)) {
870 warning("Couldn't read wav file \"%s\"", filename);
874 convertWAV2mono(&wav, &wav2, 44100);
875 samples = (U16*)wav2.data;
876 numsamples = wav2.size/2;
880 tag = swf_InsertTag(tag, ST_DEFINESOUND);
881 swf_SetU16(tag, id); //id
882 swf_SetSoundDefine(tag, samples, numsamples);
884 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
888 if(dictionary_lookup(&sounds, name))
889 syntaxerror("sound %s defined twice", name);
890 dictionary_put2(&sounds, name, sound);
898 static char* gradient_getToken(const char**p)
902 while(**p && strchr(" \t\n\r", **p)) {
906 while(**p && !strchr(" \t\n\r", **p)) {
909 result = malloc((*p)-start+1);
910 memcpy(result,start,(*p)-start+1);
911 result[(*p)-start] = 0;
915 float parsePercent(char*str);
916 RGBA parseColor(char*str);
918 GRADIENT parseGradient(const char*str)
922 memset(&gradient, 0, sizeof(GRADIENT));
924 char*posstr,*colorstr;
925 posstr = gradient_getToken(&p);
928 float pos = parsePercent(posstr);
929 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
930 colorstr = gradient_getToken(&p);
931 RGBA color = parseColor(colorstr);
932 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
933 warning("gradient record too big- max size is 8, rest ignored");
936 gradient.ratios[gradient.num] = (int)(pos*255.0);
937 gradient.rgba[gradient.num] = color;
945 void s_gradient(char*name, const char*text, int radial)
947 gradient_t* gradient;
948 gradient = malloc(sizeof(gradient_t));
949 memset(gradient, 0, sizeof(gradient_t));
950 gradient->gradient = parseGradient(text);
951 gradient->radial = radial;
953 if(dictionary_lookup(&gradients, name))
954 syntaxerror("gradient %s defined twice", name);
955 dictionary_put2(&gradients, name, gradient);
958 void s_outline(char*name, char*format, char*source)
967 swf_DrawerInit(&draw, 0);
968 swf_DrawString(&draw, source);
969 swf_DrawerFinish(&draw);
970 shape = swf_DrawerToShape(&draw);
971 shape2 = swf_ShapeToShape2(shape);
972 bounds = swf_GetShapeBoundingBox(shape2);
973 //swf_Shape2Free(shape2);
975 outline = (outline_t*)malloc(sizeof(outline_t));
976 memset(outline, 0, sizeof(outline_t));
977 outline->shape = shape;
978 outline->bbox = bounds;
980 if(dictionary_lookup(&outlines, name))
981 syntaxerror("outline %s defined twice", name);
982 dictionary_put2(&outlines, name, outline);
985 void s_playsound(char*name, int loops, int nomultiple, int stop)
987 sound_t* sound = dictionary_lookup(&sounds, name);
990 syntaxerror("Don't know anything about sound \"%s\"", name);
992 tag = swf_InsertTag(tag, ST_STARTSOUND);
993 swf_SetU16(tag, sound->id); //id
994 memset(&info, 0, sizeof(info));
997 info.nomultiple = nomultiple;
998 swf_SetSoundInfo(tag, &info);
1001 void s_includeswf(char*name, char*filename)
1009 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1010 f = open(filename,O_RDONLY);
1012 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1013 s_box(name, 0, 0, black, 20, 0);
1016 if (swf_ReadSWF(f,&swf)<0) {
1017 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1018 s_box(name, 0, 0, black, 20, 0);
1023 /* FIXME: The following sets the bounding Box for the character.
1024 It is wrong for two reasons:
1025 a) It may be too small (in case objects in the movie clip at the borders)
1026 b) it may be too big (because the poor movie never got autocropped)
1030 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1031 swf_SetU16(tag, id);
1034 swf_Relocate(&swf, idmap);
1036 ftag = swf.firstTag;
1040 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1041 if(cutout[t] == ftag->id) {
1045 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1047 if(ftag->id == ST_END)
1051 /* We simply dump all tags right after the sprite
1052 header, relying on the fact that swf_OptimizeTagOrder() will
1053 sort things out for us later.
1054 We also rely on the fact that the imported SWF is well-formed.
1056 tag = swf_InsertTag(tag, ftag->id);
1057 swf_SetBlock(tag, ftag->data, ftag->len);
1061 syntaxerror("Included file %s contains errors", filename);
1062 tag = swf_InsertTag(tag, ST_END);
1066 s_addcharacter(name, id, tag, r);
1069 SRECT s_getCharBBox(char*name)
1071 character_t* c = dictionary_lookup(&characters, name);
1072 if(!c) syntaxerror("character '%s' unknown(2)", name);
1075 SRECT s_getInstanceBBox(char*name)
1077 instance_t * i = dictionary_lookup(&instances, name);
1079 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1081 if(!c) syntaxerror("internal error(5)");
1084 parameters_t s_getParameters(char*name)
1086 instance_t * i = dictionary_lookup(&instances, name);
1087 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1088 return i->parameters;
1090 void s_startclip(char*instance, char*character, parameters_t p)
1092 character_t* c = dictionary_lookup(&characters, character);
1096 syntaxerror("character %s not known", character);
1098 i = s_addinstance(instance, c, currentdepth);
1100 m = s_instancepos(i, &p);
1102 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1103 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1104 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1106 i->lastFrame= currentframe;
1108 stack[stackpos].tag = tag;
1109 stack[stackpos].type = 2;
1118 swf_SetTagPos(stack[stackpos].tag, 0);
1119 swf_GetPlaceObject(stack[stackpos].tag, &p);
1120 p.clipdepth = currentdepth;
1121 swf_ClearTag(stack[stackpos].tag);
1122 swf_SetPlaceObject(stack[stackpos].tag, &p);
1126 void s_put(char*instance, char*character, parameters_t p)
1128 character_t* c = dictionary_lookup(&characters, character);
1132 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1135 i = s_addinstance(instance, c, currentdepth);
1137 m = s_instancepos(i, &p);
1139 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1140 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1142 i->lastFrame = currentframe;
1146 void s_jump(char*instance, parameters_t p)
1148 instance_t* i = dictionary_lookup(&instances, instance);
1151 syntaxerror("instance %s not known", instance);
1155 m = s_instancepos(i, &p);
1157 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1158 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1160 i->lastFrame = currentframe;
1163 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1167 if(num==0 || num==1)
1169 ratio = (float)pos/(float)num;
1171 p.x = (p2->x-p1->x)*ratio + p1->x;
1172 p.y = (p2->y-p1->y)*ratio + p1->y;
1173 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1174 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1175 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1176 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1178 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1179 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1180 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1181 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1183 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1184 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1185 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1186 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1188 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1189 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1190 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1191 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1195 void s_change(char*instance, parameters_t p2)
1197 instance_t* i = dictionary_lookup(&instances, instance);
1201 int frame, allframes;
1203 syntaxerror("instance %s not known", instance);
1207 allframes = currentframe - i->lastFrame - 1;
1209 warning(".change ignored. can only .put/.change an object once per frame.");
1213 m = s_instancepos(i, &p2);
1214 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1215 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1218 /* o.k., we got the start and end point set. Now iterate though all the
1219 tags in between, inserting object changes after each new frame */
1222 if(!t) syntaxerror("internal error(6)");
1224 while(frame < allframes) {
1225 if(t->id == ST_SHOWFRAME) {
1230 p = s_interpolate(&p1, &p2, frame, allframes);
1231 m = s_instancepos(i, &p); //needed?
1232 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1233 i->lastFrame = currentframe;
1234 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1236 if(frame == allframes)
1241 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1245 void s_delinstance(char*instance)
1247 instance_t* i = dictionary_lookup(&instances, instance);
1249 syntaxerror("instance %s not known", instance);
1251 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1252 swf_SetU16(tag, i->depth);
1253 dictionary_del(&instances, instance);
1256 void s_qchange(char*instance, parameters_t p)
1263 syntaxerror(".end unexpected");
1264 if(stack[stackpos-1].type == 0)
1266 else if(stack[stackpos-1].type == 1)
1268 else if(stack[stackpos-1].type == 2)
1270 else syntaxerror("internal error 1");
1273 // ------------------------------------------------------------------------
1275 typedef int command_func_t(map_t*args);
1277 SRECT parseBox(char*str)
1280 float xmin, xmax, ymin, ymax;
1281 char*x = strchr(str, 'x');
1283 if(!strcmp(str, "autocrop")) {
1284 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1288 d1 = strchr(x+1, ':');
1290 d2 = strchr(d1+1, ':');
1292 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1296 else if(d1 && !d2) {
1297 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1303 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1308 r.xmin = (SCOORD)(xmin*20);
1309 r.ymin = (SCOORD)(ymin*20);
1310 r.xmax = (SCOORD)(xmax*20);
1311 r.ymax = (SCOORD)(ymax*20);
1314 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1317 float parseFloat(char*str)
1321 int parseInt(char*str)
1326 if(str[0]=='+' || str[0]=='-')
1330 if(str[t]<'0' || str[t]>'9')
1331 syntaxerror("Not an Integer: \"%s\"", str);
1334 int parseTwip(char*str)
1338 if(str[0]=='+' || str[0]=='-') {
1343 dot = strchr(str, '.');
1347 return sign*parseInt(str)*20;
1349 int l=strlen(++dot);
1351 for(s=str;s<dot-1;s++)
1352 if(*s<'0' || *s>'9')
1353 syntaxerror("Not a coordinate: \"%s\"", str);
1355 if(*s<'0' || *s>'9')
1356 syntaxerror("Not a coordinate: \"%s\"", str);
1358 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1359 warning("precision loss: %s converted to twip", str);
1364 return sign*atoi(str)*20;
1366 return sign*atoi(str)*20+atoi(dot)*2;
1368 return sign*atoi(str)*20+atoi(dot)/5;
1373 int isPoint(char*str)
1375 if(strchr(str, '('))
1381 SPOINT parsePoint(char*str)
1385 int l = strlen(str);
1386 char*comma = strchr(str, ',');
1387 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1388 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1389 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1390 p.x = parseTwip(tmp);
1391 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1392 p.y = parseTwip(tmp);
1396 int parseColor2(char*str, RGBA*color)
1398 int l = strlen(str);
1402 struct {unsigned char r,g,b;char*name;} colors[] =
1403 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1404 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1405 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1406 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1407 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1408 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1409 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1410 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1411 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1412 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1413 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1414 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1418 if(str[0]=='#' && (l==7 || l==9)) {
1419 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1421 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1423 color->r = r; color->g = g; color->b = b; color->a = a;
1426 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1427 if(!strcmp(str, colors[t].name)) {
1432 color->r = r; color->g = g; color->b = b; color->a = a;
1438 RGBA parseColor(char*str)
1441 if(!parseColor2(str, &c))
1442 syntaxerror("Expression '%s' is not a color", str);
1446 typedef struct _muladd {
1451 MULADD parseMulAdd(char*str)
1454 char* str2 = (char*)malloc(strlen(str)+5);
1461 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1462 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1463 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1464 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1465 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1466 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1467 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1468 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1469 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1470 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1472 syntaxerror("'%s' is not a valid color transform expression", str);
1474 m.add = (int)(add*256);
1475 m.mul = (int)(mul*256);
1480 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1482 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1483 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1485 if(a<-32768) a=-32768;
1486 if(a>32767) a=32767;
1487 if(m<-32768) m=-32768;
1488 if(m>32767) m=32767;
1494 float parsePercent(char*str)
1496 int l = strlen(str);
1500 return atoi(str)/100.0;
1502 syntaxerror("Expression '%s' is not a percentage", str);
1505 int isPercent(char*str)
1507 return str[strlen(str)-1]=='%';
1509 int parseNewSize(char*str, int size)
1512 return parsePercent(str)*size;
1514 return (int)(atof(str)*20);
1517 int isColor(char*str)
1520 return parseColor2(str, &c);
1523 static char* lu(map_t* args, char*name)
1525 char* value = map_lookup(args, name);
1527 map_dump(args, stdout, "");
1528 syntaxerror("internal error 2: value %s should be set", name);
1533 static int c_flash(map_t*args)
1535 char* name = lu(args, "name");
1536 char* compressstr = lu(args, "compress");
1537 SRECT bbox = parseBox(lu(args, "bbox"));
1538 int version = parseInt(lu(args, "version"));
1539 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1541 RGBA color = parseColor(lu(args, "background"));
1542 if(!strcmp(name, "!default!") || override_outputname)
1545 if(!strcmp(compressstr, "default"))
1546 compress = version==6;
1547 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1549 else if(!strcmp(compressstr, "no"))
1551 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1553 s_swf(name, bbox, version, fps, compress, color);
1556 int isRelative(char*str)
1558 return !strncmp(str, "<plus>", 6) ||
1559 !strncmp(str, "<minus>", 7);
1561 char* getOffset(char*str)
1563 if(!strncmp(str, "<plus>", 6))
1565 if(!strncmp(str, "<minus>", 7))
1567 syntaxerror("internal error (347)");
1570 int getSign(char*str)
1572 if(!strncmp(str, "<plus>", 6))
1574 if(!strncmp(str, "<minus>", 7))
1576 syntaxerror("internal error (348)");
1579 static dictionary_t points;
1580 static mem_t mpoints;
1581 int points_initialized = 0;
1583 SPOINT getPoint(SRECT r, char*name)
1586 if(!strcmp(name, "center")) {
1588 p.x = (r.xmin + r.xmax)/2;
1589 p.y = (r.ymin + r.ymax)/2;
1593 if(points_initialized)
1594 l = (int)dictionary_lookup(&points, name);
1596 syntaxerror("Invalid point: \"%s\".", name);
1599 return *(SPOINT*)&mpoints.buffer[l];
1601 static int c_gradient(map_t*args)
1603 char*name = lu(args, "name");
1604 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1608 syntaxerror("colon (:) expected");
1610 s_gradient(name, text, radial);
1613 static int c_point(map_t*args)
1615 char*name = lu(args, "name");
1619 if(!points_initialized) {
1620 dictionary_init(&points);
1622 points_initialized = 1;
1624 p.x = parseTwip(lu(args, "x"));
1625 p.y = parseTwip(lu(args, "y"));
1626 pos = mem_put(&mpoints, &p, sizeof(p));
1627 string_set(&s1, name);
1629 dictionary_put(&points, s1, (void*)pos);
1632 static int c_play(map_t*args)
1634 char*name = lu(args, "sound");
1635 char*loop = lu(args, "loop");
1636 char*nomultiple = lu(args, "nomultiple");
1638 if(!strcmp(nomultiple, "nomultiple"))
1641 nm = parseInt(nomultiple);
1643 s_playsound(name, parseInt(loop), nm, 0);
1647 static int c_stop(map_t*args)
1649 char*name = lu(args, "sound");
1650 s_playsound(name, 0,0,1);
1654 static int c_placement(map_t*args, int type)
1656 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1659 char* luminancestr = lu(args, "luminance");
1660 char* scalestr = lu(args, "scale");
1661 char* scalexstr = lu(args, "scalex");
1662 char* scaleystr = lu(args, "scaley");
1663 char* rotatestr = lu(args, "rotate");
1664 char* shearstr = lu(args, "shear");
1665 char* xstr="", *pivotstr="";
1666 char* ystr="", *anglestr="";
1667 char*above = lu(args, "above"); /*FIXME*/
1668 char*below = lu(args, "below");
1669 char* rstr = lu(args, "red");
1670 char* gstr = lu(args, "green");
1671 char* bstr = lu(args, "blue");
1672 char* astr = lu(args, "alpha");
1673 char* pinstr = lu(args, "pin");
1682 pivotstr = lu(args, "pivot");
1683 anglestr = lu(args, "angle");
1685 xstr = lu(args, "x");
1686 ystr = lu(args, "y");
1689 luminance = parseMulAdd(luminancestr);
1692 luminance.mul = 256;
1696 if(scalexstr[0]||scaleystr[0])
1697 syntaxerror("scalex/scaley and scale cannot both be set");
1698 scalexstr = scaleystr = scalestr;
1701 if(type == 0 || type == 4) {
1703 character = lu(args, "character");
1704 parameters_clear(&p);
1706 p = s_getParameters(instance);
1711 if(isRelative(xstr)) {
1712 if(type == 0 || type == 4)
1713 syntaxerror("relative x values not allowed for initial put or startclip");
1714 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
1716 p.x = parseTwip(xstr);
1720 if(isRelative(ystr)) {
1721 if(type == 0 || type == 4)
1722 syntaxerror("relative y values not allowed for initial put or startclip");
1723 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
1725 p.y = parseTwip(ystr);
1729 /* scale, scalex, scaley */
1731 oldbbox = s_getCharBBox(character);
1733 oldbbox = s_getInstanceBBox(instance);
1735 oldwidth = oldbbox.xmax - oldbbox.xmin;
1736 oldheight = oldbbox.ymax - oldbbox.ymin;
1738 if(oldwidth==0) p.scalex = 1.0;
1741 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
1745 if(oldheight==0) p.scaley = 1.0;
1748 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
1754 if(isRelative(rotatestr)) {
1755 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
1757 p.rotate = parseFloat(rotatestr);
1763 if(isRelative(shearstr)) {
1764 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
1766 p.shear = parseFloat(shearstr);
1771 if(isPoint(pivotstr))
1772 p.pivot = parsePoint(pivotstr);
1774 p.pivot = getPoint(oldbbox, pivotstr);
1778 p.pin = parsePoint(pinstr);
1780 p.pin = getPoint(oldbbox, pinstr);
1783 /* color transform */
1785 if(rstr[0] || luminancestr[0]) {
1788 r = parseMulAdd(rstr);
1790 r.add = p.cxform.r0;
1791 r.mul = p.cxform.r1;
1793 r = mergeMulAdd(r, luminance);
1794 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
1796 if(gstr[0] || luminancestr[0]) {
1799 g = parseMulAdd(gstr);
1801 g.add = p.cxform.g0;
1802 g.mul = p.cxform.g1;
1804 g = mergeMulAdd(g, luminance);
1805 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
1807 if(bstr[0] || luminancestr[0]) {
1810 b = parseMulAdd(bstr);
1812 b.add = p.cxform.b0;
1813 b.mul = p.cxform.b1;
1815 b = mergeMulAdd(b, luminance);
1816 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
1819 MULADD a = parseMulAdd(astr);
1820 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
1824 s_put(instance, character, p);
1826 s_change(instance, p);
1828 s_qchange(instance, p);
1830 s_jump(instance, p);
1832 s_startclip(instance, character, p);
1835 static int c_put(map_t*args)
1837 c_placement(args, 0);
1840 static int c_change(map_t*args)
1842 c_placement(args, 1);
1845 static int c_qchange(map_t*args)
1847 c_placement(args, 2);
1850 static int c_arcchange(map_t*args)
1852 c_placement(args, 2);
1855 static int c_jump(map_t*args)
1857 c_placement(args, 3);
1860 static int c_startclip(map_t*args)
1862 c_placement(args, 4);
1865 static int c_del(map_t*args)
1867 char*instance = lu(args, "name");
1868 s_delinstance(instance);
1871 static int c_end(map_t*args)
1876 static int c_sprite(map_t*args)
1878 char* name = lu(args, "name");
1882 static int c_frame(map_t*args)
1884 char*framestr = lu(args, "n");
1885 char*cutstr = lu(args, "cut");
1888 if(strcmp(cutstr, "no"))
1890 if(isRelative(framestr)) {
1891 frame = s_getframe();
1892 if(getSign(framestr)<0)
1893 syntaxerror("relative frame expressions must be positive");
1894 frame += parseInt(getOffset(framestr));
1897 frame = parseInt(framestr);
1898 if(s_getframe() >= frame
1899 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
1900 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
1902 s_frame(frame, cut);
1905 static int c_primitive(map_t*args)
1907 char*name = lu(args, "name");
1908 char*command = lu(args, "commandname");
1909 int width=0, height=0, r=0;
1910 int linewidth = parseTwip(lu(args, "line"));
1911 char*colorstr = lu(args, "color");
1912 RGBA color = parseColor(colorstr);
1913 char*fillstr = lu(args, "fill");
1920 if(!strcmp(command, "circle"))
1922 else if(!strcmp(command, "filled"))
1926 width = parseTwip(lu(args, "width"));
1927 height = parseTwip(lu(args, "height"));
1928 } else if (type==1) {
1929 r = parseTwip(lu(args, "r"));
1930 } else if (type==2) {
1931 outline = lu(args, "outline");
1934 if(!strcmp(fillstr, "fill"))
1936 if(!strcmp(fillstr, "none"))
1938 if(width<0 || height<0 || linewidth<0 || r<0)
1939 syntaxerror("values width, height, line, r must be positive");
1941 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
1942 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
1943 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
1947 static int c_textshape(map_t*args)
1949 char*name = lu(args, "name");
1950 char*text = lu(args, "text");
1951 char*font = lu(args, "font");
1953 s_textshape(name, font, text);
1959 static int c_swf(map_t*args)
1961 char*name = lu(args, "name");
1962 char*filename = lu(args, "filename");
1963 char*command = lu(args, "commandname");
1964 if(!strcmp(command, "shape"))
1965 warning("Please use .swf instead of .shape");
1966 s_includeswf(name, filename);
1970 static int c_font(map_t*args)
1972 char*name = lu(args, "name");
1973 char*filename = lu(args, "filename");
1974 s_font(name, filename);
1978 static int c_sound(map_t*args)
1980 char*name = lu(args, "name");
1981 char*filename = lu(args, "filename");
1982 s_sound(name, filename);
1986 static int c_text(map_t*args)
1988 char*name = lu(args, "name");
1989 char*text = lu(args, "text");
1990 char*font = lu(args, "font");
1991 float size = parsePercent(lu(args, "size"));
1992 RGBA color = parseColor(lu(args, "color"));
1993 s_text(name, font, text, (int)(size*100), color);
1997 static int c_soundtrack(map_t*args)
2002 static int c_image(map_t*args)
2004 char*command = lu(args, "commandname");
2005 char*name = lu(args, "name");
2006 char*filename = lu(args, "filename");
2007 if(!strcmp(command,"jpeg")) {
2008 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2009 s_image(name, "jpeg", filename, quality);
2011 s_image(name, "png", filename, 0);
2016 static int c_outline(map_t*args)
2018 char*name = lu(args, "name");
2019 char*format = lu(args, "format");
2023 syntaxerror("colon (:) expected");
2025 s_outline(name, format, text);
2029 int fakechar(map_t*args)
2031 char*name = lu(args, "name");
2032 s_box(name, 0, 0, black, 20, 0);
2036 static int c_egon(map_t*args) {return fakechar(args);}
2037 static int c_button(map_t*args) {return fakechar(args);}
2038 static int c_edittext(map_t*args) {return fakechar(args);}
2040 static int c_morphshape(map_t*args) {return fakechar(args);}
2041 static int c_movie(map_t*args) {return fakechar(args);}
2043 static int c_buttonsounds(map_t*args) {return 0;}
2044 static int c_buttonput(map_t*args) {return 0;}
2045 static int c_texture(map_t*args) {return 0;}
2046 static int c_action(map_t*args) {return 0;}
2050 command_func_t* func;
2053 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2054 {"frame", c_frame, "n=<plus>1 @cut=no"},
2055 // "import" type stuff
2056 {"swf", c_swf, "name filename"},
2057 {"shape", c_swf, "name filename"},
2058 {"jpeg", c_image, "name filename quality=80%"},
2059 {"png", c_image, "name filename"},
2060 {"movie", c_movie, "name filename"},
2061 {"sound", c_sound, "name filename"},
2062 {"font", c_font, "name filename"},
2063 {"soundtrack", c_soundtrack, "filename"},
2065 // generators of primitives
2067 {"point", c_point, "name x=0 y=0"},
2068 {"gradient", c_gradient, "name @radial=0"},
2069 {"outline", c_outline, "name format=simple"},
2070 {"textshape", c_textshape, "name text font"},
2072 // character generators
2073 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2074 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2075 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2077 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2078 {"button", c_button, "name shape over=*shape press=*shape area=*shape"},
2079 {"text", c_text, "name text font size=100% color=white"},
2080 {"edittext", c_edittext, "name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2081 {"morphshape", c_morphshape, "name start end"},
2083 {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
2086 {"play", c_play, "sound loop=0 @nomultiple=0"},
2087 {"stop", c_stop, "sound"},
2089 // object placement tags
2090 {"put", c_put, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
2091 {"startclip", c_startclip, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
2092 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
2093 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
2094 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
2095 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
2096 {"del", c_del, "name"},
2097 // virtual object placement
2098 {"buttonput", c_buttonput, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex=100% scaley=100% shear=0 rotate=0 above= below="},
2099 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2101 // commands which start a block
2102 //startclip (see above)
2103 {"sprite", c_sprite, "name"},
2104 {"action", c_action, ""},
2110 static map_t parseArguments(char*command, char*pattern)
2126 string_set(&t1, "commandname");
2127 string_set(&t2, command);
2128 map_put(&result, t1, t2);
2130 if(!pattern || !*pattern)
2137 if(!strncmp("<i> ", x, 3)) {
2139 if(type == COMMAND || type == RAWDATA) {
2141 syntaxerror("character name expected");
2143 name[pos].str = "instance";
2145 value[pos].str = text;
2146 value[pos].len = strlen(text);
2150 if(type == ASSIGNMENT)
2153 name[pos].str = "character";
2155 value[pos].str = text;
2156 value[pos].len = strlen(text);
2164 isboolean[pos] = (x[0] =='@');
2177 name[pos].len = d-x;
2182 name[pos].len = e-x;
2183 value[pos].str = e+1;
2184 value[pos].len = d-e-1;
2192 /* for(t=0;t<len;t++) {
2193 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2194 isboolean[t]?"(boolean)":"");
2199 if(type == RAWDATA || type == COMMAND) {
2204 // first, search for boolean arguments
2205 for(pos=0;pos<len;pos++)
2207 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2209 if(type == ASSIGNMENT)
2211 value[pos].str = text;
2212 value[pos].len = strlen(text);
2213 /*printf("setting boolean parameter %s (to %s)\n",
2214 strdup_n(name[pos], namelen[pos]),
2215 strdup_n(value[pos], valuelen[pos]));*/
2220 // second, search for normal arguments
2222 for(pos=0;pos<len;pos++)
2224 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2225 (type != ASSIGNMENT && !set[pos])) {
2227 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2229 if(type == ASSIGNMENT)
2232 value[pos].str = text;
2233 value[pos].len = strlen(text);
2235 printf("setting parameter %s (to %s)\n",
2236 strdup_n(name[pos].str, name[pos].len),
2237 strdup_n(value[pos].str, value[pos].len));
2243 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
2247 for(t=0;t<len;t++) {
2248 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2251 for(t=0;t<len;t++) {
2252 if(value[t].str && value[t].str[0] == '*') {
2253 //relative default- take value from some other parameter
2255 for(s=0;s<len;s++) {
2256 if(value[s].len == value[t].len-1 &&
2257 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2258 value[t].str = value[s].str;
2261 if(value[t].str == 0) {
2263 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2267 /* ok, now construct the dictionary from the parameters */
2271 map_put(&result, name[t], value[t]);
2275 static void parseArgumentsForCommand(char*command)
2280 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2281 if(!strcmp(arguments[t].command, command)) {
2283 /* ugly hack- will be removed soon (once documentation and .sc generating
2284 utilities have been changed) */
2285 if(!strcmp(command, "swf") && !stackpos) {
2286 warning("Please use .flash instead of .swf- this will be mandatory soon");
2291 args = parseArguments(command, arguments[t].arguments);
2297 syntaxerror("command %s not known", command);
2300 printf(".%s\n", command);fflush(stdout);
2301 map_dump(&args, stdout, "\t");fflush(stdout);
2304 (*arguments[nr].func)(&args);
2306 if(!strcmp(command, "button") ||
2307 !strcmp(command, "action")) {
2310 if(type == COMMAND) {
2311 if(!strcmp(text, "end"))
2325 int main (int argc,char ** argv)
2328 processargs(argc, argv);
2329 initLog(0,-1,0,0,-1,verbose);
2332 args_callback_usage(argv[0]);
2335 file = generateTokens(filename);
2337 printf("parser returned error.\n");
2344 while(!noMoreTokens()) {
2347 syntaxerror("command expected");
2348 parseArgumentsForCommand(text);