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)
80 printf("Usage: %s [-o filename] file.sc\n", name);
81 printf("\t-v , --verbose\t\t\t Be more verbose\n");
82 printf("\t-o , --output filename\t\t set output filename (default: output.swf)\n");
83 printf("\t-V , --version\t\t\t Print program version and exit\n");
85 int args_callback_command(char*name,char*val)
88 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
95 static struct token_t* file;
104 static void syntaxerror(char*format, ...)
108 va_start(arglist, format);
109 vsprintf(buf, format, arglist);
111 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
115 static void warning(char*format, ...)
119 va_start(arglist, format);
120 vsprintf(buf, format, arglist);
122 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
125 static void readToken()
127 type = file[pos].type;
129 syntaxerror("unexpected end of file");
131 text = file[pos].text;
132 textlen = strlen(text);
133 line = file[pos].line;
134 column = file[pos].column;
136 //printf("---> %d(%s) %s\n", type, type_names[type], text);
139 static void pushBack()
142 if(!pos) syntaxerror("internal error 3");
147 textlen = strlen(text);
150 column = file[p].column;
153 static int noMoreTokens()
155 if(file[pos].type == END)
160 // ------------------------------ swf routines ----------------------------
164 int type; //0=swf, 1=sprite, 2=clip
170 /* for sprites (1): */
176 dictionary_t oldinstances;
181 static int stackpos = 0;
183 static dictionary_t characters;
184 static dictionary_t images;
185 static dictionary_t outlines;
186 static dictionary_t gradients;
187 static char idmap[65536];
188 static TAG*tag = 0; //current tag
190 static int id; //current character id
191 static int currentframe; //current frame in current level
192 static SRECT currentrect; //current bounding box in current level
193 static U16 currentdepth;
194 static dictionary_t instances;
195 static dictionary_t fonts;
196 static dictionary_t sounds;
198 typedef struct _parameters {
200 float scalex, scaley;
208 typedef struct _character {
214 typedef struct _instance {
215 character_t*character;
217 parameters_t parameters;
218 TAG* lastTag; //last tag which set the object
219 U16 lastFrame; //frame lastTag is in
222 typedef struct _outline {
227 typedef struct _gradient {
232 static void character_init(character_t*c)
234 memset(c, 0, sizeof(character_t));
236 static character_t* character_new()
239 c = (character_t*)malloc(sizeof(character_t));
243 static void instance_init(instance_t*i)
245 memset(i, 0, sizeof(instance_t));
247 static instance_t* instance_new()
250 c = (instance_t*)malloc(sizeof(instance_t));
255 static void incrementid()
259 syntaxerror("Out of character ids.");
264 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
266 character_t* c = character_new();
268 c->definingTag = ctag;
271 if(dictionary_lookup(&characters, name))
272 syntaxerror("character %s defined twice", name);
273 dictionary_put2(&characters, name, c);
275 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
277 swf_SetString(tag, name);
278 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
281 swf_SetString(tag, name);
283 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
285 character_t* c = character_new();
286 c->definingTag = ctag;
290 if(dictionary_lookup(&images, name))
291 syntaxerror("image %s defined twice", name);
292 dictionary_put2(&images, name, c);
294 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
296 instance_t* i = instance_new();
299 //swf_GetMatrix(0, &i->matrix);
300 if(dictionary_lookup(&instances, name))
301 syntaxerror("object %s defined twice", name);
302 dictionary_put2(&instances, name, i);
306 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)
309 p->scalex = scalex; p->scaley = scaley;
310 p->pin = pin; p->pivot = pivot;
311 p->rotate = rotate; p->cxform = cxform;
315 static void parameters_clear(parameters_t*p)
318 p->scalex = 1.0; p->scaley = 1.0;
319 p->pin.x = 1; p->pin.y = 0;
320 p->pivot.x = 0; p->pivot.y = 0;
323 swf_GetCXForm(0, &p->cxform, 1);
326 static void makeMatrix(MATRIX*m, parameters_t*p)
335 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
336 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
337 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
338 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
340 m->sx = (int)(sx*65536+0.5);
341 m->r1 = (int)(r1*65536+0.5);
342 m->r0 = (int)(r0*65536+0.5);
343 m->sy = (int)(sy*65536+0.5);
347 h = swf_TurnPoint(p->pin, m);
352 static MATRIX s_instancepos(instance_t*i, parameters_t*p)
357 r = swf_TurnRect(i->character->size, &m);
358 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
359 currentrect.xmax == 0 && currentrect.ymax == 0)
362 swf_ExpandRect2(¤trect, &r);
366 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
368 SWF*swf = (SWF*)malloc(sizeof(SWF));
371 syntaxerror(".swf blocks can't be nested");
373 memset(swf, 0, sizeof(swf));
374 swf->fileVersion = version;
376 swf->frameRate = fps;
377 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
378 swf->compressed = compress;
379 swf_SetRGB(tag,&background);
381 if(stackpos==sizeof(stack)/sizeof(stack[0]))
382 syntaxerror("too many levels of recursion");
384 dictionary_init(&characters);
385 dictionary_init(&images);
386 dictionary_init(&outlines);
387 dictionary_init(&gradients);
388 dictionary_init(&instances);
389 dictionary_init(&fonts);
390 dictionary_init(&sounds);
392 memset(&stack[stackpos], 0, sizeof(stack[0]));
393 stack[stackpos].type = 0;
394 stack[stackpos].filename = strdup(name);
395 stack[stackpos].swf = swf;
396 stack[stackpos].oldframe = -1;
401 memset(¤trect, 0, sizeof(currentrect));
404 memset(idmap, 0, sizeof(idmap));
408 void s_sprite(char*name)
410 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
411 swf_SetU16(tag, id); //id
412 swf_SetU16(tag, 0); //frames
414 memset(&stack[stackpos], 0, sizeof(stack[0]));
415 stack[stackpos].type = 1;
416 stack[stackpos].oldframe = currentframe;
417 stack[stackpos].olddepth = currentdepth;
418 stack[stackpos].oldrect = currentrect;
419 stack[stackpos].oldinstances = instances;
420 stack[stackpos].tag = tag;
421 stack[stackpos].id = id;
422 stack[stackpos].name = strdup(name);
424 /* FIXME: those four fields should be bundled together */
425 dictionary_init(&instances);
428 memset(¤trect, 0, sizeof(currentrect));
434 TAG* removeFromTo(TAG*from, TAG*to)
436 TAG*save = from->prev;
438 TAG*next = from->next;
446 static void s_endSprite()
448 SRECT r = currentrect;
450 if(stack[stackpos].cut)
451 tag = removeFromTo(stack[stackpos].cut, tag);
455 /* TODO: before clearing, prepend "<spritename>." to names and
456 copy into old instances dict */
457 dictionary_clear(&instances);
459 currentframe = stack[stackpos].oldframe;
460 currentrect = stack[stackpos].oldrect;
461 currentdepth = stack[stackpos].olddepth;
462 instances = stack[stackpos].oldinstances;
464 tag = swf_InsertTag(tag, ST_END);
466 tag = stack[stackpos].tag;
469 syntaxerror("internal error(7)");
471 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
472 free(stack[stackpos].name);
475 static void s_endSWF()
481 if(stack[stackpos].cut)
482 tag = removeFromTo(stack[stackpos].cut, tag);
486 swf = stack[stackpos].swf;
487 filename = stack[stackpos].filename;
489 //tag = swf_InsertTag(tag, ST_SHOWFRAME); //?
491 tag = swf_InsertTag(tag, ST_END);
493 swf_OptimizeTagOrder(swf);
495 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin))
496 swf->movieSize = currentrect; /* "autocrop" */
498 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
499 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
500 swf->movieSize.ymax += 20;
503 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
505 syntaxerror("couldn't create output file %s", filename);
508 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
510 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
514 dictionary_clear(&instances);
515 dictionary_clear(&characters);
516 dictionary_clear(&images);
517 dictionary_clear(&outlines);
518 dictionary_clear(&gradients);
519 dictionary_clear(&fonts);
520 dictionary_clear(&sounds);
530 if(stack[stackpos-1].type == 0)
531 syntaxerror("End of file encountered in .flash block");
532 if(stack[stackpos-1].type == 1)
533 syntaxerror("End of file encountered in .sprite block");
534 if(stack[stackpos-1].type == 2)
535 syntaxerror("End of file encountered in .clip block");
544 void s_frame(int nr, int cut)
549 for(t=currentframe;t<nr;t++) {
550 tag = swf_InsertTag(tag, ST_SHOWFRAME);
555 syntaxerror("Can't cut, frame empty");
557 stack[stackpos].cut = tag;
563 int parseColor2(char*str, RGBA*color);
565 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
570 if(texture[0] == '#') {
571 parseColor2(texture, &color);
572 return swf_ShapeAddSolidFillStyle(s, &color);
573 } else if((image = dictionary_lookup(&images, texture))) {
575 swf_GetMatrix(0, &m);
576 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
577 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
580 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
581 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
582 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
584 swf_GetMatrix(0, &m);
585 m.sx = (r->xmax - r->xmin)*2;
586 m.sy = (r->ymax - r->ymin)*2;
587 m.tx = r->xmin + (r->xmax - r->xmin)/2;
588 m.ty = r->ymin + (r->ymax - r->ymin)/2;
589 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
590 } else if (parseColor2(texture, &color)) {
591 return swf_ShapeAddSolidFillStyle(s, &color);
593 syntaxerror("not a color/fillstyle: %s", texture);
598 RGBA black={r:0,g:0,b:0,a:0};
599 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
608 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
610 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
613 fs1 = addFillStyle(s, &r2, texture);
616 r.xmin = r2.xmin-linewidth-linewidth/2;
617 r.ymin = r2.ymin-linewidth-linewidth/2;
618 r.xmax = r2.xmax+linewidth+linewidth/2;
619 r.ymax = r2.ymax+linewidth+linewidth/2;
621 swf_SetShapeHeader(tag,s);
622 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
623 swf_ShapeSetLine(tag,s,width,0);
624 swf_ShapeSetLine(tag,s,0,height);
625 swf_ShapeSetLine(tag,s,-width,0);
626 swf_ShapeSetLine(tag,s,0,-height);
627 swf_ShapeSetEnd(tag);
630 s_addcharacter(name, id, tag, r);
634 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
640 outline = dictionary_lookup(&outlines, outlinename);
642 syntaxerror("outline %s not defined", outlinename);
646 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
648 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
650 fs1 = addFillStyle(s, &r2, texture);
652 syntaxerror("non filled outlines not yet supported- please supply a fill=<color/texture> argument");
654 rect.xmin = r2.xmin-linewidth-linewidth/2;
655 rect.ymin = r2.ymin-linewidth-linewidth/2;
656 rect.xmax = r2.xmax+linewidth+linewidth/2;
657 rect.ymax = r2.ymax+linewidth+linewidth/2;
659 swf_SetRect(tag,&rect);
660 swf_SetShapeStyles(tag, s);
661 swf_SetShapeBits(tag, outline->shape); //does not count bits!
662 swf_SetBlock(tag, outline->shape->data, (outline->shape->bitlen+7)/8);
665 s_addcharacter(name, id, tag, rect);
669 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
674 r2.xmin = r2.ymin = 0;
678 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
680 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
682 fs1 = addFillStyle(s, &r2, texture);
684 rect.xmin = r2.xmin-linewidth-linewidth/2;
685 rect.ymin = r2.ymin-linewidth-linewidth/2;
686 rect.xmax = r2.xmax+linewidth+linewidth/2;
687 rect.ymax = r2.ymax+linewidth+linewidth/2;
689 swf_SetRect(tag,&rect);
690 swf_SetShapeHeader(tag,s);
691 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
692 swf_ShapeSetCircle(tag, s, r,r,r,r);
693 swf_ShapeSetEnd(tag);
696 s_addcharacter(name, id, tag, rect);
700 void s_textshape(char*name, char*fontname, char*_text)
703 U8*text = (U8*)_text;
707 font = dictionary_lookup(&fonts, fontname);
709 syntaxerror("font \"%s\" not known!", fontname);
711 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
712 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
713 s_box(name, 0, 0, black, 20, 0);
716 g = font->ascii2glyph[text[0]];
718 outline = malloc(sizeof(outline_t));
719 memset(outline, 0, sizeof(outline_t));
720 outline->shape = font->glyph[g].shape;
721 outline->bbox = font->layout->bounds[g];
725 swf_Shape11DrawerInit(&draw, 0);
726 swf_DrawText(&draw, font, _text);
728 outline->shape = swf_ShapeDrawerToShape(&draw);
729 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
733 if(dictionary_lookup(&outlines, name))
734 syntaxerror("outline %s defined twice", name);
735 dictionary_put2(&outlines, name, outline);
738 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
743 font = dictionary_lookup(&fonts, fontname);
745 syntaxerror("font \"%s\" not known!", fontname);
747 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
749 if(!font->numchars) {
750 s_box(name, 0, 0, black, 20, 0);
753 r = swf_SetDefineText(tag, font, &color, text, size);
755 s_addcharacter(name, id, tag, r);
759 /* type: either "jpeg" or "png"
761 void s_image(char*name, char*type, char*filename, int quality)
763 /* an image is actually two folded: 1st bitmap, 2nd character.
764 Both of them can be used separately */
766 /* step 1: the bitmap */
771 warning("image type \"png\" not supported yet!");
772 s_box(name, 0, 0, black, 20, 0);
775 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
776 swf_SetU16(tag, imageID);
778 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
779 syntaxerror("Image \"%s\" not found, or contains errors", filename);
782 swf_GetJPEGSize(filename, &width, &height);
789 s_addimage(name, id, tag, r);
792 /* step 2: the character */
793 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
795 swf_ShapeSetBitmapRect(tag, imageID, width, height);
797 s_addcharacter(name, id, tag, r);
801 void dumpSWF(SWF*swf)
803 TAG* tag = swf->firstTag;
804 printf("vvvvvvvvvvvvvvvvvvvvv\n");
806 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
809 printf("^^^^^^^^^^^^^^^^^^^^^\n");
812 void s_font(char*name, char*filename)
815 font = swf_LoadFont(filename);
818 warning("Couldn't open font file \"%s\"", filename);
819 font = (SWFFONT*)malloc(sizeof(SWFFONT));
820 memset(font, 0, sizeof(SWFFONT));
821 dictionary_put2(&fonts, name, font);
827 /* fix the layout. Only needed for old fonts */
829 for(t=0;t<font->numchars;t++) {
830 font->glyph[t].advance = 0;
833 swf_FontCreateLayout(font);
837 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
838 swf_FontSetDefine2(tag, font);
841 if(dictionary_lookup(&fonts, name))
842 syntaxerror("font %s defined twice", name);
843 dictionary_put2(&fonts, name, font);
848 typedef struct _sound_t
854 void s_sound(char*name, char*filename)
856 struct WAV wav, wav2;
861 if(!readWAV(filename, &wav)) {
862 warning("Couldn't read wav file \"%s\"", filename);
866 convertWAV2mono(&wav, &wav2, 44100);
867 samples = (U16*)wav2.data;
868 numsamples = wav2.size/2;
872 tag = swf_InsertTag(tag, ST_DEFINESOUND);
873 swf_SetU16(tag, id); //id
874 swf_SetSoundDefine(tag, samples, numsamples);
876 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
880 if(dictionary_lookup(&sounds, name))
881 syntaxerror("sound %s defined twice", name);
882 dictionary_put2(&sounds, name, sound);
890 static char* gradient_getToken(const char**p)
894 while(**p && strchr(" \t\n\r", **p)) {
898 while(**p && !strchr(" \t\n\r", **p)) {
901 result = malloc((*p)-start+1);
902 memcpy(result,start,(*p)-start+1);
903 result[(*p)-start] = 0;
907 float parsePercent(char*str);
908 RGBA parseColor(char*str);
910 GRADIENT parseGradient(const char*str)
914 memset(&gradient, 0, sizeof(GRADIENT));
916 char*posstr,*colorstr;
919 posstr = gradient_getToken(&p);
922 pos = parsePercent(posstr);
923 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
924 colorstr = gradient_getToken(&p);
925 color = parseColor(colorstr);
926 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
927 warning("gradient record too big- max size is 8, rest ignored");
930 gradient.ratios[gradient.num] = (int)(pos*255.0);
931 gradient.rgba[gradient.num] = color;
939 void s_gradient(char*name, const char*text, int radial)
941 gradient_t* gradient;
942 gradient = malloc(sizeof(gradient_t));
943 memset(gradient, 0, sizeof(gradient_t));
944 gradient->gradient = parseGradient(text);
945 gradient->radial = radial;
947 if(dictionary_lookup(&gradients, name))
948 syntaxerror("gradient %s defined twice", name);
949 dictionary_put2(&gradients, name, gradient);
952 void s_action(const char*text)
955 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
957 tag = swf_InsertTag(tag, ST_DOACTION);
959 swf_ActionSet(tag, a);
964 void s_outline(char*name, char*format, char*source)
973 swf_Shape11DrawerInit(&draw, 0);
974 draw_string(&draw, source);
976 shape = swf_ShapeDrawerToShape(&draw);
977 //shape2 = swf_ShapeToShape2(shape);
978 //bounds = swf_GetShapeBoundingBox(shape2);
979 //swf_Shape2Free(shape2);
980 bounds = swf_ShapeDrawerGetBBox(&draw);
983 outline = (outline_t*)malloc(sizeof(outline_t));
984 memset(outline, 0, sizeof(outline_t));
985 outline->shape = shape;
986 outline->bbox = bounds;
988 if(dictionary_lookup(&outlines, name))
989 syntaxerror("outline %s defined twice", name);
990 dictionary_put2(&outlines, name, outline);
993 void s_playsound(char*name, int loops, int nomultiple, int stop)
995 sound_t* sound = dictionary_lookup(&sounds, name);
998 syntaxerror("Don't know anything about sound \"%s\"", name);
1000 tag = swf_InsertTag(tag, ST_STARTSOUND);
1001 swf_SetU16(tag, sound->id); //id
1002 memset(&info, 0, sizeof(info));
1005 info.nomultiple = nomultiple;
1006 swf_SetSoundInfo(tag, &info);
1009 void s_includeswf(char*name, char*filename)
1017 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1018 f = open(filename,O_RDONLY);
1020 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1021 s_box(name, 0, 0, black, 20, 0);
1024 if (swf_ReadSWF(f,&swf)<0) {
1025 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1026 s_box(name, 0, 0, black, 20, 0);
1031 /* FIXME: The following sets the bounding Box for the character.
1032 It is wrong for two reasons:
1033 a) It may be too small (in case objects in the movie clip at the borders)
1034 b) it may be too big (because the poor movie never got autocropped)
1038 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1039 swf_SetU16(tag, id);
1042 swf_Relocate(&swf, idmap);
1044 ftag = swf.firstTag;
1048 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1049 if(cutout[t] == ftag->id) {
1053 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1055 if(ftag->id == ST_END)
1059 /* We simply dump all tags right after the sprite
1060 header, relying on the fact that swf_OptimizeTagOrder() will
1061 sort things out for us later.
1062 We also rely on the fact that the imported SWF is well-formed.
1064 tag = swf_InsertTag(tag, ftag->id);
1065 swf_SetBlock(tag, ftag->data, ftag->len);
1069 syntaxerror("Included file %s contains errors", filename);
1070 tag = swf_InsertTag(tag, ST_END);
1074 s_addcharacter(name, id, tag, r);
1077 SRECT s_getCharBBox(char*name)
1079 character_t* c = dictionary_lookup(&characters, name);
1080 if(!c) syntaxerror("character '%s' unknown(2)", name);
1083 SRECT s_getInstanceBBox(char*name)
1085 instance_t * i = dictionary_lookup(&instances, name);
1087 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1089 if(!c) syntaxerror("internal error(5)");
1092 parameters_t s_getParameters(char*name)
1094 instance_t * i = dictionary_lookup(&instances, name);
1095 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1096 return i->parameters;
1098 void s_startclip(char*instance, char*character, parameters_t p)
1100 character_t* c = dictionary_lookup(&characters, character);
1104 syntaxerror("character %s not known", character);
1106 i = s_addinstance(instance, c, currentdepth);
1108 m = s_instancepos(i, &p);
1110 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1111 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1112 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1114 i->lastFrame= currentframe;
1116 stack[stackpos].tag = tag;
1117 stack[stackpos].type = 2;
1126 swf_SetTagPos(stack[stackpos].tag, 0);
1127 swf_GetPlaceObject(stack[stackpos].tag, &p);
1128 p.clipdepth = currentdepth;
1129 swf_ClearTag(stack[stackpos].tag);
1130 swf_SetPlaceObject(stack[stackpos].tag, &p);
1134 void s_put(char*instance, char*character, parameters_t p)
1136 character_t* c = dictionary_lookup(&characters, character);
1140 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1143 i = s_addinstance(instance, c, currentdepth);
1145 m = s_instancepos(i, &p);
1147 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1148 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1150 i->lastFrame = currentframe;
1154 void s_jump(char*instance, parameters_t p)
1156 instance_t* i = dictionary_lookup(&instances, instance);
1159 syntaxerror("instance %s not known", instance);
1163 m = s_instancepos(i, &p);
1165 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1166 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1168 i->lastFrame = currentframe;
1171 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1175 if(num==0 || num==1)
1177 ratio = (float)pos/(float)num;
1179 p.x = (p2->x-p1->x)*ratio + p1->x;
1180 p.y = (p2->y-p1->y)*ratio + p1->y;
1181 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1182 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1183 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1184 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1186 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1187 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1188 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1189 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1191 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1192 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1193 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1194 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1196 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1197 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1198 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1199 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1203 void s_change(char*instance, parameters_t p2)
1205 instance_t* i = dictionary_lookup(&instances, instance);
1209 int frame, allframes;
1211 syntaxerror("instance %s not known", instance);
1215 allframes = currentframe - i->lastFrame - 1;
1217 warning(".change ignored. can only .put/.change an object once per frame.");
1221 m = s_instancepos(i, &p2);
1222 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1223 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1226 /* o.k., we got the start and end point set. Now iterate though all the
1227 tags in between, inserting object changes after each new frame */
1230 if(!t) syntaxerror("internal error(6)");
1232 while(frame < allframes) {
1233 if(t->id == ST_SHOWFRAME) {
1238 p = s_interpolate(&p1, &p2, frame, allframes);
1239 m = s_instancepos(i, &p); //needed?
1240 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1241 i->lastFrame = currentframe;
1242 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1244 if(frame == allframes)
1249 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1253 void s_delinstance(char*instance)
1255 instance_t* i = dictionary_lookup(&instances, instance);
1257 syntaxerror("instance %s not known", instance);
1259 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1260 swf_SetU16(tag, i->depth);
1261 dictionary_del(&instances, instance);
1264 void s_qchange(char*instance, parameters_t p)
1271 syntaxerror(".end unexpected");
1272 if(stack[stackpos-1].type == 0)
1274 else if(stack[stackpos-1].type == 1)
1276 else if(stack[stackpos-1].type == 2)
1278 else syntaxerror("internal error 1");
1281 // ------------------------------------------------------------------------
1283 typedef int command_func_t(map_t*args);
1285 SRECT parseBox(char*str)
1288 float xmin, xmax, ymin, ymax;
1289 char*x = strchr(str, 'x');
1291 if(!strcmp(str, "autocrop")) {
1292 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1296 d1 = strchr(x+1, ':');
1298 d2 = strchr(d1+1, ':');
1300 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1304 else if(d1 && !d2) {
1305 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1311 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1316 r.xmin = (SCOORD)(xmin*20);
1317 r.ymin = (SCOORD)(ymin*20);
1318 r.xmax = (SCOORD)(xmax*20);
1319 r.ymax = (SCOORD)(ymax*20);
1322 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1325 float parseFloat(char*str)
1329 int parseInt(char*str)
1334 if(str[0]=='+' || str[0]=='-')
1338 if(str[t]<'0' || str[t]>'9')
1339 syntaxerror("Not an Integer: \"%s\"", str);
1342 int parseTwip(char*str)
1346 if(str[0]=='+' || str[0]=='-') {
1351 dot = strchr(str, '.');
1355 return sign*parseInt(str)*20;
1357 int l=strlen(++dot);
1359 for(s=str;s<dot-1;s++)
1360 if(*s<'0' || *s>'9')
1361 syntaxerror("Not a coordinate: \"%s\"", str);
1363 if(*s<'0' || *s>'9')
1364 syntaxerror("Not a coordinate: \"%s\"", str);
1366 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1367 warning("precision loss: %s converted to twip", str);
1372 return sign*atoi(str)*20;
1374 return sign*atoi(str)*20+atoi(dot)*2;
1376 return sign*atoi(str)*20+atoi(dot)/5;
1381 int isPoint(char*str)
1383 if(strchr(str, '('))
1389 SPOINT parsePoint(char*str)
1393 int l = strlen(str);
1394 char*comma = strchr(str, ',');
1395 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1396 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1397 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1398 p.x = parseTwip(tmp);
1399 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1400 p.y = parseTwip(tmp);
1404 int parseColor2(char*str, RGBA*color)
1406 int l = strlen(str);
1410 struct {unsigned char r,g,b;char*name;} colors[] =
1411 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1412 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1413 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1414 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1415 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1416 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1417 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1418 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1419 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1420 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1421 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1422 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1426 if(str[0]=='#' && (l==7 || l==9)) {
1427 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1429 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1431 color->r = r; color->g = g; color->b = b; color->a = a;
1434 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1435 if(!strcmp(str, colors[t].name)) {
1440 color->r = r; color->g = g; color->b = b; color->a = a;
1446 RGBA parseColor(char*str)
1449 if(!parseColor2(str, &c))
1450 syntaxerror("Expression '%s' is not a color", str);
1454 typedef struct _muladd {
1459 MULADD parseMulAdd(char*str)
1462 char* str2 = (char*)malloc(strlen(str)+5);
1469 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1470 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1471 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1472 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1473 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1474 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1475 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1476 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1477 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1478 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1480 syntaxerror("'%s' is not a valid color transform expression", str);
1482 m.add = (int)(add*256);
1483 m.mul = (int)(mul*256);
1488 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1490 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1491 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1493 if(a<-32768) a=-32768;
1494 if(a>32767) a=32767;
1495 if(m<-32768) m=-32768;
1496 if(m>32767) m=32767;
1502 float parsePercent(char*str)
1504 int l = strlen(str);
1508 return atoi(str)/100.0;
1510 syntaxerror("Expression '%s' is not a percentage", str);
1513 int isPercent(char*str)
1515 return str[strlen(str)-1]=='%';
1517 int parseNewSize(char*str, int size)
1520 return parsePercent(str)*size;
1522 return (int)(atof(str)*20);
1525 int isColor(char*str)
1528 return parseColor2(str, &c);
1531 static char* lu(map_t* args, char*name)
1533 char* value = map_lookup(args, name);
1535 map_dump(args, stdout, "");
1536 syntaxerror("internal error 2: value %s should be set", name);
1541 static int c_flash(map_t*args)
1543 char* name = lu(args, "name");
1544 char* compressstr = lu(args, "compress");
1545 SRECT bbox = parseBox(lu(args, "bbox"));
1546 int version = parseInt(lu(args, "version"));
1547 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1549 RGBA color = parseColor(lu(args, "background"));
1550 if(!strcmp(name, "!default!") || override_outputname)
1553 if(!strcmp(compressstr, "default"))
1554 compress = version==6;
1555 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1557 else if(!strcmp(compressstr, "no"))
1559 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1561 s_swf(name, bbox, version, fps, compress, color);
1564 int isRelative(char*str)
1566 return !strncmp(str, "<plus>", 6) ||
1567 !strncmp(str, "<minus>", 7);
1569 char* getOffset(char*str)
1571 if(!strncmp(str, "<plus>", 6))
1573 if(!strncmp(str, "<minus>", 7))
1575 syntaxerror("internal error (347)");
1578 int getSign(char*str)
1580 if(!strncmp(str, "<plus>", 6))
1582 if(!strncmp(str, "<minus>", 7))
1584 syntaxerror("internal error (348)");
1587 static dictionary_t points;
1588 static mem_t mpoints;
1589 int points_initialized = 0;
1591 SPOINT getPoint(SRECT r, char*name)
1594 if(!strcmp(name, "center")) {
1596 p.x = (r.xmin + r.xmax)/2;
1597 p.y = (r.ymin + r.ymax)/2;
1601 if(points_initialized)
1602 l = (int)dictionary_lookup(&points, name);
1604 syntaxerror("Invalid point: \"%s\".", name);
1607 return *(SPOINT*)&mpoints.buffer[l];
1609 static int c_gradient(map_t*args)
1611 char*name = lu(args, "name");
1612 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1616 syntaxerror("colon (:) expected");
1618 s_gradient(name, text, radial);
1621 static int c_point(map_t*args)
1623 char*name = lu(args, "name");
1627 if(!points_initialized) {
1628 dictionary_init(&points);
1630 points_initialized = 1;
1632 p.x = parseTwip(lu(args, "x"));
1633 p.y = parseTwip(lu(args, "y"));
1634 pos = mem_put(&mpoints, &p, sizeof(p));
1635 string_set(&s1, name);
1637 dictionary_put(&points, s1, (void*)pos);
1640 static int c_play(map_t*args)
1642 char*name = lu(args, "sound");
1643 char*loop = lu(args, "loop");
1644 char*nomultiple = lu(args, "nomultiple");
1646 if(!strcmp(nomultiple, "nomultiple"))
1649 nm = parseInt(nomultiple);
1651 s_playsound(name, parseInt(loop), nm, 0);
1655 static int c_stop(map_t*args)
1657 char*name = lu(args, "sound");
1658 s_playsound(name, 0,0,1);
1662 static int c_placement(map_t*args, int type)
1664 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1667 char* luminancestr = lu(args, "luminance");
1668 char* scalestr = lu(args, "scale");
1669 char* scalexstr = lu(args, "scalex");
1670 char* scaleystr = lu(args, "scaley");
1671 char* rotatestr = lu(args, "rotate");
1672 char* shearstr = lu(args, "shear");
1673 char* xstr="", *pivotstr="";
1674 char* ystr="", *anglestr="";
1675 char*above = lu(args, "above"); /*FIXME*/
1676 char*below = lu(args, "below");
1677 char* rstr = lu(args, "red");
1678 char* gstr = lu(args, "green");
1679 char* bstr = lu(args, "blue");
1680 char* astr = lu(args, "alpha");
1681 char* pinstr = lu(args, "pin");
1690 pivotstr = lu(args, "pivot");
1691 anglestr = lu(args, "angle");
1693 xstr = lu(args, "x");
1694 ystr = lu(args, "y");
1697 luminance = parseMulAdd(luminancestr);
1700 luminance.mul = 256;
1704 if(scalexstr[0]||scaleystr[0])
1705 syntaxerror("scalex/scaley and scale cannot both be set");
1706 scalexstr = scaleystr = scalestr;
1709 if(type == 0 || type == 4) {
1711 character = lu(args, "character");
1712 parameters_clear(&p);
1714 p = s_getParameters(instance);
1719 if(isRelative(xstr)) {
1720 if(type == 0 || type == 4)
1721 syntaxerror("relative x values not allowed for initial put or startclip");
1722 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
1724 p.x = parseTwip(xstr);
1728 if(isRelative(ystr)) {
1729 if(type == 0 || type == 4)
1730 syntaxerror("relative y values not allowed for initial put or startclip");
1731 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
1733 p.y = parseTwip(ystr);
1737 /* scale, scalex, scaley */
1739 oldbbox = s_getCharBBox(character);
1741 oldbbox = s_getInstanceBBox(instance);
1743 oldwidth = oldbbox.xmax - oldbbox.xmin;
1744 oldheight = oldbbox.ymax - oldbbox.ymin;
1746 if(oldwidth==0) p.scalex = 1.0;
1749 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
1753 if(oldheight==0) p.scaley = 1.0;
1756 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
1762 if(isRelative(rotatestr)) {
1763 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
1765 p.rotate = parseFloat(rotatestr);
1771 if(isRelative(shearstr)) {
1772 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
1774 p.shear = parseFloat(shearstr);
1779 if(isPoint(pivotstr))
1780 p.pivot = parsePoint(pivotstr);
1782 p.pivot = getPoint(oldbbox, pivotstr);
1786 p.pin = parsePoint(pinstr);
1788 p.pin = getPoint(oldbbox, pinstr);
1791 /* color transform */
1793 if(rstr[0] || luminancestr[0]) {
1796 r = parseMulAdd(rstr);
1798 r.add = p.cxform.r0;
1799 r.mul = p.cxform.r1;
1801 r = mergeMulAdd(r, luminance);
1802 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
1804 if(gstr[0] || luminancestr[0]) {
1807 g = parseMulAdd(gstr);
1809 g.add = p.cxform.g0;
1810 g.mul = p.cxform.g1;
1812 g = mergeMulAdd(g, luminance);
1813 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
1815 if(bstr[0] || luminancestr[0]) {
1818 b = parseMulAdd(bstr);
1820 b.add = p.cxform.b0;
1821 b.mul = p.cxform.b1;
1823 b = mergeMulAdd(b, luminance);
1824 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
1827 MULADD a = parseMulAdd(astr);
1828 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
1832 s_put(instance, character, p);
1834 s_change(instance, p);
1836 s_qchange(instance, p);
1838 s_jump(instance, p);
1840 s_startclip(instance, character, p);
1843 static int c_put(map_t*args)
1845 c_placement(args, 0);
1848 static int c_change(map_t*args)
1850 c_placement(args, 1);
1853 static int c_qchange(map_t*args)
1855 c_placement(args, 2);
1858 static int c_arcchange(map_t*args)
1860 c_placement(args, 2);
1863 static int c_jump(map_t*args)
1865 c_placement(args, 3);
1868 static int c_startclip(map_t*args)
1870 c_placement(args, 4);
1873 static int c_del(map_t*args)
1875 char*instance = lu(args, "name");
1876 s_delinstance(instance);
1879 static int c_end(map_t*args)
1884 static int c_sprite(map_t*args)
1886 char* name = lu(args, "name");
1890 static int c_frame(map_t*args)
1892 char*framestr = lu(args, "n");
1893 char*cutstr = lu(args, "cut");
1896 if(strcmp(cutstr, "no"))
1898 if(isRelative(framestr)) {
1899 frame = s_getframe();
1900 if(getSign(framestr)<0)
1901 syntaxerror("relative frame expressions must be positive");
1902 frame += parseInt(getOffset(framestr));
1905 frame = parseInt(framestr);
1906 if(s_getframe() >= frame
1907 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
1908 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
1910 s_frame(frame, cut);
1913 static int c_primitive(map_t*args)
1915 char*name = lu(args, "name");
1916 char*command = lu(args, "commandname");
1917 int width=0, height=0, r=0;
1918 int linewidth = parseTwip(lu(args, "line"));
1919 char*colorstr = lu(args, "color");
1920 RGBA color = parseColor(colorstr);
1921 char*fillstr = lu(args, "fill");
1928 if(!strcmp(command, "circle"))
1930 else if(!strcmp(command, "filled"))
1934 width = parseTwip(lu(args, "width"));
1935 height = parseTwip(lu(args, "height"));
1936 } else if (type==1) {
1937 r = parseTwip(lu(args, "r"));
1938 } else if (type==2) {
1939 outline = lu(args, "outline");
1942 if(!strcmp(fillstr, "fill"))
1944 if(!strcmp(fillstr, "none"))
1946 if(width<0 || height<0 || linewidth<0 || r<0)
1947 syntaxerror("values width, height, line, r must be positive");
1949 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
1950 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
1951 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
1955 static int c_textshape(map_t*args)
1957 char*name = lu(args, "name");
1958 char*text = lu(args, "text");
1959 char*font = lu(args, "font");
1961 s_textshape(name, font, text);
1967 static int c_swf(map_t*args)
1969 char*name = lu(args, "name");
1970 char*filename = lu(args, "filename");
1971 char*command = lu(args, "commandname");
1972 if(!strcmp(command, "shape"))
1973 warning("Please use .swf instead of .shape");
1974 s_includeswf(name, filename);
1978 static int c_font(map_t*args)
1980 char*name = lu(args, "name");
1981 char*filename = lu(args, "filename");
1982 s_font(name, filename);
1986 static int c_sound(map_t*args)
1988 char*name = lu(args, "name");
1989 char*filename = lu(args, "filename");
1990 s_sound(name, filename);
1994 static int c_text(map_t*args)
1996 char*name = lu(args, "name");
1997 char*text = lu(args, "text");
1998 char*font = lu(args, "font");
1999 float size = parsePercent(lu(args, "size"));
2000 RGBA color = parseColor(lu(args, "color"));
2001 s_text(name, font, text, (int)(size*100), color);
2005 static int c_soundtrack(map_t*args)
2010 static int c_image(map_t*args)
2012 char*command = lu(args, "commandname");
2013 char*name = lu(args, "name");
2014 char*filename = lu(args, "filename");
2015 if(!strcmp(command,"jpeg")) {
2016 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2017 s_image(name, "jpeg", filename, quality);
2019 s_image(name, "png", filename, 0);
2024 static int c_outline(map_t*args)
2026 char*name = lu(args, "name");
2027 char*format = lu(args, "format");
2031 syntaxerror("colon (:) expected");
2033 s_outline(name, format, text);
2037 int fakechar(map_t*args)
2039 char*name = lu(args, "name");
2040 s_box(name, 0, 0, black, 20, 0);
2044 static int c_egon(map_t*args) {return fakechar(args);}
2045 static int c_button(map_t*args) {
2053 return fakechar(args);
2055 static int c_edittext(map_t*args) {return fakechar(args);}
2057 static int c_morphshape(map_t*args) {return fakechar(args);}
2058 static int c_movie(map_t*args) {return fakechar(args);}
2060 static int c_buttonsounds(map_t*args) {return 0;}
2061 static int c_buttonput(map_t*args) {return 0;}
2062 static int c_texture(map_t*args) {return 0;}
2064 static int c_action(map_t*args)
2068 syntaxerror("colon (:) expected");
2077 command_func_t* func;
2080 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2081 {"frame", c_frame, "n=<plus>1 @cut=no"},
2082 // "import" type stuff
2083 {"swf", c_swf, "name filename"},
2084 {"shape", c_swf, "name filename"},
2085 {"jpeg", c_image, "name filename quality=80%"},
2086 {"png", c_image, "name filename"},
2087 {"movie", c_movie, "name filename"},
2088 {"sound", c_sound, "name filename"},
2089 {"font", c_font, "name filename"},
2090 {"soundtrack", c_soundtrack, "filename"},
2092 // generators of primitives
2094 {"point", c_point, "name x=0 y=0"},
2095 {"gradient", c_gradient, "name @radial=0"},
2096 {"outline", c_outline, "name format=simple"},
2097 {"textshape", c_textshape, "name text font"},
2099 // character generators
2100 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2101 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2102 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2104 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2105 {"button", c_button, "name shape over=*shape press=*shape area=*shape"},
2106 {"text", c_text, "name text font size=100% color=white"},
2107 {"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"},
2108 {"morphshape", c_morphshape, "name start end"},
2110 {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
2113 {"play", c_play, "sound loop=0 @nomultiple=0"},
2114 {"stop", c_stop, "sound"},
2116 // object placement tags
2117 {"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="},
2118 {"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="},
2119 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
2120 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
2121 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
2122 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
2123 {"del", c_del, "name"},
2124 // virtual object placement
2125 {"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="},
2126 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2128 // commands which start a block
2129 //startclip (see above)
2130 {"sprite", c_sprite, "name"},
2131 {"action", c_action, ""},
2137 static map_t parseArguments(char*command, char*pattern)
2153 string_set(&t1, "commandname");
2154 string_set(&t2, command);
2155 map_put(&result, t1, t2);
2157 if(!pattern || !*pattern)
2164 if(!strncmp("<i> ", x, 3)) {
2166 if(type == COMMAND || type == RAWDATA) {
2168 syntaxerror("character name expected");
2170 name[pos].str = "instance";
2172 value[pos].str = text;
2173 value[pos].len = strlen(text);
2177 if(type == ASSIGNMENT)
2180 name[pos].str = "character";
2182 value[pos].str = text;
2183 value[pos].len = strlen(text);
2191 isboolean[pos] = (x[0] =='@');
2204 name[pos].len = d-x;
2209 name[pos].len = e-x;
2210 value[pos].str = e+1;
2211 value[pos].len = d-e-1;
2219 /* for(t=0;t<len;t++) {
2220 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2221 isboolean[t]?"(boolean)":"");
2226 if(type == RAWDATA || type == COMMAND) {
2231 // first, search for boolean arguments
2232 for(pos=0;pos<len;pos++)
2234 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2236 if(type == ASSIGNMENT)
2238 value[pos].str = text;
2239 value[pos].len = strlen(text);
2240 /*printf("setting boolean parameter %s (to %s)\n",
2241 strdup_n(name[pos], namelen[pos]),
2242 strdup_n(value[pos], valuelen[pos]));*/
2247 // second, search for normal arguments
2249 for(pos=0;pos<len;pos++)
2251 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2252 (type != ASSIGNMENT && !set[pos])) {
2254 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2256 if(type == ASSIGNMENT)
2259 value[pos].str = text;
2260 value[pos].len = strlen(text);
2262 printf("setting parameter %s (to %s)\n",
2263 strdup_n(name[pos].str, name[pos].len),
2264 strdup_n(value[pos].str, value[pos].len));
2270 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
2274 for(t=0;t<len;t++) {
2275 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2278 for(t=0;t<len;t++) {
2279 if(value[t].str && value[t].str[0] == '*') {
2280 //relative default- take value from some other parameter
2282 for(s=0;s<len;s++) {
2283 if(value[s].len == value[t].len-1 &&
2284 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2285 value[t].str = value[s].str;
2288 if(value[t].str == 0) {
2290 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2294 /* ok, now construct the dictionary from the parameters */
2298 map_put(&result, name[t], value[t]);
2302 static void parseArgumentsForCommand(char*command)
2307 msg("<verbose> parse Command: %s (line %d)", command, line);
2308 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2309 if(!strcmp(arguments[t].command, command)) {
2311 /* ugly hack- will be removed soon (once documentation and .sc generating
2312 utilities have been changed) */
2313 if(!strcmp(command, "swf") && !stackpos) {
2314 warning("Please use .flash instead of .swf- this will be mandatory soon");
2319 args = parseArguments(command, arguments[t].arguments);
2325 syntaxerror("command %s not known", command);
2328 printf(".%s\n", command);fflush(stdout);
2329 map_dump(&args, stdout, "\t");fflush(stdout);
2332 (*arguments[nr].func)(&args);
2334 /*if(!strcmp(command, "button") ||
2335 !strcmp(command, "action")) {
2338 if(type == COMMAND) {
2339 if(!strcmp(text, "end"))
2353 int main (int argc,char ** argv)
2356 processargs(argc, argv);
2357 initLog(0,-1,0,0,-1,verbose);
2360 args_callback_usage(argv[0]);
2363 file = generateTokens(filename);
2365 printf("parser returned error.\n");
2372 while(!noMoreTokens()) {
2375 syntaxerror("command expected");
2376 parseArgumentsForCommand(text);