#include <math.h>
#include "../config.h"
#include "../lib/rfxswf.h"
+#include "../lib/drawer.h"
#include "../lib/log.h"
#include "../lib/args.h"
#include "../lib/q.h"
static int verbose = 2;
static int override_outputname = 0;
-static struct options_t options[] =
-{
- {"o","output"},
- {"v","verbose"},
- {"V","version"},
- {0,0}
+static struct options_t options[] = {
+{"h", "help"},
+{"V", "version"},
+{"v", "verbose"},
+{"o", "output"},
+{0,0}
};
int args_callback_option(char*name,char*val)
{
return args_long2shortoption(options, name, val);
}
-void args_callback_usage(char*name)
+void args_callback_usage(char *name)
{
- printf("Usage: %s [-o filename] file.wav\n", name);
- printf("\t-v , --verbose\t\t\t Be more verbose\n");
- printf("\t-o , --output filename\t\t set output filename (default: output.swf)\n");
- printf("\t-V , --version\t\t\t Print program version and exit\n");
+ printf("\n");
+ printf("Usage: %s [-o file.swf] file.sc\n", name);
+ printf("\n");
+ printf("-h , --help Print short help message and exit\n");
+ printf("-V , --version Print version info and exit\n");
+ printf("-v , --verbose Increase verbosity. \n");
+ printf("-o , --output <filename> Set output file to <filename>.\n");
+ printf("\n");
}
int args_callback_command(char*name,char*val)
{
va_end(arglist);
printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
}
-
+
static void readToken()
{
type = file[pos].type;
static dictionary_t characters;
static dictionary_t images;
+static dictionary_t outlines;
+static dictionary_t gradients;
static char idmap[65536];
static TAG*tag = 0; //current tag
U16 lastFrame; //frame lastTag is in
} instance_t;
+typedef struct _outline {
+ SHAPE* shape;
+ SRECT bbox;
+} outline_t;
+
+typedef struct _gradient {
+ GRADIENT gradient;
+ char radial;
+} gradient_t;
+
static void character_init(character_t*c)
{
memset(c, 0, sizeof(character_t));
dictionary_init(&characters);
dictionary_init(&images);
+ dictionary_init(&outlines);
+ dictionary_init(&gradients);
dictionary_init(&instances);
dictionary_init(&fonts);
dictionary_init(&sounds);
dictionary_clear(&instances);
dictionary_clear(&characters);
dictionary_clear(&images);
+ dictionary_clear(&outlines);
+ dictionary_clear(&gradients);
dictionary_clear(&fonts);
dictionary_clear(&sounds);
{
if(stackpos) {
if(stack[stackpos-1].type == 0)
- syntaxerror("End of file encountered in .swf block");
+ syntaxerror("End of file encountered in .flash block");
if(stack[stackpos-1].type == 1)
syntaxerror("End of file encountered in .sprite block");
if(stack[stackpos-1].type == 2)
{
RGBA color;
character_t*image;
+ gradient_t*gradient;
if(texture[0] == '#') {
parseColor2(texture, &color);
return swf_ShapeAddSolidFillStyle(s, &color);
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 (parseColor2(texture, &color)) {
+ } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
+ MATRIX m;
+ swf_GetMatrix(0, &m);
+ m.sx = (r->xmax - r->xmin)*2;
+ m.sy = (r->ymax - r->ymin)*2;
+ 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)) {
return swf_ShapeAddSolidFillStyle(s, &color);
} else {
syntaxerror("not a color/fillstyle: %s", texture);
incrementid();
}
+void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
+{
+ SRECT rect,r2;
+ SHAPE* s;
+ int ls1,fs1=0;
+ outline_t* outline;
+ outline = dictionary_lookup(&outlines, outlinename);
+ if(!outline) {
+ syntaxerror("outline %s not defined", outlinename);
+ }
+ r2 = outline->bbox;
+
+ tag = swf_InsertTag(tag, ST_DEFINESHAPE);
+ swf_ShapeNew(&s);
+ 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;
+
+ 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_ShapeFree(s);
+
+ s_addcharacter(name, id, tag, rect);
+ incrementid();
+}
+
void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
{
SRECT rect,r2;
incrementid();
}
-void s_textshape(char*name, char*fontname, char*_text, RGBA color, int linewidth, char*texture)
+void s_textshape(char*name, char*fontname, char*_text)
{
- SRECT rect,r2;
- SHAPE* s;
- int ls1,fs1=0;
int g;
U8*text = (U8*)_text;
+ outline_t* outline;
SWFFONT*font;
font = dictionary_lookup(&fonts, fontname);
if(!font)
syntaxerror("font \"%s\" not known!", fontname);
- if(!texture)
- /* the shape information we have implies exactly one fill style
- This means to support outlines we'd have to rework the whole shape.
- */
- syntaxerror("textshapes must be filled", fontname);
-
- /* TODO: supporting more than once character would be nice... */
-
if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
s_box(name, 0, 0, black, 20, 0);
return;
}
g = font->ascii2glyph[text[0]];
- rect = font->layout->bounds[g];
-
- swf_ShapeNew(&s);
- ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
- if(texture)
- fs1 = addFillStyle(s, &rect, texture);
- rect.xmin -= linewidth + linewidth/2;
- rect.ymin -= linewidth + linewidth/2;
- rect.xmin += linewidth + linewidth/2;
- rect.ymin += linewidth + linewidth/2;
-
- tag = swf_InsertTag(tag, ST_DEFINESHAPE);
- swf_SetU16(tag,id);
- swf_SetRect(tag, &rect);
- swf_SetShapeStyles(tag, s);
- swf_SetSimpleShape(tag, font->glyph[g].shape);
- swf_ShapeFree(s);
+ outline = malloc(sizeof(outline_t));
+ memset(outline, 0, sizeof(outline_t));
+ outline->shape = font->glyph[g].shape;
+ outline->bbox = font->layout->bounds[g];
- s_addcharacter(name, id, tag, rect);
- incrementid();
+ {
+ drawer_t draw;
+ swf_Shape11DrawerInit(&draw, 0);
+ swf_DrawText(&draw, font, _text);
+ draw.finish(&draw);
+ outline->shape = swf_ShapeDrawerToShape(&draw);
+ outline->bbox = swf_ShapeDrawerGetBBox(&draw);
+ draw.dealloc(&draw);
+ }
+
+ if(dictionary_lookup(&outlines, name))
+ syntaxerror("outline %s defined twice", name);
+ dictionary_put2(&outlines, name, outline);
}
void s_text(char*name, char*fontname, char*text, int size, RGBA color)
void s_font(char*name, char*filename)
{
- int f;
- SWF swf;
SWFFONT* font;
- f = open(filename,O_RDONLY|O_BINARY);
- if (f<0) {
- warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
+ font = swf_LoadFont(filename);
+
+ if(font == 0) {
+ warning("Couldn't open font file \"%s\"", filename);
font = (SWFFONT*)malloc(sizeof(SWFFONT));
memset(font, 0, sizeof(SWFFONT));
dictionary_put2(&fonts, name, font);
return;
}
- font = 0;
- if (swf_ReadSWF(f,&swf)>=0) {
- swf_FontExtract(&swf, 0x4e46, &font);
- swf_FreeTags(&swf);
- }
- close(f);
- if (font==0) {
- syntaxerror("File \"%s\" isn't a valid rfxswf font file", filename);
- }
if(0)
{
dictionary_put2(&fonts, name, font);
}
+
+
typedef struct _sound_t
{
U16 id;
free(samples);
}
+static char* gradient_getToken(const char**p)
+{
+ const char*start;
+ char*result;
+ while(**p && strchr(" \t\n\r", **p)) {
+ (*p)++;
+ }
+ start = *p;
+ while(**p && !strchr(" \t\n\r", **p)) {
+ (*p)++;
+ }
+ result = malloc((*p)-start+1);
+ memcpy(result,start,(*p)-start+1);
+ result[(*p)-start] = 0;
+ return result;
+}
+
+float parsePercent(char*str);
+RGBA parseColor(char*str);
+
+GRADIENT parseGradient(const char*str)
+{
+ GRADIENT gradient;
+ const char* p = str;
+ memset(&gradient, 0, sizeof(GRADIENT));
+ while(*p) {
+ char*posstr,*colorstr;
+ float pos;
+ RGBA color;
+ posstr = gradient_getToken(&p);
+ if(!*posstr)
+ break;
+ pos = parsePercent(posstr);
+ 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");
+ break;
+ }
+ gradient.ratios[gradient.num] = (int)(pos*255.0);
+ gradient.rgba[gradient.num] = color;
+ gradient.num++;
+ free(posstr);
+ free(colorstr);
+ }
+ return gradient;
+}
+
+void s_gradient(char*name, const char*text, int radial)
+{
+ gradient_t* gradient;
+ gradient = malloc(sizeof(gradient_t));
+ memset(gradient, 0, sizeof(gradient_t));
+ gradient->gradient = parseGradient(text);
+ gradient->radial = radial;
+
+ if(dictionary_lookup(&gradients, name))
+ syntaxerror("gradient %s defined twice", name);
+ dictionary_put2(&gradients, name, gradient);
+}
+
+void s_action(const char*text)
+{
+ ActionTAG* a = 0;
+ a = swf_ActionCompile(text, stack[0].swf->fileVersion);
+ if(!a) {
+ syntaxerror("Couldn't compile ActionScript");
+ }
+
+ tag = swf_InsertTag(tag, ST_DOACTION);
+
+ swf_ActionSet(tag, a);
+
+ swf_ActionFree(a);
+}
+
+void s_outline(char*name, char*format, char*source)
+{
+ outline_t* outline;
+
+ drawer_t draw;
+ SHAPE* shape;
+ SHAPE2* shape2;
+ SRECT bounds;
+
+ 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->shape = shape;
+ outline->bbox = bounds;
+
+ if(dictionary_lookup(&outlines, name))
+ syntaxerror("outline %s defined twice", name);
+ dictionary_put2(&outlines, name, outline);
+}
+
void s_playsound(char*name, int loops, int nomultiple, int stop)
{
sound_t* sound = dictionary_lookup(&sounds, name);
}
static int c_gradient(map_t*args)
{
+ char*name = lu(args, "name");
+ int radial= strcmp(lu(args, "radial"), "radial")?0:1;
+
+ readToken();
+ if(type != RAWDATA)
+ syntaxerror("colon (:) expected");
+
+ s_gradient(name, text, radial);
return 0;
}
static int c_point(map_t*args)
int type=0;
char* font;
char* text;
+ char* outline=0;
RGBA fill;
if(!strcmp(command, "circle"))
type = 1;
- else if(!strcmp(command, "textshape"))
+ else if(!strcmp(command, "filled"))
type = 2;
if(type==0) {
} else if (type==1) {
r = parseTwip(lu(args, "r"));
} else if (type==2) {
- text = lu(args, "text");
- font = lu(args, "font");
+ outline = lu(args, "outline");
}
if(!strcmp(fillstr, "fill"))
if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
else if(type==1) s_circle(name, r, color, linewidth, fillstr);
- else if(type==2) s_textshape(name, font, text, color, linewidth, fillstr);
+ else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
+ return 0;
+}
+
+static int c_textshape(map_t*args)
+{
+ char*name = lu(args, "name");
+ char*text = lu(args, "text");
+ char*font = lu(args, "font");
+
+ s_textshape(name, font, text);
return 0;
}
+
+
static int c_swf(map_t*args)
{
char*name = lu(args, "name");
return 0;
}
+static int c_outline(map_t*args)
+{
+ char*name = lu(args, "name");
+ char*format = lu(args, "format");
+
+ readToken();
+ if(type != RAWDATA)
+ syntaxerror("colon (:) expected");
+
+ s_outline(name, format, text);
+ return 0;
+}
+
int fakechar(map_t*args)
{
char*name = lu(args, "name");
}
static int c_egon(map_t*args) {return fakechar(args);}
-static int c_button(map_t*args) {return fakechar(args);}
+static int c_button(map_t*args) {
+ char*action = "";
+ readToken();
+ if(type == RAWDATA)
+ action = text;
+ else
+ pushBack();
+
+ return fakechar(args);
+}
static int c_edittext(map_t*args) {return fakechar(args);}
static int c_morphshape(map_t*args) {return fakechar(args);}
static int c_buttonsounds(map_t*args) {return 0;}
static int c_buttonput(map_t*args) {return 0;}
static int c_texture(map_t*args) {return 0;}
-static int c_action(map_t*args) {return 0;}
+
+static int c_action(map_t*args)
+{
+ readToken();
+ if(type != RAWDATA) {
+ syntaxerror("colon (:) expected");
+ }
+
+ s_action(text);
+
+ return 0;
+}
static struct {
char*command;
// "import" type stuff
{"swf", c_swf, "name filename"},
{"shape", c_swf, "name filename"},
- {"morphshape", c_morphshape, "name start end"},
{"jpeg", c_image, "name filename quality=80%"},
{"png", c_image, "name filename"},
{"movie", c_movie, "name filename"},
// generators of primitives
{"point", c_point, "name x=0 y=0"},
- {"gradient", c_gradient, "name"},
+ {"gradient", c_gradient, "name @radial=0"},
+ {"outline", c_outline, "name format=simple"},
+ {"textshape", c_textshape, "name text font"},
// 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"},
- {"textshape", c_primitive, "name text font color=white line=1 @fill=none"},
+ {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
{"egon", c_egon, "name vertices color=white line=1 @fill=none"},
{"button", c_button, "name shape over=*shape press=*shape area=*shape"},
{"text", c_text, "name text font size=100% color=white"},
{"edittext", c_edittext, "name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
+ {"morphshape", c_morphshape, "name start end"},
{"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
{"stop", c_stop, "sound"},
// 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= 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= above= below="},
- {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
- {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
- {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
- {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
+ {"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="},
{"del", c_del, "name"},
// virtual object placement
- {"buttonput", c_buttonput, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex=100% scaley=100% shear=0 rotate=0 above= below="},
+ {"buttonput", c_buttonput, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex=100% scaley=100% shear=0 rotate=0 above= below="}, //TODO: ratio???
{"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
// commands which start a block
if(!strncmp("<i> ", x, 3)) {
readToken();
- if(type == COMMAND || type == LABEL) {
+ if(type == COMMAND || type == RAWDATA) {
pushBack();
syntaxerror("character name expected");
}
while(1) {
readToken();
- if(type == LABEL || type == COMMAND) {
+ if(type == RAWDATA || type == COMMAND) {
pushBack();
break;
}
int t;
map_t args;
int nr = -1;
+ msg("<verbose> parse Command: %s (line %d)", command, line);
+
for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
if(!strcmp(arguments[t].command, command)) {
}
if(nr<0)
syntaxerror("command %s not known", command);
+
+ // catch missing .flash directives at the beginning of a file
+ if(strcmp(command, "flash") && !stackpos)
+ {
+ syntaxerror("No movie defined- use .flash first");
+ }
#ifdef DEBUG
printf(".%s\n", command);fflush(stdout);
(*arguments[nr].func)(&args);
- if(!strcmp(command, "button") ||
+ /*if(!strcmp(command, "button") ||
!strcmp(command, "action")) {
while(1) {
readToken();
}
}
}
- }
+ }*/
map_clear(&args);
return;
args_callback_usage(argv[0]);
exit(1);
}
+
file = generateTokens(filename);
if(!file) {
printf("parser returned error.\n");
return 1;
}
pos=0;
-
t=0;
while(!noMoreTokens()) {