+ if (samples)
+ free(samples);
+}
+
+static char* gradient_getToken(const char**p)
+{
+ const char*start;
+ char*result;
+ while(**p && strchr(" \t\n\r", **p)) {
+ (*p)++;
+ }
+ start = *p;
+ while(**p && !strchr(" \t\n\r", **p)) {
+ (*p)++;
+ }
+ result = malloc((*p)-start+1);
+ memcpy(result,start,(*p)-start+1);
+ result[(*p)-start] = 0;
+ return result;
+}
+
+float parsePercent(char*str);
+RGBA parseColor(char*str);
+
+GRADIENT parseGradient(const char*str)
+{
+ GRADIENT gradient;
+ int lastpos = -1;
+ const char* p = str;
+ memset(&gradient, 0, sizeof(GRADIENT));
+ gradient.ratios = rfx_calloc(16*sizeof(U8));
+ gradient.rgba = rfx_calloc(16*sizeof(RGBA));
+
+ while(*p)
+ {
+ char*posstr,*colorstr;
+ 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;
+ }
+ return gradient;
+}
+
+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 = dictionary_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(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;
+
+ dictionary_put2(&gradients, name, gradient);
+}
+
+void s_gradientglow(char*name, char*gradient, float blurx, float blury,
+ float angle, float distance, float strength, char innershadow,
+ char knockout, char composite, char ontop, int passes)
+{
+ if(dictionary_lookup(&filters, name))
+ syntaxerror("filter %s defined twice", name);
+
+ gradient_t* g = dictionary_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;
+
+ dictionary_put2(&filters, name, filter);
+}
+
+void s_dropshadow(char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
+{
+ if(dictionary_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;
+
+ dictionary_put2(&filters, name, filter);
+}
+
+void s_bevel(char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes)
+{
+ if(dictionary_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;
+
+ dictionary_put2(&filters, name, filter);
+}
+
+void s_blur(char*name, double blurx, double blury, int passes)
+{
+ if(dictionary_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;
+
+ dictionary_put2(&filters, name, filter);
+}
+
+void s_action(const char*text)
+{
+ 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);
+}
+
+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");
+ }
+
+ c = (character_t*)dictionary_lookup(&characters, character);
+
+ tag = swf_InsertTag(tag, ST_DOINITACTION);
+ swf_SetU16(tag, c->id);
+ swf_ActionSet(tag, a);
+
+ swf_ActionFree(a);
+}
+
+int s_swf3action(char*name, char*action)
+{
+ ActionTAG* a = 0;
+ instance_t* object = 0;
+ if(name)
+ object = (instance_t*)dictionary_lookup(&instances, name);
+ if(!object && name && *name) {
+ /* we have a name, but couldn't find it. Abort. */
+ return 0;
+ }
+ a = action_SetTarget(0, name);
+ if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
+ else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
+ else if(!strcmp(action, "stop")) a = action_Stop(a);
+ else if(!strcmp(action, "play")) a = action_Play(a);
+ a = action_SetTarget(a, "");
+ a = action_End(a);
+
+ tag = swf_InsertTag(tag, ST_DOACTION);
+ swf_ActionSet(tag, a);
+ swf_ActionFree(a);
+ return 1;
+}
+
+void s_outline(char*name, char*format, char*source)
+{
+ if(dictionary_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);
+ bounds = swf_ShapeDrawerGetBBox(&draw);
+ draw.dealloc(&draw);
+
+ outline = (outline_t*)rfx_calloc(sizeof(outline_t));
+ outline->shape = shape;
+ outline->bbox = bounds;
+
+ dictionary_put2(&outlines, name, outline);