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 */
31 typedef struct _renderpoint
42 enum {clip_type, solidfill_type, texturefill_type, gradientfill_type} type;
57 // texture- & gradientfill;
63 typedef struct _renderline
65 TAG*points; //incremented in 128 byte steps
67 U32 pending_clipdepth;
70 typedef struct _bitmap {
78 typedef struct _renderbuf_internal
94 static inline void add_pixel(RENDERBUF*dest, float x, int y, renderpoint_t*p)
96 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
97 if(x >= i->width2 || y >= i->height2 || y<0) return;
99 if(y<i->ymin) i->ymin = y;
100 if(y>i->ymax) i->ymax = y;
103 swf_SetBlock(i->lines[y].points, (U8*)p, sizeof(renderpoint_t));
106 /* set this to 0.777777 or something if the "both fillstyles set while not inside shape"
107 problem appears to often */
110 #define INT(x) ((int)((x)+16)-16)
112 static void add_line(RENDERBUF*buf, double x1, double y1, double x2, double y2, renderpoint_t*p)
114 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
116 double ny1, ny2, stepx;
118 int l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
119 printf(" l[%d - %.2f/%.2f -> %.2f/%.2f]\n", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
121 assert(p->shapeline);
147 ny1 = INT(y1) + 1.0 + CUT;
150 ny2 = INT(y2) - 1.0 + CUT;
157 x1 = x1 + (ny1-y1)*stepx;
158 x2 = x2 + (ny2-y2)*stepx;
167 float xx = (float)(startx + posx);
168 add_pixel(buf, xx ,posy, p);
174 #define PI 3.14159265358979
175 static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double y2, int width, renderpoint_t*p)
177 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
190 /* Make sure the line is always at least one pixel wide */
192 /* That's what Macromedia's Player does at least at zoom level >= 1. */
195 /* That's what Macromedia's Player seems to do at zoom level 0. */
196 /* TODO: needs testing */
201 sd = (double)dx*(double)dx+(double)dy*(double)dy;
223 add_line(buf, x1+vx, y1+vy, xx, yy, p);
226 for(t=1;t<segments;t++) {
227 double s = sin(t*PI/segments);
228 double c = cos(t*PI/segments);
229 xx = (x2 + vx*c - vy*s);
230 yy = (y2 + vx*s + vy*c);
231 add_line(buf, lastx, lasty, xx, yy, p);
238 add_line(buf, lastx, lasty, xx, yy, p);
243 add_line(buf, lastx, lasty, xx, yy, p);
246 for(t=1;t<segments;t++) {
247 double s = sin(t*PI/segments);
248 double c = cos(t*PI/segments);
249 xx = (x1 - vx*c + vy*s);
250 yy = (y1 - vx*s - vy*c);
251 add_line(buf, lastx, lasty, xx, yy, p);
255 add_line(buf, lastx, lasty, (x1+vx), (y1+vy), p);
258 static inline void transform_point(MATRIX*m, int x, int y, int*dx, int*dy)
263 d = swf_TurnPoint(p, m);
268 static int compare_renderpoints(const void * _a, const void * _b)
270 renderpoint_t*a = (renderpoint_t*)_a;
271 renderpoint_t*b = (renderpoint_t*)_b;
272 if(a->x < b->x) return -1;
273 if(a->x > b->x) return 1;
277 void swf_Render_Init(RENDERBUF*buf, int posx, int posy, int width, int height, char antialize, int multiply)
279 renderbuf_internal*i;
281 memset(buf, 0, sizeof(RENDERBUF));
282 buf->width = width*multiply;
283 buf->height = height*multiply;
286 buf->internal = (renderbuf_internal*)rfx_calloc(sizeof(renderbuf_internal));
287 i = (renderbuf_internal*)buf->internal;
288 i->antialize = !!antialize;
289 i->multiply = antialize?multiply*2:multiply;
290 i->height2 = antialize?2*buf->height:buf->height;
291 i->width2 = antialize?2*buf->width:buf->width;
292 i->lines = (renderline_t*)rfx_alloc(i->height2*sizeof(renderline_t));
293 for(y=0;y<i->height2;y++) {
294 memset(&i->lines[y], 0, sizeof(renderline_t));
295 i->lines[y].points = swf_InsertTag(0, 0);
298 i->zbuf = (int*)rfx_calloc(sizeof(int)*i->width2*i->height2);
299 i->img = (RGBA*)rfx_calloc(sizeof(RGBA)*i->width2*i->height2);
301 i->ymin = 0x7fffffff;
302 i->ymax = -0x80000000;
304 void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height)
306 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
308 int xstep=width*65536/i->width2;
309 int ystep=height*65536/i->height2;
311 fprintf(stderr, "rfxswf: Warning: swf_Render_SetBackground() called after drawing shapes\n");
313 for(y=0,yy=0;y<i->height2;y++,yy+=ystep) {
314 RGBA*src = &img[(yy>>16) * width];
315 RGBA*line = &i->img[y * i->width2];
316 for(x=0,xx=0;x<i->width2;x++,xx+=xstep) {
317 line[x] = src[xx>>16];
321 void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color)
323 swf_Render_SetBackground(buf, &color, 1, 1);
325 void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height)
327 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
329 bitmap_t*bm = rfx_calloc(sizeof(bitmap_t));
333 bm->data = rfx_alloc(width*height*4);
334 memcpy(bm->data, img, width*height*4);
336 bm->next = i->bitmaps;
339 void swf_Render_ClearCanvas(RENDERBUF*dest)
341 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
343 for(y=0;y<i->height2;y++) {
344 swf_ClearTag(i->lines[y].points);
346 memset(i->zbuf, 0, sizeof(int)*i->width2*i->height2);
347 memset(i->img, 0, sizeof(RGBA)*i->width2*i->height2);
349 void swf_Render_Delete(RENDERBUF*dest)
351 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
353 bitmap_t*b = i->bitmaps;
359 /* delete line buffers */
360 for(y=0;y<i->height2;y++) {
361 swf_DeleteTag(i->lines[y].points);
362 i->lines[y].points = 0;
367 bitmap_t*next = b->next;
368 free(b->data);b->data=0;
373 rfx_free(i->lines); i->lines = 0;
374 rfx_free(dest->internal); dest->internal = 0;
377 static SHAPE2* linestyle2fillstyle(SHAPE2*shape)
379 SHAPE2*s = rfx_calloc(sizeof(SHAPE2));
381 s->numfillstyles = shape->numlinestyles;
382 s->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles);
383 s->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles);
384 for(t=0;t<shape->numlinestyles;t++) {
385 s->lines[t].fillstyle0 = t+1;
386 s->fillstyles[t].type = FILL_SOLID;
387 s->fillstyles[t].color = shape->linestyles[t].color;
392 void swf_Process(RENDERBUF*dest, U32 clipdepth);
394 void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth)
396 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
406 memset(&p, 0, sizeof(renderpoint_t));
407 memset(&lp, 0, sizeof(renderpoint_t));
409 clipdepth = _clipdepth? _clipdepth << 16 | 0xffff : 0;
410 p.depth = _depth << 16;
412 mat.tx -= dest->posx*20;
413 mat.ty -= dest->posy*20;
415 s2 = swf_Shape2Clone(shape);
417 if(shape->numfillstyles) {
420 /* multiply fillstyles matrices with placement matrix-
421 important for texture and gradient fill */
422 for(t=0;t<s2->numfillstyles;t++) {
424 swf_MatrixJoin(&nm, &s2->fillstyles[t].m, &mat); //TODO: is this the right order?
425 nm.sx *= i->multiply;
426 nm.sy *= i->multiply;
427 nm.r0 *= i->multiply;
428 nm.r1 *= i->multiply;
429 nm.tx *= i->multiply;
430 nm.ty *= i->multiply;
431 s2->fillstyles[t].m = nm;
435 if(shape->numlinestyles) {
436 lshape = linestyle2fillstyle(shape);
438 lp.depth = (_depth << 16)+1;
443 int x1,y1,x2,y2,x3,y3;
445 if(line->type == moveTo) {
446 } else if(line->type == lineTo) {
447 transform_point(&mat, x, y, &x1, &y1);
448 transform_point(&mat, line->x, line->y, &x3, &y3);
450 if(line->linestyle && ! clipdepth) {
451 lp.shapeline = &lshape->lines[line->linestyle-1];
452 add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width, &lp);
455 if(line->fillstyle0 || line->fillstyle1) {
456 assert(shape->numfillstyles);
458 add_line(dest, x1, y1, x3, y3, &p);
460 } else if(line->type == splineTo) {
461 int c,t,parts,qparts;
464 transform_point(&mat, x, y, &x1, &y1);
465 transform_point(&mat, line->sx, line->sy, &x2, &y2);
466 transform_point(&mat, line->x, line->y, &x3, &y3);
468 c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1);
472 parts = (int)(sqrt(c)/3);
473 if(!parts) parts = 1;
475 for(t=1;t<=parts;t++) {
476 double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts);
477 double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts);
479 if(line->linestyle && ! clipdepth) {
480 lp.shapeline = &lshape->lines[line->linestyle-1];
481 add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width, &lp);
484 if(line->fillstyle0 || line->fillstyle1) {
485 assert(shape->numfillstyles);
487 add_line(dest, xx, yy, nx, ny, &p);
499 swf_Process(dest, clipdepth);
502 swf_Shape2Free(s2);rfx_free(s2);s2=0;
505 swf_Shape2Free(lshape);rfx_free(lshape);lshape=0;
510 static RGBA color_red = {255,255,0,0};
511 static RGBA color_white = {255,255,255,255};
512 static RGBA color_black = {255,0,0,0};
514 static void fill_clip(RGBA*line, int*z, int y, int x1, int x2, U32 depth)
526 static void fill_solid(RGBA*line, int*z, int y, int x1, int x2, RGBA col, U32 depth)
531 int ainv = 255-col.a;
532 col.r = (col.r*col.a)>>8;
533 col.g = (col.g*col.a)>>8;
534 col.b = (col.b*col.a)>>8;
538 line[x].r = ((line[x].r*ainv)>>8)+col.r;
539 line[x].g = ((line[x].g*ainv)>>8)+col.g;
540 line[x].b = ((line[x].b*ainv)>>8)+col.b;
555 static void fill_bitmap(RGBA*line, int*z, int y, int x1, int x2, MATRIX*m, bitmap_t*b, int clipbitmap, U32 depth)
558 double m11=m->sx/65536.0, m21=m->r1/65536.0;
559 double m12=m->r0/65536.0, m22=m->sy/65536.0;
560 double rx = m->tx/20.0;
561 double ry = m->ty/20.0;
562 double det = m11*m22 - m12*m21;
563 if(fabs(det) < 0.0005) {
564 /* x direction equals y direction- the image is invisible */
569 if(!b->width || !b->height) {
570 fill_solid(line, z, y, x1, x2, color_red, depth);
577 int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det);
578 int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
583 if(xx>=b->width) xx = b->width-1;
585 if(yy>=b->height) yy = b->height-1;
591 col = b->data[yy*b->width+xx];
594 line[x].r = ((line[x].r*ainv)>>8)+col.r;
595 line[x].g = ((line[x].g*ainv)>>8)+col.g;
596 line[x].b = ((line[x].b*ainv)>>8)+col.b;
604 typedef struct _layer {
616 static void fill(RENDERBUF*dest, RGBA*line, int*zline, int y, int x1, int x2, state_t*fillstate, U32 clipdepth)
618 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
621 layer_t*l = fillstate->layers;
623 if(x1>=x2) //zero width? nothing to do.
628 /* not filled. TODO: we should never add those in the first place */
630 printf("(not filled)");
631 } else if(l->fillid > l->p->s->numfillstyles) {
632 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->numlinestyles);
633 } else if(clipdepth) {
634 /* filled region- not used for clipping */
639 printf("(%d -> %d style %d)", x1, x2, l->fillid);
641 f = &l->p->s->fillstyles[l->fillid-1];
643 if(f->type == FILL_SOLID) {
644 /* plain color fill */
645 fill_solid(line, zline, y, x1, x2, f->color, l->p->depth);
646 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
647 /* TODO: optimize (do this in add_pixel()?) */
648 bitmap_t* b = i->bitmaps;
649 while(b && b->id != f->id_bitmap) {
653 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
654 fill_solid(line, zline, y, x1, x2, color_red, l->p->depth);
656 fill_bitmap(line, zline, y, x1, x2, &f->m, b, FILL_CLIPPED?1:0, l->p->depth);
659 fprintf(stderr, "Undefined fillmode: %02x\n", f->type);
664 if(clip && clipdepth) {
665 fill_clip(line, zline, y, x1, x2, clipdepth);
669 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
671 layer_t*last=0,*l = state->layers;
672 while(l && l->p->depth < depth) {
677 if(l && l->p->depth == depth)
682 static void delete_layer(state_t*state, layer_t*todel)
684 layer_t*before=todel->prev;
685 layer_t*next = todel->next;
688 state->layers = next;
694 before->next->prev = before;
697 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
700 toadd->next = state->layers;
704 toadd->next = before->next;
705 toadd->prev = before;
706 before->next = toadd;
709 toadd->next->prev = toadd;
711 static void free_layers(state_t* state)
713 layer_t*l = state->layers;
715 layer_t*next = l->next;
721 static void change_state(int y, state_t* state, renderpoint_t*p)
723 layer_t*before=0, *self=0, *after=0;
726 printf("[(%d,%d)/%d/%d-%d]", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
729 search_layer(state, p->depth, &before, &self, &after);
733 if(self->fillid<0/*??*/ || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
735 if(DEBUG&2) printf("<D>");
737 delete_layer(state, self);
739 /*both fill0 and fill1 are set- exchange the two, updating the layer */
740 if(self->fillid == p->shapeline->fillstyle0) {
741 self->fillid = p->shapeline->fillstyle1;
743 if(DEBUG&2) printf("<X>");
744 } else if(self->fillid == p->shapeline->fillstyle1) {
745 self->fillid = p->shapeline->fillstyle0;
747 if(DEBUG&2) printf("<X>");
749 /* buggy shape. keep everything as-is. */
750 if(DEBUG&2) printf("<!>");
751 //fprintf(stderr, "<line %d: bad swap>\n", y);
757 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
758 /* this is a hack- a better way would be to make sure that
759 we always get (0,32), (32, 33), (33, 0) in the right order if
760 they happen to fall on the same pixel.
761 (not: (0,32), (33, 0), (32, 33))
763 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
767 n = rfx_calloc(sizeof(layer_t));
769 if(DEBUG&2) printf("<+>");
771 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
774 add_layer(state, before, n);
778 void swf_Process(RENDERBUF*dest, U32 clipdepth)
780 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
783 if(i->ymax < i->ymin) {
784 /* shape is empty. return.
785 only, if it's a clipshape, remember the clipdepth */
787 for(y=0;y<i->height2;y++) {
788 if(clipdepth > i->lines[y].pending_clipdepth)
789 i->lines[y].pending_clipdepth = clipdepth;
792 return; //nothing (else) to do
796 /* lines outside the clip shape are not filled
797 immediately, only the highest clipdepth so far is
798 stored there. They will be clipfilled once there's
799 actually something about to happen in that line */
800 for(y=0;y<i->ymin;y++) {
801 if(clipdepth > i->lines[y].pending_clipdepth)
802 i->lines[y].pending_clipdepth = clipdepth;
804 for(y=i->ymax+1;y<i->height2;y++) {
805 if(clipdepth > i->lines[y].pending_clipdepth)
806 i->lines[y].pending_clipdepth = clipdepth;
810 for(y=i->ymin;y<=i->ymax;y++) {
812 TAG*tag = i->lines[y].points;
813 int num = i->lines[y].num;
814 renderpoint_t*points = (renderpoint_t*)tag->data;
815 RGBA*line = &i->img[i->width2*y];
816 int*zline = &i->zbuf[i->width2*y];
819 memset(&fillstate, 0, sizeof(state_t));
820 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
822 if(i->lines[y].pending_clipdepth && !clipdepth) {
823 fill_clip(line, zline, y, 0, i->width2, i->lines[y].pending_clipdepth);
824 i->lines[y].pending_clipdepth=0;
828 renderpoint_t*p = &points[n];
829 renderpoint_t*next= n<num-1?&points[n+1]:0;
831 int endx = next?next->x:i->width2;
840 /* for clipping, the inverse is filled */
841 fill_clip(line, zline, y, lastx, startx, clipdepth);
843 change_state(y, &fillstate, p);
845 fill(dest, line, zline, y, startx, endx, &fillstate, clipdepth);
846 /* if(y == 0 && startx == 232 && endx == 418) {
847 printf("ymin=%d ymax=%d\n", i->ymin, i->ymax);
849 renderpoint_t*p = &points[n];
850 printf("x=%f depth=%08x\n", p->x, p->depth);
855 if(endx == i->width2)
859 fill_clip(line, zline, y, lastx, i->width2, clipdepth);
861 free_layers(&fillstate);
864 swf_ClearTag(i->lines[y].points);
866 i->ymin = 0x7fffffff;
867 i->ymax = -0x80000000;
870 RGBA* swf_Render(RENDERBUF*dest)
872 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
873 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
877 for(y=0;y<i->height2;y++) {
879 RGBA*line = &i->img[y*i->width2];
882 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
890 p = &img[(y/2)*dest->width];
891 for(x=0;x<dest->width;x++) {
892 RGBA*p1 = &line1[x*2];
893 RGBA*p2 = &line1[x*2+1];
894 RGBA*p3 = &line2[x*2];
895 RGBA*p4 = &line2[x*2+1];
896 p[x].r = (p1->r + p2->r + p3->r + p4->r)/4;
897 p[x].g = (p1->g + p2->g + p3->g + p4->g)/4;
898 p[x].b = (p1->b + p2->b + p3->b + p4->b)/4;
899 p[x].a = (p1->a + p2->a + p3->a + p4->a)/4;
919 enum {none_type, shape_type, image_type, text_type, font_type} type;
926 int compare_placements(const void *v1, const void *v2)
928 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
929 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
930 if(p1->depth != p2->depth)
931 return (int)p1->depth - (int)p2->depth;
934 return 1; // do the clip first
938 /* if(!p1->clipdepth) {
940 // !p1->clipdepth && !p2->clipdepth
941 return (int)p1->depth - (int)p2->depth;
943 // !p1->clipdepth && p2->clipdepth
944 if(p1->depth != p2->clipdepth)
945 return (int)p1->depth - (int)p2->clipdepth;
947 return 1; // do the clip first
951 // p1->clipdepth && !p2->clipdepth
952 if(p1->clipdepth != p2->depth)
953 return (int)p1->clipdepth - (int)p2->depth;
955 return -1;// do the clip first
957 if(p1->clipdepth != p2->clipdepth)
958 return (int)p1->clipdepth - (int)p2->clipdepth;
960 return (int)p1->depth - (int)p2->depth;
965 typedef struct textcallbackblock
973 } textcallbackblock_t;
975 static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize,
976 int xstart, int ystart, RGBA* color)
978 textcallbackblock_t * info = (textcallbackblock_t*)self;
981 if(!info->idtable[fontid].obj.font) {
982 fprintf(stderr, "Font %d unknown\n", fontid);
985 font = info->idtable[fontid].obj.font;
988 int x = xstart + xpos[t];
994 p = swf_TurnPoint(p, &m);
996 m.sx = (m.sx * fontsize) / 1024;
997 m.sy = (m.sy * fontsize) / 1024;
998 m.r0 = (m.r0 * fontsize) / 1024;
999 m.r1 = (m.r1 * fontsize) / 1024;
1003 if(chars[t]<0 || chars[t]>= font->numchars) {
1004 fprintf(stderr, "Character out of range: %d\n", chars[t]);
1006 SHAPE2*shape = font->glyphs[chars[t]];
1007 shape->fillstyles[0].color = *color; //q&d
1008 /*printf("Rendering char %d (size %d, x:%d, y:%d) color:%02x%02x%02x%02x\n", chars[t], fontsize, x, y,
1009 color->a, color->r, color->g, color->b);
1010 swf_DumpMatrix(stdout, &m);
1011 swf_DumpShape(shape);*/
1012 swf_RenderShape(info->buf, shape, &m, info->cxform, info->depth, info->clipdepth);
1017 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1023 SWFPLACEOBJECT* placements;
1025 character_t* idtable = rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1026 SWFPLACEOBJECT** depthtable = rfx_calloc(sizeof(SWFPLACEOBJECT*)*65536); // depth to placeobject mapping
1028 tag = swf->firstTag;
1031 if(tag->id == ST_PLACEOBJECT ||
1032 tag->id == ST_PLACEOBJECT2) {
1037 placements = rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
1040 /* set background color */
1041 color = swf_GetSWFBackgroundColor(swf);
1042 swf_Render_SetBackgroundColor(buf, color);
1044 /* parse definitions */
1045 tag = swf->firstTag;
1047 if(swf_isDefiningTag(tag)) {
1048 int id = swf_GetDefineID(tag);
1049 idtable[id].tag = tag;
1050 idtable[id].bbox = rfx_alloc(sizeof(SRECT));
1051 *idtable[id].bbox = swf_GetDefineBBox(tag);
1053 if(swf_isShapeTag(tag)) {
1054 SHAPE2* shape = rfx_calloc(sizeof(SHAPE2));
1055 swf_ParseDefineShape(tag, shape);
1056 idtable[id].type = shape_type;
1057 idtable[id].obj.shape = shape;
1058 } else if(swf_isImageTag(tag)) {
1060 RGBA*data = swf_ExtractImage(tag, &width, &height);
1061 idtable[id].type = image_type;
1062 swf_Render_AddImage(buf, id, data, width, height);
1064 } else if(tag->id == ST_DEFINEFONT ||
1065 tag->id == ST_DEFINEFONT2) {
1068 font_t*font = rfx_calloc(sizeof(font_t));
1069 idtable[id].obj.font = font;
1070 swf_FontExtract(swf,id,&swffont);
1071 font->numchars = swffont->numchars;
1072 font->glyphs = rfx_calloc(sizeof(SHAPE2*)*font->numchars);
1073 for(t=0;t<font->numchars;t++) {
1074 if(!swffont->glyph[t].shape->fillstyle.n) {
1075 /* the actual fill color will be overwritten while rendering */
1076 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
1078 font->glyphs[t] = swf_ShapeToShape2(swffont->glyph[t].shape);
1080 swf_FontFree(swffont);
1081 idtable[id].type = font_type;
1083 } else if(tag->id == ST_DEFINEFONTINFO ||
1084 tag->id == ST_DEFINEFONTINFO2) {
1085 idtable[id].type = font_type;
1086 } else if(tag->id == ST_DEFINETEXT ||
1087 tag->id == ST_DEFINETEXT2) {
1088 idtable[id].type = text_type;
1090 } else if(tag->id == ST_PLACEOBJECT ||
1091 tag->id == ST_PLACEOBJECT2) {
1093 swf_GetPlaceObject(tag, &p);
1094 /* TODO: add move and deletion */
1095 placements[numplacements++] = p;
1096 swf_PlaceObjectFree(&p); //dirty! but it only removes items we don't need
1101 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1103 for(t=0;t<numplacements;t++) {
1104 SWFPLACEOBJECT*p = &placements[t];
1107 if(!idtable[id].tag) {
1108 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1112 if(idtable[id].type == shape_type) {
1113 //SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1114 swf_RenderShape(buf, idtable[id].obj.shape, &p->matrix, &p->cxform, p->depth, p->clipdepth);
1115 } else if(idtable[id].type == text_type) {
1116 TAG* tag = idtable[id].tag;
1117 textcallbackblock_t info;
1120 swf_SetTagPos(tag, 0);
1123 swf_GetMatrix(tag,&m);
1124 swf_MatrixJoin(&info.m, &m, &p->matrix);
1125 /*printf("Text matrix:\n");
1126 swf_DumpMatrix(stdout, &m);
1127 printf("Placement matrix:\n");
1128 swf_DumpMatrix(stdout, &p->matrix);*/
1130 info.idtable = idtable;
1131 info.depth = p->depth;
1132 info.cxform = &p->cxform;
1133 info.clipdepth = p->clipdepth;
1136 swf_ParseDefineText(tag, textcallback, &info);
1138 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1142 /* free id and depth tables again */
1143 for(t=0;t<65536;t++) {
1144 if(idtable[t].bbox) {
1145 free(idtable[t].bbox);
1148 if(idtable[t].type == shape_type) {
1149 SHAPE2* shape = idtable[t].obj.shape;
1151 swf_Shape2Free(shape); // FIXME
1152 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;
1154 } else if(idtable[t].type == font_type) {
1155 font_t* font = idtable[t].obj.font;
1159 for(t=0;t<font->numchars;t++) {
1160 swf_Shape2Free(font->glyphs[t]);
1161 free(font->glyphs[t]); font->glyphs[t] = 0;
1166 free(idtable[t].obj.font); idtable[t].obj.font = 0;