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;
589 if(xx<0) xx += b->width;
590 if(yy<0) yy += b->height;
593 col = b->data[yy*b->width+xx];
596 line[x].r = ((line[x].r*ainv)>>8)+col.r;
597 line[x].g = ((line[x].g*ainv)>>8)+col.g;
598 line[x].b = ((line[x].b*ainv)>>8)+col.b;
606 typedef struct _layer {
618 static void fill(RENDERBUF*dest, RGBA*line, int*zline, int y, int x1, int x2, state_t*fillstate, U32 clipdepth)
620 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
623 layer_t*l = fillstate->layers;
625 if(x1>=x2) //zero width? nothing to do.
630 /* not filled. TODO: we should never add those in the first place */
632 printf("(not filled)");
633 } else if(l->fillid > l->p->s->numfillstyles) {
634 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->numlinestyles);
635 } else if(clipdepth) {
636 /* filled region- not used for clipping */
641 printf("(%d -> %d style %d)", x1, x2, l->fillid);
643 f = &l->p->s->fillstyles[l->fillid-1];
645 if(f->type == FILL_SOLID) {
646 /* plain color fill */
647 fill_solid(line, zline, y, x1, x2, f->color, l->p->depth);
648 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
649 /* TODO: optimize (do this in add_pixel()?) */
650 bitmap_t* b = i->bitmaps;
651 while(b && b->id != f->id_bitmap) {
655 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
656 fill_solid(line, zline, y, x1, x2, color_red, l->p->depth);
658 fill_bitmap(line, zline, y, x1, x2, &f->m, b, FILL_CLIPPED?1:0, l->p->depth);
661 fprintf(stderr, "Undefined fillmode: %02x\n", f->type);
666 if(clip && clipdepth) {
667 fill_clip(line, zline, y, x1, x2, clipdepth);
671 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
673 layer_t*last=0,*l = state->layers;
674 while(l && l->p->depth < depth) {
679 if(l && l->p->depth == depth)
684 static void delete_layer(state_t*state, layer_t*todel)
686 layer_t*before=todel->prev;
687 layer_t*next = todel->next;
690 state->layers = next;
696 before->next->prev = before;
699 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
702 toadd->next = state->layers;
706 toadd->next = before->next;
707 toadd->prev = before;
708 before->next = toadd;
711 toadd->next->prev = toadd;
713 static void free_layers(state_t* state)
715 layer_t*l = state->layers;
717 layer_t*next = l->next;
723 static void change_state(int y, state_t* state, renderpoint_t*p)
725 layer_t*before=0, *self=0, *after=0;
728 printf("[(%d,%d)/%d/%d-%d]", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
731 search_layer(state, p->depth, &before, &self, &after);
735 if(self->fillid<0/*??*/ || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
737 if(DEBUG&2) printf("<D>");
739 delete_layer(state, self);
741 /*both fill0 and fill1 are set- exchange the two, updating the layer */
742 if(self->fillid == p->shapeline->fillstyle0) {
743 self->fillid = p->shapeline->fillstyle1;
745 if(DEBUG&2) printf("<X>");
746 } else if(self->fillid == p->shapeline->fillstyle1) {
747 self->fillid = p->shapeline->fillstyle0;
749 if(DEBUG&2) printf("<X>");
751 /* buggy shape. keep everything as-is. */
752 if(DEBUG&2) printf("<!>");
753 //fprintf(stderr, "<line %d: bad swap>\n", y);
759 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
760 /* this is a hack- a better way would be to make sure that
761 we always get (0,32), (32, 33), (33, 0) in the right order if
762 they happen to fall on the same pixel.
763 (not: (0,32), (33, 0), (32, 33))
765 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
769 n = rfx_calloc(sizeof(layer_t));
771 if(DEBUG&2) printf("<+>");
773 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
776 add_layer(state, before, n);
780 void swf_Process(RENDERBUF*dest, U32 clipdepth)
782 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
785 if(i->ymax < i->ymin) {
786 /* shape is empty. return.
787 only, if it's a clipshape, remember the clipdepth */
789 for(y=0;y<i->height2;y++) {
790 if(clipdepth > i->lines[y].pending_clipdepth)
791 i->lines[y].pending_clipdepth = clipdepth;
794 return; //nothing (else) to do
798 /* lines outside the clip shape are not filled
799 immediately, only the highest clipdepth so far is
800 stored there. They will be clipfilled once there's
801 actually something about to happen in that line */
802 for(y=0;y<i->ymin;y++) {
803 if(clipdepth > i->lines[y].pending_clipdepth)
804 i->lines[y].pending_clipdepth = clipdepth;
806 for(y=i->ymax+1;y<i->height2;y++) {
807 if(clipdepth > i->lines[y].pending_clipdepth)
808 i->lines[y].pending_clipdepth = clipdepth;
812 for(y=i->ymin;y<=i->ymax;y++) {
814 TAG*tag = i->lines[y].points;
815 int num = i->lines[y].num;
816 renderpoint_t*points = (renderpoint_t*)tag->data;
817 RGBA*line = &i->img[i->width2*y];
818 int*zline = &i->zbuf[i->width2*y];
821 memset(&fillstate, 0, sizeof(state_t));
822 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
824 if(i->lines[y].pending_clipdepth && !clipdepth) {
825 fill_clip(line, zline, y, 0, i->width2, i->lines[y].pending_clipdepth);
826 i->lines[y].pending_clipdepth=0;
830 renderpoint_t*p = &points[n];
831 renderpoint_t*next= n<num-1?&points[n+1]:0;
833 int endx = next?next->x:i->width2;
842 /* for clipping, the inverse is filled */
843 fill_clip(line, zline, y, lastx, startx, clipdepth);
845 change_state(y, &fillstate, p);
847 fill(dest, line, zline, y, startx, endx, &fillstate, clipdepth);
848 /* if(y == 0 && startx == 232 && endx == 418) {
849 printf("ymin=%d ymax=%d\n", i->ymin, i->ymax);
851 renderpoint_t*p = &points[n];
852 printf("x=%f depth=%08x\n", p->x, p->depth);
857 if(endx == i->width2)
861 fill_clip(line, zline, y, lastx, i->width2, clipdepth);
863 free_layers(&fillstate);
866 swf_ClearTag(i->lines[y].points);
868 i->ymin = 0x7fffffff;
869 i->ymax = -0x80000000;
872 RGBA* swf_Render(RENDERBUF*dest)
874 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
875 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
879 for(y=0;y<i->height2;y++) {
881 RGBA*line = &i->img[y*i->width2];
884 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
892 p = &img[(y/2)*dest->width];
893 for(x=0;x<dest->width;x++) {
894 RGBA*p1 = &line1[x*2];
895 RGBA*p2 = &line1[x*2+1];
896 RGBA*p3 = &line2[x*2];
897 RGBA*p4 = &line2[x*2+1];
898 p[x].r = (p1->r + p2->r + p3->r + p4->r)/4;
899 p[x].g = (p1->g + p2->g + p3->g + p4->g)/4;
900 p[x].b = (p1->b + p2->b + p3->b + p4->b)/4;
901 p[x].a = (p1->a + p2->a + p3->a + p4->a)/4;
921 enum {none_type, shape_type, image_type, text_type, font_type} type;
928 int compare_placements(const void *v1, const void *v2)
930 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
931 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
932 if(p1->depth != p2->depth)
933 return (int)p1->depth - (int)p2->depth;
936 return 1; // do the clip first
940 /* if(!p1->clipdepth) {
942 // !p1->clipdepth && !p2->clipdepth
943 return (int)p1->depth - (int)p2->depth;
945 // !p1->clipdepth && p2->clipdepth
946 if(p1->depth != p2->clipdepth)
947 return (int)p1->depth - (int)p2->clipdepth;
949 return 1; // do the clip first
953 // p1->clipdepth && !p2->clipdepth
954 if(p1->clipdepth != p2->depth)
955 return (int)p1->clipdepth - (int)p2->depth;
957 return -1;// do the clip first
959 if(p1->clipdepth != p2->clipdepth)
960 return (int)p1->clipdepth - (int)p2->clipdepth;
962 return (int)p1->depth - (int)p2->depth;
967 typedef struct textcallbackblock
975 } textcallbackblock_t;
977 static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize,
978 int xstart, int ystart, RGBA* color)
980 textcallbackblock_t * info = (textcallbackblock_t*)self;
983 if(!info->idtable[fontid].obj.font) {
984 fprintf(stderr, "Font %d unknown\n", fontid);
987 font = info->idtable[fontid].obj.font;
990 int x = xstart + xpos[t];
996 p = swf_TurnPoint(p, &m);
998 m.sx = (m.sx * fontsize) / 1024;
999 m.sy = (m.sy * fontsize) / 1024;
1000 m.r0 = (m.r0 * fontsize) / 1024;
1001 m.r1 = (m.r1 * fontsize) / 1024;
1005 if(chars[t]<0 || chars[t]>= font->numchars) {
1006 fprintf(stderr, "Character out of range: %d\n", chars[t]);
1008 SHAPE2*shape = font->glyphs[chars[t]];
1009 shape->fillstyles[0].color = *color; //q&d
1010 /*printf("Rendering char %d (size %d, x:%d, y:%d) color:%02x%02x%02x%02x\n", chars[t], fontsize, x, y,
1011 color->a, color->r, color->g, color->b);
1012 swf_DumpMatrix(stdout, &m);
1013 swf_DumpShape(shape);*/
1014 swf_RenderShape(info->buf, shape, &m, info->cxform, info->depth, info->clipdepth);
1019 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1025 SWFPLACEOBJECT* placements;
1027 character_t* idtable = rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1028 SWFPLACEOBJECT** depthtable = rfx_calloc(sizeof(SWFPLACEOBJECT*)*65536); // depth to placeobject mapping
1030 tag = swf->firstTag;
1033 if(tag->id == ST_PLACEOBJECT ||
1034 tag->id == ST_PLACEOBJECT2) {
1039 placements = rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
1042 /* set background color */
1043 color = swf_GetSWFBackgroundColor(swf);
1044 swf_Render_SetBackgroundColor(buf, color);
1046 /* parse definitions */
1047 tag = swf->firstTag;
1049 if(swf_isDefiningTag(tag)) {
1050 int id = swf_GetDefineID(tag);
1051 idtable[id].tag = tag;
1052 idtable[id].bbox = rfx_alloc(sizeof(SRECT));
1053 *idtable[id].bbox = swf_GetDefineBBox(tag);
1055 if(swf_isShapeTag(tag)) {
1056 SHAPE2* shape = rfx_calloc(sizeof(SHAPE2));
1057 swf_ParseDefineShape(tag, shape);
1058 idtable[id].type = shape_type;
1059 idtable[id].obj.shape = shape;
1060 } else if(swf_isImageTag(tag)) {
1062 RGBA*data = swf_ExtractImage(tag, &width, &height);
1063 idtable[id].type = image_type;
1064 swf_Render_AddImage(buf, id, data, width, height);
1066 } else if(tag->id == ST_DEFINEFONT ||
1067 tag->id == ST_DEFINEFONT2) {
1070 font_t*font = rfx_calloc(sizeof(font_t));
1071 idtable[id].obj.font = font;
1072 swf_FontExtract(swf,id,&swffont);
1073 font->numchars = swffont->numchars;
1074 font->glyphs = rfx_calloc(sizeof(SHAPE2*)*font->numchars);
1075 for(t=0;t<font->numchars;t++) {
1076 if(!swffont->glyph[t].shape->fillstyle.n) {
1077 /* the actual fill color will be overwritten while rendering */
1078 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
1080 font->glyphs[t] = swf_ShapeToShape2(swffont->glyph[t].shape);
1082 swf_FontFree(swffont);
1083 idtable[id].type = font_type;
1085 } else if(tag->id == ST_DEFINEFONTINFO ||
1086 tag->id == ST_DEFINEFONTINFO2) {
1087 idtable[id].type = font_type;
1088 } else if(tag->id == ST_DEFINETEXT ||
1089 tag->id == ST_DEFINETEXT2) {
1090 idtable[id].type = text_type;
1092 } else if(tag->id == ST_PLACEOBJECT ||
1093 tag->id == ST_PLACEOBJECT2) {
1095 swf_GetPlaceObject(tag, &p);
1096 /* TODO: add move and deletion */
1097 placements[numplacements++] = p;
1098 swf_PlaceObjectFree(&p); //dirty! but it only removes items we don't need
1103 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1105 for(t=0;t<numplacements;t++) {
1106 SWFPLACEOBJECT*p = &placements[t];
1109 if(!idtable[id].tag) {
1110 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1114 if(idtable[id].type == shape_type) {
1115 //SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1116 swf_RenderShape(buf, idtable[id].obj.shape, &p->matrix, &p->cxform, p->depth, p->clipdepth);
1117 } else if(idtable[id].type == text_type) {
1118 TAG* tag = idtable[id].tag;
1119 textcallbackblock_t info;
1122 swf_SetTagPos(tag, 0);
1125 swf_GetMatrix(tag,&m);
1126 swf_MatrixJoin(&info.m, &m, &p->matrix);
1127 /*printf("Text matrix:\n");
1128 swf_DumpMatrix(stdout, &m);
1129 printf("Placement matrix:\n");
1130 swf_DumpMatrix(stdout, &p->matrix);*/
1132 info.idtable = idtable;
1133 info.depth = p->depth;
1134 info.cxform = &p->cxform;
1135 info.clipdepth = p->clipdepth;
1138 swf_ParseDefineText(tag, textcallback, &info);
1140 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1144 /* free id and depth tables again */
1145 for(t=0;t<65536;t++) {
1146 if(idtable[t].bbox) {
1147 free(idtable[t].bbox);
1150 if(idtable[t].type == shape_type) {
1151 SHAPE2* shape = idtable[t].obj.shape;
1153 swf_Shape2Free(shape); // FIXME
1154 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;
1156 } else if(idtable[t].type == font_type) {
1157 font_t* font = idtable[t].obj.font;
1161 for(t=0;t<font->numchars;t++) {
1162 swf_Shape2Free(font->glyphs[t]);
1163 free(font->glyphs[t]); font->glyphs[t] = 0;
1168 free(idtable[t].obj.font); idtable[t].obj.font = 0;