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
79 typedef struct _bitmap {
87 typedef struct _renderbuf_internal
95 dummyshape_t*dshapes_next;
101 } renderbuf_internal;
105 static inline void add_pixel(RENDERBUF*dest, float x, int y, renderpoint_t*p)
107 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
108 if(x >= i->width2 || y >= i->height2 || y<0) return;
110 if(y<i->ymin) i->ymin = y;
111 if(y>i->ymax) i->ymax = y;
114 swf_SetBlock(i->lines[y].points, (U8*)p, sizeof(renderpoint_t));
117 /* set this to 0.777777 or something if the "both fillstyles set while not inside shape"
118 problem appears to often */
121 static void add_line(RENDERBUF*buf, double x1, double y1, double x2, double y2, renderpoint_t*p)
123 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
125 double ny1, ny2, stepx;
127 int l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
128 printf(" l[%d - %.2f/%.2f -> %.2f/%.2f]", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
155 ny1 = (int)(y1) + 1.0 + CUT;
158 ny2 = (int)(y2) - 1.0 + CUT;
165 x1 = x1 + (ny1-y1)*stepx;
166 x2 = x2 + (ny2-y2)*stepx;
175 float xx = (float)(startx + posx);
176 add_pixel(buf, xx ,posy, p);
182 #define PI 3.14159265358979
183 static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double y2, int width, renderpoint_t*p)
185 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
198 /* Make sure the line is always at least one pixel wide */
200 /* That's what Macromedia's Player does at least at zoom level >= 1. */
203 /* That's what Macromedia's Player seems to do at zoom level 0. */
204 /* TODO: needs testing */
209 sd = (double)dx*(double)dx+(double)dy*(double)dy;
231 add_line(buf, x1+vx, y1+vy, xx, yy, p);
234 for(t=1;t<segments;t++) {
235 double s = sin(t*PI/segments);
236 double c = cos(t*PI/segments);
237 xx = (x2 + vx*c - vy*s);
238 yy = (y2 + vx*s + vy*c);
239 add_line(buf, lastx, lasty, xx, yy, p);
246 add_line(buf, lastx, lasty, xx, yy, p);
251 add_line(buf, lastx, lasty, xx, yy, p);
254 for(t=1;t<segments;t++) {
255 double s = sin(t*PI/segments);
256 double c = cos(t*PI/segments);
257 xx = (x1 - vx*c + vy*s);
258 yy = (y1 - vx*s - vy*c);
259 add_line(buf, lastx, lasty, xx, yy, p);
263 add_line(buf, lastx, lasty, (x1+vx), (y1+vy), p);
266 static inline void transform_point(MATRIX*m, int x, int y, int*dx, int*dy)
271 d = swf_TurnPoint(p, m);
276 static int compare_renderpoints(const void * _a, const void * _b)
278 renderpoint_t*a = (renderpoint_t*)_a;
279 renderpoint_t*b = (renderpoint_t*)_b;
280 if(a->x < b->x) return -1;
281 if(a->x > b->x) return 1;
285 void swf_Render_Init(RENDERBUF*buf, int posx, int posy, int width, int height, char antialize, int multiply)
287 renderbuf_internal*i;
289 memset(buf, 0, sizeof(RENDERBUF));
290 buf->width = width*multiply;
291 buf->height = height*multiply;
294 buf->internal = (renderbuf_internal*)rfx_calloc(sizeof(renderbuf_internal));
295 i = (renderbuf_internal*)buf->internal;
296 i->antialize = !!antialize;
297 i->multiply = antialize?multiply*2:multiply;
298 i->height2 = antialize?2*buf->height:buf->height;
299 i->width2 = antialize?2*buf->width:buf->width;
300 i->lines = (renderline_t*)rfx_alloc(i->height2*sizeof(renderline_t));
301 for(y=0;y<i->height2;y++) {
302 i->lines[y].points = swf_InsertTag(0, 0);
305 i->zbuf = (int*)rfx_calloc(sizeof(int)*i->width2*i->height2);
306 i->img = (RGBA*)rfx_calloc(sizeof(RGBA)*i->width2*i->height2);
308 i->ymin = 0x7fffffff;
309 i->ymax = -0x80000000;
311 void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height)
313 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
315 fprintf(stderr, "rfxswf: Warning: swf_Render_SetBackground() called after drawing shapes\n");
318 int xstep=width*65536/i->width2;
319 int ystep=height*65536/i->height2;
320 for(y=0,yy=0;y<i->height2;y++,yy+=ystep) {
321 RGBA*src = &img[(yy>>16) * width];
322 RGBA*line = &i->img[y * i->width2];
323 for(x=0,xx=0;x<i->width2;x++,xx+=xstep) {
324 line[x] = src[xx>>16];
328 void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color)
330 swf_Render_SetBackground(buf, &color, 1, 1);
332 void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height)
334 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
336 bitmap_t*bm = rfx_calloc(sizeof(bitmap_t));
340 bm->data = rfx_alloc(width*height*4);
341 memcpy(bm->data, img, width*height*4);
343 bm->next = i->bitmaps;
346 void swf_Render_ClearCanvas(RENDERBUF*dest)
348 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
350 for(y=0;y<i->height2;y++) {
351 swf_ClearTag(i->lines[y].points);
353 memset(i->zbuf, 0, sizeof(int)*i->width2*i->height2);
354 memset(i->img, 0, sizeof(RGBA)*i->width2*i->height2);
356 void swf_Render_Delete(RENDERBUF*dest)
358 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
360 bitmap_t*b = i->bitmaps;
361 dummyshape_t*d = i->dshapes;
367 /* delete line buffers */
368 for(y=0;y<i->height2;y++) {
369 swf_DeleteTag(i->lines[y].points);
370 i->lines[y].points = 0;
374 dummyshape_t*next = d->next;
375 swf_Shape2Free(d->shape);
376 free(d->shape);d->shape=0;
384 bitmap_t*next = b->next;
385 free(b->data);b->data=0;
390 rfx_free(i->lines); i->lines = 0;
391 rfx_free(dest->internal); dest->internal = 0;
394 static void swf_Render_AddShape(RENDERBUF*dest,dummyshape_t*s)
396 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
400 i->dshapes_next->next = s;
407 static SHAPE2* linestyle2fillstyle(SHAPE2*shape)
409 SHAPE2*s = rfx_calloc(sizeof(SHAPE2));
411 s->numfillstyles = shape->numlinestyles;
412 s->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles);
413 s->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles);
414 for(t=0;t<shape->numlinestyles;t++) {
415 s->lines[t].fillstyle0 = t+1;
416 s->fillstyles[t].type = FILL_SOLID;
417 s->fillstyles[t].color = shape->linestyles[t].color;
422 void swf_Process(RENDERBUF*dest);
424 void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth)
426 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
434 SHAPE2* s2 = swf_Shape2Clone(shape);
435 /* add this shape to the global shape list, for deallocing */
436 dummyshape_t*fshape = rfx_calloc(sizeof(dummyshape_t));
438 swf_Render_AddShape(dest, fshape);
442 memset(&p, 0, sizeof(renderpoint_t));
443 memset(&lp, 0, sizeof(renderpoint_t));
445 p.type = _clipdepth?clip_type:fill_type;
446 p.depth = _depth << 16;
447 p.clipdepth = _clipdepth? _clipdepth << 16 | 0xffff : 0;
449 mat.tx -= dest->posx*20;
450 mat.ty -= dest->posy*20;
453 if(shape->numfillstyles) {
456 /* multiply fillstyles matrices with placement matrix-
457 important for texture and gradient fill */
458 for(t=0;t<s2->numfillstyles;t++) {
460 swf_MatrixJoin(&nm, &s2->fillstyles[t].m, &mat); //TODO: is this the right order?
461 nm.sx *= i->multiply;
462 nm.sy *= i->multiply;
463 nm.r0 *= i->multiply;
464 nm.r1 *= i->multiply;
465 nm.tx *= i->multiply;
466 nm.ty *= i->multiply;
467 s2->fillstyles[t].m = nm;
472 if(shape->numlinestyles) {
473 dummyshape_t*dshape = rfx_calloc(sizeof(dummyshape_t));
475 lshape = linestyle2fillstyle(shape);
479 lp.depth = (_depth << 16)+1;
481 dshape->shape = lshape;
483 /* add this shape to the global shape list, for deallocing */
484 swf_Render_AddShape(dest, dshape);
490 add_line(dest, -20, 0, -20, i->height2*20, &p);
495 int x1,y1,x2,y2,x3,y3;
499 if(line->type == moveTo) {
500 } else if(line->type == lineTo) {
507 l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
508 printf("%d - %.2f/%.2f -> %.2f/%.2f ", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
511 transform_point(&mat, x, y, &x1, &y1);
512 transform_point(&mat, line->x, line->y, &x3, &y3);
514 if(line->linestyle && ! p.clipdepth) {
515 lp.shapeline = &lshape->lines[line->linestyle-1];
516 add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width, &lp);
519 if(line->fillstyle0 || line->fillstyle1) {
520 assert(shape->numfillstyles);
521 add_line(dest, x1, y1, x3, y3, &p);
524 if(DEBUG&4) printf("\n");
525 } else if(line->type == splineTo) {
526 int c,t,parts,qparts;
529 transform_point(&mat, x, y, &x1, &y1);
530 transform_point(&mat, line->sx, line->sy, &x2, &y2);
531 transform_point(&mat, line->x, line->y, &x3, &y3);
533 c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1);
537 parts = (int)(sqrt(c)/3);
538 if(!parts) parts = 1;
542 printf("spline %.2f/%.2f -(%.2f/%.2f)-> %.2f/%.2f (c=%d, %d parts)",
545 x3/20.0, y3/20.0, c, parts);
548 for(t=1;t<=parts;t++) {
549 double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts);
550 double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts);
552 if(line->linestyle && ! p.clipdepth) {
553 lp.shapeline = &lshape->lines[line->linestyle-1];
554 add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width, &lp);
557 if(line->fillstyle0 || line->fillstyle1) {
558 assert(shape->numfillstyles);
559 add_line(dest, (int)xx, (int)yy, (int)nx, (int)ny, &p);
575 static RGBA color_red = {255,255,0,0};
576 static RGBA color_white = {255,255,255,255};
578 static void fill_clip(RGBA*line, int*z, int x1, int x2, int depth)
588 static void fill_plain(RGBA*line, int*z, int x1, int x2, RGBA col, int depth)
592 int ainv = 255-col.a;
593 col.r = (col.r*col.a)>>8;
594 col.g = (col.g*col.a)>>8;
595 col.b = (col.b*col.a)>>8;
599 line[x].r = ((line[x].r*ainv)>>8)+col.r;
600 line[x].g = ((line[x].g*ainv)>>8)+col.g;
601 line[x].b = ((line[x].b*ainv)>>8)+col.b;
616 static void fill_bitmap(RGBA*line, int*z, int y, int x1, int x2, MATRIX*m, bitmap_t*b, int clipbitmap, int depth)
619 double m11=m->sx/65536.0, m21=m->r1/65536.0;
620 double m12=m->r0/65536.0, m22=m->sy/65536.0;
621 double rx = m->tx/20.0;
622 double ry = m->ty/20.0;
623 double det = m11*m22 - m12*m21;
624 if(fabs(det) < 0.0005) {
625 /* x direction equals y direction- the image is invisible */
630 if(!b->width || !b->height) {
631 fill_plain(line, z, x1, x2, color_red, depth);
638 int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det);
639 int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
644 if(xx>=b->width) xx = b->width-1;
646 if(yy>=b->height) yy = b->height-1;
652 col = b->data[yy*b->width+xx];
655 line[x].r = ((line[x].r*ainv)>>8)+col.r;
656 line[x].g = ((line[x].g*ainv)>>8)+col.g;
657 line[x].b = ((line[x].b*ainv)>>8)+col.b;
664 typedef struct _layer {
677 static void fill(RENDERBUF*dest, RGBA*line, int*zline, int y, int x1, int x2, state_t*clipstate, state_t*fillstate)
679 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
682 layer_t*lc = clipstate->layers;
683 layer_t*lf = fillstate->layers;
686 if(x1>=x2) //zero width? nothing to do.
691 if(lc && (!lf || lc->p->depth < lf->p->depth)) {
694 } else if(lf && (!lc || lf->p->depth < lc->p->depth)) {
697 } else if(lf && lc && lf->p->depth == lc->p->depth) {
698 /* A clipshape and a fillshape at the same depth. Yuck.
699 Bug in the SWF file */
700 fprintf(stderr, "Error: Multiple use of depth %d in SWF\n", lf->p->depth);
704 fprintf(stderr, "Internal error: %08x %08x\n", lc, lf);
705 if(lc) fprintf(stderr, " lc->depth = %08x\n", lc->p->depth);
706 if(lf) fprintf(stderr, " lf->depth = %08x\n", lf->p->depth);
709 if(l->p->depth <= clipdepth) {
710 if(DEBUG&2) printf("(clipped)");
713 if(l->fillid < 0 /*clip*/) {
714 if(DEBUG&2) printf("(add clip %d)", l->clipdepth);
715 if(l->clipdepth > clipdepth)
716 clipdepth = l->clipdepth;
717 } else if(l->fillid == 0) {
718 /* not filled. TODO: we should never add those in the first place */
720 printf("(not filled)");
721 } else if(l->fillid > l->p->s->shape->numfillstyles) {
722 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->shape->numlinestyles);
726 printf("(%d -> %d style %d)", x1, x2, l->fillid);
728 f = &l->p->s->shape->fillstyles[l->fillid-1];
730 if(l->p->clipdepth) {
731 fill_clip(line, zline, x1, x2, l->p->clipdepth);
732 } else if(f->type == FILL_SOLID) {
733 /* plain color fill */
734 fill_plain(line, zline, x1, x2, f->color, l->p->depth);
735 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
736 /* TODO: optimize (do this in add_pixel()?) */
737 bitmap_t* b = i->bitmaps;
738 while(b && b->id != f->id_bitmap) {
742 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
743 fill_plain(line, zline, x1, x2, color_red, l->p->depth);
745 //done in swf_RenderShape now
747 //m.tx -= dest->posx*20;
748 //m.ty -= dest->posy*20;
749 //m.sx *= i->multiply;
750 //m.sy *= i->multiply;
751 //m.r0 *= i->multiply;
752 //m.r1 *= i->multiply;
753 //m.tx *= i->multiply;
754 //m.ty *= i->multiply;
755 fill_bitmap(line, zline, y, x1, x2, &f->m, b, FILL_CLIPPED?1:0, l->p->depth);
762 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
764 layer_t*last=0,*l = state->layers;
765 while(l && l->p->depth < depth) {
770 if(l && l->p->depth == depth)
775 static void delete_layer(state_t*state, layer_t*todel)
777 layer_t*before=todel->prev;
778 layer_t*next = todel->next;
781 state->layers = next;
787 before->next->prev = before;
790 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
793 toadd->next = state->layers;
797 toadd->next = before->next;
798 toadd->prev = before;
799 before->next = toadd;
802 toadd->next->prev = toadd;
804 static void free_layers(state_t* state)
806 layer_t*l = state->layers;
808 layer_t*next = l->next;
814 static void change_state(int y, state_t* state, renderpoint_t*p)
816 layer_t*before=0, *self=0, *after=0;
819 printf("[%s(%d,%d)/%d/%d-%d]", p->type==clip_type?"C":"F", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
822 search_layer(state, p->depth, &before, &self, &after);
826 if(self->fillid<0 || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
827 /* filling/clipping ends */
828 if(DEBUG&2) printf("<D>");
830 delete_layer(state, self);
832 /*both fill0 and fill1 are set- exchange the two, updating the layer */
833 if(self->fillid == p->shapeline->fillstyle0) {
834 self->fillid = p->shapeline->fillstyle1;
837 if(DEBUG&2) printf("<X>");
838 } else if(self->fillid == p->shapeline->fillstyle1) {
839 self->fillid = p->shapeline->fillstyle0;
842 if(DEBUG&2) printf("<X>");
844 /* buggy shape. keep everything as-is. */
845 if(DEBUG&2) printf("<!>");
846 //fprintf(stderr, "<line %d: bad swap>\n", y);
852 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
853 /* this is a hack- a better way would be to make sure that
854 we always get (0,32), (32, 33), (33, 0) in the right order if
855 they happen to fall on the same pixel.
856 (not: (0,32), (33, 0), (32, 33))
858 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
862 n = rfx_calloc(sizeof(layer_t));
864 if(DEBUG&2) printf("<+>");
866 if(p->type == clip_type) {
869 n->clipdepth = p->clipdepth;
872 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
877 add_layer(state, before, n);
881 void swf_Process(RENDERBUF*dest)
883 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
886 for(y=i->ymin;y<i->ymax;y++) {
888 TAG*tag = i->lines[y].points;
889 int num = i->lines[y].num;
890 renderpoint_t*points = (renderpoint_t*)tag->data;
891 RGBA*line = &i->img[i->width2*y];
892 int*zline = &i->zbuf[i->width2*y];
895 memset(&clipstate, 0, sizeof(state_t));
896 memset(&fillstate, 0, sizeof(state_t));
897 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
900 renderpoint_t*p = &points[n];
901 renderpoint_t*next= n<num-1?&points[n+1]:0;
903 int endx = next?next->x:i->width2;
909 if(p->type == clip_type)
910 change_state(y, &clipstate, p);
912 change_state(y, &fillstate, p);
914 fill(dest, line, zline, y, startx, endx, &clipstate, &fillstate);
915 if(endx == i->width2)
918 free_layers(&clipstate);
919 free_layers(&fillstate);
922 swf_ClearTag(i->lines[y].points);
924 i->ymin = 0x7fffffff;
925 i->ymax = -0x80000000;
928 RGBA* swf_Render(RENDERBUF*dest)
930 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
931 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
937 for(y=0;y<i->height2;y++) {
939 RGBA*line = &i->img[y*i->width2];
942 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
949 RGBA* p = &img[(y/2)*dest->width];
950 for(x=0;x<dest->width;x++) {
951 RGBA*p1 = &line1[x*2];
952 RGBA*p2 = &line1[x*2+1];
953 RGBA*p3 = &line2[x*2];
954 RGBA*p4 = &line2[x*2+1];
955 p[x].r = (p1->r + p2->r + p3->r + p4->r)/4;
956 p[x].g = (p1->g + p2->g + p3->g + p4->g)/4;
957 p[x].b = (p1->b + p2->b + p3->b + p4->b)/4;
958 p[x].a = (p1->a + p2->a + p3->a + p4->a)/4;
972 enum {none_type, shape_type, image_type, text_type, font_type} type;
979 int compare_placements(const void *v1, const void *v2)
981 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
982 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
983 if(p1->depth != p2->depth)
984 (int)p1->depth - (int)p2->depth;
987 return 1; // do the clip first
991 /* if(!p1->clipdepth) {
993 // !p1->clipdepth && !p2->clipdepth
994 return (int)p1->depth - (int)p2->depth;
996 // !p1->clipdepth && p2->clipdepth
997 if(p1->depth != p2->clipdepth)
998 return (int)p1->depth - (int)p2->clipdepth;
1000 return 1; // do the clip first
1003 if(!p2->clipdepth) {
1004 // p1->clipdepth && !p2->clipdepth
1005 if(p1->clipdepth != p2->depth)
1006 return (int)p1->clipdepth - (int)p2->depth;
1008 return -1;// do the clip first
1010 if(p1->clipdepth != p2->clipdepth)
1011 return (int)p1->clipdepth - (int)p2->clipdepth;
1013 return (int)p1->depth - (int)p2->depth;
1018 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1024 character_t* idtable = rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1025 SWFPLACEOBJECT** depthtable = rfx_calloc(sizeof(SWFPLACEOBJECT*)*65536); // depth to placeobject mapping
1027 tag = swf->firstTag;
1030 if(tag->id == ST_PLACEOBJECT ||
1031 tag->id == ST_PLACEOBJECT2) {
1036 SWFPLACEOBJECT* placements = rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
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].obj.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].obj.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) {
1077 swf_GetPlaceObject(tag, &p);
1078 /* TODO: add move and deletion */
1079 placements[numplacements++] = p;
1084 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1086 for(t=0;t<numplacements;t++) {
1087 SWFPLACEOBJECT*p = &placements[t];
1090 if(!idtable[id].tag) {
1091 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1095 if(idtable[id].type == shape_type) {
1096 SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1097 swf_RenderShape(buf, idtable[id].obj.shape, &p->matrix, &p->cxform, p->depth, p->clipdepth);
1098 } else if(idtable[id].type == text_type) {
1101 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1105 /* free id and depth tables again */
1106 for(t=0;t<65536;t++) {
1107 if(idtable[t].bbox) {
1108 free(idtable[t].bbox);
1111 if(idtable[t].type == shape_type) {
1112 SHAPE2* shape = idtable[t].obj.shape;
1114 swf_Shape2Free(shape); // FIXME
1115 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;