From 3ef17c4cee41231e1eed731c08381d3ddf0c8d1a Mon Sep 17 00:00:00 2001 From: kramm Date: Fri, 27 Jul 2007 19:57:02 +0000 Subject: [PATCH] applied patches from Huub Schaeks --- lib/drawer.c | 64 ++- lib/modules/swfbits.c | 1 + lib/modules/swfshape.c | 9 + lib/modules/swftext.c | 60 +- lib/mp3.c | 2 + lib/q.c | 20 + lib/q.h | 2 + lib/wav.c | 119 ++-- src/swfc-feedback.c | 48 ++ src/swfc-feedback.h | 33 ++ src/swfc-history.c | 401 ++++++++++++++ src/swfc-history.h | 103 ++++ src/swfc-interpolation.c | 301 +++++++++++ src/swfc-interpolation.h | 116 ++++ src/swfc.c | 1354 ++++++++++++++++++++++++++++------------------ 15 files changed, 1991 insertions(+), 642 deletions(-) create mode 100644 src/swfc-feedback.c create mode 100644 src/swfc-feedback.h create mode 100644 src/swfc-history.c create mode 100644 src/swfc-history.h create mode 100644 src/swfc-interpolation.c create mode 100644 src/swfc-interpolation.h diff --git a/lib/drawer.c b/lib/drawer.c index 801ff38..f5196ca 100644 --- a/lib/drawer.c +++ b/lib/drawer.c @@ -94,52 +94,64 @@ static void draw_lineTo2(drawer_t*draw, double x, double y) draw->lineTo(draw, &c); } +static float getFloat(const char** p) +{ + char* token = getToken(p); + float result = atof(token); + free(token); + return result; +} void draw_string(drawer_t*draw, const char*string) { const char*p = string; while(*p) { char*token = getToken(&p); - if(!token || !*token) + if(!token) + break; + if (!*token) + { + free(token); break; + } if(!strncmp(token, "moveTo", 6) || !strncmp(token, "M", 1) //svg ) { FPOINT to; - to.x = atof(getToken(&p)); - to.y = atof(getToken(&p)); + to.x = getFloat(&p); + to.y = getFloat(&p); draw->moveTo(draw, &to); } else if(!strncmp(token, "lineTo", 6) || !strncmp(token, "L", 1) //svg ) { FPOINT to; - to.x = atof(getToken(&p)); - to.y = atof(getToken(&p)); + to.x = getFloat(&p); + to.y = getFloat(&p); draw->lineTo(draw, &to); } else if(!strncmp(token, "curveTo", 7) || !strncmp(token, "splineTo", 8)) { FPOINT mid,to; - mid.x = atof(getToken(&p)); - mid.y = atof(getToken(&p)); - to.x = atof(getToken(&p)); - to.y = atof(getToken(&p)); + mid.x = getFloat(&p); + mid.y = getFloat(&p); + to.x = getFloat(&p); + to.y = getFloat(&p); draw->splineTo(draw, &mid, &to); } else if(!strncmp(token, "conicTo", 5)) { FPOINT mid,to; - mid.x = atof(getToken(&p)); - mid.y = atof(getToken(&p)); - to.x = atof(getToken(&p)); - to.y = atof(getToken(&p)); + mid.x = getFloat(&p); + mid.y = getFloat(&p); + to.x = getFloat(&p); + to.y = getFloat(&p); draw_conicTo(draw, &mid, &to); } else if(!strncmp(token, "circle", 6)) { int mx,my,r; double r2; - mx = atof(getToken(&p)); - my = atof(getToken(&p)); - r = atof(getToken(&p)); + mx = getFloat(&p); + my = getFloat(&p); + r = getFloat(&p); r2 = 0.70710678118654757*r; draw_moveTo2(draw, mx, my-r); draw_conicTo2(draw, mx+r2, my-r2, mx+r, my); @@ -149,10 +161,10 @@ void draw_string(drawer_t*draw, const char*string) } else if(!strncmp(token, "box", 3)) { int x1,y1,x2,y2; - x1 = atof(getToken(&p)); - y1 = atof(getToken(&p)); - x2 = atof(getToken(&p)); - y2 = atof(getToken(&p)); + x1 = getFloat(&p); + y1 = getFloat(&p); + x2 = getFloat(&p); + y2 = getFloat(&p); draw_moveTo2(draw, x1, y1); draw_lineTo2(draw, x1, y2); draw_lineTo2(draw, x2, y2); @@ -163,12 +175,12 @@ void draw_string(drawer_t*draw, const char*string) !strncmp(token, "C", 1) //svg ) { FPOINT mid1,mid2,to; - mid1.x = atof(getToken(&p)); - mid1.y = atof(getToken(&p)); - mid2.x = atof(getToken(&p)); - mid2.y = atof(getToken(&p)); - to.x = atof(getToken(&p)); - to.y = atof(getToken(&p)); + mid1.x = getFloat(&p); + mid1.y = getFloat(&p); + mid2.x = getFloat(&p); + mid2.y = getFloat(&p); + to.x = getFloat(&p); + to.y = getFloat(&p); draw_cubicTo(draw, &mid1, &mid2, &to); } else if(!strncmp(token, "z", 1) //svg diff --git a/lib/modules/swfbits.c b/lib/modules/swfbits.c index 80b151b..204dcc4 100644 --- a/lib/modules/swfbits.c +++ b/lib/modules/swfbits.c @@ -393,6 +393,7 @@ int swf_SetJPEGBits(TAG * t, char *fname, int quality) } } + free(scanline); swf_SetJPEGBitsFinish(out); jpeg_finish_decompress(&cinfo); fclose(f); diff --git a/lib/modules/swfshape.c b/lib/modules/swfshape.c index 2be4ee3..7bb6424 100644 --- a/lib/modules/swfshape.c +++ b/lib/modules/swfshape.c @@ -926,6 +926,7 @@ void swf_Shape2ToShape(SHAPE2*shape2, SHAPE*shape) swf_ShapeSetEnd(tag); shape->data = tag->data; shape->bitlen = tag->len*8; + free(tag); } void swf_SetShape2(TAG*tag, SHAPE2*shape2) @@ -986,6 +987,13 @@ void swf_ParseDefineShape(TAG*tag, SHAPE2*shape) l = shape->lines; } +static void free_lines(SHAPELINE* lines) +{ + if (lines->next) + free_lines(lines->next); + free(lines); +} + void swf_RecodeShapeData(U8*data, int bitlen, int in_bits_fill, int in_bits_line, U8**destdata, U32*destbitlen, int out_bits_fill, int out_bits_line) { @@ -1009,6 +1017,7 @@ void swf_RecodeShapeData(U8*data, int bitlen, int in_bits_fill, int in_bits_line swf_Shape2ToShape(&s2,&s); + free_lines(s2.lines); free(s2.fillstyles); free(s2.linestyles); free(s.fillstyle.data); diff --git a/lib/modules/swftext.c b/lib/modules/swftext.c index 1612e63..363b55d 100644 --- a/lib/modules/swftext.c +++ b/lib/modules/swftext.c @@ -22,7 +22,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -static U32 readUTF8char(U8 ** text) +U32 readUTF8char(U8 ** text) { U32 c = 0; if (!(*(*text) & 0x80)) @@ -572,18 +572,20 @@ void swf_LayoutFree(SWFLAYOUT * l) static void font_freeglyphnames(SWFFONT*f) { - if (f->glyphnames) { - int t; - for (t = 0; t < f->numchars; t++) { - if (f->glyphnames[t]) { - rfx_free(f->glyphnames[t]); - f->glyphnames[t] = 0; - } + if (f->glyphnames) + { + int t; + for (t = 0; t < f->numchars; t++) + { + if (f->glyphnames[t]) + { + rfx_free(f->glyphnames[t]); + f->glyphnames[t] = 0; + } + } + rfx_free(f->glyphnames); + f->glyphnames = 0; } - rfx_free(f->glyphnames); - f->glyphnames = 0; - } - } static void font_freeusage(SWFFONT*f) { @@ -1036,24 +1038,28 @@ void swf_FontFree(SWFFONT * f) { int i; if (!f) - return; + return; - if (f->glyph) { - for (i = 0; i < f->numchars; i++) - if (f->glyph[i].shape) { - swf_ShapeFree(f->glyph[i].shape); - f->glyph[i].shape = NULL; - } - rfx_free(f->glyph); - f->glyph = NULL; + if (f->glyph) + { + for (i = 0; i < f->numchars; i++) + if (f->glyph[i].shape) + { + swf_ShapeFree(f->glyph[i].shape); + f->glyph[i].shape = NULL; + } + rfx_free(f->glyph); + f->glyph = NULL; } - if (f->ascii2glyph) { - rfx_free(f->ascii2glyph); - f->ascii2glyph = NULL; + if (f->ascii2glyph) + { + rfx_free(f->ascii2glyph); + f->ascii2glyph = NULL; } - if (f->glyph2ascii) { - rfx_free(f->glyph2ascii); - f->glyph2ascii = NULL; + if (f->glyph2ascii) + { + rfx_free(f->glyph2ascii); + f->glyph2ascii = NULL; } font_freename(f); font_freelayout(f); diff --git a/lib/mp3.c b/lib/mp3.c index 8bb7ee7..408ef37 100644 --- a/lib/mp3.c +++ b/lib/mp3.c @@ -157,6 +157,7 @@ int mp3_read(struct MP3*mp3, char* filename) if(!root) { fprintf(stderr, "readMP3: not a MP3 file\n"); + fclose(fi); return 0; } @@ -192,6 +193,7 @@ int mp3_read(struct MP3*mp3, char* filename) root = next; } + fclose(fi); return mp3->data != NULL; } diff --git a/lib/q.c b/lib/q.c index 7d257f7..0083dcd 100644 --- a/lib/q.c +++ b/lib/q.c @@ -384,6 +384,12 @@ void dictionary_put2(dictionary_t*dict, const char*t1, void* t2) string_set(&s, (char*)t1); dictionary_put(dict, s, t2); } +stringarray_t* dictionary_index(dictionary_t*dict) +{ + dictionary_internal_t*d = (dictionary_internal_t*)dict->internal; + return &d->keys; +} + void* dictionary_lookup(dictionary_t*dict, const char*name) { int s; @@ -430,6 +436,20 @@ void dictionary_destroy(dictionary_t*dict) free(dict); } +void dictionary_free_all(dictionary_t* dict, void (*freeFunction)(void*)) +{ + dictionary_internal_t*d = (dictionary_internal_t*)dict->internal; + int num = 0; + char* name = stringarray_at(&d->keys, num) ; + while (name) + { + freeFunction(dictionary_lookup(dict, name)); + num++; + name = stringarray_at(&d->keys, num); + } + dictionary_clear(dict); +} + // ------------------------------- heap_t ------------------------------- void heap_init(heap_t*h,int n,int elem_size, int(*compare)(const void *, const void *)) diff --git a/lib/q.h b/lib/q.h index 0e9d602..35629d8 100644 --- a/lib/q.h +++ b/lib/q.h @@ -111,11 +111,13 @@ void map_destroy(map_t*map); void dictionary_init(dictionary_t*dict); void dictionary_put(dictionary_t*dict, string_t t1, void* t2); void dictionary_put2(dictionary_t*dict, const char* t1, void* t2); +stringarray_t* dictionary_index(dictionary_t*dict); void* dictionary_lookup(dictionary_t*dict, const char*name); void dictionary_dump(dictionary_t*dict, FILE*fi, const char*prefix); void dictionary_del(dictionary_t*dict, const char* name); void dictionary_clear(dictionary_t*dict); void dictionary_destroy(dictionary_t*dict); +void dictionary_free_all(dictionary_t* dict, void (*freeFunction)(void*)); void heap_init(heap_t*h,int n,int elem_size, int(*compare)(const void *, const void *)); void heap_clear(heap_t*h); diff --git a/lib/wav.c b/lib/wav.c index 17ca2a2..72d9502 100644 --- a/lib/wav.c +++ b/lib/wav.c @@ -53,8 +53,9 @@ int wav_read(struct WAV*wav, char* filename) long int filesize; struct WAVBlock block; long int pos; + if(!fi) - return 0; + return 0; fseek(fi, 0, SEEK_END); filesize = ftell(fi); fseek(fi, 0, SEEK_SET); @@ -62,65 +63,87 @@ int wav_read(struct WAV*wav, char* filename) //printf("Filesize: %d\n", filesize); if(!getWAVBlock (fi, &block)) - return 0; - if(strncmp(block.id,"RIFF",4)) { - fprintf(stderr, "wav_read: not a WAV file\n"); - return 0; + { + fclose(fi); + return 0; + } + if(strncmp(block.id,"RIFF",4)) + { + fprintf(stderr, "wav_read: not a WAV file\n"); + fclose(fi); + return 0; } if(block.size + 8 < filesize) - fprintf(stderr, "wav_read: warning - more tags (%d extra bytes)\n", - filesize - block.size - 8); + fprintf(stderr, "wav_read: warning - more tags (%d extra bytes)\n", + filesize - block.size - 8); - if(block.size == filesize) { + if(block.size == filesize) /* some buggy software doesn't generate the right tag length */ - block.size = filesize - 8; - } + block.size = filesize - 8; if(block.size + 8 > filesize) - fprintf(stderr, "wav_read: warning - short file (%d bytes missing)\n", - block.size + 8 - filesize); - if(fread(b, 1, 4, fi) < 4) { - return 0; - } - if(strncmp(b, "WAVE", 4)) { - fprintf(stderr, "wav_read: not a WAV file (2)\n"); - return 0; - } - - do + fprintf(stderr, "wav_read: warning - short file (%d bytes missing)\n", + block.size + 8 - filesize); + if(fread(b, 1, 4, fi) < 4) { - getWAVBlock(fi, &block); - pos = ftell(fi); - if(!strncmp(block.id, "fmt ", 4)) { - if(fread(&b, 1, 16, fi)<16) - return 0; - wav->tag = b[0]|b[1]<<8; - wav->channels = b[2]|b[3]<<8; - wav->sampsPerSec = b[4]|b[5]<<8|b[6]<<16|b[7]<<24; - wav->bytesPerSec = b[8]|b[9]<<8|b[10]<<16|b[11]<<24; - wav->align = b[12]|b[13]<<8; - wav->bps = b[14]|b[15]<<8; - } else if (!strncmp(block.id, "LIST", 4)) { - // subchunk ICMT (comment) may exist - } else if (!strncmp(block.id, "data", 4)) { - int l; - wav->data = malloc(block.size); - if(!wav->data) { - fprintf(stderr, "Out of memory (%d bytes needed)", block.size); + fclose(fi); return 0; - } - l = fread(wav->data, 1, block.size, fi); - if(l < block.size) { - fprintf(stderr, "Error while reading data block of size %d (%d bytes missing)", block.size, block.size-l); + } + if(strncmp(b, "WAVE", 4)) + { + fprintf(stderr, "wav_read: not a WAV file (2)\n"); + fclose(fi); return 0; - } - wav->size = block.size; } - pos+=block.size; - fseek(fi, pos, SEEK_SET); + + do + { + getWAVBlock(fi, &block); + pos = ftell(fi); + if(!strncmp(block.id, "fmt ", 4)) + { + if(fread(&b, 1, 16, fi)<16) + { + fclose(fi); + return 0; + } + wav->tag = b[0]|b[1]<<8; + wav->channels = b[2]|b[3]<<8; + wav->sampsPerSec = b[4]|b[5]<<8|b[6]<<16|b[7]<<24; + wav->bytesPerSec = b[8]|b[9]<<8|b[10]<<16|b[11]<<24; + wav->align = b[12]|b[13]<<8; + wav->bps = b[14]|b[15]<<8; + } + else + if (!strncmp(block.id, "LIST", 4)) + { + // subchunk ICMT (comment) may exist + } + else + if (!strncmp(block.id, "data", 4)) + { + int l; + wav->data = malloc(block.size); + if(!wav->data) + { + fprintf(stderr, "Out of memory (%d bytes needed)", block.size); + fclose(fi); + return 0; + } + l = fread(wav->data, 1, block.size, fi); + if(l < block.size) + { + fprintf(stderr, "Error while reading data block of size %d (%d bytes missing)", block.size, block.size-l); + fclose(fi); + return 0; + } + wav->size = block.size; + } + pos+=block.size; + fseek(fi, pos, SEEK_SET); } while (pos < filesize); - + fclose(fi); return 1; } diff --git a/src/swfc-feedback.c b/src/swfc-feedback.c new file mode 100644 index 0000000..51e0d91 --- /dev/null +++ b/src/swfc-feedback.c @@ -0,0 +1,48 @@ +/* swfc- Compiles swf code (.sc) files into .swf files. + + Part of the swftools package. + + Copyright (c) 2007 Huub Schaeks + Copyright (c) 2007 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include "feedback.h" + +void syntaxerror(char*format, ...) +{ + char buf[1024]; + va_list arglist; + va_start(arglist, format); + vsprintf(buf, format, arglist); + va_end(arglist); + fprintf(stderr, "\"%s\", line %d column %d: error- %s\n", filename, line, column, buf); + if (cleanUp) + cleanUp(); + exit(1); +} + +void warning(char*format, ...) +{ + char buf[1024]; + va_list arglist; + va_start(arglist, format); + vsprintf(buf, format, arglist); + va_end(arglist); + fprintf(stderr, "\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf); +} diff --git a/src/swfc-feedback.h b/src/swfc-feedback.h new file mode 100644 index 0000000..6196ea1 --- /dev/null +++ b/src/swfc-feedback.h @@ -0,0 +1,33 @@ +/* swfc- Compiles swf code (.sc) files into .swf files. + + Part of the swftools package. + + Copyright (c) 2007 Huub Schaeks + Copyright (c) 2007 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef __FEEDBACK_H +#define __FEEDBACK_H + +char* filename; +int line; +int column; +void (*cleanUp)(); + +void syntaxerror(char*format, ...); +void warning(char*format, ...); + +#endif diff --git a/src/swfc-history.c b/src/swfc-history.c new file mode 100644 index 0000000..b7ce399 --- /dev/null +++ b/src/swfc-history.c @@ -0,0 +1,401 @@ +/* swfc- Compiles swf code (.sc) files into .swf files. + + Part of the swftools package. + + Copyright (c) 2007 Huub Schaeks + Copyright (c) 2007 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include "history.h" + +change_t* change_new(U16 frame, int function, float value, interpolation_t* inter) +{ + change_t* newChange = (change_t*)malloc(sizeof(change_t)); + change_init(newChange); + newChange->frame = frame; + newChange->function = function; + newChange->value = value; + newChange->interpolation = inter; + return newChange; +} + +void change_free(change_t *change) +{ + if (change->next) + change_free(change->next); + free(change); +} + +void change_init(change_t* change) +{ + memset(change, 0, sizeof(change_t)); +} + +void change_append(change_t* first, change_t* newChange) +{ + while (first->next) + first = first->next; + first->next = newChange; +} + +float interpolateParameter(float p1, float p2, float fraction, interpolation_t* inter) +{ + if (!inter) + return linear(fraction, p1, p2 - p1); + switch (inter->function) + { + case IF_LINEAR: return linear(fraction, p1, p2 - p1); + case IF_QUAD_IN: return quadIn(fraction, p1, p2 - p1); + case IF_QUAD_OUT: return quadOut(fraction, p1, p2 - p1); + case IF_QUAD_IN_OUT: return quadInOut(fraction, p1, p2 - p1); + case IF_CUBIC_IN: return cubicIn(fraction, p1, p2 - p1); + case IF_CUBIC_OUT: return cubicOut(fraction, p1, p2 - p1); + case IF_CUBIC_IN_OUT: return cubicInOut(fraction, p1, p2 - p1); + case IF_QUART_IN: return quartIn(fraction, p1, p2 - p1); + case IF_QUART_OUT: return quartOut(fraction, p1, p2 - p1); + case IF_QUART_IN_OUT: return quartInOut(fraction, p1, p2 - p1); + case IF_QUINT_IN: return quintIn(fraction, p1, p2 - p1); + case IF_QUINT_OUT: return quintOut(fraction, p1, p2 - p1); + case IF_QUINT_IN_OUT: return quintInOut(fraction, p1, p2 - p1); + case IF_CIRCLE_IN: return circleIn(fraction, p1, p2 - p1); + case IF_CIRCLE_OUT: return circleOut(fraction, p1, p2 - p1); + case IF_CIRCLE_IN_OUT: return circleInOut(fraction, p1, p2 - p1); + case IF_EXPONENTIAL_IN: return exponentialIn(fraction, p1, p2 - p1); + case IF_EXPONENTIAL_OUT: return exponentialOut(fraction, p1, p2 - p1); + case IF_EXPONENTIAL_IN_OUT: return exponentialInOut(fraction, p1, p2 - p1); + case IF_SINE_IN: return sineIn(fraction, p1, p2 - p1); + case IF_SINE_OUT: return sineOut(fraction, p1, p2 - p1); + case IF_SINE_IN_OUT: return sineInOut(fraction, p1, p2 - p1); + case IF_ELASTIC_IN: return elasticIn(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping); + case IF_ELASTIC_OUT: return elasticOut(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping); + case IF_ELASTIC_IN_OUT: return elasticInOut(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping); + case IF_BACK_IN: return backIn(fraction, p1, p2 - p1, inter->speed); + case IF_BACK_OUT: return backOut(fraction, p1, p2 - p1, inter->speed); + case IF_BACK_IN_OUT: return backInOut(fraction, p1, p2 - p1, inter->speed); + case IF_BOUNCE_IN: return bounceIn(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping); + case IF_BOUNCE_OUT: return bounceOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping); + case IF_BOUNCE_IN_OUT: return bounceInOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping); + case IF_FAST_BOUNCE_IN: return fastBounceIn(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping); + case IF_FAST_BOUNCE_OUT: return fastBounceOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping); + case IF_FAST_BOUNCE_IN_OUT: return fastBounceInOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping); + default: return linear(fraction, p1, p2 - p1); + } +} + +float change_value(change_t* first, U16 frame) +{ + change_t* previous = first; + while (first && first->frame < frame) + { + previous = first; + first = first->next; + } + if (!first) + return previous->value; + if (first->frame == frame) + { + float result; + do + { + result = first->value; + first = first->next; + } + while (first && first->frame == frame); + return result; + } + switch (first->function) + { + case CF_PUT: + return first->value; + case CF_CHANGE: + { + float fraction = (frame - previous->frame) / (float)(first->frame - previous->frame); + return interpolateParameter(previous->value, first->value, fraction, first->interpolation); + } + case CF_JUMP: + return previous->value; + default: + return 0; + } +} + +changeFilter_t* changeFilter_new(U16 frame, int function, FILTER* value, interpolation_t* inter) +{ + changeFilter_t* newChange = (changeFilter_t*)malloc(sizeof(changeFilter_t)); + changeFilter_init(newChange); + newChange->frame = frame; + newChange->function = function; + newChange->value = value; + newChange->interpolation = inter; + return newChange; +} + +void changeFilter_free(changeFilter_t *change) +{ + if (change->next) + changeFilter_free(change->next); + free(change); +} + +void changeFilter_init(changeFilter_t* change) +{ + memset(change, 0, sizeof(changeFilter_t)); +} + +void changeFilter_append(changeFilter_t* first, changeFilter_t* newChange) +{ + while (first->next) + first = first->next; + first->next = newChange; +} + +RGBA interpolateColor(RGBA c1, RGBA c2, float ratio, interpolation_t* inter) +{ + RGBA c; + c.r = c1.r * (1-ratio) + c2.r * ratio; + c.g = c1.g * (1-ratio) + c2.g * ratio; + c.b = c1.b * (1-ratio) + c2.b * ratio; + c.a = c1.a * (1-ratio) + c2.a * ratio; + return c; +} + +FILTER* interpolateFilter(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter) +{ + if(!filter1 && !filter2) + return 0; + if(!filter1) + return interpolateFilter(filter2,filter1,1-ratio, inter); + + if(filter2 && filter2->type != filter1->type) + syntaxerror("can't interpolate between %s and %s filters yet", filtername[filter1->type], filtername[filter2->type]); + + if(filter1->type == FILTERTYPE_BLUR) + { + FILTER_BLUR*f1 = (FILTER_BLUR*)filter1; + FILTER_BLUR*f2 = (FILTER_BLUR*)filter2; + if(f2 && f1->blurx == f2->blurx && f1->blury == f2->blury) + return 0; + FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR); + f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio; + f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio; + f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio; + return (FILTER*)f; + } + else + if (filter1->type == FILTERTYPE_DROPSHADOW) + { + FILTER_DROPSHADOW*f1 = (FILTER_DROPSHADOW*)filter1; + FILTER_DROPSHADOW*f2 = (FILTER_DROPSHADOW*)filter2; + if(f2 && !memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength && + f1->blurx == f2->blurx && f1->blury == f2->blury && + f1->angle == f2->angle && f1->distance == f2->distance) + return 0; + FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW); + memcpy(f, f1, sizeof(FILTER_DROPSHADOW)); + f->color = interpolateColor(f1->color, f2->color, ratio, inter); + f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio; + f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio; + f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio; + f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio; + f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio; + f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio; + return (FILTER*)f; + } + else + if (filter1->type == FILTERTYPE_BEVEL) + { + FILTER_BEVEL*f1 = (FILTER_BEVEL*)filter1; + FILTER_BEVEL*f2 = (FILTER_BEVEL*)filter2; + if(f2 && !memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) && + !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) && + f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance) + return 0; + FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL); + memcpy(f, f1, sizeof(FILTER_BEVEL)); + f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio, inter); + f->highlight = interpolateColor(f1->highlight, f2->highlight, ratio, inter); + f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio; + f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio; + f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio; + f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio; + f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio; + f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio; + return (FILTER*)f; + } /*else if (filter1->type == FILTERTYPE_GRADIENTGLOW) { + FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW); + // can't interpolate gradients + memcpy(f, filter1, sizeof(FILTER_GRADIENTGLOW)); + return (FILTER*)f; + }*/ else + syntaxerror("can't interpolate %s filters yet", filtername[filter1->type]); + return 0; +} + +FILTER* copyFilter(FILTER* original) +{ + if (!original) + return original; + FILTER* copy = swf_NewFilter(original->type); + switch (original->type) + { + case FILTERTYPE_BLUR: + memcpy(copy, original, sizeof(FILTER_BLUR)); + break; + case FILTERTYPE_GRADIENTGLOW: + memcpy(copy, original, sizeof(FILTER_GRADIENTGLOW)); + break; + case FILTERTYPE_DROPSHADOW: + memcpy(copy, original, sizeof(FILTER_DROPSHADOW)); + break; + case FILTERTYPE_BEVEL: + memcpy(copy, original, sizeof(FILTER_BEVEL)); + break; + default: printf("unsupported filterype"); + } + return copy; +} + +FILTER* changeFilter_value(changeFilter_t* first, U16 frame) +{ + changeFilter_t* previous = first; + while (first && first->frame < frame) + { + previous = first; + first = first->next; + } + if (!first) + return copyFilter(previous->value); + if (first->frame == frame) + { + FILTER* result; + do + { + result = first->value; + first = first->next; + } + while (first && first->frame == frame); + return copyFilter(result); + } + switch (first->function) + { + case CF_PUT: + return copyFilter(first->value); + case CF_CHANGE: + { + float fraction = (frame - previous->frame) / (float)(first->frame - previous->frame); + return interpolateFilter(previous->value, first->value, fraction, first->interpolation); + } + case CF_JUMP: + return copyFilter(previous->value); + default: + return 0; + } +} + +history_t* history_new() +{ + history_t* newHistory = (history_t*)malloc(sizeof(history_t)); + history_init(newHistory); + return newHistory; +} + +void history_free(history_t* past) +{ + change_free(dictionary_lookup(past->changes, "x")); + change_free(dictionary_lookup(past->changes, "y")); + change_free(dictionary_lookup(past->changes, "scalex")); + change_free(dictionary_lookup(past->changes, "scaley")); + change_free(dictionary_lookup(past->changes, "cxform.r0")); + change_free(dictionary_lookup(past->changes, "cxform.g0")); + change_free(dictionary_lookup(past->changes, "cxform.b0")); + change_free(dictionary_lookup(past->changes, "cxform.a0")); + change_free(dictionary_lookup(past->changes, "cxform.r1")); + change_free(dictionary_lookup(past->changes, "cxform.g1")); + change_free(dictionary_lookup(past->changes, "cxform.b1")); + change_free(dictionary_lookup(past->changes, "cxform.a1")); + change_free(dictionary_lookup(past->changes, "rotate")); + change_free(dictionary_lookup(past->changes, "shear")); + change_free(dictionary_lookup(past->changes, "pivot.x")); + change_free(dictionary_lookup(past->changes, "pivot.y")); + change_free(dictionary_lookup(past->changes, "pin.x")); + change_free(dictionary_lookup(past->changes, "pin.y")); + change_free(dictionary_lookup(past->changes, "blendmode")); + changeFilter_free(dictionary_lookup(past->changes, "filter")); + dictionary_destroy(past->changes); + free(past); +} + +void history_init(history_t* past) +{ + past->changes = (dictionary_t*)malloc(sizeof(dictionary_t)); + dictionary_init(past->changes); +} + +void history_begin(history_t* past, char* parameter, U16 frame, TAG* tag, float value) +{ + change_t* first = change_new(frame, CF_PUT, value, 0); + past->firstTag = tag; + past->firstFrame = frame; + dictionary_put2(past->changes, parameter, first); +} + +void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTER* value) +{ + changeFilter_t* first = changeFilter_new(frame, CF_PUT, value, 0); + past->firstTag = tag; + past->firstFrame = frame; + dictionary_put2(past->changes, "filter", first); +} + +void history_remember(history_t* past, char* parameter, U16 frame, int function, float value, interpolation_t* inter) +{ + change_t* first = dictionary_lookup(past->changes, parameter); + if (first) //should always be true + { + change_t* next = change_new(frame, function, value, inter); + change_append(first, next); + } +} + +void history_rememberFilter(history_t* past, U16 frame, int function, FILTER* value, interpolation_t* inter) +{ + changeFilter_t* first = dictionary_lookup(past->changes, "filter"); + if (first) //should always be true + { + changeFilter_t* next = changeFilter_new(frame, function, value, inter); + changeFilter_append(first, next); + } +} + +float history_value(history_t* past, U16 frame, char* parameter) +{ + change_t* first = dictionary_lookup(past->changes, parameter); + if (first) //should always be true. + return change_value(first, frame); + printf("no history found for parameter %s\n", parameter); + return 0; +} + +FILTER* history_valueFilter(history_t* past, U16 frame) +{ + changeFilter_t* first = dictionary_lookup(past->changes, "filter"); + if (first) //should always be true. + return changeFilter_value(first, frame); + printf("no history found for parameter filter\n"); + return 0; +} diff --git a/src/swfc-history.h b/src/swfc-history.h new file mode 100644 index 0000000..5ced477 --- /dev/null +++ b/src/swfc-history.h @@ -0,0 +1,103 @@ +/* swfc- Compiles swf code (.sc) files into .swf files. + + Part of the swftools package. + + Copyright (c) 2007 Huub Schaeks + Copyright (c) 2007 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef __HISTORY_H +#define __HISTORY_Y + +#include "types.h" +#include "rfxswf.h" +#include "q.h" +#include "feedback.h" +#include "interpolation.h" + +enum +{ + CF_PUT = 1, + CF_CHANGE = 2, + CF_QCHANGE = 3, + CF_ARCCHANGE = 4, + CF_JUMP = 5 +}; + +#define SF_X 0x0001 +#define SF_Y 0x0002 +#define SF_SCALEX 0x0004 +#define SF_SCALEY 0x0008 +#define SF_CX_R 0x0010 +#define SF_CX_G 0x0020 +#define SF_CX_B 0x0040 +#define SF_CX_A 0x0080 +#define SF_ROTATE 0x0100 +#define SF_SHEAR 0x0200 +#define SF_PIVOT 0x0400 +#define SF_PIN 0x0800 +#define SF_BLEND 0x01000 +#define SF_FILTER 0x02000 + + +typedef struct _change +{ + U16 frame; + float value; + int function; + interpolation_t* interpolation; + struct _change* next; +} change_t; + +change_t* change_new(U16 frame, int function, float value, interpolation_t* inter); +void change_free(change_t* change); +void change_init(change_t* change); +void change_append(change_t* first, change_t* newChange); +float change_value(change_t* first, U16 frame); + +typedef struct _changeFilter +{ + U16 frame; + FILTER* value; + int function; + interpolation_t* interpolation; + struct _changeFilter* next; +} changeFilter_t; + +changeFilter_t* changeFilter_new(U16 frame, int function, FILTER* value, interpolation_t* inter); +void changeFilter_free(changeFilter_t* change); +void changeFilter_init(changeFilter_t* change); +void changeFilter_append(changeFilter_t* first, changeFilter_t* newChange); +FILTER* changeFilter_value(changeFilter_t* first, U16 frame); + +typedef struct _history +{ + U16 firstFrame; + TAG* firstTag; + dictionary_t* changes; +} history_t; + +history_t* history_new(); +void history_free(history_t* past); +void history_init(history_t* past); +void history_begin(history_t* past, char* parameter, U16 frame, TAG* tag, float value); +void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTER* value); +void history_remember(history_t* past, char* parameter, U16 frame, int function, float value, interpolation_t* inter); +void history_rememberFilter(history_t* past, U16 frame, int function, FILTER* value, interpolation_t* inter); +float history_value(history_t* past, U16 frame, char* parameter); +FILTER* history_valueFilter(history_t* past, U16 frame); + +#endif diff --git a/src/swfc-interpolation.c b/src/swfc-interpolation.c new file mode 100644 index 0000000..17759e7 --- /dev/null +++ b/src/swfc-interpolation.c @@ -0,0 +1,301 @@ +/* swfc- Compiles swf code (.sc) files into .swf files. + + Part of the swftools package. + + Copyright (c) 2007 Huub Schaeks + Copyright (c) 2007 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include "interpolation.h" + +static inline float poly(float fraction, float start, float delta, int degree) +{ + return delta * pow(fraction, degree) + start; +} + +float linear(float fraction, float start, float delta) +{ + return poly(fraction, start, delta, 1); +} + +float quadIn(float fraction, float start, float delta) +{ + return poly(fraction, start, delta, 2); +} + +float quadOut(float fraction, float start, float delta) +{ + return quadIn(1 - fraction, start + delta, -delta); +} + +float quadInOut(float fraction, float start, float delta) +{ + if (fraction < 0.5) + return quadIn(2 * fraction, start, delta / 2); + return quadOut(2 * fraction - 1, start + delta / 2, delta / 2); +} + +float cubicIn(float fraction, float start, float delta) +{ + return poly(fraction, start, delta, 3); +} + +float cubicOut(float fraction, float start, float delta) +{ + return cubicIn(1 - fraction, start + delta, -delta); +} + +float cubicInOut(float fraction, float start, float delta) +{ + if (fraction < 0.5) + return cubicIn(2 * fraction, start, delta / 2); + return cubicOut(2 * fraction - 1, start + delta / 2, delta / 2); +} + +float quartIn(float fraction, float start, float delta) +{ + return poly(fraction, start, delta, 4); +} + +float quartOut(float fraction, float start, float delta) +{ + return quartIn(1 - fraction, start + delta, -delta); +} + +float quartInOut(float fraction, float start, float delta) +{ + if (fraction < 0.5) + return quartIn(2 * fraction, start, delta / 2); + return quartOut(2 * fraction - 1, start + delta / 2, delta / 2); +} + +float quintIn(float fraction, float start, float delta) +{ + return poly(fraction, start, delta, 5); +} + +float quintOut(float fraction, float start, float delta) +{ + return quintIn(1 - fraction, start + delta, -delta); +} + +float quintInOut(float fraction, float start, float delta) +{ + if (fraction < 0.5) + return quintIn(2 * fraction, start, delta / 2); + return quintOut(2 * fraction - 1, start + delta / 2, delta / 2); +} + +float circleIn(float fraction, float start, float delta) +{ + return delta * (1 - sqrt(1 - fraction * fraction)) + start; +} + +float circleOut(float fraction, float start, float delta) +{ + return circleIn(1 - fraction, start + delta, -delta); +} + +float circleInOut(float fraction, float start, float delta) +{ + if (fraction < 0.5) + return circleIn(2 * fraction, start, delta / 2); + return circleOut(2 * fraction - 1, start + delta / 2, delta / 2); +} + +float exponentialIn(float fraction, float start, float delta) +{ + if (fraction == 0) + return start; + return delta * pow(2, 10 * (fraction - 1)) + start; +} + +float exponentialOut(float fraction, float start, float delta) +{ + return exponentialIn(1 - fraction, start + delta, -delta); +} + +float exponentialInOut(float fraction, float start, float delta) +{ + if (fraction < 0.5) + return exponentialIn(2 * fraction, start, delta / 2); + return exponentialOut(2 * fraction - 1, start + delta / 2, delta / 2); +} + +float sineIn(float fraction, float start, float delta) +{ + return delta * (1 - cos(fraction * PI/2)) + start; +} + +float sineOut(float fraction, float start, float delta) +{ + return sineIn(1 - fraction, start + delta, -delta); +} + +float sineInOut(float fraction, float start, float delta) +{ + if (fraction < 0.5) + return sineIn(2 * fraction, start, delta / 2); + return sineOut(2 * fraction - 1, start + delta / 2, delta / 2); +} + +float elasticIn(float fraction, float start, float delta, float amplitude, int bounces, float damping) +{ + if (fraction == 0 || delta == 0) + return start; + if (fraction == 1) + return start + delta; + if (amplitude < fabs(delta)) + amplitude = delta; + float period = 1 / (bounces + 0.25); +// float s = asin(delta / amplitude) - 2 * PI / period; + return amplitude * pow(2, damping * (fraction - 1)) * sin(fraction * (2 * PI) / period /*+ fraction * s*/) + start; +} + +float elasticOut(float fraction, float start, float delta, float amplitude, int bounces, float damping) +{ + return elasticIn(1 - fraction, start + delta, -delta, amplitude, bounces, damping); +} + +float elasticInOut(float fraction, float start, float delta, float amplitude, int bounces, float damping) +{ + if (fraction < 0.5) + return elasticIn(2 * fraction, start, delta / 2, amplitude, bounces, damping); + return elasticOut(2 * fraction - 1, start + delta / 2, delta / 2, amplitude, bounces, damping); +} + +float backIn(float fraction, float start, float delta, float speed) +{ + return delta * fraction * fraction * ((speed + 1) * fraction - speed) + start; +} + +float backOut(float fraction, float start, float delta, float speed) +{ + return backIn(1 - fraction, start + delta, -delta, speed); +} + +float backInOut(float fraction, float start, float delta, float speed) +{ + if (fraction < 0.5) + return backIn(2 * fraction, start, delta / 2, speed); + return backOut(2 * fraction - 1, start + delta / 2, delta / 2, speed); +} + +/* when applied to movement bounceIn the object 'hits the floor' bounces times + * (after leaving the floor first) before gently reaching the final position at the top of the final bounce + * Each bounce takes growth times a long as the previous, except for the last one which lasts only half + * that time. The heights of the intermediate bounces are determined by the damping parameter. + * Set damping to 0 for an undamped movement.*/ + +float bounceIn(float fraction, float start, float delta, int bounces, float growth, float damping) +{ + if (fraction == 0 || delta == 0) + return start; + if (fraction == 1) + return start + delta; + float w0; + if (growth == 1.0) + w0 = 1 / (bounces + 0.5); + else + { + float gN = pow(growth, bounces); + w0 = 1 / ((gN - 1) / (growth - 1) + gN / 2 ); + } + float bounceStart = 0; + int i; + float w = w0; + for (i = 0; i <= bounces; i++) + { + float bounceEnd = bounceStart + w; + if (fraction >= bounceStart && fraction < bounceEnd) + { + float half = (bounceEnd + bounceStart) / 2; + float top = delta / pow(2, damping * ((bounces - i))); + fraction -= half; + fraction /= (w / 2); + return (1 - fraction * fraction) * top + start; + } + bounceStart = bounceEnd; + w = w * growth; + } +} + +/* bounceOut is a time-reversed bounceIn; therefore each bounce takes 1/growth times as long as + * the previous, which I think fits the idea when applied to movement */ + +float bounceOut(float fraction, float start, float delta, int bounces, float growth, float damping) +{ + return bounceIn(1 - fraction, start + delta, -delta, bounces, growth, damping); +} + +/* since bounceIn and bounceOut are combined, if growth > 1 then the bounce-times will increase in + * the first half and decrease in the second half */ + +float bounceInOut(float fraction, float start, float delta, int bounces, float growth, float damping) +{ + if (fraction < 0.5) + return bounceIn(2 * fraction, start, delta / 2, bounces, growth, damping); + return bounceOut(2 * fraction - 1, start + delta / 2, delta / 2, bounces, growth, damping); +} +/* fastBounce(In/Out) doesn't end or start in a horizontal slope (= gentle end or start) as + * bounce(In/Out) do which means fastBounceInOut doesn't have the 'delay' in the middle */ +float fastBounceIn(float fraction, float start, float delta, int bounces, float growth, float damping) +{ + if (fraction == 0 || delta == 0) + return start; + if (fraction == 1) + return start + delta; + float w0; + if (growth == 1.0) + w0 = 1 / (bounces + 0.25); /* in general (bounces + 1 / (2 * f)) */ + else + { + float gN = pow(growth, bounces); + w0 = 1 / ((gN - 1) / (growth - 1) + gN / 4 /* in general: gN / (2 * f) */ ); + } + float bounceStart = 0; + int i; + float w = w0; + for (i = 0; i <= bounces; i++) + { + float bounceEnd = bounceStart + w; + if (fraction >= bounceStart && fraction < bounceEnd) + { + float half = (bounceEnd + bounceStart) / 2; + float top = delta / 0.75/* in general: (1 - (1 / f) * (1 / f)) */ / pow(2, damping * ((bounces - i))); + fraction -= half; + fraction /= (w / 2); + return (1 - fraction * fraction) * top + start; + } + bounceStart = bounceEnd; + w = w * growth; + } +} + +float fastBounceOut(float fraction, float start, float delta, int bounces, float growth, float damping) +{ + return fastBounceIn(1 - fraction, start + delta, -delta, bounces, growth, damping); +} + +float fastBounceInOut(float fraction, float start, float delta, int bounces, float growth, float damping) +{ + if (fraction < 0.5) + return fastBounceIn(2 * fraction, start, delta / 2, bounces, growth, damping); + return fastBounceOut(2 * fraction - 1, start + delta / 2, delta / 2, bounces, growth, damping); +} diff --git a/src/swfc-interpolation.h b/src/swfc-interpolation.h new file mode 100644 index 0000000..173ae9b --- /dev/null +++ b/src/swfc-interpolation.h @@ -0,0 +1,116 @@ +/* swfc- Compiles swf code (.sc) files into .swf files. + + Part of the swftools package. + + Copyright (c) 2007 Huub Schaeks + Copyright (c) 2007 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef __EASE_H +#define __EASE_H + +typedef struct _interpolation { + int function; + float speed, amplitude, growth, damping; + int bounces; +} interpolation_t; + +enum { + IF_LINEAR = 1, + IF_QUAD_IN = 2, + IF_QUAD_OUT = 3, + IF_QUAD_IN_OUT = 4, + IF_CUBIC_IN = 5, + IF_CUBIC_OUT = 6, + IF_CUBIC_IN_OUT = 7, + IF_QUART_IN = 8, + IF_QUART_OUT = 9, + IF_QUART_IN_OUT = 10, + IF_QUINT_IN = 11, + IF_QUINT_OUT = 12, + IF_QUINT_IN_OUT = 13, + IF_CIRCLE_IN = 14, + IF_CIRCLE_OUT = 15, + IF_CIRCLE_IN_OUT = 16, + IF_EXPONENTIAL_IN = 17, + IF_EXPONENTIAL_OUT = 18, + IF_EXPONENTIAL_IN_OUT = 19, + IF_SINE_IN = 20, + IF_SINE_OUT = 21, + IF_SINE_IN_OUT = 22, + IF_ELASTIC_IN = 23, + IF_ELASTIC_OUT = 24, + IF_ELASTIC_IN_OUT = 25, + IF_BACK_IN = 26, + IF_BACK_OUT = 27, + IF_BACK_IN_OUT = 28, + IF_BOUNCE_IN = 29, + IF_BOUNCE_OUT = 30, + IF_BOUNCE_IN_OUT = 31, + IF_FAST_BOUNCE_IN = 32, + IF_FAST_BOUNCE_OUT = 33, + IF_FAST_BOUNCE_IN_OUT = 34 +}; + +#define PI 3.14159265358979 + +float linear(float fraction, float start, float delta); + +float quadIn(float fraction, float start, float delta); +float quadOut(float fraction, float start, float delta); +float quadInOut(float fraction, float start, float delta); + +float cubicIn(float fraction, float start, float delta); +float cubicOut(float fraction, float start, float delta); +float cubicInOut(float fraction, float start, float delta); + +float quartIn(float fraction, float start, float delta); +float quartOut(float fraction, float start, float delta); +float quartInOut(float fraction, float start, float delta); + +float quintIn(float fraction, float start, float delta); +float quintOut(float fraction, float start, float delta); +float quintInOut(float fraction, float start, float delta); + +float circleIn(float fraction, float start, float delta); +float circleOut(float fraction, float start, float delta); +float circleInOut(float fraction, float start, float delta); + +float exponentialIn(float fraction, float start, float delta); +float exponentialOut(float fraction, float start, float delta); +float exponentialInOut(float fraction, float start, float delta); + +float sineIn(float fraction, float start, float delta); +float sineOut(float fraction, float start, float delta); +float sineInOut(float fraction, float start, float delta); + +float elasticIn(float fraction, float start, float delta, float amplitude, int bounces, float damping); +float elasticOut(float fraction, float start, float delta, float amplitude, int bounces, float damping); +float elasticInOut(float fraction, float start, float delta, float amplitude, int bounces, float damping); + +float backIn(float fraction, float start, float delta, float speed); +float backOut(float fraction, float start, float delta, float speed); +float backInOut(float fraction, float start, float delta, float speed); + +float bounceIn(float fraction, float start, float delta, int bounces, float growth, float damping); +float bounceOut(float fraction, float start, float delta, int bounces, float growth, float damping); +float bounceInOut(float fraction, float start, float delta, int bounces, float growth, float damping); + +float fastBounceIn(float fraction, float start, float delta, int bounces, float growth, float damping); +float fastBounceOut(float fraction, float start, float delta, int bounces, float growth, float damping); +float fastBounceInOut(float fraction, float start, float delta, int bounces, float growth, float damping); + +#endif diff --git a/src/swfc.c b/src/swfc.c index 34e731e..f4d55da 100644 --- a/src/swfc.c +++ b/src/swfc.c @@ -36,10 +36,10 @@ #include "../lib/wav.h" #include "parser.h" #include "../lib/png.h" +#include "../lib/interpolation.h" +#include "../lib/history.h" //#define DEBUG - -static char * filename = 0; static char * outputname = "output.swf"; static int verbose = 2; static int optimize = 0; @@ -116,29 +116,6 @@ static int pos; 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); - fprintf(stderr, "\"%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); - fprintf(stderr, "\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf); -} static void readToken() { @@ -204,6 +181,7 @@ static dictionary_t textures; static dictionary_t outlines; static dictionary_t gradients; static dictionary_t filters; +static dictionary_t interpolations; static char idmap[65536]; static TAG*tag = 0; //current tag @@ -214,6 +192,7 @@ static U16 currentdepth; static dictionary_t instances; static dictionary_t fonts; static dictionary_t sounds; +static dictionary_t fontUsage; typedef struct _parameters { int x,y; @@ -225,6 +204,7 @@ typedef struct _parameters { SPOINT pin; U8 blendmode; //not interpolated FILTER*filter; + U16 set; // bits indicating wether a parameter was set in the c_placement function } parameters_t; typedef struct _character { @@ -239,6 +219,7 @@ typedef struct _instance { 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 { @@ -260,10 +241,49 @@ 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"}; + +typedef struct _fontData { + char *glyphs; + int notUsed, needsAll; +} fontData; + +void addFontData(char *name) +{ + fontData* newFont; + newFont = (fontData *)malloc(sizeof(fontData)); + memset(newFont, 0, sizeof(fontData)); + newFont->notUsed = 1; + dictionary_put2(&fontUsage, name, newFont); +} + +void freeFontData(fontData* font) +{ + free(font->glyphs); + free(font); +} + +fontData *getFontData(char *name) +{ + return (fontData *)dictionary_lookup(&fontUsage, name); +} + static void character_init(character_t*c) { memset(c, 0, sizeof(character_t)); } + static character_t* character_new() { character_t*c; @@ -271,10 +291,19 @@ static character_t* character_new() 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; @@ -283,6 +312,60 @@ static instance_t* instance_new() 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 free_fontData(void* fd) +{ + freeFontData((fontData*)fd); +} + +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() +{ + dictionary_free_all(&instances, free_instance); + dictionary_free_all(&characters, free); + dictionary_free_all(&images, free); + dictionary_free_all(&textures, free); + dictionary_free_all(&outlines, free_outline); + dictionary_free_all(&gradients, free_gradient); + dictionary_free_all(&filters, free); + dictionary_free_all(&fonts, free_font); + dictionary_free_all(&sounds, free); + dictionary_free_all(&fontUsage, free_fontData); + dictionary_free_all(&interpolations, free); +} + static void incrementid() { while(idmap[++id]) { @@ -294,13 +377,13 @@ static void incrementid() static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r) { + if(dictionary_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); @@ -313,23 +396,23 @@ static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r) } static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r) { + if(dictionary_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); } static instance_t* s_addinstance(char*name, character_t*c, U16 depth) { + if(dictionary_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); return i; } @@ -357,10 +440,10 @@ static void makeMatrix(MATRIX*m, parameters_t*p) * \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*PI); + r1 = -p->scalex*sin(p->rotate/360*2*PI)+sx*p->shear; + r0 = p->scaley*sin(p->rotate/360*2*PI); + sy = p->scaley*cos(p->rotate/360*2*PI)+r0*p->shear; m->sx = (int)(sx*65536+0.5); m->r1 = (int)(r1*65536+0.5); @@ -388,12 +471,92 @@ static MATRIX s_instancepos(SRECT rect, parameters_t*p) return m; } +void builtInInterpolations() +{ + interpolation_t* new; + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_LINEAR; + dictionary_put2(&interpolations, "linear", new); + + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_QUAD_IN; + dictionary_put2(&interpolations, "quadIn", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_QUAD_OUT; + dictionary_put2(&interpolations, "quadOut", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_QUAD_IN_OUT; + dictionary_put2(&interpolations, "quadInOut", new); + + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_CUBIC_IN; + dictionary_put2(&interpolations, "cubicIn", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_CUBIC_OUT; + dictionary_put2(&interpolations, "cubicOut", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_CUBIC_IN_OUT; + dictionary_put2(&interpolations, "cubicInOut", new); + + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_QUART_IN; + dictionary_put2(&interpolations, "quartIn", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_QUART_OUT; + dictionary_put2(&interpolations, "quartOut", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_QUART_IN_OUT; + dictionary_put2(&interpolations, "quartInOut", new); + + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_QUINT_IN; + dictionary_put2(&interpolations, "quintIn", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_QUINT_OUT; + dictionary_put2(&interpolations, "quintOut", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_QUINT_IN_OUT; + dictionary_put2(&interpolations, "quintInOut", new); + + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_CIRCLE_IN; + dictionary_put2(&interpolations, "circleIn", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_CIRCLE_OUT; + dictionary_put2(&interpolations, "circleOut", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_CIRCLE_IN_OUT; + dictionary_put2(&interpolations, "circleInOut", new); + + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_EXPONENTIAL_IN; + dictionary_put2(&interpolations, "exponentialIn", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_EXPONENTIAL_OUT; + dictionary_put2(&interpolations, "exponentialOut", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_EXPONENTIAL_IN_OUT; + dictionary_put2(&interpolations, "exponentialInOut", new); + + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_SINE_IN; + dictionary_put2(&interpolations, "sineIn", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_SINE_OUT; + dictionary_put2(&interpolations, "sineOut", new); + new = (interpolation_t*)malloc(sizeof(interpolation_t)); + new->function = IF_SINE_IN_OUT; + dictionary_put2(&interpolations, "sineInOut", new); +} + void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background) { - SWF*swf = (SWF*)malloc(sizeof(SWF)); - 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; @@ -402,9 +565,6 @@ void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA backgrou 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); @@ -415,6 +575,9 @@ void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA backgrou dictionary_init(&instances); dictionary_init(&fonts); dictionary_init(&sounds); + dictionary_init(&interpolations); + builtInInterpolations(); + cleanUp = &freeDictionaries; memset(&stack[stackpos], 0, sizeof(stack[0])); stack[stackpos].type = 0; @@ -615,6 +778,89 @@ TAG* removeFromTo(TAG*from, TAG*to) return save; } +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_value(history, frame, "rotate"); + 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->filter = history_valueFilter(history, frame); +} + +void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move) +{ + SWFPLACEOBJECT po; + FILTERLIST flist; + swf_GetPlaceObject(NULL, &po); + po.id = id; + po.depth = depth; + po.matrix = m; + po.cxform = p->cxform; + po.name = name; + po.move = move; + if(move) + po.id = 0; + if(p->blendmode) { + po.blendmode = p->blendmode; + } + if(p->filter) { + flist.num = 1; + flist.filter[0] = p->filter; + po.filters = &flist; + } + swf_SetPlaceObject(tag, &po); +} + +static void writeInstance(instance_t* i) +{ + parameters_t p; + MATRIX m; + int frame = i->history->firstFrame; + TAG* tag = i->history->firstTag; + while (frame < currentframe) + { + frame++; + readParameters(i->history, &p, frame); + while (tag->id != ST_SHOWFRAME) + tag = tag->next; + m = s_instancepos(i->character->size, &p); + + if(p.blendmode || p.filter) + tag = swf_InsertTag(tag, ST_PLACEOBJECT3); + else + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + setPlacement(tag, 0, i->depth, m, 0, &p, 1); + if (p.filter) + free(p.filter); + } +} + +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; @@ -623,24 +869,34 @@ static void s_endSprite() tag = removeFromTo(stack[stackpos].cut, tag); stackpos--; - + instance_t *i; + stringarray_t* index =dictionary_index(&instances); + int num = 0; + char* name = stringarray_at(index, num); + while (name) + { + i = dictionary_lookup(&instances, name); + writeInstance(i); + num++; + name = stringarray_at(index, num); + } + + tag = swf_InsertTag(tag, ST_SHOWFRAME); + tag = swf_InsertTag(tag, ST_END); + + tag = stack[stackpos].tag; + swf_FoldSprite(tag); + if(tag->next != 0) + syntaxerror("internal error(7)"); /* TODO: before clearing, prepend "." to names and copy into old instances dict */ - dictionary_clear(&instances); + dictionary_free_all(&instances, free_instance); currentframe = stack[stackpos].oldframe; currentrect = stack[stackpos].oldrect; currentdepth = stack[stackpos].olddepth; instances = stack[stackpos].oldinstances; - tag = swf_InsertTag(tag, ST_SHOWFRAME); - tag = swf_InsertTag(tag, ST_END); - - tag = stack[stackpos].tag; - 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); } @@ -651,6 +907,18 @@ static void s_endSWF() SWF* swf; char*filename; + instance_t *i; + stringarray_t* index =dictionary_index(&instances); + int num = 0; + char* name = stringarray_at(index, num); + while (name) + { + i = dictionary_lookup(&instances, name); + writeInstance(i); + num++; + name = stringarray_at(index, num); + } + if(stack[stackpos].cut) tag = removeFromTo(stack[stackpos].cut, tag); @@ -696,16 +964,8 @@ static void s_endSWF() {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");} close(fi); - - dictionary_clear(&instances); - dictionary_clear(&characters); - dictionary_clear(&images); - dictionary_clear(&textures); - dictionary_clear(&outlines); - dictionary_clear(&gradients); // mem leak - dictionary_clear(&filters); - dictionary_clear(&fonts); - dictionary_clear(&sounds); + + freeDictionaries(); swf_FreeTags(swf); free(swf); @@ -790,8 +1050,8 @@ int addFillStyle(SHAPE*s, SRECT*r, char*name) MATRIX rot,m; double ccos,csin; swf_GetMatrix(0, &rot); - ccos = cos(-gradient->rotate*2*3.14159265358979/360); - csin = sin(-gradient->rotate*2*3.14159265358979/360); + ccos = cos(-gradient->rotate*2*PI/360); + csin = sin(-gradient->rotate*2*PI/360); rot.sx = ccos*65536; rot.r1 = -csin*65536; rot.r0 = csin*65536; @@ -1086,6 +1346,7 @@ void s_image(char*name, char*type, char*filename, int 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; @@ -1133,6 +1394,8 @@ void s_getBitmapSize(char*name, int*width, int*height) void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear) { + if(dictionary_lookup(&textures, name)) + syntaxerror("texture %s defined twice", name); gradient_t* gradient = dictionary_lookup(&gradients, object); character_t* bitmap = dictionary_lookup(&images, object); texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t)); @@ -1166,27 +1429,16 @@ void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, fs->m.sy *= 20; } - - if(dictionary_lookup(&textures, name)) - syntaxerror("texture %s defined twice", name); dictionary_put2(&textures, name, texture); } -void dumpSWF(SWF*swf) -{ - TAG* tag = swf->firstTag; - printf("vvvvvvvvvvvvvvvvvvvvv\n"); - while(tag) { - printf("%8d %s\n", tag->len, swf_TagGetName(tag)); - tag = tag->next; - } - printf("^^^^^^^^^^^^^^^^^^^^^\n"); -} - -void s_font(char*name, char*filename) +void s_font(char*name, char*filename, char *glyphs) { + if(dictionary_lookup(&fonts, name)) + syntaxerror("font %s defined twice", name); + SWFFONT* font; - font = swf_LoadFont(filename); + font = swf_LoadFont(filename, glyphs); if(font == 0) { warning("Couldn't open font file \"%s\"", filename); @@ -1218,8 +1470,6 @@ void s_font(char*name, char*filename) swf_SetString(tag, name); incrementid(); - if(dictionary_lookup(&fonts, name)) - syntaxerror("font %s defined twice", name); dictionary_put2(&fonts, name, font); } @@ -1237,46 +1487,53 @@ void s_sound(char*name, char*filename) struct MP3 mp3; sound_t* sound; U16*samples = NULL; - unsigned numsamples; + unsigned numsamples = 1; unsigned blocksize = 1152; int is_mp3 = 0; - if(wav_read(&wav, filename)) { + if(dictionary_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); + 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>8)&0xff | (samples[t]<<8)&0xff00; - } + for(t=0;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(mp3_read(&mp3, filename)) + { + fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename); + blocksize = 1; + is_mp3 = 1; + } + else + { + warning("Couldn't read WAV/MP3 file \"%s\"", filename); + samples = 0; + numsamples = 0; + } if(numsamples%blocksize != 0) { // apply padding, so that block is a multiple of blocksize - int numblocks = (numsamples+blocksize-1)/blocksize; - int numsamples2; - U16* samples2; - numsamples2 = numblocks * blocksize; - samples2 = malloc(sizeof(U16)*numsamples2); - memcpy(samples2, samples, numsamples*sizeof(U16)); - memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples)); - numsamples = numsamples2; - samples = samples2; + 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); @@ -1288,12 +1545,10 @@ void s_sound(char*name, char*filename) mp3.SampRate, mp3.Channels, mp3.NumFrames); - mp3_clear(&mp3); + mp3_clear(&mp3); } else - { swf_SetSoundDefine(tag, samples, numsamples); - } tag = swf_InsertTag(tag, ST_NAMECHARACTER); swf_SetU16(tag, id); @@ -1307,14 +1562,12 @@ void s_sound(char*name, char*filename) sound->tag = tag; sound->id = id; - if(dictionary_lookup(&sounds, name)) - syntaxerror("sound %s defined twice", name); dictionary_put2(&sounds, name, sound); incrementid(); - if(samples) - free(samples); + if (samples) + free(samples); } static char* gradient_getToken(const char**p) @@ -1345,30 +1598,42 @@ GRADIENT parseGradient(const char*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) - break; - pos = (int)(parsePercent(posstr)*255.0); - if(pos == lastpos) - pos++; - if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr); - colorstr = gradient_getToken(&p); - color = parseColor(colorstr); - if(gradient.num == 16) { - warning("gradient record too big- max size is 16, rest ignored"); - break; + + 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] = pos; - gradient.rgba[gradient.num] = color; - gradient.num++; - free(posstr); - free(colorstr); - lastpos = pos; - } return gradient; } @@ -1381,8 +1646,6 @@ void s_gradient(char*name, const char*text, int radial, int rotate) gradient->radial = radial; gradient->rotate = rotate; - if(dictionary_lookup(&gradients, name)) - syntaxerror("gradient %s defined twice", name); dictionary_put2(&gradients, name, gradient); } @@ -1390,6 +1653,9 @@ 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); composite = 1; @@ -1410,13 +1676,14 @@ void s_gradientglow(char*name, char*gradient, float blurx, float blury, filter->ontop = ontop; filter->passes = passes; - if(dictionary_lookup(&filters, name)) - syntaxerror("filter %s defined twice", name); dictionary_put2(&filters, name, filter); } void s_dropshadow(char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes) { + 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; @@ -1431,13 +1698,14 @@ void s_dropshadow(char*name, RGBA color, double blurx, double blury, double angl filter->composite = composite; filter->passes = passes; - if(dictionary_lookup(&filters, name)) - syntaxerror("filter %s defined twice", name); dictionary_put2(&filters, name, filter); } void s_bevel(char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes) { + 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; @@ -1454,21 +1722,20 @@ void s_bevel(char*name, RGBA shadow, RGBA highlight, double blurx, double blury, filter->ontop = ontop; filter->passes = passes; - if(dictionary_lookup(&filters, name)) - syntaxerror("filter %s defined twice", name); dictionary_put2(&filters, name, filter); } void s_blur(char*name, double blurx, double blury, int passes) { + 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; - if(dictionary_lookup(&filters, name)) - syntaxerror("filter %s defined twice", name); dictionary_put2(&filters, name, filter); } @@ -1476,8 +1743,10 @@ void s_action(const char*text) { ActionTAG* a = 0; a = swf_ActionCompile(text, stack[0].swf->fileVersion); - if(!a) { - syntaxerror("Couldn't compile ActionScript"); + if(!a) + { + swf_ActionFree(a); + syntaxerror("Couldn't compile ActionScript"); } tag = swf_InsertTag(tag, ST_DOACTION); @@ -1492,8 +1761,10 @@ void s_initaction(const char*character, const char*text) ActionTAG* a = 0; character_t*c = 0; a = swf_ActionCompile(text, stack[0].swf->fileVersion); - if(!a) { - syntaxerror("Couldn't compile ActionScript"); + if(!a) + { + swf_ActionFree(a); + syntaxerror("Couldn't compile ActionScript"); } c = (character_t*)dictionary_lookup(&characters, character); @@ -1531,6 +1802,9 @@ int s_swf3action(char*name, char*action) 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; @@ -1551,8 +1825,6 @@ void s_outline(char*name, char*format, char*source) outline->shape = shape; outline->bbox = bounds; - if(dictionary_lookup(&outlines, name)) - syntaxerror("outline %s defined twice", name); dictionary_put2(&outlines, name, outline); } @@ -1706,28 +1978,28 @@ void s_endClip() currentdepth++; } -void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move) -{ - SWFPLACEOBJECT po; - FILTERLIST flist; - swf_GetPlaceObject(NULL, &po); - po.id = id; - po.depth = depth; - po.matrix = m; - po.cxform = p->cxform; - po.name = name; - po.move = move; - if(move) - po.id = 0; - if(p->blendmode) { - po.blendmode = p->blendmode; - } - if(p->filter) { - flist.num = 1; - flist.filter[0] = p->filter; - po.filters = &flist; - } - swf_SetPlaceObject(tag, &po); +void setStartparameters(instance_t* i, parameters_t* p, TAG* tag) +{ + 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->filter); } void s_put(char*instance, char*character, parameters_t p) @@ -1735,228 +2007,104 @@ void s_put(char*instance, char*character, parameters_t p) character_t* c = dictionary_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->character->size, &p); - if(p.blendmode || p.filter) { - 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"); + if(p.blendmode || p.filter) + { + 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); } - tag = swf_InsertTag(tag, ST_PLACEOBJECT3); - } else { - tag = swf_InsertTag(tag, ST_PLACEOBJECT2); - } + else + tag = swf_InsertTag(tag, ST_PLACEOBJECT2); setPlacement(tag, c->id, currentdepth, m, instance, &p, 0); - + setStartparameters(i, &p, tag); i->lastTag = tag; i->lastFrame = currentframe; 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); } - - i->parameters = p; - m = s_instancepos(i->character->size, &p); - - if(p.blendmode || p.filter) { - tag = swf_InsertTag(tag, ST_PLACEOBJECT3); - } else { - tag = swf_InsertTag(tag, ST_PLACEOBJECT2); + 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); } - setPlacement(tag, 0, i->depth, m, 0, &p, 1); - - i->lastTag = tag; - i->lastFrame = currentframe; -} - -RGBA interpolateColor(RGBA c1, RGBA c2, float ratio) -{ - RGBA c; - c.r = c1.r * (1-ratio) + c2.r * ratio; - c.g = c1.g * (1-ratio) + c2.g * ratio; - c.b = c1.b * (1-ratio) + c2.b * ratio; - c.a = c1.a * (1-ratio) + c2.a * ratio; - return c; -} - -FILTER* interpolateFilter(FILTER*filter1,FILTER*filter2, float ratio) -{ - if(!filter1 && !filter2) - return 0; - if(!filter1) - return interpolateFilter(filter2,filter1,1-ratio); - - if(filter2 && filter2->type != filter1->type) - syntaxerror("can't interpolate between %s and %s filters yet", filtername[filter1->type], filtername[filter2->type]); - - if(filter1->type == FILTERTYPE_BLUR) { - FILTER_BLUR*f1 = (FILTER_BLUR*)filter1; - FILTER_BLUR*f2 = (FILTER_BLUR*)filter2; - if(f2 && f1->blurx == f2->blurx && f1->blury == f2->blury) - return 0; - FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR); - f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio; - f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio; - f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio; - return (FILTER*)f; - } else if (filter1->type == FILTERTYPE_DROPSHADOW) { - FILTER_DROPSHADOW*f1 = (FILTER_DROPSHADOW*)filter1; - FILTER_DROPSHADOW*f2 = (FILTER_DROPSHADOW*)filter2; - if(f2 && !memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength && - f1->blurx == f2->blurx && f1->blury == f2->blury && - f1->angle == f2->angle && f1->distance == f2->distance) - return 0; - FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW); - memcpy(f, f1, sizeof(FILTER_DROPSHADOW)); - f->color = interpolateColor(f1->color, f2->color, ratio); - f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio; - f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio; - f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio; - f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio; - f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio; - f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio; - return (FILTER*)f; - } else if (filter1->type == FILTERTYPE_BEVEL) { - FILTER_BEVEL*f1 = (FILTER_BEVEL*)filter1; - FILTER_BEVEL*f2 = (FILTER_BEVEL*)filter2; - if(f2 && !memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) && - !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) && - f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance) - return 0; - FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL); - memcpy(f, f1, sizeof(FILTER_BEVEL)); - f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio); - f->highlight = interpolateColor(f1->highlight, f2->highlight, ratio); - f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio; - f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio; - f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio; - f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio; - f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio; - f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio; - return (FILTER*)f; - } /*else if (filter1->type == FILTERTYPE_GRADIENTGLOW) { - FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW); - // can't interpolate gradients - memcpy(f, filter1, sizeof(FILTER_GRADIENTGLOW)); - return (FILTER*)f; - }*/ else { - syntaxerror("can't interpolate %s filters yet", filtername[filter1->type]); + 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); } - return 0; + 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.filter, inter); } -parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num) +void s_jump(char* instance, parameters_t p) { - 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; - - p.filter = interpolateFilter(p1->filter, p2->filter, ratio); - return p; + instance_t* i = dictionary_lookup(&instances, instance); + if(!i) + syntaxerror("instance %s not known", instance); + recordChanges(i->history, p, CF_JUMP, 0); } -void s_change(char*instance, parameters_t p2) +void s_change(char*instance, parameters_t p2, interpolation_t* inter) { 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->character->size, &p2); - if(p2.blendmode || p2.filter) { - tag = swf_InsertTag(tag, ST_PLACEOBJECT3); - } else { - tag = swf_InsertTag(tag, ST_PLACEOBJECT2); - } - setPlacement(tag, 0, i->depth, m, 0, &p2, 1); - i->parameters = p2; - - /* o.k., we got the start and end point set. Now iterate though all the - 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->character->size, &p); //needed? - - i->lastFrame = currentframe; - if(p.blendmode || p.filter) { - lt = swf_InsertTag(t, ST_PLACEOBJECT3); - } else { - lt = swf_InsertTag(t, ST_PLACEOBJECT2); - } - setPlacement(lt, 0, i->depth, m, 0, &p, 1); - t = lt; - if(frame == allframes) - break; - } - t = t->next; - if(!t) - syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes); - } + if(!i) + syntaxerror("instance %s not known", instance); + recordChanges(i->history, p2, CF_CHANGE, inter); } void s_delinstance(char*instance) { instance_t* i = dictionary_lookup(&instances, instance); - if(!i) { - syntaxerror("instance %s not known", instance); - } + if(!i) + syntaxerror("instance %s not known", instance); tag = swf_InsertTag(tag, ST_REMOVEOBJECT2); swf_SetU16(tag, i->depth); dictionary_del(&instances, instance); @@ -1964,21 +2112,33 @@ void s_delinstance(char*instance) void s_qchange(char*instance, parameters_t p) { + instance_t* i = dictionary_lookup(&instances, instance); + if(!i) + syntaxerror("instance %s not known", instance); + recordChanges(i->history, p, CF_QCHANGE, 0); } 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 if(stack[stackpos-1].type == 3) - s_endButton(); - 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"); + } } // ------------------------------------------------------------------------ @@ -2062,12 +2222,17 @@ int parseTwip(char*str) char*s; *dot++ = 0; for(s=str;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(*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; @@ -2326,6 +2491,34 @@ static dictionary_t points; static mem_t mpoints; int points_initialized = 0; +static int c_interpolation(map_t *args) +{ + int i; + char* name = lu(args, "name"); + if (dictionary_lookup(&interpolations, name)) + syntaxerror("interpolation %s defined twice", name); + + interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t)); + 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 = parseFloat(lu(args, "amplitude")); + inter->growth = parseFloat(lu(args, "growth")); + inter->bounces = parseInt(lu(args, "bounces")); + inter->damping = parseInt(lu(args, "damping")); + + dictionary_put2(&interpolations, name, inter); + return 0; +} + SPOINT getPoint(SRECT r, char*name) { int l=0; @@ -2422,7 +2615,10 @@ static int c_gradient(map_t*args) readToken(); if(type != RAWDATA) - syntaxerror("colon (:) expected"); + syntaxerror("colon (:) expected"); + + if(dictionary_lookup(&gradients, name)) + syntaxerror("gradient %s defined twice", name); s_gradient(name, text, radial, rotate); @@ -2587,13 +2783,12 @@ static int c_stop(map_t*args) { char*name = map_lookup(args, "name"); - if(s_playsound(name, 0,0,1)) { - return 0; - } else if(s_swf3action(name, "stop")) { - return 0; - } + 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; + return 0; } static int c_nextframe(map_t*args) @@ -2640,7 +2835,7 @@ static int c_placement(map_t*args, int type) char* pinstr = lu(args, "pin"); char* as = map_lookup(args, "as"); char* blendmode = lu(args, "blend"); - char*filterstr = lu(args, "filter"); + char* filterstr = lu(args, "filter"); U8 blend; MULADD r,g,b,a; float oldwidth; @@ -2648,25 +2843,32 @@ static int c_placement(map_t*args, int type) SRECT oldbbox; MULADD luminance; parameters_t p; + U32 set = 0x00000000; - if(type==9) { // (?) .rotate or .arcchange - 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) { @@ -2682,159 +2884,216 @@ static int c_placement(map_t*args, int type) } /* 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 == 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); + } + set = set | SF_X; + } + 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); + } + 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; - } - 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; - } - 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(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; } - 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(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); + 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; } - p.blendmode = blend; - } - if(filterstr[0]) { - FILTER*f = dictionary_lookup(&filters, filterstr); - if(!f) - syntaxerror("Unknown filter %s", filterstr); - p.filter = f; - } - - - if(type == 0) - s_put(instance, character, p); - else if(type == 1) - s_change(instance, p); - else if(type == 2) - s_qchange(instance, p); - else if(type == 3) - s_jump(instance, p); - else if(type == 4) - s_startclip(instance, character, p); - else if(type == 5) { - if(as && as[0]) { - s_buttonput(character, as, p); - } else { - s_buttonput(character, "shape", p); - } + if(filterstr[0]) + { + FILTER*f = dictionary_lookup(&filters, filterstr); + if(!f) + syntaxerror("Unknown filter %s", filterstr); + p.filter = f; + set = set | SF_FILTER; } + + p.set = set; + + switch (type) + { + case 0: + s_put(instance, character, p); + break; + case 1: + { + char* interstr = lu(args, "interpolation"); + interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr); + if (!inter) + syntaxerror("unkown interpolation %s", interstr); + s_change(instance, p, inter); + } + break; + case 2: + s_qchange(instance, p); + break; + case 3: + s_jump(instance, p); + break; + case 4: + s_startclip(instance, character, p); + break; + case 5: + if(as && as[0]) + s_buttonput(character, as, p); + else + s_buttonput(character, "shape", p); + break; +// default: + } return 0; } static int c_put(map_t*args) @@ -2844,6 +3103,8 @@ static int c_put(map_t*args) } static int c_change(map_t*args) { + if (currentframe == 0) + warning("change commands in frame 1 will be ignored, please use the put command to set object parameters"); c_placement(args, 1); return 0; } @@ -2988,7 +3249,17 @@ static int c_font(map_t*args) { char*name = lu(args, "name"); char*filename = lu(args, "filename"); - s_font(name, filename); + fontData* usage = getFontData(name); + char* glyphs = usage->glyphs; + if (usage->needsAll) + glyphs = ""; + else + if (usage->notUsed) + { + printf("font %s was defined but not used\n", name); + return 0; + } + s_font(name, filename, glyphs); return 0; } @@ -3293,11 +3564,12 @@ static struct { {"font", c_font, "name filename"}, {"soundtrack", c_soundtrack, "filename"}, {"quicktime", c_quicktime, "url"}, - + // generators of primitives {"point", c_point, "name x=0 y=0"}, {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture + {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5, damping=2"}, {"outline", c_outline, "name format=simple"}, {"textshape", c_textshape, "name font size=100% text"}, @@ -3333,7 +3605,7 @@ static struct { // object placement tags {"put", c_put, " 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, " x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="}, - {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="}, + {"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="}, {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="}, {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="}, -- 1.7.10.4