2 Compiles swf code (.sc) files into .swf files.
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/drawer.h"
32 #include "../lib/log.h"
33 #include "../lib/args.h"
40 static char * filename = 0;
41 static char * outputname = "output.swf";
42 static int verbose = 2;
43 static int override_outputname = 0;
45 static struct options_t options[] = {
53 int args_callback_option(char*name,char*val)
55 if(!strcmp(name, "V")) {
56 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
59 else if(!strcmp(name, "o")) {
61 override_outputname = 1;
64 else if(!strcmp(name, "v")) {
69 printf("Unknown option: -%s\n", name);
74 int args_callback_longoption(char*name,char*val)
76 return args_long2shortoption(options, name, val);
78 void args_callback_usage(char *name)
81 printf("Usage: %s [-o file.swf] file.sc\n", name);
83 printf("-h , --help Print short help message and exit\n");
84 printf("-V , --version Print version info and exit\n");
85 printf("-v , --verbose Increase verbosity. \n");
86 printf("-o , --output <filename> Set output file to <filename>.\n");
89 int args_callback_command(char*name,char*val)
92 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
99 static struct token_t* file;
108 static void syntaxerror(char*format, ...)
112 va_start(arglist, format);
113 vsprintf(buf, format, arglist);
115 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
119 static void warning(char*format, ...)
123 va_start(arglist, format);
124 vsprintf(buf, format, arglist);
126 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
129 static void readToken()
131 type = file[pos].type;
133 syntaxerror("unexpected end of file");
135 text = file[pos].text;
136 textlen = strlen(text);
137 line = file[pos].line;
138 column = file[pos].column;
140 //printf("---> %d(%s) %s\n", type, type_names[type], text);
143 static void pushBack()
146 if(!pos) syntaxerror("internal error 3");
151 textlen = strlen(text);
154 column = file[p].column;
157 static int noMoreTokens()
159 if(file[pos].type == END)
164 // ------------------------------ swf routines ----------------------------
168 int type; //0=swf, 1=sprite, 2=clip
174 /* for sprites (1): */
180 dictionary_t oldinstances;
185 static int stackpos = 0;
187 static dictionary_t characters;
188 static dictionary_t images;
189 static dictionary_t outlines;
190 static dictionary_t gradients;
191 static char idmap[65536];
192 static TAG*tag = 0; //current tag
194 static int id; //current character id
195 static int currentframe; //current frame in current level
196 static SRECT currentrect; //current bounding box in current level
197 static U16 currentdepth;
198 static dictionary_t instances;
199 static dictionary_t fonts;
200 static dictionary_t sounds;
202 typedef struct _parameters {
204 float scalex, scaley;
212 typedef struct _character {
218 typedef struct _instance {
219 character_t*character;
221 parameters_t parameters;
222 TAG* lastTag; //last tag which set the object
223 U16 lastFrame; //frame lastTag is in
226 typedef struct _outline {
231 typedef struct _gradient {
236 static void character_init(character_t*c)
238 memset(c, 0, sizeof(character_t));
240 static character_t* character_new()
243 c = (character_t*)malloc(sizeof(character_t));
247 static void instance_init(instance_t*i)
249 memset(i, 0, sizeof(instance_t));
251 static instance_t* instance_new()
254 c = (instance_t*)malloc(sizeof(instance_t));
259 static void incrementid()
263 syntaxerror("Out of character ids.");
268 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
270 character_t* c = character_new();
272 c->definingTag = ctag;
275 if(dictionary_lookup(&characters, name))
276 syntaxerror("character %s defined twice", name);
277 dictionary_put2(&characters, name, c);
279 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
281 swf_SetString(tag, name);
282 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
285 swf_SetString(tag, name);
287 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
289 character_t* c = character_new();
290 c->definingTag = ctag;
294 if(dictionary_lookup(&images, name))
295 syntaxerror("image %s defined twice", name);
296 dictionary_put2(&images, name, c);
298 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
300 instance_t* i = instance_new();
303 //swf_GetMatrix(0, &i->matrix);
304 if(dictionary_lookup(&instances, name))
305 syntaxerror("object %s defined twice", name);
306 dictionary_put2(&instances, name, i);
310 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)
313 p->scalex = scalex; p->scaley = scaley;
314 p->pin = pin; p->pivot = pivot;
315 p->rotate = rotate; p->cxform = cxform;
319 static void parameters_clear(parameters_t*p)
322 p->scalex = 1.0; p->scaley = 1.0;
323 p->pin.x = 1; p->pin.y = 0;
324 p->pivot.x = 0; p->pivot.y = 0;
327 swf_GetCXForm(0, &p->cxform, 1);
330 static void makeMatrix(MATRIX*m, parameters_t*p)
339 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
340 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
341 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
342 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
344 m->sx = (int)(sx*65536+0.5);
345 m->r1 = (int)(r1*65536+0.5);
346 m->r0 = (int)(r0*65536+0.5);
347 m->sy = (int)(sy*65536+0.5);
351 h = swf_TurnPoint(p->pin, m);
356 static MATRIX s_instancepos(instance_t*i, parameters_t*p)
361 r = swf_TurnRect(i->character->size, &m);
362 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
363 currentrect.xmax == 0 && currentrect.ymax == 0)
366 swf_ExpandRect2(¤trect, &r);
370 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
372 SWF*swf = (SWF*)malloc(sizeof(SWF));
375 syntaxerror(".swf blocks can't be nested");
377 memset(swf, 0, sizeof(swf));
378 swf->fileVersion = version;
380 swf->frameRate = fps;
381 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
382 swf->compressed = compress;
383 swf_SetRGB(tag,&background);
385 if(stackpos==sizeof(stack)/sizeof(stack[0]))
386 syntaxerror("too many levels of recursion");
388 dictionary_init(&characters);
389 dictionary_init(&images);
390 dictionary_init(&outlines);
391 dictionary_init(&gradients);
392 dictionary_init(&instances);
393 dictionary_init(&fonts);
394 dictionary_init(&sounds);
396 memset(&stack[stackpos], 0, sizeof(stack[0]));
397 stack[stackpos].type = 0;
398 stack[stackpos].filename = strdup(name);
399 stack[stackpos].swf = swf;
400 stack[stackpos].oldframe = -1;
405 memset(¤trect, 0, sizeof(currentrect));
408 memset(idmap, 0, sizeof(idmap));
412 void s_sprite(char*name)
414 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
415 swf_SetU16(tag, id); //id
416 swf_SetU16(tag, 0); //frames
418 memset(&stack[stackpos], 0, sizeof(stack[0]));
419 stack[stackpos].type = 1;
420 stack[stackpos].oldframe = currentframe;
421 stack[stackpos].olddepth = currentdepth;
422 stack[stackpos].oldrect = currentrect;
423 stack[stackpos].oldinstances = instances;
424 stack[stackpos].tag = tag;
425 stack[stackpos].id = id;
426 stack[stackpos].name = strdup(name);
428 /* FIXME: those four fields should be bundled together */
429 dictionary_init(&instances);
432 memset(¤trect, 0, sizeof(currentrect));
438 TAG* removeFromTo(TAG*from, TAG*to)
440 TAG*save = from->prev;
442 TAG*next = from->next;
450 static void s_endSprite()
452 SRECT r = currentrect;
454 if(stack[stackpos].cut)
455 tag = removeFromTo(stack[stackpos].cut, tag);
459 /* TODO: before clearing, prepend "<spritename>." to names and
460 copy into old instances dict */
461 dictionary_clear(&instances);
463 currentframe = stack[stackpos].oldframe;
464 currentrect = stack[stackpos].oldrect;
465 currentdepth = stack[stackpos].olddepth;
466 instances = stack[stackpos].oldinstances;
468 tag = swf_InsertTag(tag, ST_END);
470 tag = stack[stackpos].tag;
473 syntaxerror("internal error(7)");
475 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
476 free(stack[stackpos].name);
479 static void s_endSWF()
485 if(stack[stackpos].cut)
486 tag = removeFromTo(stack[stackpos].cut, tag);
490 swf = stack[stackpos].swf;
491 filename = stack[stackpos].filename;
493 //tag = swf_InsertTag(tag, ST_SHOWFRAME); //?
495 tag = swf_InsertTag(tag, ST_END);
497 swf_OptimizeTagOrder(swf);
499 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin))
500 swf->movieSize = currentrect; /* "autocrop" */
502 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
503 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
504 swf->movieSize.ymax += 20;
507 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
509 syntaxerror("couldn't create output file %s", filename);
512 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
514 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
518 dictionary_clear(&instances);
519 dictionary_clear(&characters);
520 dictionary_clear(&images);
521 dictionary_clear(&outlines);
522 dictionary_clear(&gradients);
523 dictionary_clear(&fonts);
524 dictionary_clear(&sounds);
534 if(stack[stackpos-1].type == 0)
535 syntaxerror("End of file encountered in .flash block");
536 if(stack[stackpos-1].type == 1)
537 syntaxerror("End of file encountered in .sprite block");
538 if(stack[stackpos-1].type == 2)
539 syntaxerror("End of file encountered in .clip block");
548 void s_frame(int nr, int cut)
553 for(t=currentframe;t<nr;t++) {
554 tag = swf_InsertTag(tag, ST_SHOWFRAME);
559 syntaxerror("Can't cut, frame empty");
561 stack[stackpos].cut = tag;
567 int parseColor2(char*str, RGBA*color);
569 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
574 if(texture[0] == '#') {
575 parseColor2(texture, &color);
576 return swf_ShapeAddSolidFillStyle(s, &color);
577 } else if((image = dictionary_lookup(&images, texture))) {
579 swf_GetMatrix(0, &m);
580 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
581 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
584 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
585 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
586 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
588 swf_GetMatrix(0, &m);
589 m.sx = (r->xmax - r->xmin)*2;
590 m.sy = (r->ymax - r->ymin)*2;
591 m.tx = r->xmin + (r->xmax - r->xmin)/2;
592 m.ty = r->ymin + (r->ymax - r->ymin)/2;
593 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
594 } else if (parseColor2(texture, &color)) {
595 return swf_ShapeAddSolidFillStyle(s, &color);
597 syntaxerror("not a color/fillstyle: %s", texture);
602 RGBA black={r:0,g:0,b:0,a:0};
603 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
612 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
614 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
617 fs1 = addFillStyle(s, &r2, texture);
620 r.xmin = r2.xmin-linewidth-linewidth/2;
621 r.ymin = r2.ymin-linewidth-linewidth/2;
622 r.xmax = r2.xmax+linewidth+linewidth/2;
623 r.ymax = r2.ymax+linewidth+linewidth/2;
625 swf_SetShapeHeader(tag,s);
626 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
627 swf_ShapeSetLine(tag,s,width,0);
628 swf_ShapeSetLine(tag,s,0,height);
629 swf_ShapeSetLine(tag,s,-width,0);
630 swf_ShapeSetLine(tag,s,0,-height);
631 swf_ShapeSetEnd(tag);
634 s_addcharacter(name, id, tag, r);
638 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
644 outline = dictionary_lookup(&outlines, outlinename);
646 syntaxerror("outline %s not defined", outlinename);
650 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
652 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
654 fs1 = addFillStyle(s, &r2, texture);
656 syntaxerror("non filled outlines not yet supported- please supply a fill=<color/texture> argument");
658 rect.xmin = r2.xmin-linewidth-linewidth/2;
659 rect.ymin = r2.ymin-linewidth-linewidth/2;
660 rect.xmax = r2.xmax+linewidth+linewidth/2;
661 rect.ymax = r2.ymax+linewidth+linewidth/2;
663 swf_SetRect(tag,&rect);
664 swf_SetShapeStyles(tag, s);
665 swf_SetShapeBits(tag, outline->shape); //does not count bits!
666 swf_SetBlock(tag, outline->shape->data, (outline->shape->bitlen+7)/8);
669 s_addcharacter(name, id, tag, rect);
673 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
678 r2.xmin = r2.ymin = 0;
682 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
684 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
686 fs1 = addFillStyle(s, &r2, texture);
688 rect.xmin = r2.xmin-linewidth-linewidth/2;
689 rect.ymin = r2.ymin-linewidth-linewidth/2;
690 rect.xmax = r2.xmax+linewidth+linewidth/2;
691 rect.ymax = r2.ymax+linewidth+linewidth/2;
693 swf_SetRect(tag,&rect);
694 swf_SetShapeHeader(tag,s);
695 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
696 swf_ShapeSetCircle(tag, s, r,r,r,r);
697 swf_ShapeSetEnd(tag);
700 s_addcharacter(name, id, tag, rect);
704 void s_textshape(char*name, char*fontname, char*_text)
707 U8*text = (U8*)_text;
711 font = dictionary_lookup(&fonts, fontname);
713 syntaxerror("font \"%s\" not known!", fontname);
715 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
716 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
717 s_box(name, 0, 0, black, 20, 0);
720 g = font->ascii2glyph[text[0]];
722 outline = malloc(sizeof(outline_t));
723 memset(outline, 0, sizeof(outline_t));
724 outline->shape = font->glyph[g].shape;
725 outline->bbox = font->layout->bounds[g];
729 swf_Shape11DrawerInit(&draw, 0);
730 swf_DrawText(&draw, font, _text);
732 outline->shape = swf_ShapeDrawerToShape(&draw);
733 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
737 if(dictionary_lookup(&outlines, name))
738 syntaxerror("outline %s defined twice", name);
739 dictionary_put2(&outlines, name, outline);
742 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
747 font = dictionary_lookup(&fonts, fontname);
749 syntaxerror("font \"%s\" not known!", fontname);
751 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
753 if(!font->numchars) {
754 s_box(name, 0, 0, black, 20, 0);
757 r = swf_SetDefineText(tag, font, &color, text, size);
759 s_addcharacter(name, id, tag, r);
763 /* type: either "jpeg" or "png"
765 void s_image(char*name, char*type, char*filename, int quality)
767 /* an image is actually two folded: 1st bitmap, 2nd character.
768 Both of them can be used separately */
770 /* step 1: the bitmap */
775 warning("image type \"png\" not supported yet!");
776 s_box(name, 0, 0, black, 20, 0);
781 warning("no jpeg support compiled in");
782 s_box(name, 0, 0, black, 20, 0);
785 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
786 swf_SetU16(tag, imageID);
788 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
789 syntaxerror("Image \"%s\" not found, or contains errors", filename);
792 swf_GetJPEGSize(filename, &width, &height);
799 s_addimage(name, id, tag, r);
804 /* step 2: the character */
805 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
807 swf_ShapeSetBitmapRect(tag, imageID, width, height);
809 s_addcharacter(name, id, tag, r);
813 void dumpSWF(SWF*swf)
815 TAG* tag = swf->firstTag;
816 printf("vvvvvvvvvvvvvvvvvvvvv\n");
818 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
821 printf("^^^^^^^^^^^^^^^^^^^^^\n");
824 void s_font(char*name, char*filename)
827 font = swf_LoadFont(filename);
830 warning("Couldn't open font file \"%s\"", filename);
831 font = (SWFFONT*)malloc(sizeof(SWFFONT));
832 memset(font, 0, sizeof(SWFFONT));
833 dictionary_put2(&fonts, name, font);
839 /* fix the layout. Only needed for old fonts */
841 for(t=0;t<font->numchars;t++) {
842 font->glyph[t].advance = 0;
845 swf_FontCreateLayout(font);
849 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
850 swf_FontSetDefine2(tag, font);
853 if(dictionary_lookup(&fonts, name))
854 syntaxerror("font %s defined twice", name);
855 dictionary_put2(&fonts, name, font);
860 typedef struct _sound_t
866 void s_sound(char*name, char*filename)
868 struct WAV wav, wav2;
873 if(!readWAV(filename, &wav)) {
874 warning("Couldn't read wav file \"%s\"", filename);
878 convertWAV2mono(&wav, &wav2, 44100);
879 samples = (U16*)wav2.data;
880 numsamples = wav2.size/2;
884 tag = swf_InsertTag(tag, ST_DEFINESOUND);
885 swf_SetU16(tag, id); //id
886 swf_SetSoundDefine(tag, samples, numsamples);
888 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
892 if(dictionary_lookup(&sounds, name))
893 syntaxerror("sound %s defined twice", name);
894 dictionary_put2(&sounds, name, sound);
902 static char* gradient_getToken(const char**p)
906 while(**p && strchr(" \t\n\r", **p)) {
910 while(**p && !strchr(" \t\n\r", **p)) {
913 result = malloc((*p)-start+1);
914 memcpy(result,start,(*p)-start+1);
915 result[(*p)-start] = 0;
919 float parsePercent(char*str);
920 RGBA parseColor(char*str);
922 GRADIENT parseGradient(const char*str)
926 memset(&gradient, 0, sizeof(GRADIENT));
928 char*posstr,*colorstr;
931 posstr = gradient_getToken(&p);
934 pos = parsePercent(posstr);
935 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
936 colorstr = gradient_getToken(&p);
937 color = parseColor(colorstr);
938 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
939 warning("gradient record too big- max size is 8, rest ignored");
942 gradient.ratios[gradient.num] = (int)(pos*255.0);
943 gradient.rgba[gradient.num] = color;
951 void s_gradient(char*name, const char*text, int radial)
953 gradient_t* gradient;
954 gradient = malloc(sizeof(gradient_t));
955 memset(gradient, 0, sizeof(gradient_t));
956 gradient->gradient = parseGradient(text);
957 gradient->radial = radial;
959 if(dictionary_lookup(&gradients, name))
960 syntaxerror("gradient %s defined twice", name);
961 dictionary_put2(&gradients, name, gradient);
964 void s_action(const char*text)
967 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
969 syntaxerror("Couldn't compile ActionScript");
972 tag = swf_InsertTag(tag, ST_DOACTION);
974 swf_ActionSet(tag, a);
979 void s_outline(char*name, char*format, char*source)
988 swf_Shape11DrawerInit(&draw, 0);
989 draw_string(&draw, source);
991 shape = swf_ShapeDrawerToShape(&draw);
992 //shape2 = swf_ShapeToShape2(shape);
993 //bounds = swf_GetShapeBoundingBox(shape2);
994 //swf_Shape2Free(shape2);
995 bounds = swf_ShapeDrawerGetBBox(&draw);
998 outline = (outline_t*)malloc(sizeof(outline_t));
999 memset(outline, 0, sizeof(outline_t));
1000 outline->shape = shape;
1001 outline->bbox = bounds;
1003 if(dictionary_lookup(&outlines, name))
1004 syntaxerror("outline %s defined twice", name);
1005 dictionary_put2(&outlines, name, outline);
1008 void s_playsound(char*name, int loops, int nomultiple, int stop)
1010 sound_t* sound = dictionary_lookup(&sounds, name);
1013 syntaxerror("Don't know anything about sound \"%s\"", name);
1015 tag = swf_InsertTag(tag, ST_STARTSOUND);
1016 swf_SetU16(tag, sound->id); //id
1017 memset(&info, 0, sizeof(info));
1020 info.nomultiple = nomultiple;
1021 swf_SetSoundInfo(tag, &info);
1024 void s_includeswf(char*name, char*filename)
1032 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1033 f = open(filename,O_RDONLY);
1035 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1036 s_box(name, 0, 0, black, 20, 0);
1039 if (swf_ReadSWF(f,&swf)<0) {
1040 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1041 s_box(name, 0, 0, black, 20, 0);
1046 /* FIXME: The following sets the bounding Box for the character.
1047 It is wrong for two reasons:
1048 a) It may be too small (in case objects in the movie clip at the borders)
1049 b) it may be too big (because the poor movie never got autocropped)
1053 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1054 swf_SetU16(tag, id);
1057 swf_Relocate(&swf, idmap);
1059 ftag = swf.firstTag;
1063 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1064 if(cutout[t] == ftag->id) {
1068 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1070 if(ftag->id == ST_END)
1074 /* We simply dump all tags right after the sprite
1075 header, relying on the fact that swf_OptimizeTagOrder() will
1076 sort things out for us later.
1077 We also rely on the fact that the imported SWF is well-formed.
1079 tag = swf_InsertTag(tag, ftag->id);
1080 swf_SetBlock(tag, ftag->data, ftag->len);
1084 syntaxerror("Included file %s contains errors", filename);
1085 tag = swf_InsertTag(tag, ST_END);
1089 s_addcharacter(name, id, tag, r);
1092 SRECT s_getCharBBox(char*name)
1094 character_t* c = dictionary_lookup(&characters, name);
1095 if(!c) syntaxerror("character '%s' unknown(2)", name);
1098 SRECT s_getInstanceBBox(char*name)
1100 instance_t * i = dictionary_lookup(&instances, name);
1102 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1104 if(!c) syntaxerror("internal error(5)");
1107 parameters_t s_getParameters(char*name)
1109 instance_t * i = dictionary_lookup(&instances, name);
1110 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1111 return i->parameters;
1113 void s_startclip(char*instance, char*character, parameters_t p)
1115 character_t* c = dictionary_lookup(&characters, character);
1119 syntaxerror("character %s not known", character);
1121 i = s_addinstance(instance, c, currentdepth);
1123 m = s_instancepos(i, &p);
1125 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1126 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1127 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1129 i->lastFrame= currentframe;
1131 stack[stackpos].tag = tag;
1132 stack[stackpos].type = 2;
1141 swf_SetTagPos(stack[stackpos].tag, 0);
1142 swf_GetPlaceObject(stack[stackpos].tag, &p);
1143 p.clipdepth = currentdepth;
1144 swf_ClearTag(stack[stackpos].tag);
1145 swf_SetPlaceObject(stack[stackpos].tag, &p);
1149 void s_put(char*instance, char*character, parameters_t p)
1151 character_t* c = dictionary_lookup(&characters, character);
1155 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1158 i = s_addinstance(instance, c, currentdepth);
1160 m = s_instancepos(i, &p);
1162 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1163 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1165 i->lastFrame = currentframe;
1169 void s_jump(char*instance, parameters_t p)
1171 instance_t* i = dictionary_lookup(&instances, instance);
1174 syntaxerror("instance %s not known", instance);
1178 m = s_instancepos(i, &p);
1180 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1181 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1183 i->lastFrame = currentframe;
1186 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1190 if(num==0 || num==1)
1192 ratio = (float)pos/(float)num;
1194 p.x = (p2->x-p1->x)*ratio + p1->x;
1195 p.y = (p2->y-p1->y)*ratio + p1->y;
1196 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1197 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1198 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1199 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1201 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1202 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1203 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1204 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1206 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1207 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1208 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1209 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1211 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1212 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1213 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1214 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1218 void s_change(char*instance, parameters_t p2)
1220 instance_t* i = dictionary_lookup(&instances, instance);
1224 int frame, allframes;
1226 syntaxerror("instance %s not known", instance);
1230 allframes = currentframe - i->lastFrame - 1;
1232 warning(".change ignored. can only .put/.change an object once per frame.");
1236 m = s_instancepos(i, &p2);
1237 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1238 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1241 /* o.k., we got the start and end point set. Now iterate though all the
1242 tags in between, inserting object changes after each new frame */
1245 if(!t) syntaxerror("internal error(6)");
1247 while(frame < allframes) {
1248 if(t->id == ST_SHOWFRAME) {
1253 p = s_interpolate(&p1, &p2, frame, allframes);
1254 m = s_instancepos(i, &p); //needed?
1255 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1256 i->lastFrame = currentframe;
1257 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1259 if(frame == allframes)
1264 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1268 void s_delinstance(char*instance)
1270 instance_t* i = dictionary_lookup(&instances, instance);
1272 syntaxerror("instance %s not known", instance);
1274 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1275 swf_SetU16(tag, i->depth);
1276 dictionary_del(&instances, instance);
1279 void s_qchange(char*instance, parameters_t p)
1286 syntaxerror(".end unexpected");
1287 if(stack[stackpos-1].type == 0)
1289 else if(stack[stackpos-1].type == 1)
1291 else if(stack[stackpos-1].type == 2)
1293 else syntaxerror("internal error 1");
1296 // ------------------------------------------------------------------------
1298 typedef int command_func_t(map_t*args);
1300 SRECT parseBox(char*str)
1303 float xmin, xmax, ymin, ymax;
1304 char*x = strchr(str, 'x');
1306 if(!strcmp(str, "autocrop")) {
1307 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1311 d1 = strchr(x+1, ':');
1313 d2 = strchr(d1+1, ':');
1315 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1319 else if(d1 && !d2) {
1320 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1326 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1331 r.xmin = (SCOORD)(xmin*20);
1332 r.ymin = (SCOORD)(ymin*20);
1333 r.xmax = (SCOORD)(xmax*20);
1334 r.ymax = (SCOORD)(ymax*20);
1337 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1340 float parseFloat(char*str)
1344 int parseInt(char*str)
1349 if(str[0]=='+' || str[0]=='-')
1353 if(str[t]<'0' || str[t]>'9')
1354 syntaxerror("Not an Integer: \"%s\"", str);
1357 int parseTwip(char*str)
1361 if(str[0]=='+' || str[0]=='-') {
1366 dot = strchr(str, '.');
1370 return sign*parseInt(str)*20;
1372 int l=strlen(++dot);
1374 for(s=str;s<dot-1;s++)
1375 if(*s<'0' || *s>'9')
1376 syntaxerror("Not a coordinate: \"%s\"", str);
1378 if(*s<'0' || *s>'9')
1379 syntaxerror("Not a coordinate: \"%s\"", str);
1381 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1382 warning("precision loss: %s converted to twip", str);
1387 return sign*atoi(str)*20;
1389 return sign*atoi(str)*20+atoi(dot)*2;
1391 return sign*atoi(str)*20+atoi(dot)/5;
1396 int isPoint(char*str)
1398 if(strchr(str, '('))
1404 SPOINT parsePoint(char*str)
1408 int l = strlen(str);
1409 char*comma = strchr(str, ',');
1410 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1411 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1412 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1413 p.x = parseTwip(tmp);
1414 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1415 p.y = parseTwip(tmp);
1419 int parseColor2(char*str, RGBA*color)
1421 int l = strlen(str);
1425 struct {unsigned char r,g,b;char*name;} colors[] =
1426 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1427 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1428 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1429 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1430 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1431 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1432 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1433 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1434 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1435 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1436 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1437 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1441 if(str[0]=='#' && (l==7 || l==9)) {
1442 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1444 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1446 color->r = r; color->g = g; color->b = b; color->a = a;
1449 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1450 if(!strcmp(str, colors[t].name)) {
1455 color->r = r; color->g = g; color->b = b; color->a = a;
1461 RGBA parseColor(char*str)
1464 if(!parseColor2(str, &c))
1465 syntaxerror("Expression '%s' is not a color", str);
1469 typedef struct _muladd {
1474 MULADD parseMulAdd(char*str)
1477 char* str2 = (char*)malloc(strlen(str)+5);
1484 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1485 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1486 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1487 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1488 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1489 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1490 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1491 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1492 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1493 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1495 syntaxerror("'%s' is not a valid color transform expression", str);
1497 m.add = (int)(add*256);
1498 m.mul = (int)(mul*256);
1503 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1505 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1506 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1508 if(a<-32768) a=-32768;
1509 if(a>32767) a=32767;
1510 if(m<-32768) m=-32768;
1511 if(m>32767) m=32767;
1517 float parsePercent(char*str)
1519 int l = strlen(str);
1523 return atoi(str)/100.0;
1525 syntaxerror("Expression '%s' is not a percentage", str);
1528 int isPercent(char*str)
1530 return str[strlen(str)-1]=='%';
1532 int parseNewSize(char*str, int size)
1535 return parsePercent(str)*size;
1537 return (int)(atof(str)*20);
1540 int isColor(char*str)
1543 return parseColor2(str, &c);
1546 static char* lu(map_t* args, char*name)
1548 char* value = map_lookup(args, name);
1550 map_dump(args, stdout, "");
1551 syntaxerror("internal error 2: value %s should be set", name);
1556 static int c_flash(map_t*args)
1558 char* name = lu(args, "name");
1559 char* compressstr = lu(args, "compress");
1560 SRECT bbox = parseBox(lu(args, "bbox"));
1561 int version = parseInt(lu(args, "version"));
1562 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1564 RGBA color = parseColor(lu(args, "background"));
1565 if(!strcmp(name, "!default!") || override_outputname)
1568 if(!strcmp(compressstr, "default"))
1569 compress = version==6;
1570 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1572 else if(!strcmp(compressstr, "no"))
1574 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1576 s_swf(name, bbox, version, fps, compress, color);
1579 int isRelative(char*str)
1581 return !strncmp(str, "<plus>", 6) ||
1582 !strncmp(str, "<minus>", 7);
1584 char* getOffset(char*str)
1586 if(!strncmp(str, "<plus>", 6))
1588 if(!strncmp(str, "<minus>", 7))
1590 syntaxerror("internal error (347)");
1593 int getSign(char*str)
1595 if(!strncmp(str, "<plus>", 6))
1597 if(!strncmp(str, "<minus>", 7))
1599 syntaxerror("internal error (348)");
1602 static dictionary_t points;
1603 static mem_t mpoints;
1604 int points_initialized = 0;
1606 SPOINT getPoint(SRECT r, char*name)
1609 if(!strcmp(name, "center")) {
1611 p.x = (r.xmin + r.xmax)/2;
1612 p.y = (r.ymin + r.ymax)/2;
1616 if(points_initialized)
1617 l = (int)dictionary_lookup(&points, name);
1619 syntaxerror("Invalid point: \"%s\".", name);
1622 return *(SPOINT*)&mpoints.buffer[l];
1624 static int c_gradient(map_t*args)
1626 char*name = lu(args, "name");
1627 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1631 syntaxerror("colon (:) expected");
1633 s_gradient(name, text, radial);
1636 static int c_point(map_t*args)
1638 char*name = lu(args, "name");
1642 if(!points_initialized) {
1643 dictionary_init(&points);
1645 points_initialized = 1;
1647 p.x = parseTwip(lu(args, "x"));
1648 p.y = parseTwip(lu(args, "y"));
1649 pos = mem_put(&mpoints, &p, sizeof(p));
1650 string_set(&s1, name);
1652 dictionary_put(&points, s1, (void*)pos);
1655 static int c_play(map_t*args)
1657 char*name = lu(args, "sound");
1658 char*loop = lu(args, "loop");
1659 char*nomultiple = lu(args, "nomultiple");
1661 if(!strcmp(nomultiple, "nomultiple"))
1664 nm = parseInt(nomultiple);
1666 s_playsound(name, parseInt(loop), nm, 0);
1670 static int c_stop(map_t*args)
1672 char*name = lu(args, "sound");
1673 s_playsound(name, 0,0,1);
1677 static int c_placement(map_t*args, int type)
1679 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1682 char* luminancestr = lu(args, "luminance");
1683 char* scalestr = lu(args, "scale");
1684 char* scalexstr = lu(args, "scalex");
1685 char* scaleystr = lu(args, "scaley");
1686 char* rotatestr = lu(args, "rotate");
1687 char* shearstr = lu(args, "shear");
1688 char* xstr="", *pivotstr="";
1689 char* ystr="", *anglestr="";
1690 char*above = lu(args, "above"); /*FIXME*/
1691 char*below = lu(args, "below");
1692 char* rstr = lu(args, "red");
1693 char* gstr = lu(args, "green");
1694 char* bstr = lu(args, "blue");
1695 char* astr = lu(args, "alpha");
1696 char* pinstr = lu(args, "pin");
1705 pivotstr = lu(args, "pivot");
1706 anglestr = lu(args, "angle");
1708 xstr = lu(args, "x");
1709 ystr = lu(args, "y");
1712 luminance = parseMulAdd(luminancestr);
1715 luminance.mul = 256;
1719 if(scalexstr[0]||scaleystr[0])
1720 syntaxerror("scalex/scaley and scale cannot both be set");
1721 scalexstr = scaleystr = scalestr;
1724 if(type == 0 || type == 4) {
1726 character = lu(args, "character");
1727 parameters_clear(&p);
1729 p = s_getParameters(instance);
1734 if(isRelative(xstr)) {
1735 if(type == 0 || type == 4)
1736 syntaxerror("relative x values not allowed for initial put or startclip");
1737 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
1739 p.x = parseTwip(xstr);
1743 if(isRelative(ystr)) {
1744 if(type == 0 || type == 4)
1745 syntaxerror("relative y values not allowed for initial put or startclip");
1746 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
1748 p.y = parseTwip(ystr);
1752 /* scale, scalex, scaley */
1754 oldbbox = s_getCharBBox(character);
1756 oldbbox = s_getInstanceBBox(instance);
1758 oldwidth = oldbbox.xmax - oldbbox.xmin;
1759 oldheight = oldbbox.ymax - oldbbox.ymin;
1761 if(oldwidth==0) p.scalex = 1.0;
1764 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
1768 if(oldheight==0) p.scaley = 1.0;
1771 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
1777 if(isRelative(rotatestr)) {
1778 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
1780 p.rotate = parseFloat(rotatestr);
1786 if(isRelative(shearstr)) {
1787 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
1789 p.shear = parseFloat(shearstr);
1794 if(isPoint(pivotstr))
1795 p.pivot = parsePoint(pivotstr);
1797 p.pivot = getPoint(oldbbox, pivotstr);
1801 p.pin = parsePoint(pinstr);
1803 p.pin = getPoint(oldbbox, pinstr);
1806 /* color transform */
1808 if(rstr[0] || luminancestr[0]) {
1811 r = parseMulAdd(rstr);
1813 r.add = p.cxform.r0;
1814 r.mul = p.cxform.r1;
1816 r = mergeMulAdd(r, luminance);
1817 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
1819 if(gstr[0] || luminancestr[0]) {
1822 g = parseMulAdd(gstr);
1824 g.add = p.cxform.g0;
1825 g.mul = p.cxform.g1;
1827 g = mergeMulAdd(g, luminance);
1828 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
1830 if(bstr[0] || luminancestr[0]) {
1833 b = parseMulAdd(bstr);
1835 b.add = p.cxform.b0;
1836 b.mul = p.cxform.b1;
1838 b = mergeMulAdd(b, luminance);
1839 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
1842 MULADD a = parseMulAdd(astr);
1843 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
1847 s_put(instance, character, p);
1849 s_change(instance, p);
1851 s_qchange(instance, p);
1853 s_jump(instance, p);
1855 s_startclip(instance, character, p);
1858 static int c_put(map_t*args)
1860 c_placement(args, 0);
1863 static int c_change(map_t*args)
1865 c_placement(args, 1);
1868 static int c_qchange(map_t*args)
1870 c_placement(args, 2);
1873 static int c_arcchange(map_t*args)
1875 c_placement(args, 2);
1878 static int c_jump(map_t*args)
1880 c_placement(args, 3);
1883 static int c_startclip(map_t*args)
1885 c_placement(args, 4);
1888 static int c_del(map_t*args)
1890 char*instance = lu(args, "name");
1891 s_delinstance(instance);
1894 static int c_end(map_t*args)
1899 static int c_sprite(map_t*args)
1901 char* name = lu(args, "name");
1905 static int c_frame(map_t*args)
1907 char*framestr = lu(args, "n");
1908 char*cutstr = lu(args, "cut");
1911 if(strcmp(cutstr, "no"))
1913 if(isRelative(framestr)) {
1914 frame = s_getframe();
1915 if(getSign(framestr)<0)
1916 syntaxerror("relative frame expressions must be positive");
1917 frame += parseInt(getOffset(framestr));
1920 frame = parseInt(framestr);
1921 if(s_getframe() >= frame
1922 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
1923 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
1925 s_frame(frame, cut);
1928 static int c_primitive(map_t*args)
1930 char*name = lu(args, "name");
1931 char*command = lu(args, "commandname");
1932 int width=0, height=0, r=0;
1933 int linewidth = parseTwip(lu(args, "line"));
1934 char*colorstr = lu(args, "color");
1935 RGBA color = parseColor(colorstr);
1936 char*fillstr = lu(args, "fill");
1943 if(!strcmp(command, "circle"))
1945 else if(!strcmp(command, "filled"))
1949 width = parseTwip(lu(args, "width"));
1950 height = parseTwip(lu(args, "height"));
1951 } else if (type==1) {
1952 r = parseTwip(lu(args, "r"));
1953 } else if (type==2) {
1954 outline = lu(args, "outline");
1957 if(!strcmp(fillstr, "fill"))
1959 if(!strcmp(fillstr, "none"))
1961 if(width<0 || height<0 || linewidth<0 || r<0)
1962 syntaxerror("values width, height, line, r must be positive");
1964 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
1965 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
1966 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
1970 static int c_textshape(map_t*args)
1972 char*name = lu(args, "name");
1973 char*text = lu(args, "text");
1974 char*font = lu(args, "font");
1976 s_textshape(name, font, text);
1982 static int c_swf(map_t*args)
1984 char*name = lu(args, "name");
1985 char*filename = lu(args, "filename");
1986 char*command = lu(args, "commandname");
1987 if(!strcmp(command, "shape"))
1988 warning("Please use .swf instead of .shape");
1989 s_includeswf(name, filename);
1993 static int c_font(map_t*args)
1995 char*name = lu(args, "name");
1996 char*filename = lu(args, "filename");
1997 s_font(name, filename);
2001 static int c_sound(map_t*args)
2003 char*name = lu(args, "name");
2004 char*filename = lu(args, "filename");
2005 s_sound(name, filename);
2009 static int c_text(map_t*args)
2011 char*name = lu(args, "name");
2012 char*text = lu(args, "text");
2013 char*font = lu(args, "font");
2014 float size = parsePercent(lu(args, "size"));
2015 RGBA color = parseColor(lu(args, "color"));
2016 s_text(name, font, text, (int)(size*100), color);
2020 static int c_soundtrack(map_t*args)
2025 static int c_image(map_t*args)
2027 char*command = lu(args, "commandname");
2028 char*name = lu(args, "name");
2029 char*filename = lu(args, "filename");
2030 if(!strcmp(command,"jpeg")) {
2031 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2032 s_image(name, "jpeg", filename, quality);
2034 s_image(name, "png", filename, 0);
2039 static int c_outline(map_t*args)
2041 char*name = lu(args, "name");
2042 char*format = lu(args, "format");
2046 syntaxerror("colon (:) expected");
2048 s_outline(name, format, text);
2052 int fakechar(map_t*args)
2054 char*name = lu(args, "name");
2055 s_box(name, 0, 0, black, 20, 0);
2059 static int c_egon(map_t*args) {return fakechar(args);}
2060 static int c_button(map_t*args) {
2068 return fakechar(args);
2070 static int c_edittext(map_t*args) {return fakechar(args);}
2072 static int c_morphshape(map_t*args) {return fakechar(args);}
2073 static int c_movie(map_t*args) {return fakechar(args);}
2075 static int c_buttonsounds(map_t*args) {return 0;}
2076 static int c_buttonput(map_t*args) {return 0;}
2077 static int c_texture(map_t*args) {return 0;}
2079 static int c_action(map_t*args)
2082 if(type != RAWDATA) {
2083 syntaxerror("colon (:) expected");
2093 command_func_t* func;
2096 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2097 {"frame", c_frame, "n=<plus>1 @cut=no"},
2098 // "import" type stuff
2099 {"swf", c_swf, "name filename"},
2100 {"shape", c_swf, "name filename"},
2101 {"jpeg", c_image, "name filename quality=80%"},
2102 {"png", c_image, "name filename"},
2103 {"movie", c_movie, "name filename"},
2104 {"sound", c_sound, "name filename"},
2105 {"font", c_font, "name filename"},
2106 {"soundtrack", c_soundtrack, "filename"},
2108 // generators of primitives
2110 {"point", c_point, "name x=0 y=0"},
2111 {"gradient", c_gradient, "name @radial=0"},
2112 {"outline", c_outline, "name format=simple"},
2113 {"textshape", c_textshape, "name text font"},
2115 // character generators
2116 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2117 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2118 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2120 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2121 {"button", c_button, "name shape over=*shape press=*shape area=*shape"},
2122 {"text", c_text, "name text font size=100% color=white"},
2123 {"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"},
2124 {"morphshape", c_morphshape, "name start end"},
2126 {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
2129 {"play", c_play, "sound loop=0 @nomultiple=0"},
2130 {"stop", c_stop, "sound"},
2132 // object placement tags
2133 {"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="},
2134 {"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="},
2135 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2136 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2137 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2138 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2139 {"del", c_del, "name"},
2140 // virtual object placement
2141 {"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="}, //TODO: ratio???
2142 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2144 // commands which start a block
2145 //startclip (see above)
2146 {"sprite", c_sprite, "name"},
2147 {"action", c_action, ""},
2153 static map_t parseArguments(char*command, char*pattern)
2169 string_set(&t1, "commandname");
2170 string_set(&t2, command);
2171 map_put(&result, t1, t2);
2173 if(!pattern || !*pattern)
2180 if(!strncmp("<i> ", x, 3)) {
2182 if(type == COMMAND || type == RAWDATA) {
2184 syntaxerror("character name expected");
2186 name[pos].str = "instance";
2188 value[pos].str = text;
2189 value[pos].len = strlen(text);
2193 if(type == ASSIGNMENT)
2196 name[pos].str = "character";
2198 value[pos].str = text;
2199 value[pos].len = strlen(text);
2207 isboolean[pos] = (x[0] =='@');
2220 name[pos].len = d-x;
2225 name[pos].len = e-x;
2226 value[pos].str = e+1;
2227 value[pos].len = d-e-1;
2235 /* for(t=0;t<len;t++) {
2236 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2237 isboolean[t]?"(boolean)":"");
2242 if(type == RAWDATA || type == COMMAND) {
2247 // first, search for boolean arguments
2248 for(pos=0;pos<len;pos++)
2250 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2252 if(type == ASSIGNMENT)
2254 value[pos].str = text;
2255 value[pos].len = strlen(text);
2256 /*printf("setting boolean parameter %s (to %s)\n",
2257 strdup_n(name[pos], namelen[pos]),
2258 strdup_n(value[pos], valuelen[pos]));*/
2263 // second, search for normal arguments
2265 for(pos=0;pos<len;pos++)
2267 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2268 (type != ASSIGNMENT && !set[pos])) {
2270 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2272 if(type == ASSIGNMENT)
2275 value[pos].str = text;
2276 value[pos].len = strlen(text);
2278 printf("setting parameter %s (to %s)\n",
2279 strdup_n(name[pos].str, name[pos].len),
2280 strdup_n(value[pos].str, value[pos].len));
2286 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
2290 for(t=0;t<len;t++) {
2291 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2294 for(t=0;t<len;t++) {
2295 if(value[t].str && value[t].str[0] == '*') {
2296 //relative default- take value from some other parameter
2298 for(s=0;s<len;s++) {
2299 if(value[s].len == value[t].len-1 &&
2300 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2301 value[t].str = value[s].str;
2304 if(value[t].str == 0) {
2306 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2310 /* ok, now construct the dictionary from the parameters */
2314 map_put(&result, name[t], value[t]);
2318 static void parseArgumentsForCommand(char*command)
2323 msg("<verbose> parse Command: %s (line %d)", command, line);
2325 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2326 if(!strcmp(arguments[t].command, command)) {
2328 /* ugly hack- will be removed soon (once documentation and .sc generating
2329 utilities have been changed) */
2330 if(!strcmp(command, "swf") && !stackpos) {
2331 warning("Please use .flash instead of .swf- this will be mandatory soon");
2336 args = parseArguments(command, arguments[t].arguments);
2342 syntaxerror("command %s not known", command);
2344 // catch missing .flash directives at the beginning of a file
2345 if(strcmp(command, "flash") && !stackpos)
2347 syntaxerror("No movie defined- use .flash first");
2351 printf(".%s\n", command);fflush(stdout);
2352 map_dump(&args, stdout, "\t");fflush(stdout);
2355 (*arguments[nr].func)(&args);
2357 /*if(!strcmp(command, "button") ||
2358 !strcmp(command, "action")) {
2361 if(type == COMMAND) {
2362 if(!strcmp(text, "end"))
2376 int main (int argc,char ** argv)
2379 processargs(argc, argv);
2380 initLog(0,-1,0,0,-1,verbose);
2383 args_callback_usage(argv[0]);
2387 file = generateTokens(filename);
2389 printf("parser returned error.\n");
2395 while(!noMoreTokens()) {
2398 syntaxerror("command expected");
2399 parseArgumentsForCommand(text);