#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}
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;
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 <filename> Set output file to <filename>.\n");
printf("\n");
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);
}
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()
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
float shear;
SPOINT pivot;
SPOINT pin;
+ U8 blendmode; //not interpolated
+ FILTER*filter;
} parameters_t;
typedef struct _character {
typedef struct _gradient {
GRADIENT gradient;
char radial;
+ 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));
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;
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);
}
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);
currentdepth = stack[stackpos].olddepth;
instances = stack[stackpos].oldinstances;
+ tag = swf_InsertTag(tag, ST_SHOWFRAME);
tag = swf_InsertTag(tag, ST_END);
tag = stack[stackpos].tag;
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" */
}
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 || !strcmp(filename, "-"))
+ 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");}
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);
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;t<nr;t++) {
tag = swf_InsertTag(tag, ST_SHOWFRAME);
if(t==nr-1 && name && *name) {
tag = swf_InsertTag(tag, ST_FRAMELABEL);
swf_SetString(tag, name);
+ if(anchor)
+ swf_SetU8(tag, 1); //make this an anchor
}
}
+ if(nr == 0 && currentframe == 0 && name && *name) {
+ tag = swf_InsertTag(tag, ST_FRAMELABEL);
+ swf_SetString(tag, name);
+ if(anchor)
+ swf_SetU8(tag, 1); //make this an anchor
+ }
if(cut) {
if(now == tag) {
int parseColor2(char*str, RGBA*color);
-int addFillStyle(SHAPE*s, SRECT*r, char*texture)
+int addFillStyle(SHAPE*s, SRECT*r, char*name)
{
RGBA color;
character_t*image;
gradient_t*gradient;
- if(texture[0] == '#') {
- parseColor2(texture, &color);
+ texture_t*texture;
+ if(name[0] == '#') {
+ parseColor2(name, &color);
return swf_ShapeAddSolidFillStyle(s, &color);
- } else if((image = dictionary_lookup(&images, texture))) {
+ } else if ((texture = dictionary_lookup(&textures, name))) {
+ return swf_ShapeAddFillStyle2(s, &texture->fs);
+ } 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;
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))) {
- MATRIX m;
+ } else if ((gradient = dictionary_lookup(&gradients, name))) {
+ SRECT r2;
+ MATRIX rot,m;
+ double ccos,csin;
+ swf_GetMatrix(0, &rot);
+ ccos = cos(-gradient->rotate*2*3.14159265358979/360);
+ csin = sin(-gradient->rotate*2*3.14159265358979/360);
+ rot.sx = ccos*65536;
+ rot.r1 = -csin*65536;
+ rot.r0 = csin*65536;
+ rot.sy = ccos*65536;
+ r2 = swf_TurnRect(*r, &rot);
swf_GetMatrix(0, &m);
- m.sx = (r->xmax - r->xmin)*2;
- m.sy = (r->ymax - r->ymin)*2;
+ m.sx = (r2.xmax - r2.xmin)*2*ccos;
+ m.r1 = -(r2.xmax - r2.xmin)*2*csin;
+ m.r0 = (r2.ymax - r2.ymin)*2*csin;
+ m.sy = (r2.ymax - r2.ymin)*2*ccos;
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;
}
}
{
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_DEFINESHAPE);
+ 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);
}
r2 = outline->bbox;
- tag = swf_InsertTag(tag, ST_DEFINESHAPE);
+ 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=<color/texture> 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);
{
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_DEFINESHAPE);
+ 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);
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;
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();
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;
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 */
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(bitmap) {
+ fs->m.sx *= 20;
+ fs->m.sy *= 20;
+ }
+
+
+ if(dictionary_lookup(&textures, name))
+ syntaxerror("texture %s defined twice", name);
+ dictionary_put2(&textures, name, texture);
+}
+
void dumpSWF(SWF*swf)
{
TAG* tag = swf->firstTag;
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))
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<numsamples;t++) {
+ samples[t] = (samples[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;
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;
}
-void s_gradient(char*name, const char*text, int radial)
+void s_gradient(char*name, const char*text, int radial, int rotate)
{
gradient_t* gradient;
gradient = malloc(sizeof(gradient_t));
memset(gradient, 0, sizeof(gradient_t));
gradient->gradient = parseGradient(text);
gradient->radial = radial;
+ gradient->rotate = rotate;
if(dictionary_lookup(&gradients, name))
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)
{
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);
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;
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;
TAG* s;
int level = 0;
U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
- f = open(filename,O_RDONLY);
+ f = open(filename,O_RDONLY|O_BINARY);
if (f<0) {
warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
s_box(name, 0, 0, black, 20, 0);
s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
swf_SetU16(tag, id);
- swf_SetU16(tag, 0);
+ swf_SetU16(tag, swf.frameCount);
swf_Relocate(&swf, idmap);
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)
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);
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)
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;
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;
}
}
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
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;
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;
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<dot-1;s++)
if(*s<'0' || *s>'9')
syntaxerror("Not a coordinate: \"%s\"", 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)
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;t<sizeof(colors)/sizeof(colors[0]);t++)
- if(!strcmp(str, colors[t].name)) {
+ if(!strncmp(str, colors[t].name, len)) {
r = colors[t].r;
g = colors[t].g;
b = colors[t].b;
- a = 255;
+ a = alpha;
color->r = r; color->g = g; color->b = b; color->a = a;
return 1;
}
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);
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("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
+ msg("<notice> 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)
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");
int radial= strcmp(lu(args, "radial"), "radial")?0:1;
+ int rotate = parseInt(lu(args, "rotate"));
readToken();
if(type != RAWDATA)
syntaxerror("colon (:) expected");
- s_gradient(name, text, radial);
+ 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");
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;
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;
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)
{
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"))
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)
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;
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;
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");
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)(100*20*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");
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;
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;
}
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=<plus>1 name= @cut=no"},
+{{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
+ {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
// "import" type stuff
{"swf", c_swf, "name filename"},
{"shape", c_swf, "name filename"},
{"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"},
+ {"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"},
{"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"},
// 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, "<i> 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, "<i> 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, "<i> 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, "<i> 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, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
+ {"texture", c_texture, "<i> 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, ""}
};
}
}
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
file = generateTokens(filename);
if(!file) {
- printf("parser returned error.\n");
+ fprintf(stderr, "parser returned error.\n");
return 1;
}
pos=0;