X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fswfc.c;h=745ec2ec00d846c7f7580b26d6a9b41b711651d6;hb=b9319467a11d6cc449505955298e578571a220a1;hp=4d744ff195741edbebae8184c37dd2167bd43855;hpb=0374fd5149246f559ac9b29705fd41baac1e318d;p=swftools.git diff --git a/src/swfc.c b/src/swfc.c index 4d744ff..745ec2e 100644 --- a/src/swfc.c +++ b/src/swfc.c @@ -32,19 +32,24 @@ #include "../lib/log.h" #include "../lib/args.h" #include "../lib/q.h" +#include "../lib/mp3.h" +#include "../lib/wav.h" #include "parser.h" -#include "wav.h" +#include "../lib/png.h" //#define DEBUG static char * filename = 0; static char * outputname = "output.swf"; static int verbose = 2; +static int optimize = 0; static int override_outputname = 0; +static int do_cgi = 0; static struct options_t options[] = { {"h", "help"}, {"V", "version"}, +{"C", "cgi"}, {"v", "verbose"}, {"o", "output"}, {0,0} @@ -61,6 +66,14 @@ int args_callback_option(char*name,char*val) override_outputname = 1; return 1; } + else if(!strcmp(name, "O")) { + optimize = 1; + return 0; + } + else if(!strcmp(name, "C")) { + do_cgi = 1; + return 0; + } else if(!strcmp(name, "v")) { verbose ++; return 0; @@ -82,6 +95,7 @@ void args_callback_usage(char *name) printf("\n"); printf("-h , --help Print short help message and exit\n"); printf("-V , --version Print version info and exit\n"); + printf("-C , --cgi Output to stdout (for use in CGI environments)\n"); printf("-v , --verbose Increase verbosity. \n"); printf("-o , --output Set output file to .\n"); printf("\n"); @@ -112,7 +126,7 @@ static void syntaxerror(char*format, ...) va_start(arglist, format); vsprintf(buf, format, arglist); va_end(arglist); - printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf); + fprintf(stderr, "\"%s\", line %d column %d: error- %s\n", filename, line, column, buf); exit(1); } @@ -123,7 +137,7 @@ static void warning(char*format, ...) va_start(arglist, format); vsprintf(buf, format, arglist); va_end(arglist); - printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf); + fprintf(stderr, "\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf); } static void readToken() @@ -186,8 +200,10 @@ static int stackpos = 0; static dictionary_t characters; static dictionary_t images; +static dictionary_t textures; static dictionary_t outlines; static dictionary_t gradients; +static dictionary_t filters; static char idmap[65536]; static TAG*tag = 0; //current tag @@ -207,6 +223,8 @@ typedef struct _parameters { float shear; SPOINT pivot; SPOINT pin; + U8 blendmode; //not interpolated + FILTER*filter; } parameters_t; typedef struct _character { @@ -234,6 +252,14 @@ typedef struct _gradient { int rotate; } gradient_t; +typedef struct _filter { + FILTER filter; +} filter_t; + +typedef struct _texture { + FILLSTYLE fs; +} texture_t; + static void character_init(character_t*c) { memset(c, 0, sizeof(character_t)); @@ -308,15 +334,6 @@ static instance_t* s_addinstance(char*name, character_t*c, U16 depth) return i; } -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) -{ - p->x = x; p->y = y; - p->scalex = scalex; p->scaley = scaley; - p->pin = pin; p->pivot = pivot; - p->rotate = rotate; p->cxform = cxform; - p->shear = shear; -} - static void parameters_clear(parameters_t*p) { p->x = 0; p->y = 0; @@ -326,6 +343,8 @@ static void parameters_clear(parameters_t*p) p->pivot.x = 0; p->pivot.y = 0; p->rotate = 0; p->shear = 0; + p->blendmode = 0; + p->filter = 0; swf_GetCXForm(0, &p->cxform, 1); } @@ -383,14 +402,16 @@ void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA backgrou swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR); swf->compressed = compress; swf_SetRGB(tag,&background); - + if(stackpos==sizeof(stack)/sizeof(stack[0])) syntaxerror("too many levels of recursion"); dictionary_init(&characters); dictionary_init(&images); + dictionary_init(&textures); dictionary_init(&outlines); dictionary_init(&gradients); + dictionary_init(&filters); dictionary_init(&instances); dictionary_init(&fonts); dictionary_init(&sounds); @@ -612,6 +633,7 @@ static void s_endSprite() currentdepth = stack[stackpos].olddepth; instances = stack[stackpos].oldinstances; + tag = swf_InsertTag(tag, ST_SHOWFRAME); tag = swf_InsertTag(tag, ST_END); tag = stack[stackpos].tag; @@ -633,16 +655,22 @@ static void s_endSWF() tag = removeFromTo(stack[stackpos].cut, tag); stackpos--; - + swf = stack[stackpos].swf; filename = stack[stackpos].filename; - - //tag = swf_InsertTag(tag, ST_SHOWFRAME); //? + + //if(tag->prev && tag->prev->id != ST_SHOWFRAME) + // tag = swf_InsertTag(tag, ST_SHOWFRAME); + tag = swf_InsertTag(tag, ST_SHOWFRAME); tag = swf_InsertTag(tag, ST_END); swf_OptimizeTagOrder(swf); - + + if(optimize) { + swf_Optimize(swf); + } + if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) { swf->movieSize = currentrect; /* "autocrop" */ } @@ -650,13 +678,19 @@ static void s_endSWF() if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) { swf->movieSize.xmax += 20; /* 1 by 1 pixels */ swf->movieSize.ymax += 20; + warning("Empty bounding box for movie"); } - - fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644); + + if(do_cgi) + fi = fileno(stdout); + else + fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644); if(fi<0) { syntaxerror("couldn't create output file %s", filename); } - if(swf->compressed) + if(do_cgi) + {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");} + else if(swf->compressed) {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");} else {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");} @@ -666,8 +700,10 @@ static void s_endSWF() dictionary_clear(&instances); dictionary_clear(&characters); dictionary_clear(&images); + dictionary_clear(&textures); dictionary_clear(&outlines); - dictionary_clear(&gradients); + dictionary_clear(&gradients); // mem leak + dictionary_clear(&filters); dictionary_clear(&fonts); dictionary_clear(&sounds); @@ -690,21 +726,33 @@ void s_close() int s_getframe() { - return currentframe; + return currentframe+1; } -void s_frame(int nr, int cut, char*name) +void s_frame(int nr, int cut, char*name, char anchor) { int t; TAG*now = tag; + if(nr<1) + syntaxerror("Illegal frame number"); + nr--; // internally, frame 1 is frame 0 + for(t=currentframe;tfs); + } else if((image = dictionary_lookup(&images, name))) { MATRIX m; swf_GetMatrix(0, &m); m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax; @@ -734,8 +785,7 @@ int addFillStyle(SHAPE*s, SRECT*r, char*texture) m.tx = r->xmin; m.ty = r->ymin; return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0); - } /*else if ((texture = dictionary_lookup(&textures, texture))) { - } */ else if ((gradient = dictionary_lookup(&gradients, texture))) { + } else if ((gradient = dictionary_lookup(&gradients, name))) { SRECT r2; MATRIX rot,m; double ccos,csin; @@ -755,10 +805,10 @@ int addFillStyle(SHAPE*s, SRECT*r, char*texture) m.tx = r->xmin + (r->xmax - r->xmin)/2; m.ty = r->ymin + (r->ymax - r->ymin)/2; return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial); - } else if (parseColor2(texture, &color)) { + } else if (parseColor2(name, &color)) { return swf_ShapeAddSolidFillStyle(s, &color); } else { - syntaxerror("not a color/fillstyle: %s", texture); + syntaxerror("not a color/fillstyle: %s", name); return 0; } } @@ -768,23 +818,25 @@ void s_box(char*name, int width, int height, RGBA color, int linewidth, char*tex { SRECT r,r2; SHAPE* s; - int ls1,fs1=0; + int ls1=0,fs1=0; r2.xmin = 0; r2.ymin = 0; r2.xmax = width; r2.ymax = height; tag = swf_InsertTag(tag, ST_DEFINESHAPE3); swf_ShapeNew(&s); - ls1 = swf_ShapeAddLineStyle(s,linewidth,&color); - + if(linewidth) { + linewidth = linewidth>=20?linewidth-20:0; + ls1 = swf_ShapeAddLineStyle(s,linewidth,&color); + } if(texture) fs1 = addFillStyle(s, &r2, texture); swf_SetU16(tag,id); - r.xmin = r2.xmin-linewidth-linewidth/2; - r.ymin = r2.ymin-linewidth-linewidth/2; - r.xmax = r2.xmax+linewidth+linewidth/2; - r.ymax = r2.ymax+linewidth+linewidth/2; + r.xmin = r2.xmin-linewidth/2; + r.ymin = r2.ymin-linewidth/2; + r.xmax = r2.xmax+linewidth/2; + r.ymax = r2.ymax+linewidth/2; swf_SetRect(tag,&r); swf_SetShapeHeader(tag,s); swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0); @@ -813,21 +865,26 @@ void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*textu tag = swf_InsertTag(tag, ST_DEFINESHAPE3); swf_ShapeNew(&s); - ls1 = swf_ShapeAddLineStyle(s,linewidth,&color); + if(linewidth) { + linewidth = linewidth>=20?linewidth-20:0; + ls1 = swf_ShapeAddLineStyle(s,linewidth,&color); + } if(texture) fs1 = addFillStyle(s, &r2, texture); - else - syntaxerror("non filled outlines not yet supported- please supply a fill= argument"); + swf_SetU16(tag,id); - rect.xmin = r2.xmin-linewidth-linewidth/2; - rect.ymin = r2.ymin-linewidth-linewidth/2; - rect.xmax = r2.xmax+linewidth+linewidth/2; - rect.ymax = r2.ymax+linewidth+linewidth/2; + rect.xmin = r2.xmin-linewidth/2; + rect.ymin = r2.ymin-linewidth/2; + rect.xmax = r2.xmax+linewidth/2; + rect.ymax = r2.ymax+linewidth/2; swf_SetRect(tag,&rect); swf_SetShapeStyles(tag, s); - swf_SetShapeBits(tag, outline->shape); //does not count bits! - swf_SetBlock(tag, outline->shape->data, (outline->shape->bitlen+7)/8); + swf_ShapeCountBits(s,0,0); + swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line, + &s->data, &s->bitlen, s->bits.fill, s->bits.line); + swf_SetShapeBits(tag, s); + swf_SetBlock(tag, s->data, (s->bitlen+7)/8); swf_ShapeFree(s); s_addcharacter(name, id, tag, rect); @@ -838,21 +895,24 @@ void s_circle(char*name, int r, RGBA color, int linewidth, char*texture) { SRECT rect,r2; SHAPE* s; - int ls1,fs1=0; + int ls1=0,fs1=0; r2.xmin = r2.ymin = 0; r2.xmax = 2*r; r2.ymax = 2*r; tag = swf_InsertTag(tag, ST_DEFINESHAPE3); swf_ShapeNew(&s); - ls1 = swf_ShapeAddLineStyle(s,linewidth,&color); + if(linewidth) { + linewidth = linewidth>=20?linewidth-20:0; + ls1 = swf_ShapeAddLineStyle(s,linewidth,&color); + } if(texture) fs1 = addFillStyle(s, &r2, texture); swf_SetU16(tag,id); - rect.xmin = r2.xmin-linewidth-linewidth/2; - rect.ymin = r2.ymin-linewidth-linewidth/2; - rect.xmax = r2.xmax+linewidth+linewidth/2; - rect.ymax = r2.ymax+linewidth+linewidth/2; + rect.xmin = r2.xmin-linewidth/2; + rect.ymin = r2.ymin-linewidth/2; + rect.xmax = r2.xmax+linewidth/2; + rect.ymax = r2.ymax+linewidth/2; swf_SetRect(tag,&rect); swf_SetShapeHeader(tag,s); @@ -924,18 +984,36 @@ void s_text(char*name, char*fontname, char*text, int size, RGBA color) incrementid(); } -void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags) +void s_quicktime(char*name, char*url) { - SWFFONT*font; + SRECT r; + MATRIX _m,*m=0; + + memset(&r, 0, sizeof(r)); + + tag = swf_InsertTag(tag, ST_DEFINEMOVIE); + swf_SetU16(tag, id); + swf_SetString(tag, url); + + s_addcharacter(name, id, tag, r); + incrementid(); +} + +void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags, int align) +{ + SWFFONT*font = 0; EditTextLayout layout; SRECT r; - font = dictionary_lookup(&fonts, fontname); - if(!font) - syntaxerror("font \"%s\" not known!", fontname); + if(fontname && *fontname) { + flags |= ET_USEOUTLINES; + font = dictionary_lookup(&fonts, fontname); + if(!font) + syntaxerror("font \"%s\" not known!", fontname); + } tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT); swf_SetU16(tag, id); - layout.align = 0; + layout.align = align; layout.leftmargin = 0; layout.rightmargin = 0; layout.indent = 0; @@ -944,7 +1022,8 @@ void s_edittext(char*name, char*fontname, int size, int width, int height, char* r.ymin = 0; r.xmax = width; r.ymax = height; - swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable); + + swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable); s_addcharacter(name, id, tag, r); incrementid(); @@ -961,13 +1040,8 @@ void s_image(char*name, char*type, char*filename, int quality) SRECT r; int imageID = id; int width, height; - if(type=="png") { - warning("image type \"png\" not supported yet!"); - s_box(name, 0, 0, black, 20, 0); - return; - } - if(type=="jpeg") { -#ifndef HAVE_LIBJPEG + if(!strcmp(type,"jpeg")) { +#ifndef HAVE_JPEGLIB warning("no jpeg support compiled in"); s_box(name, 0, 0, black, 20, 0); return; @@ -989,6 +1063,31 @@ void s_image(char*name, char*type, char*filename, int quality) s_addimage(name, id, tag, r); incrementid(); #endif + } else if(!strcmp(type,"png")) { + RGBA*data = 0; + swf_SetU16(tag, imageID); + + getPNG(filename, &width, &height, (unsigned char**)&data); + + if(!data) { + syntaxerror("Image \"%s\" not found, or contains errors", filename); + } + + /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/ + tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS); + swf_SetU16(tag, imageID); + swf_SetLosslessImage(tag, data, width, height); + + r.xmin = 0; + r.ymin = 0; + r.xmax = width*20; + r.ymax = height*20; + s_addimage(name, id, tag, r); + incrementid(); + } else { + warning("image type \"%s\" not supported yet!", type); + s_box(name, 0, 0, black, 20, 0); + return; } /* step 2: the character */ @@ -1000,6 +1099,65 @@ void s_image(char*name, char*type, char*filename, int quality) incrementid(); } +void s_getBitmapSize(char*name, int*width, int*height) +{ + character_t* image = dictionary_lookup(&images, name); + gradient_t* gradient = dictionary_lookup(&gradients,name); + if(image) { + *width = image->size.xmax; + *height = image->size.ymax; + return; + } + if(gradient) { + /* internal SWF gradient size */ + if(gradient->radial) { + *width = 16384; + *height = 16384; + } else { + *width = 32768; + *height = 32768; + } + return; + } + syntaxerror("No such bitmap/gradient: %s", name); +} + +void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear) +{ + gradient_t* gradient = dictionary_lookup(&gradients, object); + character_t* bitmap = dictionary_lookup(&images, object); + texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t)); + parameters_t p; + FILLSTYLE*fs = &texture->fs; + + memset(&p, 0, sizeof(parameters_t)); + + if(bitmap) { + fs->type = FILL_TILED; + fs->id_bitmap = bitmap->id; + } else if(gradient) { + fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR; + fs->gradient = gradient->gradient; + } + p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear; + makeMatrix(&fs->m, &p); + if(gradient && !gradient->radial) { + MATRIX m = fs->m; + SPOINT p1,p2; + m.tx = 0; + m.ty = 0; + p1.x = 16384; + p1.y = 16384; + p2 = swf_TurnPoint(p1, &m); + fs->m.tx += p2.x; + fs->m.ty += p2.y; + } + + if(dictionary_lookup(&textures, name)) + syntaxerror("texture %s defined twice", name); + dictionary_put2(&textures, name, texture); +} + void dumpSWF(SWF*swf) { TAG* tag = swf->firstTag; @@ -1040,6 +1198,10 @@ void s_font(char*name, char*filename) font->id = id; tag = swf_InsertTag(tag, ST_DEFINEFONT2); swf_FontSetDefine2(tag, font); + tag = swf_InsertTag(tag, ST_EXPORTASSETS); + swf_SetU16(tag, 1); + swf_SetU16(tag, id); + swf_SetString(tag, name); incrementid(); if(dictionary_lookup(&fonts, name)) @@ -1058,25 +1220,75 @@ typedef struct _sound_t void s_sound(char*name, char*filename) { struct WAV wav, wav2; + struct MP3 mp3; sound_t* sound; - U16*samples; - int numsamples; - - if(!readWAV(filename, &wav)) { - warning("Couldn't read wav file \"%s\"", filename); - samples = 0; - numsamples = 0; - } else { - convertWAV2mono(&wav, &wav2, 44100); + U16*samples = NULL; + unsigned numsamples; + unsigned blocksize = 1152; + int is_mp3 = 0; + + if(wav_read(&wav, filename)) { + int t; + wav_convert2mono(&wav, &wav2, 44100); samples = (U16*)wav2.data; numsamples = wav2.size/2; free(wav.data); +#ifdef WORDS_BIGENDIAN + /* swap bytes */ + for(t=0;t>8)&0xff | (samples[t]<<8)&0xff00; + } +#endif + } else if(mp3_read(&mp3, filename)) { + fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename); + blocksize = 1; + is_mp3 = 1; + } + else + { + warning("Couldn't read WAV/MP3 file \"%s\"", filename); + samples = 0; + numsamples = 0; + } + + if(numsamples%blocksize != 0) + { + // apply padding, so that block is a multiple of blocksize + int numblocks = (numsamples+blocksize-1)/blocksize; + int numsamples2; + U16* samples2; + numsamples2 = numblocks * blocksize; + samples2 = malloc(sizeof(U16)*numsamples2); + memcpy(samples2, samples, numsamples*sizeof(U16)); + memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples)); + numsamples = numsamples2; + samples = samples2; } tag = swf_InsertTag(tag, ST_DEFINESOUND); swf_SetU16(tag, id); //id - swf_SetSoundDefine(tag, samples, numsamples); - + if(is_mp3) + { + swf_SetSoundDefineMP3( + tag, mp3.data, mp3.size, + mp3.SampRate, + mp3.Channels, + mp3.NumFrames); + mp3_clear(&mp3); + } + else + { + swf_SetSoundDefine(tag, samples, numsamples); + } + + tag = swf_InsertTag(tag, ST_NAMECHARACTER); + swf_SetU16(tag, id); + swf_SetString(tag, name); + tag = swf_InsertTag(tag, ST_EXPORTASSETS); + swf_SetU16(tag, 1); + swf_SetU16(tag, id); + swf_SetString(tag, name); + sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */ sound->tag = tag; sound->id = id; @@ -1114,28 +1326,34 @@ RGBA parseColor(char*str); GRADIENT parseGradient(const char*str) { GRADIENT gradient; + int lastpos = -1; const char* p = str; memset(&gradient, 0, sizeof(GRADIENT)); + gradient.ratios = rfx_calloc(16*sizeof(U8)); + gradient.rgba = rfx_calloc(16*sizeof(RGBA)); while(*p) { char*posstr,*colorstr; - float pos; + int pos; RGBA color; posstr = gradient_getToken(&p); if(!*posstr) break; - pos = parsePercent(posstr); + pos = (int)(parsePercent(posstr)*255.0); + if(pos == lastpos) + pos++; if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr); colorstr = gradient_getToken(&p); color = parseColor(colorstr); - if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) { - warning("gradient record too big- max size is 8, rest ignored"); + if(gradient.num == 16) { + warning("gradient record too big- max size is 16, rest ignored"); break; } - gradient.ratios[gradient.num] = (int)(pos*255.0); + gradient.ratios[gradient.num] = pos; gradient.rgba[gradient.num] = color; gradient.num++; free(posstr); free(colorstr); + lastpos = pos; } return gradient; } @@ -1153,6 +1371,92 @@ void s_gradient(char*name, const char*text, int radial, int rotate) syntaxerror("gradient %s defined twice", name); dictionary_put2(&gradients, name, gradient); } + +void s_gradientglow(char*name, char*gradient, float blurx, float blury, + float angle, float distance, float strength, char innershadow, + char knockout, char composite, char ontop, int passes) +{ + gradient_t* g = dictionary_lookup(&gradients, gradient); + + composite = 1; + + if(!g) + syntaxerror("unknown gradient %s", gradient); + FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW)); + filter->type = FILTERTYPE_GRADIENTGLOW; + filter->gradient = &g->gradient; + filter->blurx = blurx; + filter->blury = blury; + filter->strength = strength; + filter->angle = angle; + filter->distance = distance; + filter->innershadow = innershadow; + filter->knockout = knockout; + filter->composite = composite; + filter->ontop = ontop; + filter->passes = passes; + + if(dictionary_lookup(&filters, name)) + syntaxerror("filter %s defined twice", name); + dictionary_put2(&filters, name, filter); +} + +void s_dropshadow(char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes) +{ + composite = 1; + FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW)); + filter->type = FILTERTYPE_DROPSHADOW; + filter->color= color; + filter->blurx = blurx; + filter->blury = blury; + filter->strength = strength; + filter->angle = angle; + filter->distance = distance; + filter->innershadow = innershadow; + filter->knockout = knockout; + filter->composite = composite; + filter->passes = passes; + + if(dictionary_lookup(&filters, name)) + syntaxerror("filter %s defined twice", name); + dictionary_put2(&filters, name, filter); +} + +void s_bevel(char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes) +{ + composite = 1; + FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL)); + filter->type = FILTERTYPE_BEVEL; + filter->shadow = shadow; + filter->highlight = highlight; + filter->blurx = blurx; + filter->blury = blury; + filter->strength = strength; + filter->angle = angle; + filter->distance = distance; + filter->innershadow = innershadow; + filter->knockout = knockout; + filter->composite = composite; + filter->ontop = ontop; + filter->passes = passes; + + if(dictionary_lookup(&filters, name)) + syntaxerror("filter %s defined twice", name); + dictionary_put2(&filters, name, filter); +} + +void s_blur(char*name, double blurx, double blury, int passes) +{ + FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR)); + filter->type = FILTERTYPE_BLUR; + filter->blurx = blurx; + filter->blury = blury; + filter->passes = passes; + + if(dictionary_lookup(&filters, name)) + syntaxerror("filter %s defined twice", name); + dictionary_put2(&filters, name, filter); +} void s_action(const char*text) { @@ -1169,11 +1473,32 @@ void s_action(const char*text) swf_ActionFree(a); } +void s_initaction(const char*character, const char*text) +{ + ActionTAG* a = 0; + character_t*c = 0; + a = swf_ActionCompile(text, stack[0].swf->fileVersion); + if(!a) { + syntaxerror("Couldn't compile ActionScript"); + } + + c = (character_t*)dictionary_lookup(&characters, character); + + tag = swf_InsertTag(tag, ST_DOINITACTION); + swf_SetU16(tag, c->id); + swf_ActionSet(tag, a); + + swf_ActionFree(a); +} + int s_swf3action(char*name, char*action) { ActionTAG* a = 0; - instance_t* object = dictionary_lookup(&instances, name); - if(!object) { + instance_t* object = 0; + if(name) + object = (instance_t*)dictionary_lookup(&instances, name); + if(!object && name && *name) { + /* we have a name, but couldn't find it. Abort. */ return 0; } a = action_SetTarget(0, name); @@ -1199,18 +1524,16 @@ void s_outline(char*name, char*format, char*source) SHAPE2* shape2; SRECT bounds; + //swf_Shape10DrawerInit(&draw, 0); swf_Shape11DrawerInit(&draw, 0); + draw_string(&draw, source); draw.finish(&draw); shape = swf_ShapeDrawerToShape(&draw); - //shape2 = swf_ShapeToShape2(shape); - //bounds = swf_GetShapeBoundingBox(shape2); - //swf_Shape2Free(shape2); bounds = swf_ShapeDrawerGetBBox(&draw); draw.dealloc(&draw); - outline = (outline_t*)malloc(sizeof(outline_t)); - memset(outline, 0, sizeof(outline_t)); + outline = (outline_t*)rfx_calloc(sizeof(outline_t)); outline->shape = shape; outline->bbox = bounds; @@ -1221,8 +1544,11 @@ void s_outline(char*name, char*format, char*source) int s_playsound(char*name, int loops, int nomultiple, int stop) { - sound_t* sound = dictionary_lookup(&sounds, name); + sound_t* sound; SOUNDINFO info; + if(!name) + return 0; + sound = dictionary_lookup(&sounds, name); if(!sound) return 0; @@ -1267,7 +1593,7 @@ void s_includeswf(char*name, char*filename) s = tag = swf_InsertTag(tag, ST_DEFINESPRITE); swf_SetU16(tag, id); - swf_SetU16(tag, 0); + swf_SetU16(tag, swf.frameCount); swf_Relocate(&swf, idmap); @@ -1286,13 +1612,17 @@ void s_includeswf(char*name, char*filename) level--; if(!level) break; - /* We simply dump all tags right after the sprite - header, relying on the fact that swf_OptimizeTagOrder() will - sort things out for us later. - We also rely on the fact that the imported SWF is well-formed. - */ - tag = swf_InsertTag(tag, ftag->id); - swf_SetBlock(tag, ftag->data, ftag->len); + + if(ftag->id != ST_SETBACKGROUNDCOLOR) { + /* We simply dump all tags right after the sprite + header, relying on the fact that swf_OptimizeTagOrder() will + sort things out for us later. + We also rely on the fact that the imported SWF is well-formed. + */ + tag = swf_InsertTag(tag, ftag->id); + swf_SetBlock(tag, ftag->data, ftag->len); + } + ftag = ftag->next; } if(!ftag) @@ -1362,6 +1692,30 @@ void s_endClip() currentdepth++; } +void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move) +{ + SWFPLACEOBJECT po; + FILTERLIST flist; + swf_GetPlaceObject(NULL, &po); + po.id = id; + po.depth = depth; + po.matrix = m; + po.cxform = p->cxform; + po.name = name; + po.move = move; + if(move) + po.id = 0; + if(p->blendmode) { + po.blendmode = p->blendmode; + } + if(p->filter) { + flist.num = 1; + flist.filter[0] = p->filter; + po.filters = &flist; + } + swf_SetPlaceObject(tag, &po); +} + void s_put(char*instance, char*character, parameters_t p) { character_t* c = dictionary_lookup(&characters, character); @@ -1374,12 +1728,18 @@ void s_put(char*instance, char*character, parameters_t p) i = s_addinstance(instance, c, currentdepth); i->parameters = p; m = s_instancepos(i->character->size, &p); + + if(p.blendmode || p.filter) { + tag = swf_InsertTag(tag, ST_PLACEOBJECT3); + } else { + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + } + setPlacement(tag, c->id, currentdepth, m, instance, &p, 0); - tag = swf_InsertTag(tag, ST_PLACEOBJECT2); - swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance); i->lastTag = tag; i->lastFrame = currentframe; currentdepth++; + } void s_jump(char*instance, parameters_t p) @@ -1393,12 +1753,93 @@ void s_jump(char*instance, parameters_t p) i->parameters = p; m = s_instancepos(i->character->size, &p); - tag = swf_InsertTag(tag, ST_PLACEOBJECT2); - swf_ObjectMove(tag, i->depth, &m, &p.cxform); + if(p.blendmode || p.filter) { + tag = swf_InsertTag(tag, ST_PLACEOBJECT3); + } else { + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + } + setPlacement(tag, 0, i->depth, m, 0, &p, 1); + i->lastTag = tag; i->lastFrame = currentframe; } +RGBA interpolateColor(RGBA c1, RGBA c2, float ratio) +{ + RGBA c; + c.r = c1.r * (1-ratio) + c2.r * ratio; + c.g = c1.g * (1-ratio) + c2.g * ratio; + c.b = c1.b * (1-ratio) + c2.b * ratio; + c.a = c1.a * (1-ratio) + c2.a * ratio; + return c; +} + +FILTER* interpolateFilter(FILTER*filter1,FILTER*filter2, float ratio) +{ + if(!filter1 && !filter2) + return 0; + if(!filter1) + return interpolateFilter(filter2,filter1,1-ratio); + + if(filter2 && filter2->type != filter1->type) + syntaxerror("can't interpolate between %s and %s filters yet", filtername[filter1->type], filtername[filter2->type]); + + if(filter1->type == FILTERTYPE_BLUR) { + FILTER_BLUR*f1 = (FILTER_BLUR*)filter1; + FILTER_BLUR*f2 = (FILTER_BLUR*)filter2; + if(f2 && f1->blurx == f2->blurx && f1->blury == f2->blury) + return 0; + FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR); + f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio; + f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio; + f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio; + return (FILTER*)f; + } else if (filter1->type == FILTERTYPE_DROPSHADOW) { + FILTER_DROPSHADOW*f1 = (FILTER_DROPSHADOW*)filter1; + FILTER_DROPSHADOW*f2 = (FILTER_DROPSHADOW*)filter2; + if(f2 && !memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength && + f1->blurx == f2->blurx && f1->blury == f2->blury && + f1->angle == f2->angle && f1->distance == f2->distance) + return 0; + FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW); + memcpy(f, f1, sizeof(FILTER_DROPSHADOW)); + f->color = interpolateColor(f1->color, f2->color, ratio); + f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio; + f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio; + f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio; + f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio; + f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio; + f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio; + return (FILTER*)f; + } else if (filter1->type == FILTERTYPE_BEVEL) { + FILTER_BEVEL*f1 = (FILTER_BEVEL*)filter1; + FILTER_BEVEL*f2 = (FILTER_BEVEL*)filter2; + if(f2 && !memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) && + !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) && + f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance) + return 0; + FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL); + memcpy(f, f1, sizeof(FILTER_BEVEL)); + f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio); + f->highlight = interpolateColor(f1->highlight, f2->highlight, ratio); + f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio; + f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio; + f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio; + f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio; + f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio; + f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio; + return (FILTER*)f; + } /*else if (filter1->type == FILTERTYPE_GRADIENTGLOW) { + FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW); + // can't interpolate gradients + memcpy(f, filter1, sizeof(FILTER_GRADIENTGLOW)); + return (FILTER*)f; + }*/ else { + syntaxerror("can't interpolate %s filters yet", filtername[filter1->type]); + } + return 0; +} + parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num) { parameters_t p; @@ -1428,6 +1869,8 @@ parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num) p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y; p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x; p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y; + + p.filter = interpolateFilter(p1->filter, p2->filter, ratio); return p; } @@ -1450,8 +1893,12 @@ void s_change(char*instance, parameters_t p2) } m = s_instancepos(i->character->size, &p2); - tag = swf_InsertTag(tag, ST_PLACEOBJECT2); - swf_ObjectMove(tag, i->depth, &m, &p2.cxform); + if(p2.blendmode || p2.filter) { + tag = swf_InsertTag(tag, ST_PLACEOBJECT3); + } else { + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + } + setPlacement(tag, 0, i->depth, m, 0, &p2, 1); i->parameters = p2; /* o.k., we got the start and end point set. Now iterate though all the @@ -1468,9 +1915,14 @@ void s_change(char*instance, parameters_t p2) frame ++; p = s_interpolate(&p1, &p2, frame, allframes); m = s_instancepos(i->character->size, &p); //needed? - lt = swf_InsertTag(t, ST_PLACEOBJECT2); + i->lastFrame = currentframe; - swf_ObjectMove(lt, i->depth, &m, &p.cxform); + if(p.blendmode || p.filter) { + lt = swf_InsertTag(t, ST_PLACEOBJECT3); + } else { + lt = swf_InsertTag(t, ST_PLACEOBJECT2); + } + setPlacement(lt, 0, i->depth, m, 0, &p, 1); t = lt; if(frame == allframes) break; @@ -1517,7 +1969,7 @@ typedef int command_func_t(map_t*args); SRECT parseBox(char*str) { - SRECT r; + SRECT r = {0,0,0,0}; float xmin, xmax, ymin, ymax; char*x = strchr(str, 'x'); char*d1=0,*d2=0; @@ -1587,8 +2039,10 @@ int parseTwip(char*str) int t; return sign*parseInt(str)*20; } else { - int l=strlen(++dot); + char* old = strdup(str); + int l=strlen(dot+1); char*s; + *dot++ = 0; for(s=str;s'9') syntaxerror("Not a coordinate: \"%s\"", str); @@ -1596,11 +2050,13 @@ int parseTwip(char*str) if(*s<'0' || *s>'9') syntaxerror("Not a coordinate: \"%s\"", str); } - if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) { - warning("precision loss: %s converted to twip", str); + if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) { + dot[1] = ((dot[1]-0x30)/5)*5 + 0x30; dot[2] = 0; l=2; + warning("precision loss: %s converted to twip: %s.%s", old, str, dot); } + free(old); if(l==0) return sign*atoi(str)*20; if(l==1) @@ -1664,12 +2120,18 @@ int parseColor2(char*str, RGBA*color) color->r = r; color->g = g; color->b = b; color->a = a; return 1; } + int len=strlen(str); + U8 alpha = 255; + if(strchr(str, '/')) { + len = strchr(str, '/')-str; + sscanf(str+len+1,"%02x", &alpha); + } for(t=0;tr = r; color->g = g; color->b = b; color->a = a; return 1; } @@ -1732,6 +2194,19 @@ MULADD mergeMulAdd(MULADD m1, MULADD m2) return r; } +float parsePxOrPercent(char*fontname, char*str) +{ + int l = strlen(str); + if(strchr(str, '%')) + return parsePercent(str); + if(l>2 && str[l-2]=='p' && str[l-1]=='t') { + float p = atof(str); + return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */ + } + syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str); + return 0; +} + float parsePercent(char*str) { int l = strlen(str); @@ -1773,25 +2248,37 @@ static char* lu(map_t* args, char*name) static int c_flash(map_t*args) { - char* name = lu(args, "name"); + char* filename = map_lookup(args, "filename"); char* compressstr = lu(args, "compress"); SRECT bbox = parseBox(lu(args, "bbox")); int version = parseInt(lu(args, "version")); int fps = (int)(parseFloat(lu(args, "fps"))*256); int compress = 0; RGBA color = parseColor(lu(args, "background")); - if(!strcmp(name, "!default!") || override_outputname) - name = outputname; + + if(!filename || !*filename) { + /* for compatibility */ + filename = map_lookup(args, "name"); + if(!filename || !*filename) { + filename = 0; + } else { + //msg(" line %d: .flash name=... is deprecated, use .flash filename=...", line); + msg(" line %d: .flash name=... is deprecated, use .flash filename=...", line); + } + } + + if(!filename || override_outputname) + filename = outputname; if(!strcmp(compressstr, "default")) - compress = version==6; + compress = version>=6; else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress")) compress = 1; else if(!strcmp(compressstr, "no")) compress = 0; else syntaxerror("value \"%s\" not supported for the compress argument", compressstr); - s_swf(name, bbox, version, fps, compress, color); + s_swf(filename, bbox, version, fps, compress, color); return 0; } int isRelative(char*str) @@ -1839,6 +2326,76 @@ SPOINT getPoint(SRECT r, char*name) l--; return *(SPOINT*)&mpoints.buffer[l]; } + +static int texture2(char*name, char*object, map_t*args, int errors) +{ + SPOINT pos,size; + char*xstr = map_lookup(args, "x"); + char*ystr = map_lookup(args, "y"); + char*widthstr = map_lookup(args, "width"); + char*heightstr = map_lookup(args, "height"); + char*scalestr = map_lookup(args, "scale"); + char*scalexstr = map_lookup(args, "scalex"); + char*scaleystr = map_lookup(args, "scaley"); + char*rotatestr = map_lookup(args, "rotate"); + char* shearstr = map_lookup(args, "shear"); + char* radiusstr = map_lookup(args, "r"); + float x=0,y=0; + float scalex = 1.0, scaley = 1.0; + float rotate=0, shear=0; + float r = 0; + if(!*xstr && !*ystr) { + if(errors) + syntaxerror("x and y must be set"); + return 0; + } + if(*scalestr && (*scalexstr || *scaleystr)) { + syntaxerror("scale and scalex/scaley can't both be set"); + return 0; + } + if((*widthstr || *heightstr) && *radiusstr) { + syntaxerror("width/height and radius can't both be set"); + } + if(*radiusstr) { + widthstr = radiusstr; + heightstr = radiusstr; + } + if(!*xstr) xstr="0"; + if(!*ystr) ystr="0"; + if(!*rotatestr) rotatestr="0"; + if(!*shearstr) shearstr="0"; + + if(*scalestr) { + scalex = scaley = parsePercent(scalestr); + } else if(*scalexstr || *scaleystr) { + if(scalexstr) scalex = parsePercent(scalexstr); + if(scaleystr) scaley = parsePercent(scaleystr); + } else if(*widthstr || *heightstr) { + int width=0; + int height=0; + s_getBitmapSize(object, &width, &height); + if(*widthstr) + scalex = (float)parseTwip(widthstr)/(float)width; + if(*heightstr) + scaley = (float)parseTwip(heightstr)/(float)height; + } + x = parseTwip(xstr); + y = parseTwip(ystr); + rotate = parseFloat(rotatestr); + shear = parseFloat(shearstr); + + s_texture(name, object, x,y,scalex,scaley,rotate, shear); + + return 0; +} + +static int c_texture(map_t*args) +{ + char*name = lu(args, "instance"); + char*object = lu(args, "character"); + return texture2(name, object, args, 1); +} + static int c_gradient(map_t*args) { char*name = lu(args, "name"); @@ -1849,9 +2406,127 @@ static int c_gradient(map_t*args) if(type != RAWDATA) syntaxerror("colon (:) expected"); - s_gradient(name, text, radial,rotate); + s_gradient(name, text, radial, rotate); + + /* check whether we also have placement information, + which would make this a positioned gradient. + If there is placement information, texture2() will + add a texture, which has priority over the gradient. + */ + texture2(name, name, args, 0); return 0; } + +static int c_blur(map_t*args) +{ + char*name = lu(args, "name"); + char*blurstr = lu(args, "blur"); + char*blurxstr = lu(args, "blurx"); + char*blurystr = lu(args, "blury"); + float blurx=1.0, blury=1.0; + if(blurstr[0]) { + blurx = parseFloat(blurstr); + blury = parseFloat(blurstr); + } + if(blurxstr[0]) + blurx = parseFloat(blurxstr); + if(blurystr[0]) + blury = parseFloat(blurystr); + int passes = parseInt(lu(args, "passes")); + s_blur(name, blurx, blury, passes); + return 0; +} + +static int c_gradientglow(map_t*args) +{ + char*name = lu(args, "name"); + char*gradient = lu(args, "gradient"); + char*blurstr = lu(args, "blur"); + char*blurxstr = lu(args, "blurx"); + char*blurystr = lu(args, "blury"); + float blurx=1.0, blury=1.0; + if(blurstr[0]) { + blurx = parseFloat(blurstr); + blury = parseFloat(blurstr); + } + if(blurxstr[0]) + blurx = parseFloat(blurxstr); + if(blurystr[0]) + blury = parseFloat(blurystr); + + float angle = parseFloat(lu(args, "angle")) / 180 * M_PI; + float distance = parseFloat(lu(args, "distance")); + float strength = parseFloat(lu(args, "strength")); + char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1; + char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1; + char composite = strcmp(lu(args, "composite"),"composite")?0:1; + char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1; + int passes = parseInt(lu(args, "passes")); + + s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes); + return 0; +} + +static int c_dropshadow(map_t*args) +{ + char*name = lu(args, "name"); + RGBA color = parseColor(lu(args, "color")); + char*blurstr = lu(args, "blur"); + char*blurxstr = lu(args, "blurx"); + char*blurystr = lu(args, "blury"); + float blurx=1.0, blury=1.0; + if(blurstr[0]) { + blurx = parseFloat(blurstr); + blury = parseFloat(blurstr); + } + if(blurxstr[0]) + blurx = parseFloat(blurxstr); + if(blurystr[0]) + blury = parseFloat(blurystr); + + float angle = parseFloat(lu(args, "angle")) / 180 * M_PI; + float distance = parseFloat(lu(args, "distance")); + float strength = parseFloat(lu(args, "strength")); + char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1; + char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1; + char composite = strcmp(lu(args, "composite"),"composite")?0:1; + int passes = parseInt(lu(args, "passes")); + + s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes); + return 0; +} + +static int c_bevel(map_t*args) +{ + char*name = lu(args, "name"); + RGBA shadow = parseColor(lu(args, "shadow")); + RGBA highlight = parseColor(lu(args, "highlight")); + char*blurstr = lu(args, "blur"); + char*blurxstr = lu(args, "blurx"); + char*blurystr = lu(args, "blury"); + float blurx=1.0, blury=1.0; + if(blurstr[0]) { + blurx = parseFloat(blurstr); + blury = parseFloat(blurstr); + } + if(blurxstr[0]) + blurx = parseFloat(blurxstr); + if(blurystr[0]) + blury = parseFloat(blurystr); + + float angle = parseFloat(lu(args, "angle")) / 180 * M_PI; + float distance = parseFloat(lu(args, "distance")); + float strength = parseFloat(lu(args, "strength")); + char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1; + char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1; + char composite = strcmp(lu(args, "composite"),"composite")?0:1; + char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1; + int passes = parseInt(lu(args, "passes")); + + s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes); + return 0; +} + static int c_point(map_t*args) { char*name = lu(args, "name"); @@ -1892,7 +2567,7 @@ static int c_play(map_t*args) static int c_stop(map_t*args) { - char*name = lu(args, "name"); + char*name = map_lookup(args, "name"); if(s_playsound(name, 0,0,1)) { return 0; @@ -1946,6 +2621,9 @@ static int c_placement(map_t*args, int type) char* astr = lu(args, "alpha"); char* pinstr = lu(args, "pin"); char* as = map_lookup(args, "as"); + char* blendmode = lu(args, "blend"); + char*filterstr = lu(args, "filter"); + U8 blend; MULADD r,g,b,a; float oldwidth; float oldheight; @@ -2099,6 +2777,29 @@ static int c_placement(map_t*args, int type) p.cxform.a0 = a.mul;p.cxform.a1 = a.add; } + if(blendmode[0]) { + int t; + blend = 255; + for(t=0;blendModeNames[t];t++) { + if(!strcmp(blendModeNames[t], blendmode)) { + blend = t; + break; + } + } + if(blend == 255) { + syntaxerror("unknown blend mode: '%s'", blendmode); + } + p.blendmode = blend; + } + + if(filterstr[0]) { + FILTER*f = dictionary_lookup(&filters, filterstr); + if(!f) + syntaxerror("Unknown filter %s", filterstr); + p.filter = f; + } + + if(type == 0) s_put(instance, character, p); else if(type == 1) @@ -2174,7 +2875,14 @@ static int c_frame(map_t*args) { char*framestr = lu(args, "n"); char*cutstr = lu(args, "cut"); + char*name = lu(args, "name"); + char*anchor = lu(args, "anchor"); + char buf[40]; + + if(!strcmp(anchor, "anchor") && !*name) + name = framestr; + int frame; int cut = 0; if(strcmp(cutstr, "no")) @@ -2188,10 +2896,10 @@ static int c_frame(map_t*args) else { frame = parseInt(framestr); if(s_getframe() >= frame - && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0 + && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr); } - s_frame(frame, cut, name); + s_frame(frame, cut, name, !strcmp(anchor, "anchor")); return 0; } static int c_primitive(map_t*args) @@ -2241,7 +2949,7 @@ static int c_textshape(map_t*args) char*name = lu(args, "name"); char*text = lu(args, "text"); char*font = lu(args, "font"); - float size = parsePercent(lu(args, "size")); + float size = parsePxOrPercent(font, lu(args, "size")); s_textshape(name, font, size, text); return 0; @@ -2279,7 +2987,7 @@ static int c_text(map_t*args) char*name = lu(args, "name"); char*text = lu(args, "text"); char*font = lu(args, "font"); - float size = parsePercent(lu(args, "size")); + float size = parsePxOrPercent(font, lu(args, "size")); RGBA color = parseColor(lu(args, "color")); s_text(name, font, text, (int)(size*100), color); return 0; @@ -2290,6 +2998,14 @@ static int c_soundtrack(map_t*args) return 0; } +static int c_quicktime(map_t*args) +{ + char*name = lu(args, "name"); + char*url = lu(args, "url"); + s_quicktime(name, url); + return 0; +} + static int c_image(map_t*args) { char*command = lu(args, "commandname"); @@ -2449,10 +3165,10 @@ static int c_on_key(map_t*args) static int c_edittext(map_t*args) { - //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"}, + //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @autosize=0"}, char*name = lu(args, "name"); char*font = lu(args, "font"); - int size = (int)(1024*parsePercent(lu(args, "size"))); + int size = (int)(1024*parsePxOrPercent(font, lu(args, "size"))); int width = parseTwip(lu(args, "width")); int height = parseTwip(lu(args, "height")); char*text = lu(args, "text"); @@ -2466,6 +3182,9 @@ static int c_edittext(map_t*args) char*noselectstr = lu(args, "noselect"); char*readonlystr = lu(args, "readonly"); char*borderstr = lu(args, "border"); + char*autosizestr = lu(args, "autosize"); + char*alignstr = lu(args, "align"); + int align = -1; int flags = 0; if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD; @@ -2475,24 +3194,66 @@ static int c_edittext(map_t*args) if(!strcmp(htmlstr, "html")) flags |= ET_HTML; if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT; if(!strcmp(borderstr, "border")) flags |= ET_BORDER; - - s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags); + if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE; + if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT; + else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT; + else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER; + else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY; + else syntaxerror("Unknown alignment: %s", alignstr); + + s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align); return 0; } static int c_morphshape(map_t*args) {return fakechar(args);} static int c_movie(map_t*args) {return fakechar(args);} -static int c_texture(map_t*args) {return 0;} +static char* readfile(const char*filename) +{ + FILE*fi = fopen(filename, "rb"); + int l; + char*text; + if(!fi) + syntaxerror("Couldn't find file %s: %s", filename, strerror(errno)); + fseek(fi, 0, SEEK_END); + l = ftell(fi); + fseek(fi, 0, SEEK_SET); + text = rfx_alloc(l+1); + fread(text, l, 1, fi); + text[l]=0; + fclose(fi); + return text; +} static int c_action(map_t*args) { - readToken(); - if(type != RAWDATA) { - syntaxerror("colon (:) expected"); + char* filename = map_lookup(args, "filename"); + if(!filename ||!*filename) { + readToken(); + if(type != RAWDATA) { + syntaxerror("colon (:) expected"); + } + s_action(text); + } else { + s_action(readfile(filename)); } + + return 0; +} - s_action(text); +static int c_initaction(map_t*args) +{ + char* character = lu(args, "name"); + char* filename = map_lookup(args, "filename"); + if(!filename ||!*filename) { + readToken(); + if(type != RAWDATA) { + syntaxerror("colon (:) expected"); + } + s_initaction(character, text); + } else { + s_initaction(character, readfile(filename)); + } return 0; } @@ -2502,8 +3263,8 @@ static struct { command_func_t* func; char*arguments; } arguments[] = -{{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"}, - {"frame", c_frame, "n=1 name= @cut=no"}, +{{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"}, + {"frame", c_frame, "n=1 name= @cut=no @anchor=no"}, // "import" type stuff {"swf", c_swf, "name filename"}, {"shape", c_swf, "name filename"}, @@ -2513,14 +3274,21 @@ static struct { {"sound", c_sound, "name filename"}, {"font", c_font, "name filename"}, {"soundtrack", c_soundtrack, "filename"}, + {"quicktime", c_quicktime, "url"}, // generators of primitives {"point", c_point, "name x=0 y=0"}, - {"gradient", c_gradient, "name @radial=0 rotate=0"}, + {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture {"outline", c_outline, "name format=simple"}, {"textshape", c_textshape, "name font size=100% text"}, + // filters + {"blur", c_blur, "name blur= blurx= blury= passes=1"}, + {"gradientglow", c_gradientglow, "name gradient blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 @ontop=0 passes=1"}, + {"dropshadow", c_dropshadow, "name color blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 passes=1"}, + {"bevel", c_bevel, "name shadow highlight blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 @ontop=0 passes=1"}, + // character generators {"box", c_primitive, "name width height color=white line=1 @fill=none"}, {"circle", c_primitive, "name r color=white line=1 @fill=none"}, @@ -2528,10 +3296,10 @@ static struct { {"egon", c_egon, "name vertices color=white line=1 @fill=none"}, {"text", c_text, "name text font size=100% color=white"}, - {"edittext", c_edittext, "name font size=100% width height text="" color=white maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @border=0"}, + {"edittext", c_edittext, "name font= size=100% width height text="" color=white maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @border=0 @autosize=0 align="}, {"morphshape", c_morphshape, "name start end"}, {"button", c_button, "name"}, - {"show", c_show, "name x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below= as="}, + {"show", c_show, "name x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= as="}, {"on_press", c_on_press, "position=inside"}, {"on_release", c_on_release, "position=anywhere"}, {"on_move_in", c_on_move_in, "state=not_pressed"}, @@ -2540,25 +3308,26 @@ static struct { // control tags {"play", c_play, "name loop=0 @nomultiple=0"}, - {"stop", c_stop, "name"}, + {"stop", c_stop, "name= "}, {"nextframe", c_nextframe, "name"}, {"previousframe", c_previousframe, "name"}, // object placement tags - {"put", c_put, " x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, - {"startclip", c_startclip, " x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, - {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, - {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, - {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, - {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="}, + {"put", c_put, " x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="}, + {"startclip", c_startclip, " x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="}, + {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="}, + {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="}, + {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="}, + {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="}, {"del", c_del, "name"}, // virtual object placement - {"texture", c_texture, " x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"}, + {"texture", c_texture, " x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="}, // commands which start a block //startclip (see above) {"sprite", c_sprite, "name"}, - {"action", c_action, ""}, + {"action", c_action, "filename="}, + {"initaction", c_initaction, "name filename="}, {"end", c_end, ""} }; @@ -2697,7 +3466,7 @@ static map_t parseArguments(char*command, char*pattern) } } if(pos==len) { - syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command); + syntaxerror("Illegal argument \"%s\" to .%s", text, command); } } #if 0//def DEBUG @@ -2800,7 +3569,7 @@ int main (int argc,char ** argv) file = generateTokens(filename); if(!file) { - printf("parser returned error.\n"); + fprintf(stderr, "parser returned error.\n"); return 1; } pos=0;