+ TAG*tag;
+ int t;
+ SRECT box;
+ int fileversion = 1;
+ int frameRate = 256;
+ RGBA rgb;
+ rgb.r=rgb.b=rgb.g=0;
+ memset(&box, 0, sizeof(box));
+
+ /* scan all slaves for bounding box */
+ for(t=numslaves-1;t>=0;t--)
+ {
+ SWF head;
+ int ret;
+ int fi=open(slave_filename[t],O_RDONLY|O_BINARY);
+ TAG*tag;
+ if(fi<0 || swf_ReadSWF(fi, &head)<0) {
+ msg("<fatal> Couldn't open/read %s.", slave_filename[t]);
+ exit(1);
+ }
+ close(fi);
+ msg("<verbose> File %s has bounding box %d:%d:%d:%d\n",
+ slave_filename[t],
+ head.movieSize.xmin, head.movieSize.ymin,
+ head.movieSize.xmax, head.movieSize.ymax);
+
+ tag = head.firstTag;
+ while(tag) {
+ if(tag->id == ST_SETBACKGROUNDCOLOR && tag->len>=3) {
+ rgb.r = tag->data[0];
+ rgb.g = tag->data[1];
+ rgb.b = tag->data[2];
+ }
+ tag=tag->next;
+ }
+ frameRate = head.frameRate;
+ if(head.fileVersion > fileversion)
+ fileversion = head.fileVersion;
+ if(!t)
+ box = head.movieSize;
+ else {
+ if(head.movieSize.xmin < box.xmin)
+ box.xmin = head.movieSize.xmin;
+ if(head.movieSize.ymin < box.ymin)
+ box.ymin = head.movieSize.ymin;
+ if(head.movieSize.xmax > box.xmax)
+ box.xmax = head.movieSize.xmax;
+ if(head.movieSize.ymax > box.ymax)
+ box.ymax = head.movieSize.ymax;
+ }
+ msg("<verbose> New master bounding box is %d:%d:%d:%d\n",
+ box.xmin, box.ymin,
+ box.xmax, box.ymax);
+ swf_FreeTags(&head);
+ }
+
+ memset(swf, 0, sizeof(SWF));
+ swf->fileVersion = fileversion;
+ swf->movieSize = box;
+ swf->frameRate = frameRate;
+
+ swf->firstTag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
+ tag = swf->firstTag;
+ swf_SetRGB(tag, &rgb);
+
+ for(t=0;t<numslaves;t++)
+ {
+ char buf[128];
+ sprintf(buf, "Frame%02d", t);
+ slave_name[t] = strdup(buf);
+
+ tag = swf_InsertTag(tag, ST_DEFINESPRITE);
+ swf_SetU16(tag, t+1);
+ swf_SetU16(tag, 0);
+ tag = swf_InsertTag(tag, ST_END);
+ tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
+ swf_ObjectPlace(tag, t+1, 1+t,0,0, slave_name[t]);
+
+ if(!config.stack1 || t == numslaves-1) {
+ tag = swf_InsertTag(tag, ST_SHOWFRAME);
+ }
+ if(!config.stack)
+ if(t!=numslaves-1)
+ {
+ tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
+ swf_SetU16(tag, 1+t);
+ }
+ }
+ tag = swf_InsertTag(tag, ST_END);
+ msg("<verbose> temporary SWF created");
+}
+
+static char* slavename = 0;
+static int slaveid = -1;
+static int slaveframe = -1;
+static char masterbitmap[65536];
+
+#define FLAGS_WRITEDEFINES 1
+#define FLAGS_WRITENONDEFINES 2
+#define FLAGS_WRITESPRITE 4
+#define FLAGS_WRITESLAVE 8
+
+int get_free_id(char*bitmap)
+{
+ int t;
+ for(t=1;t<65536;t++)
+ if(!bitmap[t]) {
+ bitmap[t] = 1;
+ return t;
+ }
+ return -1;
+}
+
+void jpeg_assert(SWF*master, SWF*slave)
+{
+ /* TODO: if there's a jpegtable found, store it
+ and handle it together with the flash file
+ headers */
+
+ /* check that master and slave don't have both
+ jpegtables (which would be fatal) */
+ int pos;
+ TAG *mpos=0, *spos=0;
+ TAG *mtag,*stag;
+ pos = 0;
+ mtag = master->firstTag;
+ stag = slave->firstTag;
+ while(mtag)
+ {
+ if(mtag->id == ST_JPEGTABLES)
+ mpos = mtag;
+ mtag = mtag->next;
+ }
+ while(stag)
+ {
+ if(stag->id == ST_JPEGTABLES)
+ spos = stag;
+ stag = stag->next;
+ }
+ if(mpos && spos)
+ {
+ if(spos->len == mpos->len &&
+ !memcmp(spos->data, mpos->data, mpos->len))
+ {
+ // ok, both have jpegtables, but they're identical.
+ // delete one and don't throw an error
+ swf_DeleteTag(spos);
+ spos = 0;
+ }
+ }
+ if(spos && mpos) {
+ msg("<error> Master and slave have incompatible JPEGTABLES.");
+ }
+}
+
+TAG* write_sprite_defines(TAG*tag, SWF*sprite)
+{
+ TAG*rtag = sprite->firstTag;
+ while(rtag && rtag->id!=ST_END) {
+ if(!swf_isAllowedSpriteTag(rtag)) {
+ msg("<debug> processing sprite tag %02x", tag->id);
+ if(swf_isDefiningTag(rtag))
+ {
+ msg("<debug> [sprite defs] write tag %02x (%d bytes in body)",
+ tag->id, tag->len);
+ tag = swf_InsertTag(tag, rtag->id);
+ swf_SetBlock(tag, rtag->data, rtag->len);
+ }
+ else if(swf_isPseudoDefiningTag(rtag))
+ {
+ msg("<debug> [sprite defs] write tag %02x (%d bytes in body)",
+ tag->id, tag->len);
+ tag = swf_InsertTag(tag, rtag->id);
+ swf_SetBlock(tag, rtag->data, rtag->len);
+ }
+ else {
+ switch(rtag->id)
+ {
+ case ST_JPEGTABLES:
+ /* if we get here, jpeg_assert has already run,
+ ensuring this is the only one of it's kind,
+ so we may safely write it out */
+ tag = swf_InsertTag(tag, rtag->id);
+ swf_SetBlock(tag, rtag->data, rtag->len);
+ break;
+ case ST_EXPORTASSETS:
+ msg("<debug> deliberately ignoring EXPORTASSETS tag");
+ break;
+ case ST_ENABLEDEBUGGER:
+ msg("<debug> deliberately ignoring ENABLEDEBUGGER tag");
+ break;
+ case ST_SETBACKGROUNDCOLOR:
+ msg("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
+ break;
+ case 40:
+ case 49:
+ case 51:
+ msg("<notice> found tag %d. This is a Generator template, isn't it?", tag->id);
+ break;
+ default:
+ msg("<notice> funny tag: %d is neither defining nor sprite", tag->id);
+ }
+ }
+ }
+ rtag = rtag->next;
+ }
+ return tag;
+}
+
+void changedepth(TAG*tag, int add)
+{
+ /* fucking byteorders */
+ if(tag->id == ST_PLACEOBJECT)
+ PUT16(&tag->data[2],GET16(&tag->data[2])+add);
+ if(tag->id == ST_PLACEOBJECT2)
+ PUT16(&tag->data[1],GET16(&tag->data[1])+add);
+ if(tag->id == ST_REMOVEOBJECT)
+ PUT16(&tag->data[2],GET16(&tag->data[2])+add);
+ if(tag->id == ST_REMOVEOBJECT2)
+ PUT16(&tag->data[0],GET16(&tag->data[0])+add);
+}
+
+void matrix_adjust(MATRIX*m, int movex, int movey, float scalex, float scaley, int scalepos)
+{
+ m->sx = (int)(m->sx*scalex);
+ m->sy = (int)(m->sy*scaley);
+ m->r1 = (int)(m->r1*scalex);
+ m->r0 = (int)(m->r0*scaley);
+ if(scalepos) {
+ m->tx *= scalex;
+ m->ty *= scaley;
+ }
+ m->tx += movex;
+ m->ty += movey;
+}
+
+void write_changepos(TAG*output, TAG*tag, int movex, int movey, float scalex, float scaley, int scalepos)
+{
+ if(movex || movey || scalex != 1 || scaley != 1)
+ {
+ switch(tag->id)
+ {
+ case ST_PLACEOBJECT2: {
+ MATRIX m;
+ U8 flags;
+ swf_GetMatrix(0, &m);
+ tag->pos = 0;
+ tag->readBit = 0;
+
+ flags = swf_GetU8(tag);
+ swf_SetU8(output, flags|4);
+ swf_SetU16(output, swf_GetU16(tag)); //depth
+ //flags&1: move
+ if(flags&2) {
+ swf_SetU16(output, swf_GetU16(tag)); //id
+ }
+ // flags & 4
+ if(flags&4) {
+ swf_GetMatrix(tag, &m);
+ } else {
+ swf_GetMatrix(0, &m);
+ }
+ matrix_adjust(&m, movex, movey, scalex, scaley, scalepos);
+ swf_SetMatrix(output, &m);
+
+ //swf_ResetReadBits(tag);
+ swf_SetBlock(output, &tag->data[tag->pos], tag->len - tag->pos);
+ break;
+ }
+ case ST_PLACEOBJECT: {
+ MATRIX m;
+ swf_SetU16(output, swf_GetU16(tag)); //id
+ swf_SetU16(output, swf_GetU16(tag)); //depth
+
+ swf_GetMatrix(tag, &m);
+ matrix_adjust(&m, movex, movey, scalex, scaley, scalepos);
+ swf_SetMatrix(output, &m);
+
+ //swf_ResetReadBits(tag);
+ swf_SetBlock(output, &tag->data[tag->pos], tag->len - tag->pos);
+ break;
+ }
+ default:
+ swf_SetBlock(output, tag->data, tag->len);
+ }
+ }
+ else
+ {
+ swf_SetBlock(output, tag->data, tag->len);
+ }
+}
+
+TAG* write_sprite(TAG*tag, SWF*sprite, int spriteid, int replaceddefine)
+{
+ TAG* definespritetag;
+ TAG* rtag;
+ int tmp;
+
+ definespritetag = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
+ swf_SetU16(tag, spriteid);
+ swf_SetU16(tag, sprite->frameCount);
+ msg ("<notice> sprite id is %d", spriteid);
+
+ tmp = sprite->frameCount;
+ msg("<debug> %d frames to go",tmp);
+
+ if(config.clip) {
+ tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
+ swf_SetU8(tag, 2+64); //flags: character+clipdepth
+ swf_SetU16(tag, 0); //depth
+ swf_SetU16(tag, replaceddefine); //id
+ swf_SetU16(tag, 65535); //clipdepth
+ }
+
+ if(config.overlay && !config.isframe) {
+ tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
+ swf_SetU8(tag, 2); //flags: character
+ swf_SetU16(tag, 1); //depth
+ swf_SetU16(tag, replaceddefine); //id
+ }
+
+ rtag = sprite->firstTag;
+ while(rtag && rtag->id!=ST_END)