3 functions for rendering swf content
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2004 Mederra Oy <http://www.mederra.fi>
9 Copyright (c) 2004 Matthias Kramm
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
27 typedef struct _dummyshape
31 struct _dummyshape*next;
38 typedef struct _renderpoint
52 enum {clip_type, solidfill_type, texturefill_type, gradientfill_type} type;
67 // texture- & gradientfill;
73 typedef struct _renderline
75 TAG*points; //incremented in 128 byte steps
78 typedef struct _bitmap {
86 typedef struct _renderbuf_internal
94 dummyshape_t*dshapes_next;
96 int background_width, background_height;
101 static void renderpoint_write(TAG*tag, renderpoint_t*p)
106 int num = GET32(tag->data);
107 PUT32(tag->data, num+1);
110 swf_SetBits(tag, p->type, 1);
111 swf_SetBits(tag, *(U32*)&p->x, 32);
112 if(p->depth & 0xffff) {
113 swf_SetBits(tag, 1, 1);
114 swf_SetBits(tag, p->depth, 32);
116 swf_SetBits(tag, 0, 1);
117 swf_SetBits(tag, p->depth >> 16, 16);
120 swf_SetBits(tag, 1, 1);
121 swf_SetBits(tag, *(U32*)&p->shapeline, 32);
123 swf_SetBits(tag, 0, 1);
126 if(p->type == clip_type) {
127 //printf("type=%d x=%f, depth=%08x, shapeline=%08x, clipdepth=%08x\n", p->type, p->x, p->depth, p->shapeline, p->clipdepth);
128 assert((p->clipdepth & 0xffff) == 0xffff);
129 swf_SetBits(tag, p->clipdepth >> 16, 16);
132 //printf("type=%d x=%f, depth=%08x, shapeline=%08x, s=%08x\n", p->type, p->x, p->depth, p->shapeline, p->s);
133 swf_SetBits(tag, *(U32*)&p->s, 32);
134 /* don't set clipdepth */
137 static renderpoint_t renderpoint_read(TAG*tag, int num)
143 p.type = swf_GetBits(tag, 1);
145 dummy = swf_GetBits(tag, 32);p.x = *(float*)&dummy;
146 flag = swf_GetBits(tag, 1);
148 p.depth = swf_GetBits(tag, 32);
150 p.depth = swf_GetBits(tag, 16) << 16;
152 flag = swf_GetBits(tag, 1);
154 dummy = swf_GetBits(tag, 32);p.shapeline = *(SHAPELINE**)&dummy;
159 if(p.type == clip_type) {
160 p.clipdepth = swf_GetBits(tag, 16) << 16 | 0xffff;
163 dummy = swf_GetBits(tag, 32);p.s = *(dummyshape_t**)&dummy;
170 static int renderpoint_num(TAG*tag)
174 return GET32(tag->data);
177 static renderpoint_t* renderpoint_readall(TAG*tag)
182 swf_SetTagPos(tag, 0);
186 num = swf_GetU32(tag);
187 p = (renderpoint_t*)rfx_alloc(num*sizeof(renderpoint_t));
189 p[t] = renderpoint_read(tag,t);
193 static inline void add_pixel(RENDERBUF*dest, float x, int y, renderpoint_t*p)
195 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
196 if(x >= i->width2 || y >= i->height2 || y<0) return;
199 renderpoint_write(i->lines[y].points, p);
201 renderpoint_write(i->lines[y].points, p);
204 /* set this to 0.777777 or something if the "both fillstyles set while not inside shape"
205 problem appears to often */
208 static void add_line(RENDERBUF*buf, double x1, double y1, double x2, double y2, renderpoint_t*p)
210 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
212 double ny1, ny2, stepx;
214 int l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
215 printf(" l[%d - %.2f/%.2f -> %.2f/%.2f]", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
242 ny1 = (int)(y1) + 1.0 + CUT;
245 ny2 = (int)(y2) - 1.0 + CUT;
252 x1 = x1 + (ny1-y1)*stepx;
253 x2 = x2 + (ny2-y2)*stepx;
262 float xx = (float)(startx + posx);
263 add_pixel(buf, xx ,posy, p);
269 #define PI 3.14159265358979
270 static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double y2, int width, renderpoint_t*p)
272 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
285 /* Make sure the line is always at least one pixel wide */
287 /* That's what Macromedia's Player does at least at zoom level >= 1. */
290 /* That's what Macromedia's Player seems to do at zoom level 0. */
291 /* TODO: needs testing */
296 sd = (double)dx*(double)dx+(double)dy*(double)dy;
318 add_line(buf, x1+vx, y1+vy, xx, yy, p);
321 for(t=1;t<segments;t++) {
322 double s = sin(t*PI/segments);
323 double c = cos(t*PI/segments);
324 xx = (x2 + vx*c - vy*s);
325 yy = (y2 + vx*s + vy*c);
326 add_line(buf, lastx, lasty, xx, yy, p);
333 add_line(buf, lastx, lasty, xx, yy, p);
338 add_line(buf, lastx, lasty, xx, yy, p);
341 for(t=1;t<segments;t++) {
342 double s = sin(t*PI/segments);
343 double c = cos(t*PI/segments);
344 xx = (x1 - vx*c + vy*s);
345 yy = (y1 - vx*s - vy*c);
346 add_line(buf, lastx, lasty, xx, yy, p);
350 add_line(buf, lastx, lasty, (x1+vx), (y1+vy), p);
353 static inline void transform_point(MATRIX*m, int x, int y, int*dx, int*dy)
358 d = swf_TurnPoint(p, m);
363 static int compare_renderpoints(const void * _a, const void * _b)
365 renderpoint_t*a = (renderpoint_t*)_a;
366 renderpoint_t*b = (renderpoint_t*)_b;
367 if(a->x < b->x) return -1;
368 if(a->x > b->x) return 1;
372 void swf_Render_Init(RENDERBUF*buf, int posx, int posy, int width, int height, char antialize, int multiply)
374 renderbuf_internal*i;
376 memset(buf, 0, sizeof(RENDERBUF));
377 buf->width = width*multiply;
378 buf->height = height*multiply;
381 buf->internal = (renderbuf_internal*)rfx_calloc(sizeof(renderbuf_internal));
382 i = (renderbuf_internal*)buf->internal;
383 i->antialize = !!antialize;
384 i->multiply = antialize?multiply*2:multiply;
385 i->height2 = antialize?2*buf->height:buf->height;
386 i->width2 = antialize?2*buf->width:buf->width;
387 i->lines = (renderline_t*)rfx_alloc(i->height2*sizeof(renderline_t));
388 for(y=0;y<i->height2;y++) {
389 i->lines[y].points = swf_InsertTag(0, 0);
392 void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height)
394 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
395 RGBA*bck = (RGBA*)rfx_alloc(sizeof(RGBA)*width*height);
396 memcpy(bck, img, sizeof(RGBA)*width*height);
398 i->background_width = width;
399 i->background_height = height;
401 void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color)
403 swf_Render_SetBackground(buf, &color, 1, 1);
405 void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height)
407 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
409 bitmap_t*bm = rfx_calloc(sizeof(bitmap_t));
413 bm->data = rfx_alloc(width*height*4);
414 memcpy(bm->data, img, width*height*4);
416 bm->next = i->bitmaps;
419 void swf_Render_ClearCanvas(RENDERBUF*dest)
421 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
423 for(y=0;y<i->height2;y++) {
424 swf_ClearTag(i->lines[y].points);
427 void swf_Render_Delete(RENDERBUF*dest)
429 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
431 bitmap_t*b = i->bitmaps;
432 dummyshape_t*d = i->dshapes;
435 free(i->background);i->background=0;
438 /* delete line buffers */
439 for(y=0;y<i->height2;y++) {
440 swf_DeleteTag(i->lines[y].points);
441 i->lines[y].points = 0;
445 dummyshape_t*next = d->next;
446 swf_Shape2Free(d->shape);
447 free(d->shape);d->shape=0;
455 bitmap_t*next = b->next;
456 free(b->data);b->data=0;
461 rfx_free(i->lines); i->lines = 0;
462 rfx_free(dest->internal); dest->internal = 0;
465 static void swf_Render_AddShape(RENDERBUF*dest,dummyshape_t*s)
467 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
471 i->dshapes_next->next = s;
478 static SHAPE2* linestyle2fillstyle(SHAPE2*shape)
480 SHAPE2*s = rfx_calloc(sizeof(SHAPE2));
482 s->numfillstyles = shape->numlinestyles;
483 s->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles);
484 s->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles);
485 for(t=0;t<shape->numlinestyles;t++) {
486 s->lines[t].fillstyle0 = t+1;
487 s->fillstyles[t].type = FILL_SOLID;
488 s->fillstyles[t].color = shape->linestyles[t].color;
493 void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth)
495 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
502 SHAPE2* s2 = swf_Shape2Clone(shape);
503 /* add this shape to the global shape list, for deallocing */
504 dummyshape_t*fshape = rfx_calloc(sizeof(dummyshape_t));
506 swf_Render_AddShape(dest, fshape);
511 memset(&p, 0, sizeof(renderpoint_t));
512 memset(&lp, 0, sizeof(renderpoint_t));
514 p.type = _clipdepth?clip_type:fill_type;
515 p.depth = _depth << 16;
516 p.clipdepth = _clipdepth? _clipdepth << 16 | 0xffff : 0;
518 mat.tx -= dest->posx*20;
519 mat.ty -= dest->posy*20;
522 if(shape->numfillstyles) {
525 /* multiply fillstyles matrices with placement matrix-
526 important for texture and gradient fill */
527 for(t=0;t<s2->numfillstyles;t++) {
529 swf_MatrixJoin(&nm, &s2->fillstyles[t].m, &mat); //TODO: is this the right order?
530 nm.sx *= i->multiply;
531 nm.sy *= i->multiply;
532 nm.r0 *= i->multiply;
533 nm.r1 *= i->multiply;
534 nm.tx *= i->multiply;
535 nm.ty *= i->multiply;
536 s2->fillstyles[t].m = nm;
541 if(shape->numlinestyles) {
542 dummyshape_t*dshape = rfx_calloc(sizeof(dummyshape_t));
544 lshape = linestyle2fillstyle(shape);
548 lp.depth = (_depth << 16)+1;
550 dshape->shape = lshape;
552 /* add this shape to the global shape list, for deallocing */
553 swf_Render_AddShape(dest, dshape);
559 add_line(dest, -20, 0, -20, i->height2*20, &p);
564 int x1,y1,x2,y2,x3,y3;
568 if(line->type == moveTo) {
569 } else if(line->type == lineTo) {
576 l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
577 printf("%d - %.2f/%.2f -> %.2f/%.2f ", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
580 transform_point(&mat, x, y, &x1, &y1);
581 transform_point(&mat, line->x, line->y, &x3, &y3);
583 if(line->linestyle && ! p.clipdepth) {
584 lp.shapeline = &lshape->lines[line->linestyle-1];
585 add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width, &lp);
588 if(line->fillstyle0 || line->fillstyle1) {
589 assert(shape->numfillstyles);
590 add_line(dest, x1, y1, x3, y3, &p);
593 if(DEBUG&4) printf("\n");
594 } else if(line->type == splineTo) {
595 int c,t,parts,qparts;
598 transform_point(&mat, x, y, &x1, &y1);
599 transform_point(&mat, line->sx, line->sy, &x2, &y2);
600 transform_point(&mat, line->x, line->y, &x3, &y3);
602 c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1);
606 parts = (int)(sqrt(c)/3);
607 if(!parts) parts = 1;
611 printf("spline %.2f/%.2f -(%.2f/%.2f)-> %.2f/%.2f (c=%d, %d parts)",
614 x3/20.0, y3/20.0, c, parts);
617 for(t=1;t<=parts;t++) {
618 double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts);
619 double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts);
621 if(line->linestyle && ! p.clipdepth) {
622 lp.shapeline = &lshape->lines[line->linestyle-1];
623 add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width, &lp);
626 if(line->fillstyle0 || line->fillstyle1) {
627 assert(shape->numfillstyles);
628 add_line(dest, (int)xx, (int)yy, (int)nx, (int)ny, &p);
643 typedef struct _layer {
655 static RGBA color_red = {255,255,0,0};
656 static RGBA color_white = {255,255,255,255};
658 static void fill_plain(RGBA*line, int x1, int x2, RGBA col)
662 int ainv = 255-col.a;
663 col.r = (col.r*col.a)>>8;
664 col.g = (col.g*col.a)>>8;
665 col.b = (col.b*col.a)>>8;
668 line[x].r = ((line[x].r*ainv)>>8)+col.r;
669 line[x].g = ((line[x].g*ainv)>>8)+col.g;
670 line[x].b = ((line[x].b*ainv)>>8)+col.b;
680 static void fill_bitmap(RGBA*line, int y, int x1, int x2, MATRIX*m, bitmap_t*b, int clip)
683 double m11=m->sx/65536.0, m21=m->r1/65536.0;
684 double m12=m->r0/65536.0, m22=m->sy/65536.0;
685 double rx = m->tx/20.0;
686 double ry = m->ty/20.0;
687 double det = m11*m22 - m12*m21;
688 if(fabs(det) < 0.0005) {
689 /* x direction equals y direction- the image is invisible */
694 if(!b->width || !b->height) {
695 fill_plain(line, x1, x2, color_red);
701 int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det);
702 int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
707 if(xx>=b->width) xx = b->width-1;
709 if(yy>=b->height) yy = b->height-1;
715 col = b->data[yy*b->width+xx];
718 line[x].r = ((line[x].r*ainv)>>8)+col.r;
719 line[x].g = ((line[x].g*ainv)>>8)+col.g;
720 line[x].b = ((line[x].b*ainv)>>8)+col.b;
725 static void fill(RENDERBUF*dest, RGBA*line, int y, int x1, int x2, state_t*clipstate, state_t*fillstate)
727 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
730 layer_t*lc = clipstate->layers;
731 layer_t*lf = fillstate->layers;
734 if(x1>=x2) //zero width? nothing to do.
739 if(lc && (!lf || lc->p->depth < lf->p->depth)) {
742 } else if(lf && (!lc || lf->p->depth < lc->p->depth)) {
745 } else if(lf && lc && lf->p->depth == lc->p->depth) {
746 /* A clipshape and a fillshape at the same depth. Yuck.
747 Bug in the SWF file */
748 fprintf(stderr, "Error: Multiple use of depth %d in SWF\n", lf->p->depth);
752 fprintf(stderr, "Internal error: %08x %08x\n", lc, lf);
753 if(lc) fprintf(stderr, " lc->depth = %08x\n", lc->p->depth);
754 if(lf) fprintf(stderr, " lf->depth = %08x\n", lf->p->depth);
757 if(l->p->depth <= clipdepth) {
758 if(DEBUG&2) printf("(clipped)");
761 if(l->fillid < 0 /*clip*/) {
762 if(DEBUG&2) printf("(add clip %d)", l->clipdepth);
763 if(l->clipdepth > clipdepth)
764 clipdepth = l->clipdepth;
765 } else if(l->fillid == 0) {
766 /* not filled. TODO: we should never add those in the first place */
768 printf("(not filled)");
769 } else if(l->fillid > l->p->s->shape->numfillstyles) {
770 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->shape->numlinestyles);
774 printf("(%d -> %d style %d)", x1, x2, l->fillid);
776 f = &l->p->s->shape->fillstyles[l->fillid-1];
778 if(f->type == FILL_SOLID) {
779 /* plain color fill */
780 fill_plain(line, x1, x2, f->color);
781 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
782 /* TODO: optimize (do this in add_pixel()?) */
783 bitmap_t* b = i->bitmaps;
784 while(b && b->id != f->id_bitmap) {
788 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
789 fill_plain(line, x1, x2, color_red);
791 //done in swf_RenderShape now
793 //m.tx -= dest->posx*20;
794 //m.ty -= dest->posy*20;
795 //m.sx *= i->multiply;
796 //m.sy *= i->multiply;
797 //m.r0 *= i->multiply;
798 //m.r1 *= i->multiply;
799 //m.tx *= i->multiply;
800 //m.ty *= i->multiply;
801 fill_bitmap(line, y, x1, x2, &f->m, b, FILL_CLIPPED?1:0);
808 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
810 layer_t*last=0,*l = state->layers;
811 while(l && l->p->depth < depth) {
816 if(l && l->p->depth == depth)
821 static void delete_layer(state_t*state, layer_t*todel)
823 layer_t*before=todel->prev;
824 layer_t*next = todel->next;
827 state->layers = next;
833 before->next->prev = before;
836 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
839 toadd->next = state->layers;
843 toadd->next = before->next;
844 toadd->prev = before;
845 before->next = toadd;
848 toadd->next->prev = toadd;
850 static void free_layers(state_t* state)
852 layer_t*l = state->layers;
854 layer_t*next = l->next;
860 static void change_state(int y, state_t* state, renderpoint_t*p)
862 layer_t*before=0, *self=0, *after=0;
865 printf("[%s(%d,%d)/%d/%d-%d]", p->type==clip_type?"C":"F", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
868 search_layer(state, p->depth, &before, &self, &after);
872 if(self->fillid<0 || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
873 /* filling/clipping ends */
874 if(DEBUG&2) printf("<D>");
876 delete_layer(state, self);
878 /*both fill0 and fill1 are set- exchange the two, updating the layer */
879 if(self->fillid == p->shapeline->fillstyle0) {
880 self->fillid = p->shapeline->fillstyle1;
883 if(DEBUG&2) printf("<X>");
884 } else if(self->fillid == p->shapeline->fillstyle1) {
885 self->fillid = p->shapeline->fillstyle0;
888 if(DEBUG&2) printf("<X>");
890 /* buggy shape. keep everything as-is. */
891 if(DEBUG&2) printf("<!>");
892 //fprintf(stderr, "<line %d: bad swap>\n", y);
898 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
899 /* this is a hack- a better way would be to make sure that
900 we always get (0,32), (32, 33), (33, 0) in the right order if
901 they happen to fall on the same pixel.
902 (not: (0,32), (33, 0), (32, 33))
904 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
908 n = rfx_calloc(sizeof(layer_t));
910 if(DEBUG&2) printf("<+>");
912 if(p->type == clip_type) {
915 n->clipdepth = p->clipdepth;
918 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
923 add_layer(state, before, n);
927 RGBA* swf_Render(RENDERBUF*dest)
929 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
930 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
933 RGBA * line1 = rfx_alloc(sizeof(RGBA)*i->width2);
934 RGBA * line2 = rfx_alloc(sizeof(RGBA)*i->width2);
936 for(y=0;y<i->height2;y++) {
937 TAG*tag = i->lines[y].points;
939 int num = renderpoint_num(tag);
940 renderpoint_t*points = renderpoint_readall(tag);
944 memset(&clipstate, 0, sizeof(state_t));
945 memset(&fillstate, 0, sizeof(state_t));
947 if((y&1) && i->antialize)
951 memset(line, 0, sizeof(RGBA)*i->width2);
954 int xstep=i->background_width*65536/i->width2;
955 RGBA*src = &i->background[(i->background_height*y/i->height2)*i->background_width];
956 for(x=0,xx=0;x<i->width2;x++,xx+=xstep) {
957 line[x] = src[xx>>16];
960 memory += tag->memsize;
961 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
963 renderpoint_t*p = &points[n];
964 renderpoint_t*next= n<num-1?&points[n+1]:0;
966 int endx = next?next->x:i->width2;
972 if(p->type == clip_type)
973 change_state(y, &clipstate, p);
975 change_state(y, &fillstate, p);
977 fill(dest, line, y, startx, endx, &clipstate, &fillstate);
978 if(endx == i->width2)
981 free_layers(&clipstate);
982 free_layers(&fillstate);
983 if(DEBUG&2) printf("\n");
986 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
990 RGBA* p = &img[(y/2)*dest->width];
991 for(x=0;x<dest->width;x++) {
992 RGBA*p1 = &line1[x*2];
993 RGBA*p2 = &line1[x*2+1];
994 RGBA*p3 = &line2[x*2];
995 RGBA*p4 = &line2[x*2+1];
996 p[x].r = (p1->r + p2->r + p3->r + p4->r)/4;
997 p[x].g = (p1->g + p2->g + p3->g + p4->g)/4;
998 p[x].b = (p1->b + p2->b + p3->b + p4->b)/4;
999 p[x].a = (p1->a + p2->a + p3->a + p4->a)/4;
1010 if(DEBUG) printf("\nMemory used: %d\n", memory);
1012 if(DEBUG) printf("Statistics:\n");
1013 if(DEBUG) printf("Average layer depth: %f\n", (double)layers/layernum);
1024 enum {none_type, shape_type, image_type, text_type, font_type} type;
1031 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1036 character_t* idtable = rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1037 SWFPLACEOBJECT** depthtable = rfx_calloc(sizeof(SWFPLACEOBJECT*)*65536); // depth to placeobject mapping
1039 /* set background color */
1040 RGBA color = swf_GetSWFBackgroundColor(swf);
1041 swf_Render_SetBackgroundColor(buf, color);
1043 /* parse definitions */
1044 tag = swf->firstTag;
1046 if(swf_isDefiningTag(tag)) {
1047 int id = swf_GetDefineID(tag);
1048 idtable[id].tag = tag;
1049 idtable[id].bbox = rfx_alloc(sizeof(SRECT));
1050 *idtable[id].bbox = swf_GetDefineBBox(tag);
1052 if(swf_isShapeTag(tag)) {
1053 SHAPE2* shape = rfx_calloc(sizeof(SHAPE2));
1054 swf_ParseDefineShape(tag, shape);
1055 idtable[id].type = shape_type;
1056 idtable[id].shape = shape;
1057 } else if(swf_isImageTag(tag)) {
1059 RGBA*data = swf_ExtractImage(tag, &width, &height);
1060 idtable[id].type = image_type;
1061 swf_Render_AddImage(buf, id, data, width, height);
1063 } else if(tag->id == ST_DEFINEFONT ||
1064 tag->id == ST_DEFINEFONT2) {
1065 //swf_FontExtract(swf,id,&idtable[id].font);
1066 idtable[id].font = 0;
1067 } else if(tag->id == ST_DEFINEFONTINFO ||
1068 tag->id == ST_DEFINEFONTINFO2) {
1069 idtable[id].type = font_type;
1070 } else if(tag->id == ST_DEFINETEXT ||
1071 tag->id == ST_DEFINETEXT2) {
1072 idtable[id].type = text_type;
1074 } else if(tag->id == ST_PLACEOBJECT ||
1075 tag->id == ST_PLACEOBJECT2) {
1076 SWFPLACEOBJECT* p = rfx_calloc(sizeof(SWFPLACEOBJECT));
1077 swf_GetPlaceObject(tag, p);
1078 /* TODO: add move and deletion */
1079 depthtable[p->depth] = p;
1084 for(t=65535;t>=0;t--) if(depthtable[t]) {
1085 SWFPLACEOBJECT*p = depthtable[t];
1088 if(!idtable[id].tag) {
1089 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1093 if(idtable[id].type == shape_type) {
1094 SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1095 swf_RenderShape(buf, idtable[id].shape, &p->matrix, &p->cxform, p->depth, p->clipdepth);
1096 } else if(idtable[id].type == text_type) {
1099 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1103 /* free id and depth tables again */
1104 for(t=0;t<65536;t++) {
1105 if(idtable[t].bbox) {
1106 free(idtable[t].bbox);
1109 if(idtable[t].type == shape_type) {
1110 SHAPE2* shape = idtable[t].shape;
1112 swf_Shape2Free(shape); // FIXME
1113 free(idtable[t].shape);idtable[t].shape = 0;
1117 swf_PlaceObjectFree(depthtable[t]);
1118 free(depthtable[t]);depthtable[t] = 0;