Part of the swftools package.
Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- This file is distributed under the GPL, see file COPYING for details */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <errno.h>
-#define logf logarithmf // logf is also used by ../lib/log.h
#include <math.h>
-#undef logf
#include "../config.h"
#include "../lib/rfxswf.h"
+#include "../lib/drawer.h"
#include "../lib/log.h"
#include "../lib/args.h"
#include "../lib/q.h"
static char * filename = 0;
static char * outputname = "output.swf";
static int verbose = 2;
+static int optimize = 0;
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)
override_outputname = 1;
return 1;
}
+ else if(!strcmp(name, "O")) {
+ optimize = 1;
+ return 0;
+ }
else if(!strcmp(name, "v")) {
verbose ++;
return 0;
{
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;
struct _character;
static struct level
{
- int type; //0=swf, 1=sprite, 2=clip
+ int type; //0=swf, 1=sprite, 2=clip, 3=button
/* for swf (0): */
SWF*swf;
int oldframe;
dictionary_t oldinstances;
SRECT oldrect;
+ TAG* cut;
} stack[256];
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 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;
+ int rotate;
+} gradient_t;
+
+typedef struct _texture {
+ FILLSTYLE fs;
+} texture_t;
+
static void character_init(character_t*c)
{
memset(c, 0, sizeof(character_t));
swf_SetU16(tag, id);
swf_SetString(tag, name);
}
+static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
+{
+ character_t* c = character_new();
+ c->definingTag = ctag;
+ c->id = id;
+ c->size = r;
+
+ if(dictionary_lookup(&images, name))
+ syntaxerror("image %s defined twice", name);
+ dictionary_put2(&images, name, c);
+}
static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
{
instance_t* i = instance_new();
{
p->x = 0; p->y = 0;
p->scalex = 1.0; p->scaley = 1.0;
- p->pin.x = 1; p->pin.y = 0;
+ p->pin.x = 0; //1??
+ p->pin.y = 0;
p->pivot.x = 0; p->pivot.y = 0;
p->rotate = 0;
p->shear = 0;
m->sy = (int)(sy*65536+0.5);
m->tx = m->ty = 0;
-
+
h = swf_TurnPoint(p->pin, m);
m->tx = p->x - h.x;
m->ty = p->y - h.y;
}
-static MATRIX s_instancepos(instance_t*i, parameters_t*p)
+static MATRIX s_instancepos(SRECT rect, parameters_t*p)
{
MATRIX m;
SRECT r;
makeMatrix(&m, p);
- r = swf_TurnRect(i->character->size, &m);
+ r = swf_TurnRect(rect, &m);
if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
currentrect.xmax == 0 && currentrect.ymax == 0)
currentrect = r;
return m;
}
-void s_swf(char*name, SRECT r, int version, int fps, int compress)
+void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
{
SWF*swf = (SWF*)malloc(sizeof(SWF));
- RGBA rgb;
if(stackpos)
syntaxerror(".swf blocks can't be nested");
swf->frameRate = fps;
swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
swf->compressed = compress;
- rgb.r = 0x00;rgb.g = 0x00;rgb.b = 0x00;
- swf_SetRGB(tag,&rgb);
-
+ 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(&instances);
dictionary_init(&fonts);
dictionary_init(&sounds);
incrementid();
}
+typedef struct _buttonrecord
+{
+ U16 id;
+ MATRIX matrix;
+ CXFORM cxform;
+ char set;
+} buttonrecord_t;
+
+typedef struct _button
+{
+ int endofshapes;
+ int nr_actions;
+ buttonrecord_t records[4];
+} button_t;
+
+static button_t mybutton;
+
+void s_button(char*name)
+{
+ tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
+ swf_SetU16(tag, id); //id
+ swf_ButtonSetFlags(tag, 0); //menu=no
+
+ memset(&mybutton, 0, sizeof(mybutton));
+
+ memset(&stack[stackpos], 0, sizeof(stack[0]));
+ stack[stackpos].type = 3;
+ stack[stackpos].tag = tag;
+ stack[stackpos].id = id;
+ stack[stackpos].name = strdup(name);
+ stack[stackpos].oldrect = currentrect;
+ memset(¤trect, 0, sizeof(currentrect));
+
+ stackpos++;
+ incrementid();
+}
+void s_buttonput(char*character, char*as, parameters_t p)
+{
+ character_t* c = dictionary_lookup(&characters, character);
+ MATRIX m;
+ int flags = 0;
+ char*o = as,*s = as;
+ buttonrecord_t r;
+ if(!stackpos || (stack[stackpos-1].type != 3)) {
+ syntaxerror(".show may only appear in .button");
+ }
+ if(!c) {
+ syntaxerror("character %s not known (in .shape %s)", character, character);
+ }
+ if(mybutton.endofshapes) {
+ syntaxerror("a .do may not precede a .show", character, character);
+ }
+
+ m = s_instancepos(c->size, &p);
+
+ r.id = c->id;
+ r.matrix = m;
+ r.cxform = p.cxform;
+ r.set = 1;
+
+ while(1) {
+ if(*s==',' || *s==0) {
+ if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
+ else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
+ else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
+ else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
+ else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
+ else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
+ }
+ if(!*s)
+ break;
+ s++;
+ }
+}
+static void setbuttonrecords(TAG*tag)
+{
+ int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
+ if(!mybutton.endofshapes) {
+ int t;
+
+ if(!mybutton.records[3].set) {
+ memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
+ }
+
+ for(t=0;t<4;t++) {
+ if(mybutton.records[t].set) {
+ swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
+ }
+ }
+ swf_SetU8(tag,0); // end of button records
+ mybutton.endofshapes = 1;
+ }
+}
+
+void s_buttonaction(int flags, char*action)
+{
+ ActionTAG* a = 0;
+ if(flags==0) {
+ return;
+ }
+ setbuttonrecords(stack[stackpos-1].tag);
+
+ a = swf_ActionCompile(text, stack[0].swf->fileVersion);
+ if(!a) {
+ syntaxerror("Couldn't compile ActionScript");
+ }
+
+ swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
+ swf_ActionSet(stack[stackpos-1].tag, a);
+ mybutton.nr_actions++;
+
+ swf_ActionFree(a);
+}
+
+static void setactionend(TAG*tag)
+{
+ if(!mybutton.nr_actions) {
+ /* no actions means we didn't have an actionoffset,
+ which means we can't signal the end of the
+ buttonaction records, so, *sigh*, we have
+ to insert a dummy record */
+ swf_SetU16(tag, 0); //offset
+ swf_SetU16(tag, 0); //condition
+ swf_SetU8(tag, 0); //action
+ }
+}
+
+static void s_endButton()
+{
+ SRECT r;
+ setbuttonrecords(stack[stackpos-1].tag);
+ setactionend(stack[stackpos-1].tag);
+ stackpos--;
+
+ swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
+
+ r = currentrect;
+
+ tag = stack[stackpos].tag;
+ currentrect = stack[stackpos].oldrect;
+
+ s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
+ free(stack[stackpos].name);
+}
+
+TAG* removeFromTo(TAG*from, TAG*to)
+{
+ TAG*save = from->prev;
+ while(from!=to) {
+ TAG*next = from->next;
+ swf_DeleteTag(from);
+ from = next;
+ }
+ save->next = 0;
+ return save;
+}
+
static void s_endSprite()
{
SRECT r = currentrect;
+
+ if(stack[stackpos].cut)
+ tag = removeFromTo(stack[stackpos].cut, tag);
+
stackpos--;
/* TODO: before clearing, prepend "<spritename>." to names and
currentrect = stack[stackpos].oldrect;
currentdepth = stack[stackpos].olddepth;
instances = stack[stackpos].oldinstances;
+
+ tag = swf_InsertTag(tag, ST_SHOWFRAME);
tag = swf_InsertTag(tag, ST_END);
tag = stack[stackpos].tag;
int fi;
SWF* swf;
char*filename;
- stackpos--;
+
+ if(stack[stackpos].cut)
+ tag = removeFromTo(stack[stackpos].cut, tag);
+ stackpos--;
+
swf = stack[stackpos].swf;
filename = stack[stackpos].filename;
-
+
+ //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(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin))
+
+ 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(fi<0) {
syntaxerror("couldn't create output file %s", filename);
dictionary_clear(&instances);
dictionary_clear(&characters);
+ dictionary_clear(&images);
+ dictionary_clear(&textures);
+ dictionary_clear(&outlines);
+ dictionary_clear(&gradients);
dictionary_clear(&fonts);
dictionary_clear(&sounds);
free(swf);
free(filename);
}
+
void s_close()
{
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)
int s_getframe()
{
- return currentframe;
+ return currentframe+1;
}
-void s_frame(int nr)
+void s_frame(int nr, int cut, char*name)
{
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);
+ swf_SetU8(tag, 1); //make this an anchor
+ }
}
+ if(nr == 0 && currentframe == 0 && name) {
+ tag = swf_InsertTag(tag, ST_FRAMELABEL);
+ swf_SetString(tag, name);
+ swf_SetU8(tag, 1); //make this an anchor
+ }
+
+ if(cut) {
+ if(now == tag) {
+ syntaxerror("Can't cut, frame empty");
+ }
+ stack[stackpos].cut = tag;
+ }
+
currentframe = nr;
}
+
+int parseColor2(char*str, RGBA*color);
+
+int addFillStyle(SHAPE*s, SRECT*r, char*name)
+{
+ RGBA color;
+ character_t*image;
+ gradient_t*gradient;
+ texture_t*texture;
+ if(name[0] == '#') {
+ parseColor2(name, &color);
+ return swf_ShapeAddSolidFillStyle(s, &color);
+ } 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.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
+ m.tx = r->xmin;
+ m.ty = r->ymin;
+ return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
+ } 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 = (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(name, &color)) {
+ return swf_ShapeAddSolidFillStyle(s, &color);
+ } else {
+ syntaxerror("not a color/fillstyle: %s", name);
+ return 0;
+ }
+}
RGBA black={r:0,g:0,b:0,a:0};
-void s_box(char*name, int width, int height, RGBA color, int linewidth, RGBA fill, int dofill)
+void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
{
- SRECT r;
+ SRECT r,r2;
SHAPE* s;
- int ls1,fs1=0;
- tag = swf_InsertTag(tag, ST_DEFINESHAPE);
+ 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(dofill)
- fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
+ 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 = -linewidth-linewidth/2;
- r.ymin = -linewidth-linewidth/2;
- r.xmax = width+linewidth+linewidth/2;
- r.ymax = height+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);
incrementid();
}
-void s_circle(char*name, int r, RGBA color, int linewidth, RGBA fill, int dofill)
+void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
{
- SRECT rect;
+ SRECT rect,r2;
SHAPE* s;
int ls1,fs1=0;
- tag = swf_InsertTag(tag, ST_DEFINESHAPE);
+ outline_t* outline;
+ outline = dictionary_lookup(&outlines, outlinename);
+ if(!outline) {
+ syntaxerror("outline %s not defined", outlinename);
+ }
+ r2 = outline->bbox;
+
+ tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
swf_ShapeNew(&s);
- ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
- if(dofill)
- fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
+ 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 = -linewidth-linewidth/2;
- rect.ymin = -linewidth-linewidth/2;
- rect.xmax = 2*r+linewidth+linewidth/2;
- rect.ymax = 2*r+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_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);
+ incrementid();
+}
+
+void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
+{
+ SRECT rect,r2;
+ SHAPE* s;
+ 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);
+ 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/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_textshape(char*name, char*fontname, char*_text, RGBA color, int linewidth, RGBA fill, int dofill)
+void s_textshape(char*name, char*fontname, float size, char*_text)
{
- SRECT rect;
- 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(!dofill)
- syntaxerror("textshapes must be filled", fontname);
-
+
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, black, 0);
+ 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(dofill)
- fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
-
- 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, (int)(size*100), _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)
{
SRECT r;
-
+ MATRIX _m,*m=0;
SWFFONT*font;
font = dictionary_lookup(&fonts, fontname);
if(!font)
tag = swf_InsertTag(tag, ST_DEFINETEXT2);
swf_SetU16(tag, id);
if(!font->numchars) {
- s_box(name, 0, 0, black, 20, black, 0);
+ s_box(name, 0, 0, black, 20, 0);
return;
}
r = swf_SetDefineText(tag, font, &color, text, size);
incrementid();
}
+void s_quicktime(char*name, char*url)
+{
+ 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;
+
+ 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 = align;
+ layout.leftmargin = 0;
+ layout.rightmargin = 0;
+ layout.indent = 0;
+ layout.leading = 0;
+ r.xmin = 0;
+ r.ymin = 0;
+ r.xmax = width;
+ r.ymax = height;
+
+ swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
+
+ s_addcharacter(name, id, tag, r);
+ incrementid();
+}
+
+/* type: either "jpeg" or "png"
+ */
+void s_image(char*name, char*type, char*filename, int quality)
+{
+ /* an image is actually two folded: 1st bitmap, 2nd character.
+ Both of them can be used separately */
+
+ /* step 1: the bitmap */
+ 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
+ warning("no jpeg support compiled in");
+ s_box(name, 0, 0, black, 20, 0);
+ return;
+#else
+ tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
+ swf_SetU16(tag, imageID);
+
+ if(swf_SetJPEGBits(tag, filename, quality) < 0) {
+ syntaxerror("Image \"%s\" not found, or contains errors", filename);
+ }
+
+ swf_GetJPEGSize(filename, &width, &height);
+
+ r.xmin = 0;
+ r.ymin = 0;
+ r.xmax = width*20;
+ r.ymax = height*20;
+
+ s_addimage(name, id, tag, r);
+ incrementid();
+#endif
+ }
+
+ /* step 2: the character */
+ tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
+ swf_SetU16(tag, id);
+ swf_ShapeSetBitmapRect(tag, imageID, width, height);
+
+ s_addcharacter(name, id, tag, r);
+ 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;
+
+ 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;
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)
{
font->layout = 0;
swf_FontCreateLayout(font);
}
+ /* just in case this thing is used in .edittext later on */
+ swf_FontPrepareForEditText(font);
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))
dictionary_put2(&fonts, name, font);
}
+
+
typedef struct _sound_t
{
U16 id;
sound_t* sound;
U16*samples;
int numsamples;
+ int t;
+ int blocksize = 1152;
if(!readWAV(filename, &wav)) {
warning("Couldn't read wav file \"%s\"", filename);
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
+ }
+
+ 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);
free(samples);
}
-void s_playsound(char*name, int loops, int nomultiple, int stop)
+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;
+ int lastpos = -1;
+ const char* p = str;
+ memset(&gradient, 0, sizeof(GRADIENT));
+ while(*p) {
+ char*posstr,*colorstr;
+ int pos;
+ RGBA color;
+ posstr = gradient_getToken(&p);
+ if(!*posstr)
+ break;
+ 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");
+ break;
+ }
+ 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, 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_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_initaction(const char*character, const char*text)
{
- sound_t* sound = dictionary_lookup(&sounds, name);
+ 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 = 0;
+ if(name)
+ 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);
+ if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
+ else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
+ else if(!strcmp(action, "stop")) a = action_Stop(a);
+ else if(!strcmp(action, "play")) a = action_Play(a);
+ a = action_SetTarget(a, "");
+ a = action_End(a);
+
+ tag = swf_InsertTag(tag, ST_DOACTION);
+ swf_ActionSet(tag, a);
+ swf_ActionFree(a);
+ return 1;
+}
+
+void s_outline(char*name, char*format, char*source)
+{
+ outline_t* outline;
+
+ drawer_t draw;
+ SHAPE* shape;
+ SHAPE2* shape2;
+ SRECT bounds;
+
+ //swf_Shape10DrawerInit(&draw, 0);
+ swf_Shape11DrawerInit(&draw, 0);
+
+ draw_string(&draw, source);
+ draw.finish(&draw);
+ shape = swf_ShapeDrawerToShape(&draw);
+ bounds = swf_ShapeDrawerGetBBox(&draw);
+ draw.dealloc(&draw);
+
+ outline = (outline_t*)rfx_calloc(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);
+}
+
+int s_playsound(char*name, int loops, int nomultiple, int stop)
+{
+ sound_t* sound;
SOUNDINFO info;
+ if(!name)
+ return 0;
+ sound = dictionary_lookup(&sounds, name);
if(!sound)
- syntaxerror("Don't know anything about sound \"%s\"", name);
+ return 0;
tag = swf_InsertTag(tag, ST_STARTSOUND);
swf_SetU16(tag, sound->id); //id
info.loops = loops;
info.nomultiple = nomultiple;
swf_SetSoundInfo(tag, &info);
+ return 1;
}
-void s_shape(char*name, char*filename)
+void s_includeswf(char*name, char*filename)
{
int f;
SWF swf;
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, black, 0);
+ s_box(name, 0, 0, black, 20, 0);
return;
}
if (swf_ReadSWF(f,&swf)<0) {
warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
- s_box(name, 0, 0, black, 20, black, 0);
+ s_box(name, 0, 0, black, 20, 0);
return;
}
close(f);
s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
swf_SetU16(tag, id);
- swf_SetU16(tag, 0);
+ swf_SetU16(tag, swf.frameCount);
swf_Relocate(&swf, idmap);
}
i = s_addinstance(instance, c, currentdepth);
i->parameters = p;
- m = s_instancepos(i, &p);
+ m = s_instancepos(i->character->size, &p);
tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
/* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
swf_SetTagPos(stack[stackpos].tag, 0);
swf_GetPlaceObject(stack[stackpos].tag, &p);
p.clipdepth = currentdepth;
+ p.name = 0;
swf_ClearTag(stack[stackpos].tag);
swf_SetPlaceObject(stack[stackpos].tag, &p);
currentdepth++;
i = s_addinstance(instance, c, currentdepth);
i->parameters = p;
- m = s_instancepos(i, &p);
+ m = s_instancepos(i->character->size, &p);
tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
}
i->parameters = p;
- m = s_instancepos(i, &p);
+ m = s_instancepos(i->character->size, &p);
tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
swf_ObjectMove(tag, i->depth, &m, &p.cxform);
return;
}
- m = s_instancepos(i, &p2);
+ m = s_instancepos(i->character->size, &p2);
tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
i->parameters = p2;
TAG*lt;
frame ++;
p = s_interpolate(&p1, &p2, frame, allframes);
- m = s_instancepos(i, &p); //needed?
+ 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);
s_endSprite();
else if(stack[stackpos-1].type == 2)
s_endClip();
+ else if(stack[stackpos-1].type == 3)
+ s_endButton();
else syntaxerror("internal error 1");
}
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'))) {
+ warning("precision loss: %s converted to twip: %s", str, dot);
dot[2] = 0;
l=2;
}
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);
return value;
}
-static int c_swf(map_t*args)
+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;
- if(!strcmp(name, "!default!") || override_outputname)
- name = outputname;
+ RGBA color = parseColor(lu(args, "background"));
+
+ 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 = 0;
else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
- s_swf(name, bbox, version, fps, compress);
+ 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, 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_point(map_t*args)
{
char*name = lu(args, "name");
}
static int c_play(map_t*args)
{
- char*name = lu(args, "sound");
+ char*name = lu(args, "name");
char*loop = lu(args, "loop");
char*nomultiple = lu(args, "nomultiple");
int nm = 0;
else
nm = parseInt(nomultiple);
- s_playsound(name, parseInt(loop), nm, 0);
+ if(s_playsound(name, parseInt(loop), nm, 0)) {
+ return 0;
+ } else if(s_swf3action(name, "play")) {
+ return 0;
+ }
return 0;
}
static int c_stop(map_t*args)
{
- char*name = lu(args, "sound");
- s_playsound(name, 0,0,1);
+ char*name = map_lookup(args, "name");
+
+ if(s_playsound(name, 0,0,1)) {
+ return 0;
+ } else if(s_swf3action(name, "stop")) {
+ return 0;
+ }
+ syntaxerror("I don't know anything about sound/movie \"%s\"", name);
+ return 0;
+}
+
+static int c_nextframe(map_t*args)
+{
+ char*name = lu(args, "name");
+
+ if(s_swf3action(name, "nextframe")) {
+ return 0;
+ }
+ syntaxerror("I don't know anything about movie \"%s\"", name);
+ return 0;
+}
+
+static int c_previousframe(map_t*args)
+{
+ char*name = lu(args, "name");
+
+ if(s_swf3action(name, "previousframe")) {
+ return 0;
+ }
+ syntaxerror("I don't know anything about movie \"%s\"", name);
return 0;
}
char* bstr = lu(args, "blue");
char* astr = lu(args, "alpha");
char* pinstr = lu(args, "pin");
+ char* as = map_lookup(args, "as");
MULADD r,g,b,a;
float oldwidth;
float oldheight;
MULADD luminance;
parameters_t p;
- if(type==5) {
+ if(type==9) { // (?) .rotate or .arcchange
pivotstr = lu(args, "pivot");
anglestr = lu(args, "angle");
} else {
// put or startclip
character = lu(args, "character");
parameters_clear(&p);
+ } else if (type == 5) {
+ character = lu(args, "name");
+ parameters_clear(&p);
+ // button's show
} else {
p = s_getParameters(instance);
}
if(type == 0)
s_put(instance, character, p);
- if(type == 1)
+ else if(type == 1)
s_change(instance, p);
- if(type == 2)
+ else if(type == 2)
s_qchange(instance, p);
- if(type == 3)
+ else if(type == 3)
s_jump(instance, p);
- if(type == 4)
+ else if(type == 4)
s_startclip(instance, character, p);
+ else if(type == 5) {
+ if(as && as[0]) {
+ s_buttonput(character, as, p);
+ } else {
+ s_buttonput(character, "shape", p);
+ }
+ }
return 0;
}
static int c_put(map_t*args)
c_placement(args, 4);
return 0;
}
+static int c_show(map_t*args)
+{
+ c_placement(args, 5);
+ return 0;
+}
static int c_del(map_t*args)
{
char*instance = lu(args, "name");
static int c_frame(map_t*args)
{
char*framestr = lu(args, "n");
+ char*cutstr = lu(args, "cut");
+ char*name = lu(args, "name");
int frame;
+ int cut = 0;
+ if(strcmp(cutstr, "no"))
+ cut = 1;
if(isRelative(framestr)) {
frame = s_getframe();
if(getSign(framestr)<0)
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);
+ s_frame(frame, cut, name);
return 0;
}
static int c_primitive(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"))
fillstr = colorstr;
if(!strcmp(fillstr, "none"))
- dofill = 0;
+ fillstr = 0;
if(width<0 || height<0 || linewidth<0 || r<0)
syntaxerror("values width, height, line, r must be positive");
- if(!dofill || isColor(fillstr)) {
- if(dofill)
- fill = parseColor(fillstr);
- } else {
- /* FIXME - texture fill */
- fill.r = fill.g = 0;
- fill.b = fill.a = 255;
- warning("texture fill not supported yet. Filling with black.");
- }
- if(type == 0) s_box(name, width, height, color, linewidth, fill, dofill);
- else if(type==1) s_circle(name, r, color, linewidth, fill, dofill);
- else if(type==2) s_textshape(name, font, text, color, linewidth, fill, dofill);
+
+ 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_filled(name, outline, color, linewidth, fillstr);
return 0;
}
-static int c_shape(map_t*args)
+static int c_textshape(map_t*args)
+{
+ char*name = lu(args, "name");
+ char*text = lu(args, "text");
+ char*font = lu(args, "font");
+ float size = parsePxOrPercent(font, lu(args, "size"));
+
+ s_textshape(name, font, size, text);
+ return 0;
+}
+
+static int c_swf(map_t*args)
{
char*name = lu(args, "name");
char*filename = lu(args, "filename");
- s_shape(name, filename);
+ char*command = lu(args, "commandname");
+ if(!strcmp(command, "shape"))
+ warning("Please use .swf instead of .shape");
+ s_includeswf(name, filename);
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");
+ char*name = lu(args, "name");
+ char*filename = lu(args, "filename");
+ if(!strcmp(command,"jpeg")) {
+ int quality = (int)(parsePercent(lu(args, "quality"))*100);
+ s_image(name, "jpeg", filename, quality);
+ } else {
+ s_image(name, "png", filename, 0);
+ }
+ 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");
- s_box(name, 0, 0, black, 20, black, 0);
+ s_box(name, 0, 0, black, 20, 0);
return 0;
}
static int c_egon(map_t*args) {return fakechar(args);}
-static int c_button(map_t*args) {return fakechar(args);}
-static int c_edittext(map_t*args) {return fakechar(args);}
+static int c_button(map_t*args) {
+ char*name = lu(args, "name");
+ s_button(name);
+ return 0;
+}
+static int current_button_flags = 0;
+static int c_on_press(map_t*args)
+{
+ char*position = lu(args, "position");
+ char*action = "";
+ if(!strcmp(position, "inside")) {
+ current_button_flags |= BC_OVERUP_OVERDOWN;
+ } else if(!strcmp(position, "outside")) {
+ //current_button_flags |= BC_IDLE_OUTDOWN;
+ syntaxerror("IDLE_OVERDOWN not supported by SWF");
+ } else if(!strcmp(position, "anywhere")) {
+ current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
+ }
+ readToken();
+ if(type == RAWDATA) {
+ action = text;
+ s_buttonaction(current_button_flags, action);
+ current_button_flags = 0;
+ }
+ else
+ pushBack();
+ return 0;
+}
+static int c_on_release(map_t*args)
+{
+ char*position = lu(args, "position");
+ char*action = "";
+ if(!strcmp(position, "inside")) {
+ current_button_flags |= BC_OVERDOWN_OVERUP;
+ } else if(!strcmp(position, "outside")) {
+ current_button_flags |= BC_OUTDOWN_IDLE;
+ } else if(!strcmp(position, "anywhere")) {
+ current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
+ }
+ readToken();
+ if(type == RAWDATA) {
+ action = text;
+ s_buttonaction(current_button_flags, action);
+ current_button_flags = 0;
+ }
+ else
+ pushBack();
+ return 0;
+}
+static int c_on_move_in(map_t*args)
+{
+ char*position = lu(args, "state");
+ char*action = "";
+ if(!strcmp(position, "pressed")) {
+ current_button_flags |= BC_OUTDOWN_OVERDOWN;
+ } else if(!strcmp(position, "not_pressed")) {
+ current_button_flags |= BC_IDLE_OVERUP;
+ } else if(!strcmp(position, "any")) {
+ current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
+ }
+ readToken();
+ if(type == RAWDATA) {
+ action = text;
+ s_buttonaction(current_button_flags, action);
+ current_button_flags = 0;
+ }
+ else
+ pushBack();
+ return 0;
+}
+static int c_on_move_out(map_t*args)
+{
+ char*position = lu(args, "state");
+ char*action = "";
+ if(!strcmp(position, "pressed")) {
+ current_button_flags |= BC_OVERDOWN_OUTDOWN;
+ } else if(!strcmp(position, "not_pressed")) {
+ current_button_flags |= BC_OVERUP_IDLE;
+ } else if(!strcmp(position, "any")) {
+ current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
+ }
+ readToken();
+ if(type == RAWDATA) {
+ action = text;
+ s_buttonaction(current_button_flags, action);
+ current_button_flags = 0;
+ }
+ else
+ pushBack();
+ return 0;
+}
+static int c_on_key(map_t*args)
+{
+ char*key = lu(args, "key");
+ char*action = "";
+ if(strlen(key)==1) {
+ /* ascii */
+ if(key[0]>=32) {
+ current_button_flags |= 0x4000 + (key[0]*0x200);
+ } else {
+ syntaxerror("invalid character: %c"+key[0]);
+ return 1;
+ }
+ } else {
+ /* TODO:
+ <ctrl-x> = 0x200*(x-'a')
+ esc = = 0x3600
+ space = = 0x4000;
+ */
+ syntaxerror("invalid key: %s",key);
+ }
+ readToken();
+ if(type == RAWDATA) {
+ action = text;
+ s_buttonaction(current_button_flags, action);
+ current_button_flags = 0;
+ }
+ else
+ pushBack();
+ return 0;
+}
+
+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 @autosize=0"},
+ char*name = lu(args, "name");
+ char*font = lu(args, "font");
+ 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");
+ RGBA color = parseColor(lu(args, "color"));
+ int maxlength = parseInt(lu(args, "maxlength"));
+ char*variable = lu(args, "variable");
+ char*passwordstr = lu(args, "password");
+ char*wordwrapstr = lu(args, "wordwrap");
+ char*multilinestr = lu(args, "multiline");
+ char*htmlstr = lu(args, "html");
+ 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(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
+ if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
+ if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
+ if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
+ if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
+ if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
+ 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_image(map_t*args) {return fakechar(args);}
static int c_movie(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 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)
+{
+ 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;
+}
+
+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;
+}
static struct {
char*command;
command_func_t* func;
char*arguments;
} arguments[] =
-{{"swf", c_swf, "bbox=autocrop version=5 fps=50 name=!default! @compress=default"},
- {"frame", c_frame, "n=<plus>1"},
-
- // "import" type stuff
- {"shape", c_shape, "name filename"},
- {"morphshape", c_morphshape, "name start end"},
+{{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
+ {"frame", c_frame, "n=<plus>1 name= @cut=no"},
+ // "import" type stuff
+ {"swf", c_swf, "name filename"},
+ {"shape", c_swf, "name filename"},
{"jpeg", c_image, "name filename quality=80%"},
{"png", c_image, "name filename"},
{"movie", c_movie, "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 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"},
// 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"},
+ {"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="},
+ {"on_press", c_on_press, "position=inside"},
+ {"on_release", c_on_release, "position=anywhere"},
+ {"on_move_in", c_on_move_in, "state=not_pressed"},
+ {"on_move_out", c_on_move_out, "state=not_pressed"},
+ {"on_key", c_on_key, "key=any"},
- {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
-
// control tags
- {"play", c_play, "sound loop=0 @nomultiple=0"},
- {"stop", c_stop, "sound"},
+ {"play", c_play, "name loop=0 @nomultiple=0"},
+ {"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= 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="},
- {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
- {"point", c_point, "name x=0 y=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(!strncmp("<i> ", x, 3)) {
readToken();
- if(type == COMMAND || type == LABEL) {
+ if(type == COMMAND || type == RAWDATA) {
pushBack();
syntaxerror("character name expected");
}
len = pos;
/* for(t=0;t<len;t++) {
- printf("(%d) %s=%s %s\n", t, strndup(name[t], namelen[t]), strndup(value[t], valuelen[t]),
+ printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
isboolean[t]?"(boolean)":"");
}*/
while(1) {
readToken();
- if(type == LABEL || type == COMMAND) {
+ if(type == RAWDATA || type == COMMAND) {
pushBack();
break;
}
value[pos].str = text;
value[pos].len = strlen(text);
/*printf("setting boolean parameter %s (to %s)\n",
- strndup(name[pos], namelen[pos]),
- strndup(value[pos], valuelen[pos]));*/
+ strdup_n(name[pos], namelen[pos]),
+ strdup_n(value[pos], valuelen[pos]));*/
break;
}
}
if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
(type != ASSIGNMENT && !set[pos])) {
if(set[pos]) {
- syntaxerror("value %s set twice (old value:%s)", text, strndup(value[pos].str, value[pos].len));
+ syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
}
if(type == ASSIGNMENT)
readToken();
value[pos].len = strlen(text);
#if 0//def DEBUG
printf("setting parameter %s (to %s)\n",
- strndup(name[pos].str, name[pos].len),
- strndup(value[pos].str, value[pos].len));
+ strdup_n(name[pos].str, name[pos].len),
+ strdup_n(value[pos].str, value[pos].len));
#endif
break;
}
}
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
for(t=0;t<len;t++) {
- printf("%s=%s\n", strndup(name[t].str, name[t].len), strndup(value[t].str, value[t].len));
+ printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
}
#endif
for(t=0;t<len;t++) {
}
if(value[t].str == 0) {
pushBack();
- syntaxerror("value for parameter %s missing (no default)", strndup(name[t].str, name[t].len));
+ syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
}
}
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)) {
+
+ /* ugly hack- will be removed soon (once documentation and .sc generating
+ utilities have been changed) */
+ if(!strcmp(command, "swf") && !stackpos) {
+ warning("Please use .flash instead of .swf- this will be mandatory soon");
+ command = "flash";
+ t = 0;
+ }
+
args = parseArguments(command, arguments[t].arguments);
nr = t;
+ break;
}
}
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()) {