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, int 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;
290 i->antialize = antialize;
291 i->multiply = multiply*antialize;
292 i->height2 = antialize*buf->height;
293 i->width2 = antialize*buf->width;
294 i->lines = (renderline_t*)rfx_alloc(i->height2*sizeof(renderline_t));
295 for(y=0;y<i->height2;y++) {
296 memset(&i->lines[y], 0, sizeof(renderline_t));
297 i->lines[y].points = swf_InsertTag(0, 0);
300 i->zbuf = (int*)rfx_calloc(sizeof(int)*i->width2*i->height2);
301 i->img = (RGBA*)rfx_calloc(sizeof(RGBA)*i->width2*i->height2);
303 i->ymin = 0x7fffffff;
304 i->ymax = -0x80000000;
306 void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height)
308 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
310 int xstep=width*65536/i->width2;
311 int ystep=height*65536/i->height2;
313 fprintf(stderr, "rfxswf: Warning: swf_Render_SetBackground() called after drawing shapes\n");
315 for(y=0,yy=0;y<i->height2;y++,yy+=ystep) {
316 RGBA*src = &img[(yy>>16) * width];
317 RGBA*line = &i->img[y * i->width2];
318 for(x=0,xx=0;x<i->width2;x++,xx+=xstep) {
319 line[x] = src[xx>>16];
323 void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color)
325 swf_Render_SetBackground(buf, &color, 1, 1);
327 void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height)
329 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
331 bitmap_t*bm = rfx_calloc(sizeof(bitmap_t));
335 bm->data = rfx_alloc(width*height*4);
336 memcpy(bm->data, img, width*height*4);
338 bm->next = i->bitmaps;
341 void swf_Render_ClearCanvas(RENDERBUF*dest)
343 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
345 for(y=0;y<i->height2;y++) {
346 swf_ClearTag(i->lines[y].points);
348 memset(i->zbuf, 0, sizeof(int)*i->width2*i->height2);
349 memset(i->img, 0, sizeof(RGBA)*i->width2*i->height2);
351 void swf_Render_Delete(RENDERBUF*dest)
353 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
355 bitmap_t*b = i->bitmaps;
361 /* delete line buffers */
362 for(y=0;y<i->height2;y++) {
363 swf_DeleteTag(i->lines[y].points);
364 i->lines[y].points = 0;
369 bitmap_t*next = b->next;
370 free(b->data);b->data=0;
375 rfx_free(i->lines); i->lines = 0;
376 rfx_free(dest->internal); dest->internal = 0;
379 static SHAPE2* linestyle2fillstyle(SHAPE2*shape)
381 SHAPE2*s = rfx_calloc(sizeof(SHAPE2));
383 s->numfillstyles = shape->numlinestyles;
384 s->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles);
385 s->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles);
386 for(t=0;t<shape->numlinestyles;t++) {
387 s->lines[t].fillstyle0 = t+1;
388 s->fillstyles[t].type = FILL_SOLID;
389 s->fillstyles[t].color = shape->linestyles[t].color;
394 void swf_Process(RENDERBUF*dest, U32 clipdepth);
396 void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth)
398 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
408 memset(&p, 0, sizeof(renderpoint_t));
409 memset(&lp, 0, sizeof(renderpoint_t));
411 clipdepth = _clipdepth? _clipdepth << 16 | 0xffff : 0;
412 p.depth = _depth << 16;
414 mat.tx -= dest->posx*20;
415 mat.ty -= dest->posy*20;
417 s2 = swf_Shape2Clone(shape);
419 if(shape->numfillstyles) {
422 /* multiply fillstyles matrices with placement matrix-
423 important for texture and gradient fill */
424 for(t=0;t<s2->numfillstyles;t++) {
426 swf_MatrixJoin(&nm, &s2->fillstyles[t].m, &mat); //TODO: is this the right order?
427 /*nm.sx *= i->multiply;
428 nm.sy *= i->multiply;
429 nm.r0 *= i->multiply;
430 nm.r1 *= i->multiply;
431 nm.tx *= i->multiply;
432 nm.ty *= i->multiply;*/
433 s2->fillstyles[t].m = nm;
437 if(shape->numlinestyles) {
438 lshape = linestyle2fillstyle(shape);
440 lp.depth = (_depth << 16)+1;
445 int x1,y1,x2,y2,x3,y3;
447 if(line->type == moveTo) {
448 } else if(line->type == lineTo) {
449 transform_point(&mat, x, y, &x1, &y1);
450 transform_point(&mat, line->x, line->y, &x3, &y3);
452 if(line->linestyle && ! clipdepth) {
453 lp.shapeline = &lshape->lines[line->linestyle-1];
454 add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width, &lp);
457 if(line->fillstyle0 || line->fillstyle1) {
458 assert(shape->numfillstyles);
460 add_line(dest, x1, y1, x3, y3, &p);
462 } else if(line->type == splineTo) {
463 int c,t,parts,qparts;
466 transform_point(&mat, x, y, &x1, &y1);
467 transform_point(&mat, line->sx, line->sy, &x2, &y2);
468 transform_point(&mat, line->x, line->y, &x3, &y3);
470 c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1);
474 parts = (int)(sqrt(c)/3);
475 if(!parts) parts = 1;
477 for(t=1;t<=parts;t++) {
478 double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts);
479 double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts);
481 if(line->linestyle && ! clipdepth) {
482 lp.shapeline = &lshape->lines[line->linestyle-1];
483 add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width, &lp);
486 if(line->fillstyle0 || line->fillstyle1) {
487 assert(shape->numfillstyles);
489 add_line(dest, xx, yy, nx, ny, &p);
501 swf_Process(dest, clipdepth);
504 swf_Shape2Free(s2);rfx_free(s2);s2=0;
507 swf_Shape2Free(lshape);rfx_free(lshape);lshape=0;
512 static RGBA color_red = {255,255,0,0};
513 static RGBA color_white = {255,255,255,255};
514 static RGBA color_black = {255,0,0,0};
516 static void fill_clip(RGBA*line, int*z, int y, int x1, int x2, U32 depth)
528 static void fill_solid(RGBA*line, int*z, int y, int x1, int x2, RGBA col, U32 depth)
533 int ainv = 255-col.a;
534 col.r = (col.r*col.a)>>8;
535 col.g = (col.g*col.a)>>8;
536 col.b = (col.b*col.a)>>8;
540 line[x].r = ((line[x].r*ainv)>>8)+col.r;
541 line[x].g = ((line[x].g*ainv)>>8)+col.g;
542 line[x].b = ((line[x].b*ainv)>>8)+col.b;
557 static void fill_bitmap(RGBA*line, int*z, int y, int x1, int x2, MATRIX*m, bitmap_t*b, int clipbitmap, U32 depth, double fmultiply)
561 double m11= m->sx*fmultiply/65536.0, m21= m->r1*fmultiply/65536.0;
562 double m12= m->r0*fmultiply/65536.0, m22= m->sy*fmultiply/65536.0;
563 double rx = m->tx*fmultiply/20.0;
564 double ry = m->ty*fmultiply/20.0;
566 double det = m11*m22 - m12*m21;
567 if(fabs(det) < 0.0005) {
568 /* x direction equals y direction- the image is invisible */
573 if(!b->width || !b->height) {
574 fill_solid(line, z, y, x1, x2, color_red, depth);
581 int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det);
582 int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
587 if(xx>=b->width) xx = b->width-1;
589 if(yy>=b->height) yy = b->height-1;
593 if(xx<0) xx += b->width;
594 if(yy<0) yy += b->height;
597 col = b->data[yy*b->width+xx];
600 line[x].r = ((line[x].r*ainv)>>8)+col.r;
601 line[x].g = ((line[x].g*ainv)>>8)+col.g;
602 line[x].b = ((line[x].b*ainv)>>8)+col.b;
610 typedef struct _layer {
622 static void fill(RENDERBUF*dest, RGBA*line, int*zline, int y, int x1, int x2, state_t*fillstate, U32 clipdepth)
624 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
627 layer_t*l = fillstate->layers;
629 if(x1>=x2) //zero width? nothing to do.
634 /* not filled. TODO: we should never add those in the first place */
636 printf("(not filled)");
637 } else if(l->fillid > l->p->s->numfillstyles) {
638 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->numlinestyles);
639 } else if(clipdepth) {
640 /* filled region- not used for clipping */
645 printf("(%d -> %d style %d)", x1, x2, l->fillid);
647 f = &l->p->s->fillstyles[l->fillid-1];
649 if(f->type == FILL_SOLID) {
650 /* plain color fill */
651 fill_solid(line, zline, y, x1, x2, f->color, l->p->depth);
652 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
653 /* TODO: optimize (do this in add_pixel()?) */
654 bitmap_t* b = i->bitmaps;
655 while(b && b->id != f->id_bitmap) {
659 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
660 fill_solid(line, zline, y, x1, x2, color_red, l->p->depth);
662 fill_bitmap(line, zline, y, x1, x2, &f->m, b, FILL_CLIPPED?1:0, l->p->depth, i->multiply);
665 fprintf(stderr, "Undefined fillmode: %02x\n", f->type);
670 if(clip && clipdepth) {
671 fill_clip(line, zline, y, x1, x2, clipdepth);
675 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
677 layer_t*last=0,*l = state->layers;
678 while(l && l->p->depth < depth) {
683 if(l && l->p->depth == depth)
688 static void delete_layer(state_t*state, layer_t*todel)
690 layer_t*before=todel->prev;
691 layer_t*next = todel->next;
694 state->layers = next;
700 before->next->prev = before;
703 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
706 toadd->next = state->layers;
710 toadd->next = before->next;
711 toadd->prev = before;
712 before->next = toadd;
715 toadd->next->prev = toadd;
717 static void free_layers(state_t* state)
719 layer_t*l = state->layers;
721 layer_t*next = l->next;
727 static void change_state(int y, state_t* state, renderpoint_t*p)
729 layer_t*before=0, *self=0, *after=0;
732 printf("[(%d,%d)/%d/%d-%d]", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
735 search_layer(state, p->depth, &before, &self, &after);
739 if(self->fillid<0/*??*/ || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
741 if(DEBUG&2) printf("<D>");
743 delete_layer(state, self);
745 /*both fill0 and fill1 are set- exchange the two, updating the layer */
746 if(self->fillid == p->shapeline->fillstyle0) {
747 self->fillid = p->shapeline->fillstyle1;
749 if(DEBUG&2) printf("<X>");
750 } else if(self->fillid == p->shapeline->fillstyle1) {
751 self->fillid = p->shapeline->fillstyle0;
753 if(DEBUG&2) printf("<X>");
755 /* buggy shape. keep everything as-is. */
756 if(DEBUG&2) printf("<!>");
757 //fprintf(stderr, "<line %d: bad swap>\n", y);
763 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
764 /* this is a hack- a better way would be to make sure that
765 we always get (0,32), (32, 33), (33, 0) in the right order if
766 they happen to fall on the same pixel.
767 (not: (0,32), (33, 0), (32, 33))
769 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
773 n = rfx_calloc(sizeof(layer_t));
775 if(DEBUG&2) printf("<+>");
777 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
780 add_layer(state, before, n);
784 void swf_Process(RENDERBUF*dest, U32 clipdepth)
786 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
789 if(i->ymax < i->ymin) {
790 /* shape is empty. return.
791 only, if it's a clipshape, remember the clipdepth */
793 for(y=0;y<i->height2;y++) {
794 if(clipdepth > i->lines[y].pending_clipdepth)
795 i->lines[y].pending_clipdepth = clipdepth;
798 return; //nothing (else) to do
802 /* lines outside the clip shape are not filled
803 immediately, only the highest clipdepth so far is
804 stored there. They will be clipfilled once there's
805 actually something about to happen in that line */
806 for(y=0;y<i->ymin;y++) {
807 if(clipdepth > i->lines[y].pending_clipdepth)
808 i->lines[y].pending_clipdepth = clipdepth;
810 for(y=i->ymax+1;y<i->height2;y++) {
811 if(clipdepth > i->lines[y].pending_clipdepth)
812 i->lines[y].pending_clipdepth = clipdepth;
816 for(y=i->ymin;y<=i->ymax;y++) {
818 TAG*tag = i->lines[y].points;
819 int num = i->lines[y].num;
820 renderpoint_t*points = (renderpoint_t*)tag->data;
821 RGBA*line = &i->img[i->width2*y];
822 int*zline = &i->zbuf[i->width2*y];
825 memset(&fillstate, 0, sizeof(state_t));
826 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
828 if(i->lines[y].pending_clipdepth && !clipdepth) {
829 fill_clip(line, zline, y, 0, i->width2, i->lines[y].pending_clipdepth);
830 i->lines[y].pending_clipdepth=0;
834 renderpoint_t*p = &points[n];
835 renderpoint_t*next= n<num-1?&points[n+1]:0;
837 int endx = next?next->x:i->width2;
846 /* for clipping, the inverse is filled */
847 fill_clip(line, zline, y, lastx, startx, clipdepth);
849 change_state(y, &fillstate, p);
851 fill(dest, line, zline, y, startx, endx, &fillstate, clipdepth);
852 /* if(y == 0 && startx == 232 && endx == 418) {
853 printf("ymin=%d ymax=%d\n", i->ymin, i->ymax);
855 renderpoint_t*p = &points[n];
856 printf("x=%f depth=%08x\n", p->x, p->depth);
861 if(endx == i->width2)
865 fill_clip(line, zline, y, lastx, i->width2, clipdepth);
867 free_layers(&fillstate);
870 swf_ClearTag(i->lines[y].points);
872 i->ymin = 0x7fffffff;
873 i->ymax = -0x80000000;
876 RGBA* swf_Render(RENDERBUF*dest)
878 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
879 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
881 int antialize = i->antialize;
883 if(antialize <= 1) /* no antializing */ {
884 for(y=0;y<i->height2;y++) {
885 RGBA*line = &i->img[y*i->width2];
886 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
889 RGBA**lines = (RGBA**)rfx_calloc(sizeof(RGBA*)*antialize);
890 int q = antialize*antialize;
892 for(y=0;y<i->height2;y++) {
894 ypos = y % antialize;
895 lines[ypos] = &i->img[y*i->width2];
896 if(ypos == antialize-1) {
897 RGBA*out = &img[(y / antialize)*dest->width];
900 for(x=0;x<dest->width;x++) {
901 int xpos = x*antialize;
904 for(yp=0;yp<antialize;yp++) {
905 RGBA*lp = &lines[yp][xpos];
907 for(xp=0;xp<antialize;xp++) {
937 enum {none_type, shape_type, image_type, text_type, font_type} type;
944 int compare_placements(const void *v1, const void *v2)
946 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
947 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
948 if(p1->depth != p2->depth)
949 return (int)p1->depth - (int)p2->depth;
952 return 1; // do the clip first
956 /* if(!p1->clipdepth) {
958 // !p1->clipdepth && !p2->clipdepth
959 return (int)p1->depth - (int)p2->depth;
961 // !p1->clipdepth && p2->clipdepth
962 if(p1->depth != p2->clipdepth)
963 return (int)p1->depth - (int)p2->clipdepth;
965 return 1; // do the clip first
969 // p1->clipdepth && !p2->clipdepth
970 if(p1->clipdepth != p2->depth)
971 return (int)p1->clipdepth - (int)p2->depth;
973 return -1;// do the clip first
975 if(p1->clipdepth != p2->clipdepth)
976 return (int)p1->clipdepth - (int)p2->clipdepth;
978 return (int)p1->depth - (int)p2->depth;
983 typedef struct textcallbackblock
991 } textcallbackblock_t;
993 static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize,
994 int xstart, int ystart, RGBA* color)
996 textcallbackblock_t * info = (textcallbackblock_t*)self;
999 if(!info->idtable[fontid].obj.font) {
1000 fprintf(stderr, "Font %d unknown\n", fontid);
1003 font = info->idtable[fontid].obj.font;
1006 int x = xstart + xpos[t];
1012 p = swf_TurnPoint(p, &m);
1014 m.sx = (m.sx * fontsize) / 1024;
1015 m.sy = (m.sy * fontsize) / 1024;
1016 m.r0 = (m.r0 * fontsize) / 1024;
1017 m.r1 = (m.r1 * fontsize) / 1024;
1021 if(chars[t]<0 || chars[t]>= font->numchars) {
1022 fprintf(stderr, "Character out of range: %d\n", chars[t]);
1024 SHAPE2*shape = font->glyphs[chars[t]];
1025 shape->fillstyles[0].color = *color; //q&d
1026 /*printf("Rendering char %d (size %d, x:%d, y:%d) color:%02x%02x%02x%02x\n", chars[t], fontsize, x, y,
1027 color->a, color->r, color->g, color->b);
1028 swf_DumpMatrix(stdout, &m);
1029 swf_DumpShape(shape);*/
1030 swf_RenderShape(info->buf, shape, &m, info->cxform, info->depth, info->clipdepth);
1035 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1041 SWFPLACEOBJECT* placements;
1043 character_t* idtable = rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1044 SWFPLACEOBJECT** depthtable = rfx_calloc(sizeof(SWFPLACEOBJECT*)*65536); // depth to placeobject mapping
1046 tag = swf->firstTag;
1049 if(tag->id == ST_PLACEOBJECT ||
1050 tag->id == ST_PLACEOBJECT2) {
1055 placements = rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
1058 /* set background color */
1059 color = swf_GetSWFBackgroundColor(swf);
1060 swf_Render_SetBackgroundColor(buf, color);
1062 /* parse definitions */
1063 tag = swf->firstTag;
1065 if(swf_isDefiningTag(tag)) {
1066 int id = swf_GetDefineID(tag);
1067 idtable[id].tag = tag;
1068 idtable[id].bbox = rfx_alloc(sizeof(SRECT));
1069 *idtable[id].bbox = swf_GetDefineBBox(tag);
1071 if(swf_isShapeTag(tag)) {
1072 SHAPE2* shape = rfx_calloc(sizeof(SHAPE2));
1073 swf_ParseDefineShape(tag, shape);
1074 idtable[id].type = shape_type;
1075 idtable[id].obj.shape = shape;
1076 } else if(swf_isImageTag(tag)) {
1078 RGBA*data = swf_ExtractImage(tag, &width, &height);
1079 idtable[id].type = image_type;
1080 swf_Render_AddImage(buf, id, data, width, height);
1082 } else if(tag->id == ST_DEFINEFONT ||
1083 tag->id == ST_DEFINEFONT2) {
1086 font_t*font = rfx_calloc(sizeof(font_t));
1087 idtable[id].obj.font = font;
1088 swf_FontExtract(swf,id,&swffont);
1089 font->numchars = swffont->numchars;
1090 font->glyphs = rfx_calloc(sizeof(SHAPE2*)*font->numchars);
1091 for(t=0;t<font->numchars;t++) {
1092 if(!swffont->glyph[t].shape->fillstyle.n) {
1093 /* the actual fill color will be overwritten while rendering */
1094 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
1096 font->glyphs[t] = swf_ShapeToShape2(swffont->glyph[t].shape);
1098 swf_FontFree(swffont);
1099 idtable[id].type = font_type;
1101 } else if(tag->id == ST_DEFINEFONTINFO ||
1102 tag->id == ST_DEFINEFONTINFO2) {
1103 idtable[id].type = font_type;
1104 } else if(tag->id == ST_DEFINETEXT ||
1105 tag->id == ST_DEFINETEXT2) {
1106 idtable[id].type = text_type;
1108 } else if(tag->id == ST_PLACEOBJECT ||
1109 tag->id == ST_PLACEOBJECT2) {
1111 swf_GetPlaceObject(tag, &p);
1112 /* TODO: add move and deletion */
1113 placements[numplacements++] = p;
1114 swf_PlaceObjectFree(&p); //dirty! but it only removes items we don't need
1119 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1121 for(t=0;t<numplacements;t++) {
1122 SWFPLACEOBJECT*p = &placements[t];
1125 if(!idtable[id].tag) {
1126 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1130 if(idtable[id].type == shape_type) {
1131 //SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1132 swf_RenderShape(buf, idtable[id].obj.shape, &p->matrix, &p->cxform, p->depth, p->clipdepth);
1133 } else if(idtable[id].type == text_type) {
1134 TAG* tag = idtable[id].tag;
1135 textcallbackblock_t info;
1138 swf_SetTagPos(tag, 0);
1141 swf_GetMatrix(tag,&m);
1142 swf_MatrixJoin(&info.m, &m, &p->matrix);
1143 /*printf("Text matrix:\n");
1144 swf_DumpMatrix(stdout, &m);
1145 printf("Placement matrix:\n");
1146 swf_DumpMatrix(stdout, &p->matrix);*/
1148 info.idtable = idtable;
1149 info.depth = p->depth;
1150 info.cxform = &p->cxform;
1151 info.clipdepth = p->clipdepth;
1154 swf_ParseDefineText(tag, textcallback, &info);
1156 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1160 /* free id and depth tables again */
1161 for(t=0;t<65536;t++) {
1162 if(idtable[t].bbox) {
1163 free(idtable[t].bbox);
1166 if(idtable[t].type == shape_type) {
1167 SHAPE2* shape = idtable[t].obj.shape;
1169 swf_Shape2Free(shape); // FIXME
1170 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;
1172 } else if(idtable[t].type == font_type) {
1173 font_t* font = idtable[t].obj.font;
1177 for(t=0;t<font->numchars;t++) {
1178 swf_Shape2Free(font->glyphs[t]);
1179 free(font->glyphs[t]); font->glyphs[t] = 0;
1184 free(idtable[t].obj.font); idtable[t].obj.font = 0;