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
#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"
+#include "swfc-feedback.h"
+#include "swfc-interpolation.h"
+#include "swfc-history.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 struct options_t options[] =
-{
- {"o","output"},
- {"v","verbose"},
- {"V","version"},
- {0,0}
+static int do_cgi = 0;
+static int change_sets_all = 0;
+static int do_exports = 0;
+
+static struct options_t options[] = {
+{"h", "help"},
+{"V", "version"},
+{"C", "cgi"},
+{"v", "verbose"},
+{"o", "output"},
+{0,0}
};
-
+
int args_callback_option(char*name,char*val)
{
if(!strcmp(name, "V")) {
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;
{
return args_long2shortoption(options, name, val);
}
-void args_callback_usage(char*name)
+void args_callback_usage(char *name)
{
- printf("Usage: %s [-o filename] file.sc\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("-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");
}
int args_callback_command(char*name,char*val)
{
static char*text;
static int textlen;
static int type;
-static int line;
-static int column;
-
-static void syntaxerror(char*format, ...)
-{
- char buf[1024];
- va_list arglist;
- va_start(arglist, format);
- vsprintf(buf, format, arglist);
- va_end(arglist);
- printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
- exit(1);
-}
-
-static void warning(char*format, ...)
-{
- char buf[1024];
- va_list arglist;
- va_start(arglist, format);
- vsprintf(buf, format, arglist);
- va_end(arglist);
- printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
-}
static void readToken()
{
return 0;
}
+enum
+{
+ PT_PUT = 0,
+ PT_CHANGE = 1,
+ PT_SCHANGE = 2,
+ PT_MOVE = 3,
+ PT_SMOVE = 4,
+ PT_SWEEP = 5,
+ PT_JUMP = 6,
+ PT_STARTCLIP = 7,
+ PT_BUTTON = 8
+};
+
// ------------------------------ swf routines ----------------------------
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;
- char*filename;
+ char*filename;
+ char as3;
/* for sprites (1): */
TAG*tag;
char*name;
U16 olddepth;
int oldframe;
- dictionary_t oldinstances;
+ dict_t oldinstances;
SRECT oldrect;
TAG* cut;
+ SRECT scalegrid;
+
} stack[256];
static int stackpos = 0;
-static dictionary_t characters;
-static dictionary_t images;
-static dictionary_t outlines;
-static dictionary_t gradients;
+static dict_t characters;
+static dict_t images;
+static dict_t textures;
+static dict_t outlines;
+static dict_t gradients;
+static dict_t filters;
+static dict_t interpolations;
static char idmap[65536];
static TAG*tag = 0; //current tag
static int currentframe; //current frame in current level
static SRECT currentrect; //current bounding box in current level
static U16 currentdepth;
-static dictionary_t instances;
-static dictionary_t fonts;
-static dictionary_t sounds;
+static dict_t instances;
+static dict_t fonts;
+static dict_t sounds;
+static dict_t fontUsage;
typedef struct _parameters {
- int x,y;
- float scalex, scaley;
+ int x,y;
+ float scalex, scaley;
CXFORM cxform;
float rotate;
float shear;
SPOINT pivot;
SPOINT pin;
+ U8 blendmode; //not interpolated
+ FILTERLIST* filters;
+ U16 set; // bits indicating wether a parameter was set in the c_placement function
+ U16 flags; // bits to toggle anything you may care to implement as a toggle
} parameters_t;
typedef struct _character {
character_t*character;
U16 depth;
parameters_t parameters;
- TAG* lastTag; //last tag which set the object
- U16 lastFrame; //frame lastTag is in
+ history_t* history;
} instance_t;
typedef struct _outline {
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;
+
+char* interpolationFunctions[] = {"linear", \
+ "quadIn", "quadOut", "quadInOut", \
+ "cubicIn", "cubicOut", "cubicInOut", \
+ "quartIn", "quartOut", "quartInOut", \
+ "quintIn", "quintOut", "quintInOut", \
+ "circleIn", "circleOut", "circleInOut", \
+ "exponentialIn", "exponentialOut", "exponentialInOut", \
+ "sineIn", "sineOut", "sineInOut", \
+ "elasticIn", "elasticOut", "elasticInOut", \
+ "backIn", "backOut", "backInOut", \
+ "bounceIn", "bounceOut", "bounceInOut", \
+ "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
+
static void character_init(character_t*c)
{
memset(c, 0, sizeof(character_t));
}
+
static character_t* character_new()
{
character_t*c;
character_init(c);
return c;
}
+
static void instance_init(instance_t*i)
{
memset(i, 0, sizeof(instance_t));
+ i->history = history_new();
+}
+
+static void instance_free(instance_t* i)
+{
+ history_free(i->history);
+ free(i);
}
+
static instance_t* instance_new()
{
instance_t*c;
return c;
}
+static void free_instance(void* i)
+{
+ instance_free((instance_t*)i);
+}
+
+static void free_font(void* f)
+{
+ swf_FontFree((SWFFONT*)f);
+}
+
+static void gradient_free(GRADIENT* grad)
+{
+ free(grad->ratios);
+ free(grad->rgba);
+ free(grad);
+}
+
+static void free_gradient(void* grad)
+{
+ gradient_free((GRADIENT*) grad);
+}
+
+static void outline_free(outline_t* o)
+{
+ free(o->shape->data);
+ free(o->shape);
+ free(o);
+}
+
+static void free_outline(void* o)
+{
+ outline_free((outline_t*)o);
+}
+
+static void freeDictionaries()
+{
+ dict_free_all(&instances, 1, free_instance);
+ dict_free_all(&characters, 1, free);
+ dict_free_all(&images, 1, free);
+ dict_free_all(&textures, 1, free);
+ dict_free_all(&outlines, 1, free_outline);
+ dict_free_all(&gradients, 1, free_gradient);
+ dict_free_all(&filters, 1, free);
+ dict_free_all(&fonts, 1, free_font);
+ dict_free_all(&sounds, 1, free);
+ dict_free_all(&interpolations, 1, free);
+ cleanUp = 0;
+}
+
+static void freeFontDictionary()
+{
+ dict_free_all(&fonts, 1, free_font);
+}
+
static void incrementid()
{
- while(idmap[++id]) {
- if(id==65535)
- syntaxerror("Out of character ids.");
+ while(id<65536 && idmap[id]) {
+ id++;
}
+ if(id>=65536)
+ syntaxerror("Out of character ids.");
idmap[id] = 1;
}
-static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
+static void s_addcharacter(const char*name, U16 id, TAG*ctag, SRECT r)
{
+ if(dict_lookup(&characters, name))
+ syntaxerror("character %s defined twice", name);
character_t* c = character_new();
-
+
c->definingTag = ctag;
c->id = id;
c->size = r;
- if(dictionary_lookup(&characters, name))
- syntaxerror("character %s defined twice", name);
- dictionary_put2(&characters, name, c);
-
- 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);
+ dict_put(&characters, name, c);
+
+ if(do_exports) {
+ 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);
+ }
}
-static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
+static void s_addimage(const char*name, U16 id, TAG*ctag, SRECT r)
{
+ if(dict_lookup(&images, name))
+ syntaxerror("image %s defined twice", name);
+
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);
+ dict_put(&images, name, c);
}
-static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
+static instance_t* s_addinstance(const char*name, character_t*c, U16 depth)
{
+ if(dict_lookup(&instances, name))
+ syntaxerror("object %s defined twice", name);
instance_t* i = instance_new();
i->character = c;
i->depth = depth;
//swf_GetMatrix(0, &i->matrix);
- if(dictionary_lookup(&instances, name))
- syntaxerror("object %s defined twice", name);
- dictionary_put2(&instances, name, i);
+ dict_put(&instances, name, i);
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->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;
+ p->rotate = 0;
+ p->shear = 0;
+ p->blendmode = 0;
+ p->filters = 0;
swf_GetCXForm(0, &p->cxform, 1);
}
SPOINT h;
float sx,r1,r0,sy;
- /* /sx r1\ /x\
+ /* /sx r1\ /x\
* \r0 sy/ \y/
*/
- sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
- r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
- r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
- sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
+ sx = p->scalex*cos(p->rotate/360*2*M_PI);
+ r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
+ r0 = p->scaley*sin(p->rotate/360*2*M_PI);
+ sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
m->sx = (int)(sx*65536+0.5);
m->r1 = (int)(r1*65536+0.5);
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);
- if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
+ r = swf_TurnRect(rect, &m);
+ if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
currentrect.xmax == 0 && currentrect.ymax == 0)
currentrect = r;
else
return m;
}
-void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
+void initBuiltIns()
{
- SWF*swf = (SWF*)malloc(sizeof(SWF));
+ interpolation_t* new;
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_LINEAR;
+ dict_put(&interpolations, "linear", new);
+
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_QUAD_IN;
+ new->slope = 0;
+ dict_put(&interpolations, "quadIn", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_QUAD_OUT;
+ new->slope = 0;
+ dict_put(&interpolations, "quadOut", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_QUAD_IN_OUT;
+ new->slope = 0;
+ dict_put(&interpolations, "quadInOut", new);
+
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_CUBIC_IN;
+ new->slope = 0;
+ dict_put(&interpolations, "cubicIn", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_CUBIC_OUT;
+ new->slope = 0;
+ dict_put(&interpolations, "cubicOut", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_CUBIC_IN_OUT;
+ new->slope = 0;
+ dict_put(&interpolations, "cubicInOut", new);
+
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_QUART_IN;
+ new->slope = 0;
+ dict_put(&interpolations, "quartIn", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_QUART_OUT;
+ new->slope = 0;
+ dict_put(&interpolations, "quartOut", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_QUART_IN_OUT;
+ new->slope = 0;
+ dict_put(&interpolations, "quartInOut", new);
+
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_QUINT_IN;
+ new->slope = 0;
+ dict_put(&interpolations, "quintIn", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_QUINT_OUT;
+ new->slope = 0;
+ dict_put(&interpolations, "quintOut", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_QUINT_IN_OUT;
+ new->slope = 0;
+ dict_put(&interpolations, "quintInOut", new);
+
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_CIRCLE_IN;
+ dict_put(&interpolations, "circleIn", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_CIRCLE_OUT;
+ dict_put(&interpolations, "circleOut", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_CIRCLE_IN_OUT;
+ dict_put(&interpolations, "circleInOut", new);
+
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_EXPONENTIAL_IN;
+ dict_put(&interpolations, "exponentialIn", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_EXPONENTIAL_OUT;
+ dict_put(&interpolations, "exponentialOut", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_EXPONENTIAL_IN_OUT;
+ dict_put(&interpolations, "exponentialInOut", new);
+
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_SINE_IN;
+ dict_put(&interpolations, "sineIn", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_SINE_OUT;
+ dict_put(&interpolations, "sineOut", new);
+ new = (interpolation_t*)malloc(sizeof(interpolation_t));
+ new->function = IF_SINE_IN_OUT;
+ dict_put(&interpolations, "sineInOut", new);
+
+ RGBA c;
+ memset(&c, 0, sizeof(RGBA));
+ gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
+ noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
+ noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
+ noGradient->gradient.num = 2;
+ noGradient->gradient.rgba[0] = c;
+ noGradient->gradient.ratios[0] = 0;
+ noGradient->gradient.rgba[1] = c;
+ noGradient->gradient.ratios[1] = 255;
+ noGradient->radial = 0;
+ noGradient->rotate = 0;
+ dict_put(&gradients, "no_gradient", noGradient);
+
+ noFilters = 0;
+// put a no_filters entry in the filters dictionary to provoce a message when a user tries
+// to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
+ FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
+ dict_put(&filters, "no_filters", dummy);
+ noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
+ noBlur->passes = 1;
+ dict_put(&filters, "no_blur", noBlur);
+ noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
+ noBevel->passes = 1;
+ noBevel->composite = 1;
+ dict_put(&filters, "no_bevel", noBevel);
+ noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
+ noDropshadow->passes = 1;
+ noDropshadow->composite = 1;
+ dict_put(&filters, "no_dropshadow", noDropshadow);
+ noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
+ noGradientGlow->passes = 1;
+ noGradientGlow->composite = 1;
+ noGradientGlow->gradient = &noGradient->gradient;
+ dict_put(&filters, "no_gradientglow", noGradientGlow);
+}
+void s_swf(const char*name, SRECT r, int version, int fps, int compress, RGBA background)
+{
if(stackpos)
- syntaxerror(".swf blocks can't be nested");
+ syntaxerror(".swf blocks can't be nested");
+ if(stackpos==sizeof(stack)/sizeof(stack[0]))
+ syntaxerror("too many levels of recursion");
+
+ SWF*swf = (SWF*)malloc(sizeof(SWF));
memset(swf, 0, sizeof(swf));
swf->fileVersion = version;
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(&outlines);
- dictionary_init(&gradients);
- dictionary_init(&instances);
- dictionary_init(&fonts);
- dictionary_init(&sounds);
+
+ dict_init(&characters, 16);
+ dict_init(&images, 16);
+ dict_init(&textures, 16);
+ dict_init(&outlines, 16);
+ dict_init(&gradients, 16);
+ dict_init(&filters, 16);
+ dict_init(&instances, 16);
+ dict_init(&sounds, 16);
+ dict_init(&interpolations, 16);
+ initBuiltIns();
+ cleanUp = &freeDictionaries;
memset(&stack[stackpos], 0, sizeof(stack[0]));
stack[stackpos].type = 0;
stack[stackpos].swf = swf;
stack[stackpos].oldframe = -1;
stackpos++;
- id = 0;
currentframe = 0;
memset(¤trect, 0, sizeof(currentrect));
currentdepth = 1;
-
+
memset(idmap, 0, sizeof(idmap));
+ idmap[0]=1; //main movie has ID 0
+
incrementid();
}
-void s_sprite(char*name)
+void s_sprite(const char*name, SRECT*scalegrid)
{
tag = swf_InsertTag(tag, ST_DEFINESPRITE);
swf_SetU16(tag, id); //id
stack[stackpos].tag = tag;
stack[stackpos].id = id;
stack[stackpos].name = strdup(name);
-
+ if(scalegrid) {
+ stack[stackpos].scalegrid = *scalegrid;
+ } else {
+ memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
+ }
+
/* FIXME: those four fields should be bundled together */
- dictionary_init(&instances);
+ dict_init(&instances, 16);
currentframe = 0;
currentdepth = 1;
memset(¤trect, 0, sizeof(currentrect));
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(const 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(const char*character, const char*as, parameters_t p)
+{
+ character_t* c = dict_lookup(&characters, character);
+ MATRIX m;
+ int flags = 0;
+ const 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, const char*action)
+{
+ ActionTAG* a = 0;
+ if(flags==0) {
+ return;
+ }
+ if(!stackpos || !stack[stackpos-1].tag ||
+ stack[stackpos-1].tag->id != ST_DEFINEBUTTON2) {
+ syntaxerror("Need to be inside a button for .on_* commands");
+ }
+ 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);
+ if(swf_isAllowedSpriteTag(from))
+ swf_DeleteTag(0, from);
from = next;
}
save->next = 0;
return save;
}
+static int parametersChange(history_t* history, int frame)
+{
+ int willChange = 0;
+
+ willChange = willChange || history_change(history, frame, "x");
+ willChange = willChange || history_change(history, frame, "y");
+ willChange = willChange || history_change(history, frame, "scalex");
+ willChange = willChange || history_change(history, frame, "scaley");
+ willChange = willChange || history_change(history, frame, "cxform.r0");
+ willChange = willChange || history_change(history, frame, "cxform.g0");
+ willChange = willChange || history_change(history, frame, "cxform.b0");
+ willChange = willChange || history_change(history, frame, "cxform.a0");
+ willChange = willChange || history_change(history, frame, "cxform.r1");
+ willChange = willChange || history_change(history, frame, "cxform.g1");
+ willChange = willChange || history_change(history, frame, "cxform.b1");
+ willChange = willChange || history_change(history, frame, "cxform.a1");
+ willChange = willChange || history_change(history, frame, "rotate");
+ willChange = willChange || history_change(history, frame, "shear");
+ willChange = willChange || history_change(history, frame, "pivot.x");
+ willChange = willChange || history_change(history, frame, "pivot.y");
+ willChange = willChange || history_change(history, frame, "pin.x");
+ willChange = willChange || history_change(history, frame, "pin.y");
+ willChange = willChange || history_change(history, frame, "blendmode");
+ willChange = willChange || history_changeFilter(history, frame);
+
+ return willChange;
+}
+
+static void free_filterlist(FILTERLIST* f_list)
+{
+ int i;
+ for (i = 0; i < f_list->num; i++)
+ {
+ if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
+ gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
+ free(f_list->filter[i]);
+ }
+ free(f_list);
+}
+
+static void readParameters(history_t* history, parameters_t* p, int frame)
+{
+ p->x = history_value(history, frame, "x");
+ p->y = history_value(history, frame, "y");
+ p->scalex = history_value(history, frame, "scalex");
+ p->scaley = history_value(history, frame, "scaley");
+ p->cxform.r0 = history_value(history, frame, "cxform.r0");
+ p->cxform.g0 = history_value(history, frame, "cxform.g0");
+ p->cxform.b0 = history_value(history, frame, "cxform.b0");
+ p->cxform.a0 = history_value(history, frame, "cxform.a0");
+ p->cxform.r1 = history_value(history, frame, "cxform.r1");
+ p->cxform.g1 = history_value(history, frame, "cxform.g1");
+ p->cxform.b1 = history_value(history, frame, "cxform.b1");
+ p->cxform.a1 = history_value(history, frame, "cxform.a1");
+ p->rotate = history_rotateValue(history, frame);
+ p->shear = history_value(history, frame, "shear");
+ p->pivot.x = history_value(history, frame, "pivot.x");
+ p->pivot.y = history_value(history, frame, "pivot.y");
+ p->pin.x = history_value(history, frame, "pin.x");
+ p->pin.y = history_value(history, frame, "pin.y");
+ p->blendmode = history_value(history, frame, "blendmode");
+ p->filters = history_filterValue(history, frame);
+}
+
+void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, const 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 = (char*)name;
+ po.move = move;
+ if(move)
+ po.id = 0;
+ if(p->blendmode) {
+ po.blendmode = p->blendmode;
+ }
+ if (p->filters)
+ po.filters = p->filters;
+ swf_SetPlaceObject(tag, &po);
+}
+
+static void writeInstance(void* _i)
+{
+ instance_t*i = (instance_t*)_i;
+ parameters_t p;
+ MATRIX m;
+ int frame = i->history->firstFrame;
+ TAG* tag = i->history->firstTag;
+ history_processFlags(i->history);
+ while (tag && frame < currentframe)
+ {
+ frame++;
+ while (tag && tag->id != ST_SHOWFRAME)
+ tag = tag->next;
+ if (parametersChange(i->history, frame))
+ {
+ readParameters(i->history, &p, frame);
+ m = s_instancepos(i->character->size, &p);
+
+ if(p.blendmode || p.filters)
+ tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
+ else
+ tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
+ setPlacement(tag, 0, i->depth, m, 0, &p, 1);
+ if (p.filters)
+ free_filterlist(p.filters);
+ } else if(tag) {
+ tag = tag->next;
+ }
+ }
+}
+
+void dumpSWF(SWF*swf)
+{
+ TAG* tag = swf->firstTag;
+ printf("vvvvvvvvvvvvvvvvvvvvv\n");
+ while(tag) {
+ printf("%8d %s\n", tag->len, swf_TagGetName(tag));
+ tag = tag->next;
+ }
+ printf("^^^^^^^^^^^^^^^^^^^^^\n");
+}
+
static void s_endSprite()
{
SRECT r = currentrect;
-
+
+ stackpos--;
+ instance_t *i;
+
+ dict_foreach_value(&instances, writeInstance);
+
if(stack[stackpos].cut)
tag = removeFromTo(stack[stackpos].cut, tag);
- stackpos--;
-
+ // the writeInstance loop above may have inserted tags after what used to be the current tag,
+ // so let's make sure 'tag' point to the current tag again.
+ while (tag->next)
+ tag = tag->next;
+
+ tag = swf_InsertTag(tag, ST_SHOWFRAME);
+ tag = swf_InsertTag(tag, ST_END);
+
+ tag = stack[stackpos].tag;
+ swf_FoldSprite(tag);
+
+ if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
+ stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
+ {
+ tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
+ swf_SetU16(tag, stack[stackpos].id);
+ swf_SetRect(tag, &stack[stackpos].scalegrid);
+ }
+
+ if(tag->next != 0)
+ syntaxerror("internal error(7)");
/* TODO: before clearing, prepend "<spritename>." to names and
copy into old instances dict */
- dictionary_clear(&instances);
+ dict_free_all(&instances, 1, free_instance);
currentframe = stack[stackpos].oldframe;
currentrect = stack[stackpos].oldrect;
currentdepth = stack[stackpos].olddepth;
instances = stack[stackpos].oldinstances;
- tag = swf_InsertTag(tag, ST_END);
-
- tag = stack[stackpos].tag;
- swf_FoldSprite(tag);
- if(tag->next != 0)
- syntaxerror("internal error(7)");
-
s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
free(stack[stackpos].name);
}
int fi;
SWF* swf;
char*filename;
-
+
+ dict_foreach_value(&instances, writeInstance);
+
if(stack[stackpos].cut)
tag = removeFromTo(stack[stackpos].cut, tag);
swf = stack[stackpos].swf;
filename = stack[stackpos].filename;
-
- //tag = swf_InsertTag(tag, ST_SHOWFRAME); //?
+
+ // the writeInstance loop above may have inserted tags after what used yo be the current tag,
+ // so let's make sure 'tag' point to the current tag again.
+ while (tag->next)
+ tag = tag->next;
+
+ //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
+ // tag = swf_InsertTag(tag, ST_SHOWFRAME);
+ tag = swf_InsertTag(tag, ST_SHOWFRAME);
+
+ if(stack[0].as3) {
+ TAG*tag = swf->firstTag;
+ tag = swf_InsertTag(tag, ST_DOABC);
+ void*code = as3_getcode();
+ swf_WriteABC(tag, code);
+ if(as3_getglobalclass()) {
+ tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
+ swf_SetU16(tag, 1);
+ swf_SetU16(tag, 0);
+ swf_SetString(tag, as3_getglobalclass());
+ } else {
+ warning("no global public MovieClip subclass");
+ }
+ as3_destroy();
+ }
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(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(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
+ if(do_cgi)
+ {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
else
{if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
close(fi);
-
- dictionary_clear(&instances);
- dictionary_clear(&characters);
- dictionary_clear(&images);
- dictionary_clear(&outlines);
- dictionary_clear(&gradients);
- dictionary_clear(&fonts);
- dictionary_clear(&sounds);
+
+ freeDictionaries();
swf_FreeTags(swf);
free(swf);
int s_getframe()
{
- return currentframe;
+ return currentframe+1;
}
-void s_frame(int nr, int cut)
+void s_frame(int nr, int cut, const 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) {
currentframe = nr;
}
-int parseColor2(char*str, RGBA*color);
+int parseColor2(const char*str, RGBA*color);
-int addFillStyle(SHAPE*s, SRECT*r, char*texture)
+int addFillStyle(SHAPE*s, SRECT*r, const 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 = dict_lookup(&textures, name))) {
+ return swf_ShapeAddFillStyle2(s, &texture->fs);
+ } else if((image = dict_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 = dict_lookup(&gradients, name))) {
+ SRECT r2;
+ MATRIX rot,m;
+ double ccos,csin;
+ swf_GetMatrix(0, &rot);
+ ccos = cos(-gradient->rotate*2*M_PI/360);
+ csin = sin(-gradient->rotate*2*M_PI/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;
}
}
-
+
RGBA black={r:0,g:0,b:0,a:0};
-void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
+void s_box(const char*name, int width, int height, RGBA color, int linewidth, const char*texture)
{
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);
swf_ShapeSetLine(tag,s,0,-height);
swf_ShapeSetEnd(tag);
swf_ShapeFree(s);
-
+
s_addcharacter(name, id, tag, r);
incrementid();
}
-void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
+void s_filled(const char*name, const char*outlinename, RGBA color, int linewidth, const char*texture)
{
SRECT rect,r2;
SHAPE* s;
int ls1,fs1=0;
outline_t* outline;
- outline = dictionary_lookup(&outlines, outlinename);
+ outline = dict_lookup(&outlines, outlinename);
if(!outline) {
syntaxerror("outline %s not defined", outlinename);
}
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);
incrementid();
}
-void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
+void s_circle(const char*name, int r, RGBA color, int linewidth, const char*texture)
{
SRECT rect,r2;
SHAPE* s;
- int ls1,fs1=0;
+ int ls1=0,fs1=0;
r2.xmin = r2.ymin = 0;
r2.xmax = 2*r;
r2.ymax = 2*r;
- tag = swf_InsertTag(tag, ST_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);
swf_ShapeSetCircle(tag, s, r,r,r,r);
swf_ShapeSetEnd(tag);
swf_ShapeFree(s);
-
+
s_addcharacter(name, id, tag, rect);
incrementid();
}
-void s_textshape(char*name, char*fontname, char*_text)
+void s_textshape(const char*name, const char*fontname, float size, const char*_text)
{
int g;
U8*text = (U8*)_text;
outline_t* outline;
SWFFONT*font;
- font = dictionary_lookup(&fonts, fontname);
+ font = dict_lookup(&fonts, fontname);
if(!font)
syntaxerror("font \"%s\" not known!", 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, 0);
memset(outline, 0, sizeof(outline_t));
outline->shape = font->glyph[g].shape;
outline->bbox = font->layout->bounds[g];
-
+
{
drawer_t draw;
swf_Shape11DrawerInit(&draw, 0);
- swf_DrawText(&draw, font, _text);
+ swf_DrawText(&draw, font, (int)(size*100), (char*)_text);
draw.finish(&draw);
outline->shape = swf_ShapeDrawerToShape(&draw);
outline->bbox = swf_ShapeDrawerGetBBox(&draw);
draw.dealloc(&draw);
}
- if(dictionary_lookup(&outlines, name))
+ if(dict_lookup(&outlines, name))
syntaxerror("outline %s defined twice", name);
- dictionary_put2(&outlines, name, outline);
+ dict_put(&outlines, name, outline);
}
-void s_text(char*name, char*fontname, char*text, int size, RGBA color)
+void s_text(const char*name, const char*fontname, const char*text, int size, RGBA color)
{
SRECT r;
-
+ MATRIX _m,*m=0;
SWFFONT*font;
- font = dictionary_lookup(&fonts, fontname);
+ font = dict_lookup(&fonts, fontname);
if(!font)
syntaxerror("font \"%s\" not known!", fontname);
-
+
tag = swf_InsertTag(tag, ST_DEFINETEXT2);
swf_SetU16(tag, id);
if(!font->numchars) {
s_box(name, 0, 0, black, 20, 0);
return;
}
- r = swf_SetDefineText(tag, font, &color, text, size);
-
+ r = swf_SetDefineText(tag, font, &color, (char*)text, size);
+
+ if(stack[0].swf->fileVersion >= 8) {
+ tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
+ swf_SetU16(tag, id);
+ swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
+ swf_SetU32(tag, 0);//thickness
+ swf_SetU32(tag, 0);//sharpness
+ swf_SetU8(tag, 0);//reserved
+ }
+
s_addcharacter(name, id, tag, r);
incrementid();
}
-/* type: either "jpeg" or "png"
- */
-void s_image(char*name, char*type, char*filename, int quality)
+void s_quicktime(const char*name, const char*url)
{
- /* an image is actually two folded: 1st bitmap, 2nd character.
- Both of them can be used separately */
-
+ 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_video(const char *name, int width, int height)
+{
+ SRECT r;
+
+ memset(&r, 0, sizeof(r));
+
+ tag = swf_InsertTag(tag, ST_DEFINEVIDEOSTREAM);
+ swf_SetU16(tag, id);
+ swf_SetU16(tag, 0); // numframes
+ swf_SetU16(tag, width);
+ swf_SetU16(tag, height);
+ swf_SetU8(tag, 0); // videoflags
+ swf_SetU8(tag, 0); // codecid
+
+ s_addcharacter(name, id, tag, r);
+ incrementid();
+}
+
+void s_edittext(const char*name, const char*fontname, int size, int width, int height, const char*text, RGBA*color, int maxlength, const char*variable, int flags, int align)
+{
+ SWFFONT*font = 0;
+ EditTextLayout layout;
+ SRECT r;
+
+ if(fontname && *fontname) {
+ flags |= ET_USEOUTLINES;
+ font = dict_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, (char*)text, color, maxlength, font?font->id:0, size, &layout, (char*)variable);
+
+ s_addcharacter(name, id, tag, r);
+ incrementid();
+}
+
+/* type: either "jpeg" or "png"
+ */
+void s_image(const char*name, const char*type, const 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!");
+ if(!strcmp(type,"jpeg")) {
+#ifndef HAVE_JPEGLIB
+ warning("no jpeg support compiled in");
s_box(name, 0, 0, black, 20, 0);
return;
- }
- tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
- swf_SetU16(tag, imageID);
+#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);
- }
+ if(swf_SetJPEGBits(tag, (char*)filename, quality) < 0) {
+ syntaxerror("Image \"%s\" not found, or contains errors", filename);
+ }
- swf_GetJPEGSize(filename, &width, &height);
+ swf_GetJPEGSize(filename, &width, &height);
- r.xmin = 0;
- r.ymin = 0;
- r.xmax = width*20;
- r.ymax = height*20;
+ r.xmin = 0;
+ r.ymin = 0;
+ r.xmax = width*20;
+ r.ymax = height*20;
- s_addimage(name, id, tag, r);
- incrementid();
+ 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);
+ free(data);
+
+ 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 */
tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
incrementid();
}
-void dumpSWF(SWF*swf)
+void s_getBitmapSize(const char*name, int*width, int*height)
{
- TAG* tag = swf->firstTag;
- printf("vvvvvvvvvvvvvvvvvvvvv\n");
- while(tag) {
- printf("%8d %s\n", tag->len, swf_TagGetName(tag));
- tag = tag->next;
+ character_t* image = dict_lookup(&images, name);
+ gradient_t* gradient = dict_lookup(&gradients,name);
+ if(image) {
+ *width = image->size.xmax;
+ *height = image->size.ymax;
+ return;
}
- printf("^^^^^^^^^^^^^^^^^^^^^\n");
+ 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_font(char*name, char*filename)
+
+void s_texture(const char*name, const char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
{
- SWFFONT* font;
- 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;
+ if(dict_lookup(&textures, name))
+ syntaxerror("texture %s defined twice", name);
+ gradient_t* gradient = dict_lookup(&gradients, object);
+ character_t* bitmap = dict_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;
+ }
+
+ dict_put(&textures, name, texture);
+}
+void s_font(const char*name, const char*filename)
+{
+ SWFFONT* font;
+ font = dict_lookup(&fonts, name);
if(0)
{
/* fix the layout. Only needed for old fonts */
font->layout = 0;
swf_FontCreateLayout(font);
}
-
font->id = id;
+ swf_FontReduce_swfc(font);
tag = swf_InsertTag(tag, ST_DEFINEFONT2);
swf_FontSetDefine2(tag, font);
- incrementid();
+ if(do_exports) {
+ tag = swf_InsertTag(tag, ST_EXPORTASSETS);
+ swf_SetU16(tag, 1);
+ swf_SetU16(tag, id);
+ swf_SetString(tag, name);
+ }
- if(dictionary_lookup(&fonts, name))
- syntaxerror("font %s defined twice", name);
- dictionary_put2(&fonts, name, font);
+ incrementid();
}
TAG*tag;
} sound_t;
-void s_sound(char*name, char*filename)
+void s_sound(const char*name, const char*filename)
{
struct WAV wav, wav2;
+ struct MP3 mp3;
sound_t* sound;
- U16*samples;
- int numsamples;
+ U16*samples = NULL;
+ unsigned numsamples = 1;
+ unsigned blocksize = 1152;
+ int is_mp3 = 0;
- if(!readWAV(filename, &wav)) {
- warning("Couldn't read wav file \"%s\"", filename);
- samples = 0;
- numsamples = 0;
- } else {
- convertWAV2mono(&wav, &wav2, 44100);
- samples = (U16*)wav2.data;
- numsamples = wav2.size/2;
- free(wav.data);
+ if(dict_lookup(&sounds, name))
+ syntaxerror("sound %s defined twice", name);
+
+ 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;
+ free(samples);
+ 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);
+
+ if(do_exports) {
+ 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;
- if(dictionary_lookup(&sounds, name))
- syntaxerror("sound %s defined twice", name);
- dictionary_put2(&sounds, name, sound);
-
+ dict_put(&sounds, name, sound);
+
incrementid();
- if(samples)
- free(samples);
+ if (samples)
+ free(samples);
}
static char* gradient_getToken(const char**p)
char*result;
while(**p && strchr(" \t\n\r", **p)) {
(*p)++;
- }
+ }
start = *p;
while(**p && !strchr(" \t\n\r", **p)) {
(*p)++;
return result;
}
-float parsePercent(char*str);
-RGBA parseColor(char*str);
+float parsePercent(const char*str);
+RGBA parseColor(const 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;
- 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 = rfx_calloc(16*sizeof(U8));
+ gradient.rgba = rfx_calloc(16*sizeof(RGBA));
+
+ while(*p)
+ {
+ char*posstr,*colorstr;
+ int pos;
+ RGBA color;
+ posstr = gradient_getToken(&p);
+ if(!*posstr)
+ {
+ free(posstr);
+ break;
+ }
+ pos = (int)(parsePercent(posstr)*255.0);
+ if(pos == lastpos)
+ pos++;
+ if(!*p)
+ {
+ rfx_free(gradient.ratios);
+ rfx_free(gradient.rgba);
+ free(posstr);
+ syntaxerror("Error in shape data: Color expected after %s", posstr);
+ }
+ colorstr = gradient_getToken(&p);
+ color = parseColor(colorstr);
+ if(gradient.num == 16)
+ {
+ warning("gradient record too big- max size is 16, rest ignored");
+ break;
+ }
+ gradient.ratios[gradient.num] = pos;
+ gradient.rgba[gradient.num] = color;
+ gradient.num++;
+ free(posstr);
+ free(colorstr);
+ lastpos = pos;
}
- 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)
+FILTERLIST* parseFilters(char* list)
+{
+ if (!strcmp(list, "no_filters"))
+ return 0;
+ FILTER* f;
+ FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
+ f_list->num = 0;
+ char* f_start = list;
+ char* f_end;
+ while (f_start)
+ {
+ f_end = strchr(f_start, ',');
+ if (f_end)
+ *f_end = '\0';
+ f = dict_lookup(&filters, f_start);
+ if (!f)
+ {
+ free(f_list);
+ syntaxerror("unknown filter %s", f_start);
+ }
+ if (f_list->num == 8)
+ {
+ warning("too many filters in filterlist, no more than 8 please, rest ignored");
+ break;
+ }
+ f_list->filter[f_list->num] = f;
+ f_list->num++;
+ if (f_end)
+ {
+ *f_end = ',';
+ f_start = f_end + 1;
+ }
+ else
+ f_start = 0;
+ }
+ return f_list;
+}
+
+void s_gradient(const 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;
+
+ dict_put(&gradients, name, gradient);
+}
+
+void s_gradientglow(const char*name, const char*gradient, float blurx, float blury,
+ float angle, float distance, float strength, char innershadow,
+ char knockout, char composite, char ontop, int passes)
+{
+ if(dict_lookup(&filters, name))
+ syntaxerror("filter %s defined twice", name);
+
+ gradient_t* g = dict_lookup(&gradients, gradient);
+ if(!g)
+ syntaxerror("unknown gradient %s", gradient);
+
+ composite = 1;
+
+ 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;
+
+ dict_put(&filters, name, filter);
+}
+
+void s_dropshadow(const char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
+{
+ if(dict_lookup(&filters, name))
+ syntaxerror("filter %s defined twice", name);
+
+ 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;
+
+ dict_put(&filters, name, filter);
+}
+
+void s_bevel(const 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)
+{
+ if(dict_lookup(&filters, name))
+ syntaxerror("filter %s defined twice", name);
+
+ 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;
+
+ dict_put(&filters, name, filter);
+}
+
+void s_blur(const char*name, double blurx, double blury, int passes)
+{
+ if(dict_lookup(&filters, name))
+ syntaxerror("filter %s defined twice", name);
+
+ FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
+ filter->type = FILTERTYPE_BLUR;
+ filter->blurx = blurx;
+ filter->blury = blury;
+ filter->passes = passes;
- if(dictionary_lookup(&gradients, name))
- syntaxerror("gradient %s defined twice", name);
- dictionary_put2(&gradients, name, gradient);
+ dict_put(&filters, name, filter);
}
void s_action(const char*text)
{
+ if(stack[0].swf->fileVersion < 9) {
+ ActionTAG* a = 0;
+ a = swf_ActionCompile(text, stack[0].swf->fileVersion);
+ if(!a) {
+ swf_ActionFree(a);
+ syntaxerror("Couldn't compile ActionScript");
+ }
+ tag = swf_InsertTag(tag, ST_DOACTION);
+ swf_ActionSet(tag, a);
+ swf_ActionFree(a);
+ } else {
+ as3_parse_bytearray(stack[0].filename, text, strlen(text));
+ stack[0].as3 = 1;
+ }
+}
+
+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)
+ {
+ swf_ActionFree(a);
+ syntaxerror("Couldn't compile ActionScript");
+ }
- tag = swf_InsertTag(tag, ST_DOACTION);
+ c = (character_t*)dict_lookup(&characters, character);
+ tag = swf_InsertTag(tag, ST_DOINITACTION);
+ swf_SetU16(tag, c->id);
swf_ActionSet(tag, a);
swf_ActionFree(a);
}
-void s_outline(char*name, char*format, char*source)
+int s_swf3action(const char*name, const char*action)
{
+ ActionTAG* a = 0;
+ instance_t* object = 0;
+ if(name)
+ object = (instance_t*)dict_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(const char*name, const char*format, const char*source)
+{
+ if(dict_lookup(&outlines, name))
+ syntaxerror("outline %s defined twice", name);
+
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);
- //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;
-
- if(dictionary_lookup(&outlines, name))
- syntaxerror("outline %s defined twice", name);
- dictionary_put2(&outlines, name, outline);
+
+ dict_put(&outlines, name, outline);
}
-void s_playsound(char*name, int loops, int nomultiple, int stop)
+int s_playsound(const 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 = dict_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_includeswf(char*name, char*filename)
+void s_includeswf(const char*name, const 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);
- if (f<0) {
+ 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);
return;
}
- if (swf_ReadSWF(f,&swf)<0) {
+ 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, 0);
return;
}
close(f);
- /* FIXME: The following sets the bounding Box for the character.
+ /* FIXME: The following sets the bounding Box for the character.
It is wrong for two reasons:
a) It may be too small (in case objects in the movie clip at the borders)
b) it may be too big (because the poor movie never got autocropped)
*/
r = swf.movieSize;
-
+
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)
s_addcharacter(name, id, tag, r);
incrementid();
}
-SRECT s_getCharBBox(char*name)
+SRECT s_getCharBBox(const char*name)
{
- character_t* c = dictionary_lookup(&characters, name);
+ character_t* c = dict_lookup(&characters, name);
if(!c) syntaxerror("character '%s' unknown(2)", name);
return c->size;
}
-SRECT s_getInstanceBBox(char*name)
+SRECT s_getInstanceBBox(const char*name)
{
- instance_t * i = dictionary_lookup(&instances, name);
+ instance_t * i = dict_lookup(&instances, name);
character_t * c;
if(!i) syntaxerror("instance '%s' unknown(4)", name);
c = i->character;
if(!c) syntaxerror("internal error(5)");
return c->size;
}
-parameters_t s_getParameters(char*name)
+void s_getParameters(const char*name, parameters_t* p)
+{
+ instance_t * i = dict_lookup(&instances, name);
+ if(!i)
+ syntaxerror("instance '%s' unknown(10)", name);
+ if (change_sets_all)
+ readParameters(i->history, p, currentframe);
+ else
+ *p = i->parameters;
+}
+
+void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
{
- instance_t * i = dictionary_lookup(&instances, name);
- if(!i) syntaxerror("instance '%s' unknown(10)", name);
- return i->parameters;
+ history_begin(i->history, "x", currentframe, tag, p->x);
+ history_begin(i->history, "y", currentframe, tag, p->y);
+ history_begin(i->history, "scalex", currentframe, tag, p->scalex);
+ history_begin(i->history, "scaley", currentframe, tag, p->scaley);
+ history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
+ history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
+ history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
+ history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
+ history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
+ history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
+ history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
+ history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
+ history_begin(i->history, "rotate", currentframe, tag, p->rotate);
+ history_begin(i->history, "shear", currentframe, tag, p->shear);
+ history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
+ history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
+ history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
+ history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
+ history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
+ history_beginFilter(i->history, currentframe, tag, p->filters);
+ history_begin(i->history, "flags", currentframe, tag, 0);
}
-void s_startclip(char*instance, char*character, parameters_t p)
+
+void s_startclip(const char*instance, const char*character, parameters_t p)
{
- character_t* c = dictionary_lookup(&characters, character);
+ character_t* c = dict_lookup(&characters, character);
instance_t* i;
MATRIX m;
if(!c) {
}
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_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
- i->lastTag = tag;
- i->lastFrame= currentframe;
stack[stackpos].tag = tag;
stack[stackpos].type = 2;
stackpos++;
+ setStartparameters(i, &p, tag);
currentdepth++;
}
void s_endClip()
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++;
}
-void s_put(char*instance, char*character, parameters_t p)
+void s_put(const char*instance, const char*character, parameters_t p)
{
- character_t* c = dictionary_lookup(&characters, character);
+ character_t* c = dict_lookup(&characters, character);
instance_t* i;
MATRIX m;
- if(!c) {
- syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
- }
-
+ if(!c)
+ syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
+
i = s_addinstance(instance, c, currentdepth);
i->parameters = p;
- m = s_instancepos(i, &p);
-
- tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
- swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
- i->lastTag = tag;
- i->lastFrame = currentframe;
+ m = s_instancepos(i->character->size, &p);
+
+ if(p.blendmode || p.filters)
+ {
+ if(stack[0].swf->fileVersion < 8)
+ {
+ if(p.blendmode)
+ warning("blendmodes only supported for flash version>=8");
+ else
+ warning("filters only supported for flash version>=8");
+ }
+ tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
+ }
+ else
+ tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
+ setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
+ setStartparameters(i, &p, tag);
currentdepth++;
}
-void s_jump(char*instance, parameters_t p)
+void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
{
- instance_t* i = dictionary_lookup(&instances, instance);
- MATRIX m;
- if(!i) {
- syntaxerror("instance %s not known", instance);
+ if (p.set & SF_X)
+ history_remember(history, "x", currentframe, changeFunction, p.x, inter);
+ if (p.set & SF_Y)
+ history_remember(history, "y", currentframe, changeFunction, p.y, inter);
+ if (p.set & SF_SCALEX)
+ history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
+ if (p.set & SF_SCALEY)
+ history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
+ if (p.set & SF_CX_R)
+ {
+ history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
+ history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
}
+ if (p.set & SF_CX_G)
+ {
+ history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
+ history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
+ }
+ if (p.set & SF_CX_B)
+ {
+ history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
+ history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
+ }
+ if (p.set & SF_CX_A)
+ {
+ history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
+ history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
+ }
+ if (p.set & SF_ROTATE)
+ history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
+ if (p.set & SF_SHEAR)
+ history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
+ if (p.set & SF_PIVOT)
+ {
+ history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
+ history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
+ }
+ if (p.set & SF_PIN)
+ {
+ history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
+ history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
+ }
+ if (p.set & SF_BLEND)
+ history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
+ if (p.set & SF_FILTER)
+ history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
+}
- i->parameters = p;
- m = s_instancepos(i, &p);
+void s_jump(const char* instance, parameters_t p)
+{
+ instance_t* i = dict_lookup(&instances, instance);
+ if(!i)
+ syntaxerror("instance %s not known", instance);
+ recordChanges(i->history, p, CF_JUMP, 0);
+}
- tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
- swf_ObjectMove(tag, i->depth, &m, &p.cxform);
- i->lastTag = tag;
- i->lastFrame = currentframe;
+void s_change(const char*instance, parameters_t p, interpolation_t* inter)
+{
+ instance_t* i = dict_lookup(&instances, instance);
+ if(!i)
+ syntaxerror("instance %s not known", instance);
+ recordChanges(i->history, p, CF_CHANGE, inter);
}
-parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
+void s_sweep(const char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
{
- parameters_t p;
- float ratio;
- if(num==0 || num==1)
- return *p1;
- ratio = (float)pos/(float)num;
-
- p.x = (p2->x-p1->x)*ratio + p1->x;
- p.y = (p2->y-p1->y)*ratio + p1->y;
- p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
- p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
- p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
- p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
-
- p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
- p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
- p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
- p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
-
- p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
- p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
- p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
- p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
-
- p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
- 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;
- return p;
+ instance_t* i = dict_lookup(&instances, instance);
+ if(!i)
+ syntaxerror("instance %s not known", instance);
+ history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
}
-void s_change(char*instance, parameters_t p2)
+void s_toggle(const char* instance, U16 flagsOn, U16 flagsOff)
{
- instance_t* i = dictionary_lookup(&instances, instance);
- MATRIX m;
- parameters_t p1;
- TAG*t;
- int frame, allframes;
- if(!i) {
- syntaxerror("instance %s not known", instance);
- }
- p1 = i->parameters;
-
- allframes = currentframe - i->lastFrame - 1;
- if(allframes < 0) {
- warning(".change ignored. can only .put/.change an object once per frame.");
- return;
- }
-
- m = s_instancepos(i, &p2);
- tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
- swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
- i->parameters = p2;
-
- /* o.k., we got the start and end point set. Now iterate though all the
- tags in between, inserting object changes after each new frame */
- t = i->lastTag;
- i->lastTag = tag;
- if(!t) syntaxerror("internal error(6)");
- frame = 0;
- while(frame < allframes) {
- if(t->id == ST_SHOWFRAME) {
- parameters_t p;
- MATRIX m;
- TAG*lt;
- frame ++;
- p = s_interpolate(&p1, &p2, frame, allframes);
- m = s_instancepos(i, &p); //needed?
- lt = swf_InsertTag(t, ST_PLACEOBJECT2);
- i->lastFrame = currentframe;
- swf_ObjectMove(lt, i->depth, &m, &p.cxform);
- t = lt;
- if(frame == allframes)
- break;
- }
- t = t->next;
- if(!t)
- syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
- }
+ instance_t* i = dict_lookup(&instances, instance);
+ if (!i)
+ syntaxerror("instance %s not known", instance);
+ U16 flags = (U16)history_value(i->history, currentframe, "flags");
+ flags |= flagsOn;
+ flags &= flagsOff;
+ history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
}
-void s_delinstance(char*instance)
+void s_delinstance(const char*instance)
{
- instance_t* i = dictionary_lookup(&instances, instance);
- if(!i) {
- syntaxerror("instance %s not known", instance);
- }
+ instance_t* i = dict_lookup(&instances, instance);
+ if(!i)
+ syntaxerror("instance %s not known", instance);
+ writeInstance(i);
tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
swf_SetU16(tag, i->depth);
- dictionary_del(&instances, instance);
+ dict_del(&instances, instance);
+ free(i);
}
-void s_qchange(char*instance, parameters_t p)
+void s_schange(const char*instance, parameters_t p, interpolation_t* inter)
{
+ instance_t* i = dict_lookup(&instances, instance);
+ if(!i)
+ syntaxerror("instance %s not known", instance);
+ recordChanges(i->history, p, CF_SCHANGE, inter);
}
void s_end()
{
if(!stackpos)
syntaxerror(".end unexpected");
- if(stack[stackpos-1].type == 0)
- s_endSWF();
- else if(stack[stackpos-1].type == 1)
- s_endSprite();
- else if(stack[stackpos-1].type == 2)
- s_endClip();
- else syntaxerror("internal error 1");
+ switch (stack[stackpos-1].type)
+ {
+ case 0:
+ s_endSWF();
+ break;
+ case 1:
+ s_endSprite();
+ break;
+ case 2:
+ s_endClip();
+ break;
+ case 3:
+ s_endButton();
+ break;
+ default:
+ syntaxerror("internal error 1");
+ }
}
// ------------------------------------------------------------------------
typedef int command_func_t(map_t*args);
-SRECT parseBox(char*str)
+SRECT parseBox(const 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;
syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
return r;
}
-float parseFloat(char*str)
+float parseFloat(const char*str)
{
return atof(str);
}
-int parseInt(char*str)
+int parseInt(const char*str)
{
int t;
int l=strlen(str);
syntaxerror("Not an Integer: \"%s\"", str);
return atoi(str);
}
-int parseTwip(char*str)
+static double parseRawTwip(const char*str)
{
char*dot;
int sign=1;
if(!dot) {
int l=strlen(str);
int t;
- return sign*parseInt(str)*20;
+ return sign*parseInt(str);
} else {
- int l=strlen(++dot);
- char*s;
- for(s=str;s<dot-1;s++)
- if(*s<'0' || *s>'9')
- syntaxerror("Not a coordinate: \"%s\"", str);
- for(s=dot;*s;s++) {
- 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);
+ char* old = strdup(str);
+ int l=strlen(dot+1);
+ const char*s;
+ *dot++ = 0;
+ for(s=str;s<dot-1;s++) {
+ if(*s<'0' || *s>'9')
+ {
+ free(old);
+ syntaxerror("Not a coordinate: \"%s\"", str);
+ }
+ }
+ for(s=dot;*s;s++) {
+ if(*s<'0' || *s>'9')
+ {
+ free(old);
+ syntaxerror("Not a coordinate: \"%s\"", 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;
+ return sign*(atoi(str));
if(l==1)
- return sign*atoi(str)*20+atoi(dot)*2;
+ return sign*(atoi(str)+0.1*atoi(dot));
if(l==2)
- return sign*atoi(str)*20+atoi(dot)/5;
+ return sign*(atoi(str)+0.01*atoi(dot));
}
return 0;
}
-int isPoint(char*str)
+static dict_t defines;
+static int defines_initialized = 0;
+static mem_t define_values;
+
+static double parseNameOrTwip(const char*s)
+{
+ int l = 0;
+ double v;
+ if(defines_initialized) {
+ l = (int)dict_lookup(&defines, s);
+ }
+ if(l) {
+ return *(int*)&define_values.buffer[l-1];
+ } else {
+ return parseRawTwip(s);
+ }
+}
+
+/* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
+static double parseExpression(char*s)
+{
+ int chr2index[256];
+ memset(chr2index, -1, sizeof(chr2index));
+ chr2index['+'] = 0;
+ chr2index['-'] = 1;
+ chr2index['*'] = 2;
+ chr2index['/'] = 3;
+ chr2index['('] = 5;
+ chr2index[')'] = 6;
+ chr2index['\0'] = 7;
+
+ int stackpos = 1;
+ int stack[256];
+ double values[256];
+ stack[0]=0;
+ values[0]=0;
+ int accept = 18;
+ int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
+ int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
+ int table[18][12] = {
+ {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
+ {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
+ {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
+ {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
+ {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
+ {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
+ {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
+ {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
+ {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
+ {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
+ {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
+ {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
+ {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
+ {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
+ {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
+ {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
+ {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
+ {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
+
+ char*p = s;
+ while(1) {
+ char*pnext = p+1;
+ int action;
+ double value = 0;
+ if(!stackpos) {
+ fprintf(stderr, "Error in expression\n");
+ return 0.0;
+ }
+
+ if(chr2index[*p]<0) {
+ action = table[stack[stackpos-1]][4];
+ if(action>0) {
+ while(chr2index[*pnext]<0)
+ pnext++;
+ char save = *pnext;
+ *pnext = 0;
+ value = parseNameOrTwip(p);
+ *pnext = save;
+ }
+ } else {
+ action = table[stack[stackpos-1]][chr2index[*p]];
+ }
+
+ if(action == accept) {
+ return values[stack[stackpos-1]];
+ } else if(action>0) { // shift
+ if(stackpos>254) {
+ fprintf(stderr, "Stack overflow while parsing expression\n");
+ return 0.0;
+ }
+ values[stackpos]=value;
+ stack[stackpos++]=action;
+ p=pnext;
+ } else if(action<0) { // reduce
+ stackpos-=plen[-action];
+ stack[stackpos] = table[stack[stackpos-1]][left[-action]];
+ switch(-action) {
+ case 1:
+ values[stackpos] = values[stackpos+0] + values[stackpos+2];
+ break;
+ case 2:
+ values[stackpos] = 0 - values[stackpos+1];
+ break;
+ case 3:
+ values[stackpos] = values[stackpos+0] - values[stackpos+2];
+ break;
+ case 5:
+ values[stackpos] = values[stackpos+0] * values[stackpos+2];
+ break;
+ case 6:
+ values[stackpos] = values[stackpos+0] / values[stackpos+2];
+ break;
+ case 9:
+ values[stackpos] = values[stackpos+1];
+ break;
+ }
+ stackpos++;
+ } else {
+ fprintf(stderr, "Syntax error in expression\n");
+ return 0.0;
+ }
+ }
+}
+
+int parseTwip(const char*str)
+{
+ char*str2 = (char*)str;
+ int v = (int)(parseExpression(str2)*20);
+ return v;
+}
+
+int parseArc(const char* str)
+{
+ if (!strcmp(str, "short"))
+ return 1;
+ if (!strcmp(str, "long"))
+ return 0;
+ syntaxerror("invalid value for the arc parameter: %s", str);
+ return 1;
+}
+
+int parseDir(const char* str)
+{
+ if (!strcmp(str, "clockwise"))
+ return 1;
+ if (!strcmp(str, "counterclockwise"))
+ return 0;
+ syntaxerror("invalid value for the dir parameter: %s", str);
+ return 1;
+}
+
+int isPoint(const char*str)
{
if(strchr(str, '('))
return 1;
return 0;
}
-SPOINT parsePoint(char*str)
+SPOINT parsePoint(const char*str)
{
SPOINT p;
char tmp[80];
return p;
}
-int parseColor2(char*str, RGBA*color)
+int parseColor2(const char*str, RGBA*color)
{
int l = strlen(str);
int r,g,b,a;
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 0;
}
-RGBA parseColor(char*str)
+RGBA parseColor(const char*str)
{
RGBA c;
if(!parseColor2(str, &c))
S16 add;
} MULADD;
-MULADD parseMulAdd(char*str)
+MULADD parseMulAdd(const char*str)
{
float add, mul;
char* str2 = (char*)malloc(strlen(str)+5);
return r;
}
-float parsePercent(char*str)
+float parsePxOrPercent(const char*fontname, const 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(const char*str)
{
int l = strlen(str);
if(!l)
return 1.0;
if(str[l-1]=='%') {
- return atoi(str)/100.0;
+ return atof(str)/100.0;
}
syntaxerror("Expression '%s' is not a percentage", str);
return 0;
}
-int isPercent(char*str)
+int isPercent(const char*str)
{
return str[strlen(str)-1]=='%';
}
-int parseNewSize(char*str, int size)
+int parseNewSize(const char*str, int size)
{
if(isPercent(str))
return parsePercent(str)*size;
return parseColor2(str, &c);
}
-static char* lu(map_t* args, char*name)
+static const char* lu(map_t* args, char*name)
{
- char* value = map_lookup(args, name);
+ const char* value = map_lookup(args, name);
if(!value) {
map_dump(args, stdout, "");
syntaxerror("internal error 2: value %s should be set", name);
return value;
}
-static int c_flash(map_t*args)
+static int c_flash(map_t*args)
{
- char* name = lu(args, "name");
- char* compressstr = lu(args, "compress");
+ const char* filename = map_lookup(args, "filename");
+ const char* compressstr = lu(args, "compress");
+ const char* change_modestr = lu(args, "change-sets-all");
+ const char* exportstr = lu(args, "export");
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;
-
+ int compress = 0;
+
+ 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);
+ if(!strcmp(change_modestr, "yes"))
+ change_sets_all = 1;
+ else
+ if(strcmp(change_modestr, "no"))
+ syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
+
+ do_exports=atoi(exportstr);
+
+ s_swf(filename, bbox, version, fps, compress, color);
return 0;
}
-int isRelative(char*str)
+int isRelative(const char*str)
{
return !strncmp(str, "<plus>", 6) ||
!strncmp(str, "<minus>", 7);
}
-char* getOffset(char*str)
+const char* getOffset(const char*str)
{
if(!strncmp(str, "<plus>", 6))
return str+6;
syntaxerror("internal error (347)");
return 0;
}
-int getSign(char*str)
+int getSign(const char*str)
{
if(!strncmp(str, "<plus>", 6))
return 1;
syntaxerror("internal error (348)");
return 0;
}
-static dictionary_t points;
+
+static dict_t points;
static mem_t mpoints;
-int points_initialized = 0;
+static int points_initialized = 0;
+
+static int c_interpolation(map_t *args)
+{
+ int i;
+ const char* name = lu(args, "name");
+ if (dict_lookup(&interpolations, name))
+ syntaxerror("interpolation %s defined twice", name);
+
+ interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
+ const char* functionstr = lu(args, "function");
+ inter->function = 0;
+ for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
+ if (!strcmp(functionstr,interpolationFunctions[i]))
+ {
+ inter->function = i + 1;
+ break;
+ }
+ if (!inter->function)
+ syntaxerror("unkown interpolation function %s", functionstr);
+ inter->speed = parseFloat(lu(args, "speed"));
+ inter->amplitude = parseTwip(lu(args, "amplitude"));
+ inter->growth = parseFloat(lu(args, "growth"));
+ inter->bounces = parseInt(lu(args, "bounces"));
+ inter->damping = parseFloat(lu(args, "damping"));
+ inter->slope = parseFloat(lu(args, "slope"));
+
+ dict_put(&interpolations, name, inter);
+ return 0;
+}
-SPOINT getPoint(SRECT r, char*name)
+SPOINT getPoint(SRECT r, const char*name)
{
int l=0;
if(!strcmp(name, "center")) {
- SPOINT p;
- p.x = (r.xmin + r.xmax)/2;
- p.y = (r.ymin + r.ymax)/2;
- return p;
+ SPOINT p;
+ p.x = (r.xmin + r.xmax)/2;
+ p.y = (r.ymin + r.ymax)/2;
+ return p;
+ }
+ if (!strcmp(name, "bottom-center")) {
+ SPOINT p;
+ p.x = (r.xmin + r.xmax)/2;
+ p.y = r.ymax;
+ return p;
+ }
+ if (!strcmp(name, "top-center")) {
+ SPOINT p;
+ p.x = (r.xmin + r.xmax)/2;
+ p.y = r.ymin;
+ return p;
+ }
+ if (!strcmp(name, "top-left")) {
+ SPOINT p;
+ p.x = r.xmin;
+ p.y = r.ymin;
+ return p;
+ }
+ if (!strcmp(name, "top-right")) {
+ SPOINT p;
+ p.x = r.xmax;
+ p.y = r.ymin;
+ return p;
+ }
+ if (!strcmp(name, "bottom-right")) {
+ SPOINT p;
+ p.x = r.xmax;
+ p.y = r.ymax;
+ return p;
+ }
+ if (!strcmp(name, "bottom-left")) {
+ SPOINT p;
+ p.x = r.xmin;
+ p.y = r.ymax;
+ return p;
+ }
+ if (!strcmp(name, "left-center")) {
+ SPOINT p;
+ p.x = r.xmin;
+ p.y = (r.ymin + r.ymax)/2;
+ return p;
+ }
+ if (!strcmp(name, "right-center")) {
+ SPOINT p;
+ p.x = r.xmax;
+ p.y = (r.ymin + r.ymax)/2;
+ return p;
}
+
if(points_initialized)
- l = (int)dictionary_lookup(&points, name);
+ l = (int)dict_lookup(&points, name);
if(l==0) {
- syntaxerror("Invalid point: \"%s\".", name);
+ syntaxerror("Invalid point: \"%s\".", name);
}
- l--;
- return *(SPOINT*)&mpoints.buffer[l];
+ return *(SPOINT*)&mpoints.buffer[l-1];
}
-static int c_gradient(map_t*args)
+
+
+static int texture2(const char*name, const char*object, map_t*args, int errors)
{
- char*name = lu(args, "name");
+ SPOINT pos,size;
+ const char*xstr = map_lookup(args, "x");
+ const char*ystr = map_lookup(args, "y");
+ const char*widthstr = map_lookup(args, "width");
+ const char*heightstr = map_lookup(args, "height");
+ const char*scalestr = map_lookup(args, "scale");
+ const char*scalexstr = map_lookup(args, "scalex");
+ const char*scaleystr = map_lookup(args, "scaley");
+ const char*rotatestr = map_lookup(args, "rotate");
+ const char* shearstr = map_lookup(args, "shear");
+ const 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)
+{
+ const char*name = lu(args, "instance");
+ const char*object = lu(args, "character");
+ return texture2(name, object, args, 1);
+}
+
+static int c_gradient(map_t*args)
+{
+ const 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");
+ syntaxerror("colon (:) expected");
+
+ if(dict_lookup(&gradients, name))
+ syntaxerror("gradient %s defined twice", name);
+
+ 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 const char* checkFiltername(map_t* args)
+{
+ const char* name = lu(args, "name");
+ if (strchr(name, ','))
+ syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
+ return name;
+}
+
+static int c_blur(map_t*args)
+{
+ const char*name = checkFiltername(args);
+ const char*blurstr = lu(args, "blur");
+ const char*blurxstr = lu(args, "blurx");
+ const 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)
+{
+ const char*name = checkFiltername(args);
+ const char*gradient = lu(args, "gradient");
+ const char*blurstr = lu(args, "blur");
+ const char*blurxstr = lu(args, "blurx");
+ const 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)
+{
+ const char*name = checkFiltername(args);
+ RGBA color = parseColor(lu(args, "color"));
+ const char*blurstr = lu(args, "blur");
+ const char*blurxstr = lu(args, "blurx");
+ const 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;
+}
- s_gradient(name, text, radial);
+static int c_bevel(map_t*args)
+{
+ const char*name = checkFiltername(args);
+ RGBA shadow = parseColor(lu(args, "shadow"));
+ RGBA highlight = parseColor(lu(args, "highlight"));
+ const char*blurstr = lu(args, "blur");
+ const char*blurxstr = lu(args, "blurx");
+ const 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)
+
+static int c_define(map_t*args)
{
- char*name = lu(args, "name");
+ const char*name = lu(args, "name");
+ const char*value = lu(args, "value");
+
+ if(!defines_initialized) {
+ dict_init(&defines, 16);
+ mem_init(&define_values);
+ defines_initialized = 1;
+ }
+ int val = parseTwip(value);
+ int pos = mem_put(&define_values, &val, sizeof(val));
+ dict_put(&defines, name, (void*)(pos+1));
+ return 0;
+}
+static int c_point(map_t*args)
+{
+ const char*name = lu(args, "name");
int pos;
- string_t s1;
SPOINT p;
if(!points_initialized) {
- dictionary_init(&points);
+ dict_init(&points, 16);
mem_init(&mpoints);
points_initialized = 1;
}
p.x = parseTwip(lu(args, "x"));
p.y = parseTwip(lu(args, "y"));
pos = mem_put(&mpoints, &p, sizeof(p));
- string_set(&s1, name);
- pos++;
- dictionary_put(&points, s1, (void*)pos);
+ dict_put(&points, name, (void*)(pos+1));
return 0;
}
-static int c_play(map_t*args)
+static int c_play(map_t*args)
{
- char*name = lu(args, "sound");
- char*loop = lu(args, "loop");
- char*nomultiple = lu(args, "nomultiple");
+ const char*name = lu(args, "name");
+ const char*loop = lu(args, "loop");
+ const char*nomultiple = lu(args, "nomultiple");
int nm = 0;
if(!strcmp(nomultiple, "nomultiple"))
nm = 1;
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)
+static int c_stop(map_t*args)
{
- char*name = lu(args, "sound");
- s_playsound(name, 0,0,1);
+ const 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)
+{
+ const 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)
+{
+ const char*name = lu(args, "name");
+
+ if(s_swf3action(name, "previousframe")) {
+ return 0;
+ }
+ syntaxerror("I don't know anything about movie \"%s\"", name);
+ return 0;
+}
+
+static int c_movement(map_t*args, int type)
+{
+ const char*instance = lu(args, "name");
+
+ const char* xstr="";
+ const char* ystr="";
+ SRECT oldbbox;
+ parameters_t p;
+ U16 set = 0x0000;
+
+ xstr = lu(args, "x");
+ ystr = lu(args, "y");
+
+ s_getParameters(instance, &p);
+
+ /* x,y position */
+ if(xstr[0])
+ {
+ if(isRelative(xstr))
+ {
+ if(type == PT_PUT || type == PT_STARTCLIP)
+ syntaxerror("relative x values not allowed for initial put or startclip");
+ p.x += parseTwip(getOffset(xstr))*getSign(xstr);
+ }
+ else
+ {
+ p.x = parseTwip(xstr);
+ }
+ set = set | SF_X;
+ }
+ if(ystr[0])
+ {
+ if(isRelative(ystr))
+ {
+ if(type == PT_PUT || type == PT_STARTCLIP)
+ syntaxerror("relative y values not allowed for initial put or startclip");
+ p.y += parseTwip(getOffset(ystr))*getSign(ystr);
+ }
+ else
+ {
+ p.y = parseTwip(ystr);
+ }
+ set = set | SF_Y;
+ }
+
+ if (change_sets_all)
+ set = SF_ALL;
+ p.set = set;
+
+ switch (type)
+ {
+ case PT_MOVE:
+ {
+ const char* interstr = lu(args, "interpolation");
+ interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
+ if (!inter)
+ syntaxerror("unkown interpolation %s", interstr);
+ s_change(instance, p, inter);
+ }
+ break;
+ case PT_SMOVE:
+ {
+ const char* interstr = lu(args, "interpolation");
+ interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
+ if (!inter)
+ syntaxerror("unkown interpolation %s", interstr);
+ s_schange(instance, p, inter);
+ }
+ break;
+ case PT_SWEEP:
+ {
+ const char* rstr = lu(args, "r");
+ int radius = parseTwip(rstr);
+ if (radius <= 0)
+ syntaxerror("sweep not possible: radius must be greater than 0.");
+ const char* dirstr = lu(args, "dir");
+ int clockwise = parseDir(dirstr);
+ const char* arcstr = lu(args, "arc");
+ int short_arc = parseArc(arcstr);
+ const char* interstr = lu(args, "interpolation");
+ interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
+ if (!inter)
+ syntaxerror("unkown interpolation %s", interstr);
+ s_sweep(instance, p, radius, clockwise, short_arc, inter);
+ }
+ break;
+ }
return 0;
}
static int c_placement(map_t*args, int type)
{
- char*instance = lu(args, (type==0||type==4)?"instance":"name");
- char*character = 0;
-
- char* luminancestr = lu(args, "luminance");
- char* scalestr = lu(args, "scale");
- char* scalexstr = lu(args, "scalex");
- char* scaleystr = lu(args, "scaley");
- char* rotatestr = lu(args, "rotate");
- char* shearstr = lu(args, "shear");
- char* xstr="", *pivotstr="";
- char* ystr="", *anglestr="";
- char*above = lu(args, "above"); /*FIXME*/
- char*below = lu(args, "below");
- char* rstr = lu(args, "red");
- char* gstr = lu(args, "green");
- char* bstr = lu(args, "blue");
- char* astr = lu(args, "alpha");
- char* pinstr = lu(args, "pin");
+ const char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
+ const char*character = 0;
+
+ const char* luminancestr = lu(args, "luminance");
+ const char* scalestr = lu(args, "scale");
+ const char* scalexstr = lu(args, "scalex");
+ const char* scaleystr = lu(args, "scaley");
+ const char* rotatestr = lu(args, "rotate");
+ const char* shearstr = lu(args, "shear");
+ const char* xstr="", *pivotstr="";
+ const char* ystr="", *anglestr="";
+ const char*above = lu(args, "above"); /*FIXME*/
+ const char*below = lu(args, "below");
+ const char* rstr = lu(args, "red");
+ const char* gstr = lu(args, "green");
+ const char* bstr = lu(args, "blue");
+ const char* astr = lu(args, "alpha");
+ const char* pinstr = lu(args, "pin");
+ const char* as = map_lookup(args, "as");
+ const char* blendmode = lu(args, "blend");
+ const char* filterstr = lu(args, "filter");
+ U8 blend;
MULADD r,g,b,a;
float oldwidth;
float oldheight;
SRECT oldbbox;
MULADD luminance;
parameters_t p;
+ U16 set = 0x0000;
- if(type==5) {
- pivotstr = lu(args, "pivot");
- anglestr = lu(args, "angle");
- } else {
- xstr = lu(args, "x");
- ystr = lu(args, "y");
+ if(type==9)
+ { // (?) .rotate or .arcchange
+ pivotstr = lu(args, "pivot");
+ anglestr = lu(args, "angle");
}
+ else
+ {
+ xstr = lu(args, "x");
+ ystr = lu(args, "y");
+ }
+
if(luminancestr[0])
- luminance = parseMulAdd(luminancestr);
- else {
- luminance.add = 0;
- luminance.mul = 256;
+ luminance = parseMulAdd(luminancestr);
+ else
+ {
+ luminance.add = 0;
+ luminance.mul = 256;
}
- if(scalestr[0]) {
- if(scalexstr[0]||scaleystr[0])
- syntaxerror("scalex/scaley and scale cannot both be set");
- scalexstr = scaleystr = scalestr;
+ if(scalestr[0])
+ {
+ if(scalexstr[0]||scaleystr[0])
+ syntaxerror("scalex/scaley and scale cannot both be set");
+ scalexstr = scaleystr = scalestr;
}
-
- if(type == 0 || type == 4) {
+
+ if(type == PT_PUT || type == PT_STARTCLIP) {
// put or startclip
character = lu(args, "character");
parameters_clear(&p);
+ } else if (type == PT_BUTTON) {
+ character = lu(args, "name");
+ parameters_clear(&p);
+ // button's show
} else {
- p = s_getParameters(instance);
+ s_getParameters(instance, &p);
}
/* x,y position */
- if(xstr[0]) {
- if(isRelative(xstr)) {
- if(type == 0 || type == 4)
- syntaxerror("relative x values not allowed for initial put or startclip");
- p.x += parseTwip(getOffset(xstr))*getSign(xstr);
- } else {
- p.x = parseTwip(xstr);
- }
- }
- if(ystr[0]) {
- if(isRelative(ystr)) {
- if(type == 0 || type == 4)
- syntaxerror("relative y values not allowed for initial put or startclip");
- p.y += parseTwip(getOffset(ystr))*getSign(ystr);
- } else {
- p.y = parseTwip(ystr);
+ if(xstr[0])
+ {
+ if(isRelative(xstr))
+ {
+ if(type == PT_PUT || type == PT_STARTCLIP)
+ syntaxerror("relative x values not allowed for initial put or startclip");
+ p.x += parseTwip(getOffset(xstr))*getSign(xstr);
+ }
+ else
+ {
+ p.x = parseTwip(xstr);
+ }
+ set = set | SF_X;
+ }
+ if(ystr[0])
+ {
+ if(isRelative(ystr))
+ {
+ if(type == PT_PUT || type == PT_STARTCLIP)
+ syntaxerror("relative y values not allowed for initial put or startclip");
+ p.y += parseTwip(getOffset(ystr))*getSign(ystr);
+ }
+ else
+ {
+ p.y = parseTwip(ystr);
+ }
+ set = set | SF_Y;
}
- }
/* scale, scalex, scaley */
- if(character) {
- oldbbox = s_getCharBBox(character);
- } else {
- oldbbox = s_getInstanceBBox(instance);
- }
+ if(character)
+ oldbbox = s_getCharBBox(character);
+ else
+ oldbbox = s_getInstanceBBox(instance);
oldwidth = oldbbox.xmax - oldbbox.xmin;
oldheight = oldbbox.ymax - oldbbox.ymin;
- if(scalexstr[0]) {
- if(oldwidth==0) p.scalex = 1.0;
- else {
- if(scalexstr[0])
- p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
- }
- }
- if(scaleystr[0]) {
- if(oldheight==0) p.scaley = 1.0;
- else {
- if(scaleystr[0])
- p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
- }
+ if(scalexstr[0])
+ {
+ if(oldwidth==0)
+ p.scalex = 1.0;
+ else
+ if(scalexstr[0])
+ p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
+ set = set | SF_SCALEX;
}
-
+ if(scaleystr[0])
+ {
+ if(oldheight==0)
+ p.scaley = 1.0;
+ else
+ if(scaleystr[0])
+ p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
+ set = set | SF_SCALEY;
+ }
+
/* rotation */
- if(rotatestr[0]) {
- if(isRelative(rotatestr)) {
- p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
- } else {
- p.rotate = parseFloat(rotatestr);
+ if(rotatestr[0])
+ {
+ if(isRelative(rotatestr))
+ p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
+ else
+ p.rotate = parseFloat(rotatestr);
+ set = set | SF_ROTATE;
}
- }
/* shearing */
- if(shearstr[0]) {
- if(isRelative(shearstr)) {
- p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
- } else {
- p.shear = parseFloat(shearstr);
- }
+ if(shearstr[0])
+ {
+ if(isRelative(shearstr))
+ p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
+ else
+ p.shear = parseFloat(shearstr);
+ set = set | SF_SHEAR;
}
- if(pivotstr[0]) {
- if(isPoint(pivotstr))
- p.pivot = parsePoint(pivotstr);
- else
- p.pivot = getPoint(oldbbox, pivotstr);
+ if(pivotstr[0])
+ {
+ if(isPoint(pivotstr))
+ p.pivot = parsePoint(pivotstr);
+ else
+ p.pivot = getPoint(oldbbox, pivotstr);
+ set = set | SF_PIVOT;
}
- if(pinstr[0]) {
- if(isPoint(pinstr))
- p.pin = parsePoint(pinstr);
- else
- p.pin = getPoint(oldbbox, pinstr);
+
+ if(pinstr[0])
+ {
+ if(isPoint(pinstr))
+ p.pin = parsePoint(pinstr);
+ else
+ p.pin = getPoint(oldbbox, pinstr);
+ set = set | SF_PIN;
}
-
+
/* color transform */
- if(rstr[0] || luminancestr[0]) {
- MULADD r;
- if(rstr[0])
- r = parseMulAdd(rstr);
- else {
- r.add = p.cxform.r0;
- r.mul = p.cxform.r1;
+ if(rstr[0] || luminancestr[0])
+ {
+ MULADD r;
+ if(rstr[0])
+ r = parseMulAdd(rstr);
+ else
+ {
+ r.add = p.cxform.r0;
+ r.mul = p.cxform.r1;
+ }
+ r = mergeMulAdd(r, luminance);
+ p.cxform.r0 = r.mul;
+ p.cxform.r1 = r.add;
+ set = set | SF_CX_R;
}
- r = mergeMulAdd(r, luminance);
- p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
- }
- if(gstr[0] || luminancestr[0]) {
- MULADD g;
- if(gstr[0])
- g = parseMulAdd(gstr);
- else {
- g.add = p.cxform.g0;
- g.mul = p.cxform.g1;
+ if(gstr[0] || luminancestr[0])
+ {
+ MULADD g;
+ if(gstr[0])
+ g = parseMulAdd(gstr);
+ else
+ {
+ g.add = p.cxform.g0;
+ g.mul = p.cxform.g1;
+ }
+ g = mergeMulAdd(g, luminance);
+ p.cxform.g0 = g.mul;
+ p.cxform.g1 = g.add;
+ set = set | SF_CX_G;
+ }
+ if(bstr[0] || luminancestr[0])
+ {
+ MULADD b;
+ if(bstr[0])
+ b = parseMulAdd(bstr);
+ else
+ {
+ b.add = p.cxform.b0;
+ b.mul = p.cxform.b1;
+ }
+ b = mergeMulAdd(b, luminance);
+ p.cxform.b0 = b.mul;
+ p.cxform.b1 = b.add;
+ set = set | SF_CX_B;
+ }
+ if(astr[0])
+ {
+ MULADD a = parseMulAdd(astr);
+ p.cxform.a0 = a.mul;
+ p.cxform.a1 = a.add;
+ set = set | SF_CX_A;
+ }
+
+ 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;
+ set = set | SF_BLEND;
}
- g = mergeMulAdd(g, luminance);
- p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
- }
- if(bstr[0] || luminancestr[0]) {
- MULADD b;
- if(bstr[0])
- b = parseMulAdd(bstr);
- else {
- b.add = p.cxform.b0;
- b.mul = p.cxform.b1;
+
+ if(filterstr[0])
+ {
+ p.filters = parseFilters((char*)filterstr);
+ set = set | SF_FILTER;
+ }
+
+ if (type == PT_CHANGE && set & (SF_X | SF_Y))
+ warning("As of version 0.8.2 using the .change command to modify an \
+object's position on the stage is considered deprecated. Future \
+versions may consider x and y parameters for the .change command \
+to be illegal; please use the .move command.");
+
+ if (change_sets_all)
+ set = SF_ALL;
+ p.set = set;
+
+ switch (type)
+ {
+ case PT_PUT:
+ s_put(instance, character, p);
+ break;
+ case PT_CHANGE:
+ {
+ const char* interstr = lu(args, "interpolation");
+ interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
+ if (!inter)
+ syntaxerror("unkown interpolation %s", interstr);
+ s_change(instance, p, inter);
+ }
+ break;
+ case PT_SCHANGE:
+ {
+ const char* interstr = lu(args, "interpolation");
+ interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
+ if (!inter)
+ syntaxerror("unkown interpolation %s", interstr);
+ s_schange(instance, p, inter);
+ }
+ break;
+ case PT_JUMP:
+ s_jump(instance, p);
+ break;
+ case PT_STARTCLIP:
+ s_startclip(instance, character, p);
+ break;
+ case PT_BUTTON:
+ if(as && as[0])
+ s_buttonput(character, as, p);
+ else
+ s_buttonput(character, "shape", p);
+ break;
+// default:
}
- b = mergeMulAdd(b, luminance);
- p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
- }
- if(astr[0]) {
- MULADD a = parseMulAdd(astr);
- p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
- }
-
- if(type == 0)
- s_put(instance, character, p);
- if(type == 1)
- s_change(instance, p);
- if(type == 2)
- s_qchange(instance, p);
- if(type == 3)
- s_jump(instance, p);
- if(type == 4)
- s_startclip(instance, character, p);
return 0;
}
-static int c_put(map_t*args)
+static int c_put(map_t*args)
{
- c_placement(args, 0);
+ c_placement(args, PT_PUT);
return 0;
}
-static int c_change(map_t*args)
+static int c_change(map_t*args)
{
- c_placement(args, 1);
+ if (currentframe == 0)
+ warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
+ c_placement(args, PT_CHANGE);
return 0;
}
-static int c_qchange(map_t*args)
+static int c_schange(map_t*args)
{
- c_placement(args, 2);
+ c_placement(args, PT_SCHANGE);
return 0;
}
-static int c_arcchange(map_t*args)
+static int c_move(map_t* args)
{
- c_placement(args, 2);
+ c_movement(args, PT_MOVE);
return 0;
}
-static int c_jump(map_t*args)
+static int c_smove(map_t* args)
{
- c_placement(args, 3);
+ c_movement(args, PT_SMOVE);
return 0;
}
-static int c_startclip(map_t*args)
+static int c_sweep(map_t* args)
{
- c_placement(args, 4);
+ c_movement(args, PT_SWEEP);
return 0;
}
-static int c_del(map_t*args)
+static int c_arcchange(map_t*args)
{
- char*instance = lu(args, "name");
+ c_placement(args, 0);
+ return 0;
+}
+static int c_jump(map_t*args)
+{
+ c_placement(args, PT_JUMP);
+ return 0;
+}
+static int c_startclip(map_t*args)
+{
+ c_placement(args, PT_STARTCLIP);
+ return 0;
+}
+static int c_show(map_t*args)
+{
+ c_placement(args, PT_BUTTON);
+ return 0;
+}
+static int c_toggle(map_t* args)
+{
+ const char*instance = lu(args, "name");
+ U16 flagsOn = 0x0000, flagsOff = 0xffff;
+ const char* alignstr = lu(args, "fixed_alignment");
+ if (!strcmp(alignstr, "on"))
+ flagsOn += IF_FIXED_ALIGNMENT;
+ else
+ if (!strcmp(alignstr, "off"))
+ flagsOff -= IF_FIXED_ALIGNMENT;
+ else
+ syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
+ s_toggle(instance, flagsOn, flagsOff);
+ return 0;
+}
+static int c_del(map_t*args)
+{
+ const char*instance = lu(args, "name");
s_delinstance(instance);
return 0;
}
-static int c_end(map_t*args)
+static int c_end(map_t*args)
{
s_end();
return 0;
}
-static int c_sprite(map_t*args)
+static int c_sprite(map_t*args)
{
- char* name = lu(args, "name");
- s_sprite(name);
+ const char* name = lu(args, "name");
+ const char* scalinggrid = lu(args, "scalinggrid");
+
+ if(scalinggrid && *scalinggrid) {
+ SRECT r = parseBox(scalinggrid);
+ s_sprite(name, &r);
+ } else {
+ s_sprite(name, 0);
+ }
return 0;
}
-static int c_frame(map_t*args)
+static int c_frame(map_t*args)
{
- char*framestr = lu(args, "n");
- char*cutstr = lu(args, "cut");
+ const char*framestr = lu(args, "n");
+ const char*cutstr = lu(args, "cut");
+
+ const char*name = lu(args, "name");
+ const 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);
+ s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
return 0;
}
-static int c_primitive(map_t*args)
+static int c_primitive(map_t*args)
{
- char*name = lu(args, "name");
- char*command = lu(args, "commandname");
+ const char*name = lu(args, "name");
+ const char*command = lu(args, "commandname");
int width=0, height=0, r=0;
int linewidth = parseTwip(lu(args, "line"));
- char*colorstr = lu(args, "color");
+ const char*colorstr = lu(args, "color");
RGBA color = parseColor(colorstr);
- char*fillstr = lu(args, "fill");
+ const char*fillstr = lu(args, "fill");
int dofill = 1;
int type=0;
- char* font;
- char* text;
- char* outline=0;
+ const char* font;
+ const char* text;
+ const char* outline=0;
RGBA fill;
if(!strcmp(command, "circle"))
type = 1;
else if(!strcmp(command, "filled"))
type = 2;
-
+
if(type==0) {
width = parseTwip(lu(args, "width"));
height = parseTwip(lu(args, "height"));
fillstr = 0;
if(width<0 || height<0 || linewidth<0 || r<0)
syntaxerror("values width, height, line, r must be positive");
-
+
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_textshape(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");
+ const char*name = lu(args, "name");
+ const char*text = lu(args, "text");
+ const char*font = lu(args, "font");
+ float size = parsePxOrPercent(font, lu(args, "size"));
- s_textshape(name, font, text);
+ s_textshape(name, font, size, text);
return 0;
}
-
-
-static int c_swf(map_t*args)
+static int c_swf(map_t*args)
{
- char*name = lu(args, "name");
- char*filename = lu(args, "filename");
- char*command = lu(args, "commandname");
+ const char*name = lu(args, "name");
+ const char*filename = lu(args, "filename");
+ const char*command = lu(args, "commandname");
if(!strcmp(command, "shape"))
warning("Please use .swf instead of .shape");
s_includeswf(name, filename);
return 0;
}
-static int c_font(map_t*args)
+static int c_font(map_t*args)
{
- char*name = lu(args, "name");
- char*filename = lu(args, "filename");
+ const char*name = lu(args, "name");
+ const char*filename = lu(args, "filename");
s_font(name, filename);
return 0;
}
-static int c_sound(map_t*args)
+static int c_sound(map_t*args)
{
- char*name = lu(args, "name");
- char*filename = lu(args, "filename");
+ const char*name = lu(args, "name");
+ const char*filename = lu(args, "filename");
s_sound(name, filename);
return 0;
}
-static int c_text(map_t*args)
+static int c_text(map_t*args)
{
- char*name = lu(args, "name");
- char*text = lu(args, "text");
- char*font = lu(args, "font");
- float size = parsePercent(lu(args, "size"));
+ const char*name = lu(args, "name");
+ const char*text = lu(args, "text");
+ const char*font = lu(args, "font");
+ float size = parsePxOrPercent(font, lu(args, "size"));
RGBA color = parseColor(lu(args, "color"));
s_text(name, font, text, (int)(size*100), color);
return 0;
}
-static int c_soundtrack(map_t*args)
+static int c_soundtrack(map_t*args)
{
return 0;
}
-static int c_image(map_t*args)
+static int c_quicktime(map_t*args)
{
- char*command = lu(args, "commandname");
- char*name = lu(args, "name");
- char*filename = lu(args, "filename");
+ const char*name = lu(args, "name");
+ const char*url = lu(args, "url");
+ s_quicktime(name, url);
+ return 0;
+}
+
+static int c_video(map_t*args)
+{
+ const char*name = lu(args, "name");
+ int width = parseInt(lu(args, "width"));
+ int height = parseInt(lu(args, "height"));
+ s_video(name, width, height);
+ return 0;
+}
+
+static int c_image(map_t*args)
+{
+ const char*command = lu(args, "commandname");
+ const char*name = lu(args, "name");
+ const char*filename = lu(args, "filename");
if(!strcmp(command,"jpeg")) {
int quality = (int)(parsePercent(lu(args, "quality"))*100);
s_image(name, "jpeg", filename, quality);
return 0;
}
-static int c_outline(map_t*args)
+static int c_outline(map_t*args)
{
- char*name = lu(args, "name");
- char*format = lu(args, "format");
+ const char*name = lu(args, "name");
+ const char*format = lu(args, "format");
readToken();
if(type != RAWDATA)
int fakechar(map_t*args)
{
- char*name = lu(args, "name");
+ const char*name = lu(args, "name");
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) {
- char*action = "";
+ const char*name = lu(args, "name");
+ s_button(name);
+ return 0;
+}
+static int current_button_flags = 0;
+static int c_on_press(map_t*args)
+{
+ const char*position = lu(args, "position");
+ const 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)
+{
+ const char*position = lu(args, "position");
+ const 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)
+{
+ const char*position = lu(args, "state");
+ const 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)
+{
+ const char*position = lu(args, "state");
+ const 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)
+{
+ const char*key = lu(args, "key");
+ const 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)
+ if(type == RAWDATA) {
action = text;
+ s_buttonaction(current_button_flags, action);
+ current_button_flags = 0;
+ }
else
pushBack();
+ return 0;
+}
- return fakechar(args);
+static int c_edittext(map_t*args)
+{
+ //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @autosize=0"},
+ const char*name = lu(args, "name");
+ const 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"));
+ const char*text = lu(args, "text");
+ RGBA color = parseColor(lu(args, "color"));
+ int maxlength = parseInt(lu(args, "maxlength"));
+ const char*variable = lu(args, "variable");
+ const char*passwordstr = lu(args, "password");
+ const char*wordwrapstr = lu(args, "wordwrap");
+ const char*multilinestr = lu(args, "multiline");
+ const char*htmlstr = lu(args, "html");
+ const char*noselectstr = lu(args, "noselect");
+ const char*readonlystr = lu(args, "readonly");
+ const char*borderstr = lu(args, "border");
+ const char*autosizestr = lu(args, "autosize");
+ const 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_edittext(map_t*args) {return fakechar(args);}
static int c_morphshape(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 char* readfile(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)
+static int c_action(map_t*args)
{
- readToken();
- if(type != RAWDATA)
- syntaxerror("colon (:) expected");
+ const char* filename = map_lookup(args, "filename");
+ if(!filename ||!*filename) {
+ readToken();
+ if(type != RAWDATA) {
+ syntaxerror("colon (:) expected");
+ }
+ s_action(text);
+ } else {
+ s_action(readfile((char*)filename));
+ }
+
+ return 0;
+}
+
+static int c_initaction(map_t*args)
+{
+ const char* character = lu(args, "name");
+ const 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((char*)filename));
+ }
- s_action(text);
-
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 @cut=no"},
+{{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
+ {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
// "import" type stuff
{"swf", c_swf, "name filename"},
{"shape", c_swf, "name filename"},
{"png", c_image, "name filename"},
{"movie", c_movie, "name filename"},
{"sound", c_sound, "name filename"},
- {"font", c_font, "name filename"},
+ {"font", c_font, "name filename glyphs="},
{"soundtrack", c_soundtrack, "filename"},
+ {"quicktime", c_quicktime, "url"},
+ {"video", c_video, "name width= height="},
// generators of primitives
+ {"define", c_define, "name value=0"},
{"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
+ {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
{"outline", c_outline, "name format=simple"},
- {"textshape", c_textshape, "name text font"},
+ {"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"},
{"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"},
-
- {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
+ {"button", c_button, "name"},
+ {"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"},
+ {"on_move_out", c_on_move_out, "state=not_pressed"},
+ {"on_key", c_on_key, "key=any"},
// 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= 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="},
+ {"move", c_move, "name x= y= interpolation=linear"},
+ {"smove", c_smove, "name x= y= interpolation=linear"},
+ {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
+ {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
+ //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
+ {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
+ {"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
- {"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"},
+ {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
+ // switching
+ {"toggle", c_toggle, "name fixed_alignment="},
// commands which start a block
//startclip (see above)
- {"sprite", c_sprite, "name"},
- {"action", c_action, ""},
+ {"sprite", c_sprite, "name scalinggrid="},
+ {"action", c_action, "filename="},
+ {"initaction", c_initaction, "name filename="},
{"end", c_end, ""}
};
{
char*x;
char*d,*e;
-
+
string_t name[64];
string_t value[64];
int set[64];
d=&x[strlen(x)];
set[pos] = 0;
- if(!e || d<e) {
+ if(!e || d<e) {
// no default
name[pos].str = x;
name[pos].len = d-x;
}
}
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
/* ok, now construct the dictionary from the parameters */
- for(t=0;t<len;t++)
+ for(t=0;t<len;t++)
{
map_put(&result, name[t], value[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");
+ warning("Please use .flash instead of .swf- this will be mandatory soon");
command = "flash";
t = 0;
}
if(nr<0)
syntaxerror("command %s not known", command);
+#ifndef EMPTY
+ // catch missing .flash directives at the beginning of a file
+ if(strcmp(command, "flash") && !stackpos)
+ {
+ syntaxerror("No movie defined- use .flash first");
+ }
+#endif
+
#ifdef DEBUG
printf(".%s\n", command);fflush(stdout);
map_dump(&args, stdout, "\t");fflush(stdout);
#endif
+#ifndef EMPTY
(*arguments[nr].func)(&args);
-
- /*if(!strcmp(command, "button") ||
- !strcmp(command, "action")) {
- while(1) {
- readToken();
- if(type == COMMAND) {
- if(!strcmp(text, "end"))
- break;
- else {
- pushBack();
- break;
- }
- }
+#else
+ if(!strcmp(command, "action") || !strcmp(command, "initaction") ||
+ !strcmp(command, "outline") || !strcmp(command, "gradient")) {
+ readToken();
+ if(type != RAWDATA) {
+ syntaxerror("colon (:) expected");
}
- }*/
+ }
+#endif
+ map_clear(&args);
+ return;
+}
+
+
+/* for now only intended to find what glyphs of each font are to be included in the swf file.
+ * Therefore some knowledge about the command is assumed i.e. it is font/text-related
+ * No syntax checking is done */
+static void analyseArgumentsForCommand(char*command)
+{
+ int t;
+ map_t args;
+ const char* fontfile;
+ int nr = -1;
+ U8* glyphs_to_include;
+ msg("<verbose> analyse Command: %s (line %d)", command, line);
+ for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
+ {
+ if(!strcmp(arguments[t].command, command))
+ {
+ args = parseArguments(command, arguments[t].arguments);
+ nr = t;
+ break;
+ }
+ }
+#ifdef DEBUG
+ printf(".%s\n", command);fflush(stdout);
+ map_dump(&args, stdout, "\t");fflush(stdout);
+#endif
+ const char* name = lu(&args, "name");
+ if (!strcmp(command, "font"))
+ {
+ if(dict_lookup(&fonts, name))
+ syntaxerror("font %s defined twice", name);
+
+ SWFFONT* font;
+ fontfile = lu(&args, "filename");
+ font = swf_LoadFont(fontfile);
+ if(font == 0) {
+ warning("Couldn't open font file \"%s\"", fontfile);
+ font = (SWFFONT*)malloc(sizeof(SWFFONT));
+ memset(font, 0, sizeof(SWFFONT));
+ }
+ else
+ {
+ swf_FontPrepareForEditText(font);
+ glyphs_to_include = (U8*)lu(&args, "glyphs");
+ if (!strcmp(glyphs_to_include, "all"))
+ {
+ swf_FontUseAll(font);
+ font->use->glyphs_specified = 1;
+ }
+ else
+ {
+ if (strcmp (glyphs_to_include, ""))
+ {
+ swf_FontUseUTF8(font, glyphs_to_include);
+ font->use->glyphs_specified = 1;
+ }
+ else
+ swf_FontInitUsage(font);
+ }
+ }
+ dict_put(&fonts, name, font);
+ }
+ else
+ {
+ SWFFONT* font = dict_lookup(&fonts, lu(&args, "font"));
+ if (!font) {
+ //that's ok... it might be an edittext with a system font
+ //syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
+ } else
+ if (font->use && !font->use->glyphs_specified)
+ {
+ if (!strcmp(command, "edittext"))
+ {
+ swf_FontUseAll(font);
+ font->use->glyphs_specified = 1;
+ }
+ else
+ swf_FontUseUTF8(font, (U8*)lu(&args, "text"));
+ }
+ }
map_clear(&args);
return;
}
+void skipParameters()
+{
+ do
+ readToken();
+ while (type != COMMAND);
+ pushBack();
+}
+
+void findFontUsage()
+{
+ char* fontRelated = "font;text;textshape;edittext;";
+ while(!noMoreTokens())
+ {
+ readToken();
+ if(type != COMMAND)
+ syntaxerror("command expected");
+ if (strstr(fontRelated, text))
+ analyseArgumentsForCommand(text);
+ else
+ if(strcmp(text, "end"))
+ skipParameters();
+ }
+}
+
+void firstPass()
+{
+ pos = 0;
+ id = 0;
+ dict_init(&fonts, 16);
+ cleanUp = &freeFontDictionary;
+ findFontUsage();
+}
+
int main (int argc,char ** argv)
-{
+{
int t;
processargs(argc, argv);
initLog(0,-1,0,0,-1,verbose);
args_callback_usage(argv[0]);
exit(1);
}
+
file = generateTokens(filename);
if(!file) {
- printf("parser returned error.\n");
+ fprintf(stderr, "parser returned error.\n");
return 1;
}
+ firstPass();
pos=0;
-
t=0;
while(!noMoreTokens()) {