3 Math and matrix functions, misc tools
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2000, 2001 Rainer Böhme <rfxswf@reflex-studio.de>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
24 // Matrix & Math tools for SWF files
27 SFIXED RFXSWF_SP(SFIXED a1,SFIXED a2,SFIXED b1,SFIXED b2)
28 { S64 a = ((S64)a1*(S64)b1+(S64)a2*(S64)b2)>>16;
29 SFIXED result = (SFIXED)(a);
31 fprintf(stderr, "Warning: overflow in matrix multiplication");
34 SFIXED RFXSWF_QFIX(int zaehler,int nenner) // bildet Quotient von zwei INTs in SFIXED
35 { S64 z = zaehler<<16;
36 S64 a = z/(S64)nenner;
41 MATRIX * swf_MatrixJoin(MATRIX * d,MATRIX * s1,MATRIX * s2)
44 if (!s1) return (s2)?(MATRIX *)memcpy(d,s2,sizeof(MATRIX)):NULL;
45 if (!s2) return (MATRIX *)memcpy(d,s1,sizeof(MATRIX));
47 d->tx = s1->tx + RFXSWF_SP(s1->sx,s1->r1,s2->tx,s2->ty);
48 d->ty = s1->ty + RFXSWF_SP(s1->r0,s1->sy,s2->tx,s2->ty);
50 d->sx = RFXSWF_SP(s1->sx,s1->r1,s2->sx,s2->r0);
51 d->r0 = RFXSWF_SP(s1->r0,s1->sy,s2->sx,s2->r0);
53 d->r1 = RFXSWF_SP(s1->sx,s1->r1,s2->r1,s2->sy);
54 d->sy = RFXSWF_SP(s1->r0,s1->sy,s2->r1,s2->sy);
61 MATRIX * swf_MatrixMapTriangle(MATRIX * m,int dx,int dy,int x0,int y0,
62 int x1,int y1,int x2,int y2)
69 if ((!dx)||(!dy)) return NULL; // check DIV by zero
73 m->sx = RFXSWF_QFIX(dx1,dx);
74 m->sy = RFXSWF_QFIX(dy2,dy);
75 m->r0 = RFXSWF_QFIX(dy1,dx);
76 m->r1 = RFXSWF_QFIX(dx2,dy);
81 void swf_SetDefineID(TAG * tag, U16 newid)
83 int oldlen = tag->len;
85 swf_SetU16(tag, newid); /* set defining ID */
89 U16 swf_GetDefineID(TAG * t)
94 oldTagPos = swf_GetTagPos(t);
97 switch (swf_GetTagID(t))
98 { case ST_DEFINESHAPE:
100 case ST_DEFINESHAPE3:
101 case ST_DEFINESHAPE4:
102 case ST_DEFINEMORPHSHAPE:
103 case ST_DEFINEEDITTEXT:
105 case ST_DEFINEBITSJPEG2:
106 case ST_DEFINEBITSJPEG3:
107 case ST_DEFINEBITSLOSSLESS:
108 case ST_DEFINEBITSLOSSLESS2:
109 case ST_DEFINESCALINGGRID: //pseudodefine
110 case ST_DEFINEBUTTON:
111 case ST_DEFINEBUTTON2:
112 case ST_DEFINEBUTTONCXFORM: //pseudodefine
113 case ST_DEFINEBUTTONSOUND: //pseudodefine
114 case ST_CSMTEXTSETTINGS: //pseudodefine
118 case ST_DEFINEFONTINFO: //pseudodefine
119 case ST_DEFINEFONTINFO2: //pseudodefine
120 case ST_DEFINEFONTALIGNZONES: //pseudodefine
124 case ST_DEFINESPRITE:
126 case ST_DEFINEVIDEOSTREAM:
127 case ST_GLYPHNAMES: //pseudodefine
128 case ST_VIDEOFRAME: //pseudodefine
129 case ST_NAMECHARACTER: //pseudodefine
130 case ST_DOINITACTION: //pseudodefine
134 fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t));
137 swf_SetTagPos(t,oldTagPos);
142 SRECT swf_GetDefineBBox(TAG * t)
147 memset(&b1, 0, sizeof(b1));
149 oldTagPos = swf_GetTagPos(t);
154 switch (swf_GetTagID(t))
155 { case ST_DEFINESHAPE:
156 case ST_DEFINESHAPE2:
157 case ST_DEFINESHAPE3:
158 case ST_DEFINEEDITTEXT:
161 case ST_DEFINEVIDEOSTREAM:
165 case ST_DEFINEMORPHSHAPE:
169 swf_ExpandRect2(&b1, &b2);
171 case ST_DEFINEBITSLOSSLESS:
172 case ST_DEFINEBITSLOSSLESS2:
174 case ST_DEFINEBITSJPEG2:
175 case ST_DEFINEBITSJPEG3:
180 swf_SetTagPos(t,oldTagPos);
185 U16 swf_GetPlaceID(TAG * t)
190 oldTagPos = swf_GetTagPos(t);
193 switch (swf_GetTagID(t))
194 { case ST_PLACEOBJECT:
195 case ST_REMOVEOBJECT:
196 case ST_FREECHARACTER:
201 case ST_PLACEOBJECT2:
202 { U8 flags = swf_GetU8(t);
203 U16 d = swf_GetU16(t);
204 id = (flags&PF_CHAR)?swf_GetU16(t):id;
209 swf_SetTagPos(t,oldTagPos);
214 static int swf_definingtagids[] =
229 ST_DEFINEBITSLOSSLESS,
230 ST_DEFINEBITSLOSSLESS2,
236 ST_DEFINEVIDEOSTREAM,
240 // tags which may be used inside a sprite definition
241 static int swf_spritetagids[] =
246 ST_REMOVEOBJECT2, //?
257 /* tags which add content or information to a character with a given ID */
258 static int swf_pseudodefiningtagids[] =
262 ST_DEFINEFONTALIGNZONES,
263 ST_DEFINEBUTTONCXFORM,
264 ST_DEFINEBUTTONSOUND,
265 ST_DEFINESCALINGGRID,
274 U8 swf_isAllowedSpriteTag(TAG * tag)
278 while(swf_spritetagids[t]>=0)
280 if(swf_spritetagids[t] == id)
287 U8 swf_isDefiningTag(TAG * tag)
291 while(swf_definingtagids[t]>=0)
293 if(swf_definingtagids[t] == id)
300 U8 swf_isPseudoDefiningTag(TAG * tag)
304 while(swf_pseudodefiningtagids[t]>=0)
306 if(swf_pseudodefiningtagids[t] == id)
313 int swf_GetDepth(TAG * t)
317 oldTagPos = swf_GetTagPos(t);
320 switch (swf_GetTagID(t))
321 { case ST_PLACEOBJECT:
322 case ST_REMOVEOBJECT:
324 depth = swf_GetU16(t);
326 case ST_REMOVEOBJECT2:
327 depth = swf_GetU16(t);
329 case ST_PLACEOBJECT2:
330 { U8 flags = swf_GetU8(t);
331 depth = swf_GetU16(t);
335 depth = swf_GetU16(t);
338 swf_SetTagPos(t,oldTagPos);
342 void swf_SetDepth(TAG * t, U16 depth)
344 switch (swf_GetTagID(t))
345 { case ST_PLACEOBJECT:
346 case ST_REMOVEOBJECT:
347 PUT16(t->data, depth);
349 case ST_REMOVEOBJECT2:
350 PUT16(t->data, depth);
352 case ST_PLACEOBJECT2:
353 PUT16(&t->data[1], depth);
356 PUT16(t->data, depth);
359 fprintf(stderr, "rfxswf: Error: tag %d has no depth\n", t->id);
363 char* swf_GetName(TAG * t)
369 oldTagPos = swf_GetTagPos(t);
371 switch(swf_GetTagID(t))
374 name = &t->data[swf_GetTagPos(t)];
376 case ST_PLACEOBJECT3:
377 case ST_PLACEOBJECT2: {
378 U8 flags = swf_GetU8(t);
379 if(t->id == ST_PLACEOBJECT3)
381 swf_GetU16(t); //depth;
385 swf_GetMatrix(t, &m);
387 swf_GetCXForm(t, &c, 1);
390 if(flags&PF_CLIPACTION)
393 swf_ResetReadBits(t);
394 name = &t->data[swf_GetTagPos(t)];
399 swf_SetTagPos(t,oldTagPos);
403 /* used in enumerateUsedIDs */
404 void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2)
414 gradient2->num = swf_GetU8(tag);
415 for(t=0;t<gradient1->num;t++)
420 gradient1->ratios[t] = swf_GetU8(tag);
421 swf_GetRGBA(tag, &gradient1->rgba[t]);
422 gradient2->ratios[t] = swf_GetU8(tag);
423 swf_GetRGBA(tag, &gradient2->rgba[t]);
427 #define DEBUG_ENUMERATE if(0)
429 void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph)
433 count = swf_GetU8(tag);
434 if(count == 0xff && num>1) // defineshape2,3 only
435 count = swf_GetU16(tag);
441 swf_ResetReadBits(tag);
442 type = swf_GetU8(tag); //type
445 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
447 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
449 else if(type == 0x10 || type == 0x12 || type == 0x13)
451 swf_ResetReadBits(tag);
452 swf_GetMatrix(tag, NULL);
454 swf_GetMatrix(tag, NULL);
455 swf_ResetReadBits(tag);
457 swf_GetMorphGradient(tag, NULL, NULL);
459 swf_GetGradient(tag, NULL, /*alpha*/ num>=3?1:0);
461 else if(type == 0x40 || type == 0x41 || type == 0x42 || type == 0x43)
463 swf_ResetReadBits(tag);
465 if(tag->data[tag->pos] != 0xff ||
466 tag->data[tag->pos+1] != 0xff)
467 (callback)(tag, tag->pos, callback_data);
470 swf_ResetReadBits(tag);
471 swf_GetMatrix(tag, NULL);
473 swf_GetMatrix(tag, NULL);
476 fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x\n",type);
479 swf_ResetReadBits(tag);
480 count = swf_GetU8(tag); // line style array
482 count = swf_GetU16(tag);
489 {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);}
491 {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);}
495 void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), void*callback_data)
498 swf_ResetReadBits(tag);
502 case ST_DEFINEBUTTONSOUND: {
504 callback(tag, tag->pos + base, callback_data);
507 callback(tag, tag->pos + base, callback_data);
508 swf_GetU16(tag); //sound id
509 flags = swf_GetU8(tag);
511 swf_GetU32(tag); // in point
513 swf_GetU32(tag); // out points
515 swf_GetU16(tag); // loop count
518 int npoints = swf_GetU8(tag);
520 for(s=0;s<npoints;s++)
529 case ST_DEFINEBUTTONCXFORM:
530 callback(tag, tag->pos + base, callback_data); //button id
533 case ST_EXPORTASSETS: {
534 int num = swf_GetU16(tag);
537 callback(tag, tag->pos + base, callback_data); //button id
538 swf_GetU16(tag); //id
539 while(swf_GetU8(tag)); //name
543 case ST_IMPORTASSETS:
544 case ST_IMPORTASSETS2: {
545 swf_GetString(tag); //count
546 swf_GetU8(tag); //reserved
547 swf_GetU8(tag); //reserved
548 int num = swf_GetU16(tag); //url
551 callback(tag, tag->pos + base, callback_data); //button id
552 swf_GetU16(tag); //id
553 while(swf_GetU8(tag)); //name
557 case ST_FREECHARACTER: /* unusual tags, which all start with an ID */
558 case ST_NAMECHARACTER:
559 case ST_GENERATORTEXT:
560 callback(tag, tag->pos + base, callback_data);
563 callback(tag, tag->pos + base, callback_data);
565 case ST_PLACEOBJECT2:
566 // only if placeflaghascharacter
567 if(!(tag->data[0]&2))
569 callback(tag, 3 + base, callback_data);
571 case ST_PLACEOBJECT3:
572 // only if placeflaghascharacter
573 if(!(tag->data[0]&2))
575 callback(tag, 4 + base, callback_data);
577 case ST_REMOVEOBJECT:
578 callback(tag, tag->pos + base, callback_data);
581 callback(tag, tag->pos + base, callback_data);
583 case ST_DEFINESPRITE: {
585 break; // sprite is expanded
587 swf_GetU16(tag); // id
588 swf_GetU16(tag); // framenum
591 U16 flags = swf_GetU16(tag);
594 TAG *tag2 = swf_InsertTag(NULL, id);
597 len = swf_GetU32(tag);
600 tag2->len = tag2->memsize = len;
601 tag2->data = rfx_alloc(len);
602 memcpy(tag2->data, &tag->data[tag->pos], len);
603 /* I never saw recursive sprites, but they are (theoretically)
604 possible, so better add base here again */
605 enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data);
607 swf_GetBlock(tag, NULL, len);
611 case ST_DEFINEBUTTON2: // has some font ids in the button records
614 case ST_DEFINEBUTTON: {
615 swf_GetU16(tag); //button id
619 swf_GetU8(tag); //flag
620 offset = swf_GetU16(tag); //offset
625 if(!swf_GetU8(tag)) //flags
627 callback(tag, tag->pos + base, callback_data);
628 swf_GetU16(tag); //char
629 swf_GetU16(tag); //layer
630 swf_ResetReadBits(tag);
631 swf_GetMatrix(tag, NULL);
633 swf_ResetReadBits(tag);
634 swf_GetCXForm(tag, NULL, 1);
640 case ST_DEFINEEDITTEXT: {
642 swf_GetU16(tag); //id
643 swf_GetRect(tag, NULL); //bounding box
644 swf_ResetReadBits(tag);
645 flags1 = swf_GetU8(tag);
646 flags2 = swf_GetU8(tag);
648 callback(tag, tag->pos + base, callback_data);
653 case ST_DEFINETEXT: {
654 int glyphbits, advancebits;
656 id = swf_GetU16(tag); //id
657 swf_GetRect(tag, NULL); //bounding box
658 swf_ResetReadBits(tag);
659 swf_GetMatrix(tag, NULL); //matrix
660 swf_ResetReadBits(tag);
661 glyphbits = swf_GetU8(tag); //glyphbits
662 advancebits = swf_GetU8(tag); //advancebits
666 swf_ResetReadBits(tag);
667 flags = swf_GetBits(tag, 8);
670 swf_ResetReadBits(tag);
671 if(flags & 8) { // hasfont
672 callback(tag, tag->pos + base, callback_data);
673 id = swf_GetU16(tag);
675 if(flags & 4) { // hascolor
676 if(num==1) swf_GetRGB(tag, NULL);
677 else swf_GetRGBA(tag, NULL);
679 if(flags & 2) { //has x offset
680 swf_ResetReadBits(tag);
683 if(flags & 1) { //has y offset
684 swf_ResetReadBits(tag);
687 if(flags & 8) { //has height
688 swf_ResetReadBits(tag);
692 flags = swf_GetBits(tag, 8);
694 swf_ResetReadBits(tag);
695 for(t=0;t<flags;t++) {
696 swf_GetBits(tag, glyphbits);
697 swf_GetBits(tag, advancebits);
702 case ST_DEFINEFONTALIGNZONES:
703 case ST_DEFINESCALINGGRID:
705 case ST_CSMTEXTSETTINGS:
706 case ST_DEFINEFONTINFO:
707 case ST_DEFINEFONTINFO2:
709 callback(tag, tag->pos + base, callback_data);
711 case ST_DEFINEVIDEOSTREAM:
714 case ST_DOINITACTION:
715 callback(tag, tag->pos + base, callback_data);
718 case ST_DEFINEMORPHSHAPE:
719 case ST_DEFINESHAPE4:
721 case ST_DEFINESHAPE3:
723 case ST_DEFINESHAPE2:
725 case ST_DEFINESHAPE: {
731 if(tag->id == ST_DEFINEMORPHSHAPE) {
736 id = swf_GetU16(tag); // id;
737 swf_GetRect(tag, NULL); // shape bounds
739 swf_ResetReadBits(tag);
740 swf_GetRect(tag, NULL); // shape bounds2
742 swf_GetRect(tag, NULL); // edge bounds1
745 swf_GetRect(tag, NULL); // edge bounds
746 swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke
749 swf_GetU32(tag); //offset to endedges
752 DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id);
754 enumerateUsedIDs_styles(tag, callback, callback_data, num, morph);
755 DEBUG_ENUMERATE printf("-------\n");
756 while(--numshapes>=0) /* morph shapes define two shapes */
758 DEBUG_ENUMERATE printf("shape:%d\n", numshapes);
759 fillbits = swf_GetBits(tag, 4);
760 linebits = swf_GetBits(tag, 4);
761 DEBUG_ENUMERATE printf("%d %d\n", fillbits, linebits);
762 swf_ResetReadBits(tag);
765 flags = swf_GetBits(tag, 1);
766 if(!flags) { //style change
767 flags = swf_GetBits(tag, 5);
771 int n = swf_GetBits(tag, 5);
773 x = swf_GetBits(tag, n); //x
774 y = swf_GetBits(tag, n); //y
775 DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0);
777 if(flags&2) { //fill0
779 fill0 = swf_GetBits(tag, fillbits);
780 DEBUG_ENUMERATE printf("fill0 %d\n", fill0);
782 if(flags&4) { //fill1
784 fill1 = swf_GetBits(tag, fillbits);
785 DEBUG_ENUMERATE printf("fill1 %d\n", fill1);
787 if(flags&8) { //linestyle
789 line = swf_GetBits(tag, linebits);
790 DEBUG_ENUMERATE printf("linestyle %d\n",line);
793 DEBUG_ENUMERATE printf("more fillstyles\n");
794 enumerateUsedIDs_styles(tag, callback, callback_data, num, 0);
795 fillbits = swf_GetBits(tag, 4);
796 linebits = swf_GetBits(tag, 4);
799 flags = swf_GetBits(tag, 1);
800 if(flags) { //straight edge
801 int n = swf_GetBits(tag, 4) + 2;
802 if(swf_GetBits(tag, 1)) { //line flag
804 x = swf_GetSBits(tag, n); //delta x
805 y = swf_GetSBits(tag, n); //delta y
806 DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0);
808 int v=swf_GetBits(tag, 1);
810 d = swf_GetSBits(tag, n); //vert/horz
811 DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0);
813 } else { //curved edge
814 int n = swf_GetBits(tag, 4) + 2;
816 x1 = swf_GetSBits(tag, n);
817 y1 = swf_GetSBits(tag, n);
818 x2 = swf_GetSBits(tag, n);
819 y2 = swf_GetSBits(tag, n);
820 DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0);
832 void callbackCount(TAG * t,int pos, void*ptr)
835 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
838 void callbackFillin(TAG * t,int pos, void*ptr)
842 DEBUG_ENUMERATE printf("callback(%d) %d\n", pos, *(U16*)&t->data[pos]);
845 int swf_GetNumUsedIDs(TAG * t)
848 enumerateUsedIDs(t, 0, callbackCount, &num);
852 void swf_GetUsedIDs(TAG * t, int * positions)
854 int * ptr = positions;
855 enumerateUsedIDs(t, 0, callbackFillin, &ptr);
858 void swf_Relocate (SWF*swf, char*bitmap)
862 memset(slaveids, -1, sizeof(slaveids));
870 if(swf_isDefiningTag(tag))
875 id = swf_GetDefineID(tag); //own id
877 if(!bitmap[id]) { //free
882 for (t=1;t<65536;t++)
892 slaveids[id] = newid;
894 swf_SetDefineID(tag, newid);
897 num = swf_GetNumUsedIDs(tag);
899 ptr = rfx_alloc(sizeof(int)*num);
900 swf_GetUsedIDs(tag, ptr);
903 int id = GET16(&tag->data[ptr[t]]);
905 fprintf(stderr, "swf_Relocate: Mapping id (%d) never encountered before in %s\n", id,
906 swf_TagGetName(tag));
910 PUT16(&tag->data[ptr[t]], id);
918 void swf_Relocate2(SWF*swf, int*id2id)
923 if(swf_isDefiningTag(tag)) {
924 int id = swf_GetDefineID(tag);
927 swf_SetDefineID(tag, id);
930 int num = swf_GetNumUsedIDs(tag);
934 ptr = rfx_alloc(sizeof(int)*num);
935 swf_GetUsedIDs(tag, ptr);
937 int id = GET16(&tag->data[ptr[t]]);
940 PUT16(&tag->data[ptr[t]], id);
947 void swf_RelocateDepth(SWF*swf, char*bitmap)
952 for(nr=65535;nr>=0;nr--) {
956 // now nr is the highest used depth. So we start
957 // assigning depths at nr+1
963 /* TODO * clip depths
966 if(tag->id == ST_PLACEOBJECT2) {
968 swf_GetPlaceObject(tag, &obj);
970 int newdepth = obj.clipdepth+nr;
972 fprintf(stderr, "Couldn't relocate depths: too large values\n");
975 obj.clipdepth = newdepth;
976 swf_ResetTag(tag, ST_PLACEOBJECT2);
977 swf_SetPlaceObject(tag, &obj);
979 swf_PlaceObjectFree(&obj);
982 depth = swf_GetDepth(tag);
984 int newdepth = depth+nr;
986 fprintf(stderr, "Couldn't relocate depths: too large values\n");
989 swf_SetDepth(tag, newdepth);
995 U8 swf_isShapeTag(TAG*tag)
997 if(tag->id == ST_DEFINESHAPE ||
998 tag->id == ST_DEFINESHAPE2 ||
999 tag->id == ST_DEFINESHAPE3 ||
1000 tag->id == ST_DEFINESHAPE4)
1005 U8 swf_isPlaceTag(TAG*tag)
1007 if(tag->id == ST_PLACEOBJECT ||
1008 tag->id == ST_PLACEOBJECT2 ||
1009 tag->id == ST_PLACEOBJECT3)
1013 U8 swf_isTextTag(TAG*tag)
1015 if(tag->id == ST_DEFINETEXT ||
1016 tag->id == ST_DEFINETEXT2)
1021 U8 swf_isFontTag(TAG*tag)
1023 if(tag->id == ST_DEFINEFONT ||
1024 tag->id == ST_DEFINEFONT2 ||
1025 tag->id == ST_DEFINEFONTINFO)
1030 U8 swf_isImageTag(TAG*tag)
1032 if(tag->id == ST_DEFINEBITSJPEG ||
1033 tag->id == ST_DEFINEBITSJPEG2 ||
1034 tag->id == ST_DEFINEBITSJPEG3 ||
1035 tag->id == ST_DEFINEBITSLOSSLESS ||
1036 tag->id == ST_DEFINEBITSLOSSLESS2)
1041 TAG* swf_Concatenate (TAG*list1,TAG*list2)
1043 TAG*tag=0,*lasttag=0;
1045 char depthmap[65536];
1047 memset(bitmap, 0, sizeof(bitmap));
1048 memset(depthmap, 0, sizeof(depthmap));
1049 memset(&swf1, 0, sizeof(swf1));
1050 memset(&swf2, 0, sizeof(swf2));
1052 swf1.firstTag = list1;
1054 swf2.firstTag = list2;
1059 if(!swf_isDefiningTag(tag)) {
1060 int id = swf_GetDefineID(tag);
1063 if(tag->id == ST_PLACEOBJECT ||
1064 tag->id == ST_PLACEOBJECT2) {
1065 int depth = swf_GetDepth(tag);
1066 depthmap[depth] = 1;
1068 if(tag->id == ST_REMOVEOBJECT ||
1069 tag->id == ST_REMOVEOBJECT2) {
1070 int depth = swf_GetDepth(tag);
1071 depthmap[depth] = 0;
1076 swf_Relocate(&swf2, bitmap);
1077 swf_RelocateDepth(&swf2, depthmap);
1078 lasttag->next = swf2.firstTag;
1079 swf2.firstTag->prev = lasttag;
1081 return swf1.firstTag;
1084 static int tagHash(TAG*tag)
1087 unsigned int a = 0x6b973e5a;
1088 /* start at pos 2, as 0 and 1 are the id */
1089 for(t=2;t<tag->len;t++) {
1092 a += tag->data[t]*0xefbc35a5*b*(t+1);
1094 return a&0x7fffffff; //always return positive number
1097 void swf_Optimize(SWF*swf)
1099 const int hash_size = 131072;
1100 char* dontremap = rfx_calloc(sizeof(char)*65536);
1101 U16* remap = rfx_alloc(sizeof(U16)*65536);
1102 TAG* id2tag = rfx_calloc(sizeof(TAG*)*65536);
1103 TAG** hashmap = rfx_calloc(sizeof(TAG*)*hash_size);
1106 for(t=0;t<65536;t++) {
1112 tag = swf->firstTag;
1114 /* make sure we don't remap to this tag,
1115 as it might have different "helper tags"
1116 FIXME: a better way would be to compare
1117 the helper tags, too.
1119 if(swf_isPseudoDefiningTag(tag) &&
1120 tag->id != ST_NAMECHARACTER) {
1121 dontremap[swf_GetDefineID(tag)] = 1;
1125 tag = swf->firstTag;
1127 TAG*next = tag->next;
1130 int num = swf_GetNumUsedIDs(tag);
1131 int*positions = rfx_alloc(sizeof(int)*num);
1133 swf_GetUsedIDs(tag, positions);
1134 for(t=0;t<num;t++) {
1135 int id = GET16(&tag->data[positions[t]]);
1137 PUT16(&tag->data[positions[t]], id);
1139 rfx_free(positions);
1141 /* now look for previous tags with the same
1143 if(swf_isDefiningTag(tag)) {
1145 int id = swf_GetDefineID(tag);
1146 int hash = tagHash(tag);
1149 while((tag2 = hashmap[hash%hash_size])) {
1150 if(tag2 != (TAG*)0 && tag->len == tag2->len) {
1151 if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) {
1159 while(hashmap[hash%hash_size]) hash++;
1160 hashmap[hash%hash_size] = tag;
1162 /* we found two identical tags- remap one
1164 remap[id] = swf_GetDefineID(tag2);
1166 if(tag == swf->firstTag)
1167 swf->firstTag = next;
1169 } else if(swf_isPseudoDefiningTag(tag)) {
1170 int id = swf_GetDefineID(tag);
1172 /* if this tag was remapped, we don't
1173 need the helper tag anymore. Discard
1176 if(tag == swf->firstTag)
1177 swf->firstTag = next;
1184 rfx_free(dontremap);
1190 void swf_SetDefineBBox(TAG * tag, SRECT newbbox)
1194 swf_SetTagPos(tag,0);
1196 switch (swf_GetTagID(tag))
1198 case ST_DEFINESHAPE:
1199 case ST_DEFINESHAPE2:
1200 case ST_DEFINESHAPE3:
1201 case ST_DEFINEEDITTEXT:
1203 case ST_DEFINETEXT2:
1204 case ST_DEFINEVIDEOSTREAM: {
1205 U32 after_bbox_offset = 0, len;
1207 id = swf_GetU16(tag);
1208 swf_GetRect(tag, &b1);
1209 swf_ResetReadBits(tag);
1210 after_bbox_offset = tag->pos;
1211 len = tag->len - after_bbox_offset;
1213 memcpy(data, &tag->data[after_bbox_offset], len);
1216 swf_SetRect(tag, &newbbox);
1217 swf_SetBlock(tag, data, len);
1219 tag->pos = tag->readBit = 0;
1223 fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag));
1227 RGBA swf_GetSWFBackgroundColor(SWF*swf)
1229 TAG*t=swf->firstTag;
1231 color.r = color.b = color.g = 0;
1234 if(t->id == ST_SETBACKGROUNDCOLOR) {
1235 swf_SetTagPos(t, 0);
1236 color.r = swf_GetU8(t);
1237 color.g = swf_GetU8(t);
1238 color.b = swf_GetU8(t);