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, double 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 */
198 /* TODO: how does this interact with scaling? */
199 if(width * i->multiply < 20)
200 width = 20 / i->multiply;
203 sd = (double)dx*(double)dx+(double)dy*(double)dy;
225 add_line(buf, x1+vx, y1+vy, xx, yy, p);
228 for(t=1;t<segments;t++) {
229 double s = sin(t*PI/segments);
230 double c = cos(t*PI/segments);
231 xx = (x2 + vx*c - vy*s);
232 yy = (y2 + vx*s + vy*c);
233 add_line(buf, lastx, lasty, xx, yy, p);
240 add_line(buf, lastx, lasty, xx, yy, p);
245 add_line(buf, lastx, lasty, xx, yy, p);
248 for(t=1;t<segments;t++) {
249 double s = sin(t*PI/segments);
250 double c = cos(t*PI/segments);
251 xx = (x1 - vx*c + vy*s);
252 yy = (y1 - vx*s - vy*c);
253 add_line(buf, lastx, lasty, xx, yy, p);
257 add_line(buf, lastx, lasty, (x1+vx), (y1+vy), p);
260 static inline void transform_point(MATRIX*m, int x, int y, int*dx, int*dy)
265 d = swf_TurnPoint(p, m);
270 static int compare_renderpoints(const void * _a, const void * _b)
272 renderpoint_t*a = (renderpoint_t*)_a;
273 renderpoint_t*b = (renderpoint_t*)_b;
274 if(a->x < b->x) return -1;
275 if(a->x > b->x) return 1;
279 void swf_Render_Init(RENDERBUF*buf, int posx, int posy, int width, int height, int antialize, int multiply)
281 renderbuf_internal*i;
283 memset(buf, 0, sizeof(RENDERBUF));
284 buf->width = width*multiply;
285 buf->height = height*multiply;
288 buf->internal = (renderbuf_internal*)rfx_calloc(sizeof(renderbuf_internal));
289 i = (renderbuf_internal*)buf->internal;
292 i->antialize = antialize;
293 i->multiply = multiply*antialize;
294 i->height2 = antialize*buf->height;
295 i->width2 = antialize*buf->width;
296 i->lines = (renderline_t*)rfx_alloc(i->height2*sizeof(renderline_t));
297 for(y=0;y<i->height2;y++) {
298 memset(&i->lines[y], 0, sizeof(renderline_t));
299 i->lines[y].points = swf_InsertTag(0, 0);
302 i->zbuf = (int*)rfx_calloc(sizeof(int)*i->width2*i->height2);
303 i->img = (RGBA*)rfx_calloc(sizeof(RGBA)*i->width2*i->height2);
305 i->ymin = 0x7fffffff;
306 i->ymax = -0x80000000;
308 void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height)
310 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
312 int xstep=width*65536/i->width2;
313 int ystep=height*65536/i->height2;
315 fprintf(stderr, "rfxswf: Warning: swf_Render_SetBackground() called after drawing shapes\n");
317 for(y=0,yy=0;y<i->height2;y++,yy+=ystep) {
318 RGBA*src = &img[(yy>>16) * width];
319 RGBA*line = &i->img[y * i->width2];
320 for(x=0,xx=0;x<i->width2;x++,xx+=xstep) {
321 line[x] = src[xx>>16];
325 void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color)
327 swf_Render_SetBackground(buf, &color, 1, 1);
329 void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height)
331 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
333 bitmap_t*bm = rfx_calloc(sizeof(bitmap_t));
337 bm->data = rfx_alloc(width*height*4);
338 memcpy(bm->data, img, width*height*4);
340 bm->next = i->bitmaps;
343 void swf_Render_ClearCanvas(RENDERBUF*dest)
345 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
347 for(y=0;y<i->height2;y++) {
348 swf_ClearTag(i->lines[y].points);
350 memset(i->zbuf, 0, sizeof(int)*i->width2*i->height2);
351 memset(i->img, 0, sizeof(RGBA)*i->width2*i->height2);
353 void swf_Render_Delete(RENDERBUF*dest)
355 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
357 bitmap_t*b = i->bitmaps;
363 /* delete line buffers */
364 for(y=0;y<i->height2;y++) {
365 swf_DeleteTag(i->lines[y].points);
366 i->lines[y].points = 0;
371 bitmap_t*next = b->next;
372 free(b->data);b->data=0;
377 rfx_free(i->lines); i->lines = 0;
378 rfx_free(dest->internal); dest->internal = 0;
381 static SHAPE2* linestyle2fillstyle(SHAPE2*shape)
383 SHAPE2*s = rfx_calloc(sizeof(SHAPE2));
385 s->numfillstyles = shape->numlinestyles;
386 s->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles);
387 s->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles);
388 for(t=0;t<shape->numlinestyles;t++) {
389 s->lines[t].fillstyle0 = t+1;
390 s->fillstyles[t].type = FILL_SOLID;
391 s->fillstyles[t].color = shape->linestyles[t].color;
396 void swf_Process(RENDERBUF*dest, U32 clipdepth);
398 double matrixsize(MATRIX*m)
400 double l1 = sqrt((m->sx /65536.0) * (m->sx /65536.0) + (m->r0 /65536.0) * (m->r0/65536.0) );
401 double l2 = sqrt((m->r1 /65536.0) * (m->r1 /65536.0) + (m->sy /65536.0) * (m->sy/65536.0) );
405 void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth)
407 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
416 double widthmultiply = matrixsize(m);
418 memset(&p, 0, sizeof(renderpoint_t));
419 memset(&lp, 0, sizeof(renderpoint_t));
421 clipdepth = _clipdepth? _clipdepth << 16 | 0xffff : 0;
422 p.depth = _depth << 16;
424 mat.tx -= dest->posx*20;
425 mat.ty -= dest->posy*20;
427 s2 = swf_Shape2Clone(shape);
429 if(shape->numfillstyles) {
432 /* multiply fillstyles matrices with placement matrix-
433 important for texture and gradient fill */
434 for(t=0;t<s2->numfillstyles;t++) {
436 swf_MatrixJoin(&nm, &s2->fillstyles[t].m, &mat); //TODO: is this the right order?
437 /*nm.sx *= i->multiply;
438 nm.sy *= i->multiply;
439 nm.r0 *= i->multiply;
440 nm.r1 *= i->multiply;
441 nm.tx *= i->multiply;
442 nm.ty *= i->multiply;*/
443 s2->fillstyles[t].m = nm;
447 if(shape->numlinestyles) {
448 lshape = linestyle2fillstyle(shape);
450 lp.depth = (_depth << 16)+1;
456 int x1,y1,x2,y2,x3,y3;
458 if(line->type == moveTo) {
459 } else if(line->type == lineTo) {
460 transform_point(&mat, x, y, &x1, &y1);
461 transform_point(&mat, line->x, line->y, &x3, &y3);
463 if(line->linestyle && ! clipdepth) {
464 lp.shapeline = &lshape->lines[line->linestyle-1];
465 add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width * widthmultiply, &lp);
468 if(line->fillstyle0 || line->fillstyle1) {
469 assert(shape->numfillstyles);
471 add_line(dest, x1, y1, x3, y3, &p);
473 } else if(line->type == splineTo) {
474 int c,t,parts,qparts;
477 transform_point(&mat, x, y, &x1, &y1);
478 transform_point(&mat, line->sx, line->sy, &x2, &y2);
479 transform_point(&mat, line->x, line->y, &x3, &y3);
481 c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1);
485 parts = (int)(sqrt(c)/3);
486 if(!parts) parts = 1;
488 for(t=1;t<=parts;t++) {
489 double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts);
490 double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts);
492 if(line->linestyle && ! clipdepth) {
493 lp.shapeline = &lshape->lines[line->linestyle-1];
494 add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width * widthmultiply, &lp);
497 if(line->fillstyle0 || line->fillstyle1) {
498 assert(shape->numfillstyles);
500 add_line(dest, xx, yy, nx, ny, &p);
512 swf_Process(dest, clipdepth);
515 swf_Shape2Free(s2);rfx_free(s2);s2=0;
518 swf_Shape2Free(lshape);rfx_free(lshape);lshape=0;
523 static RGBA color_red = {255,255,0,0};
524 static RGBA color_white = {255,255,255,255};
525 static RGBA color_black = {255,0,0,0};
527 static void fill_clip(RGBA*line, int*z, int y, int x1, int x2, U32 depth)
539 static void fill_solid(RGBA*line, int*z, int y, int x1, int x2, RGBA col, U32 depth)
544 int ainv = 255-col.a;
545 col.r = (col.r*col.a)>>8;
546 col.g = (col.g*col.a)>>8;
547 col.b = (col.b*col.a)>>8;
551 line[x].r = ((line[x].r*ainv)>>8)+col.r;
552 line[x].g = ((line[x].g*ainv)>>8)+col.g;
553 line[x].b = ((line[x].b*ainv)>>8)+col.b;
568 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)
572 double m11= m->sx*fmultiply/65536.0, m21= m->r1*fmultiply/65536.0;
573 double m12= m->r0*fmultiply/65536.0, m22= m->sy*fmultiply/65536.0;
574 double rx = m->tx*fmultiply/20.0;
575 double ry = m->ty*fmultiply/20.0;
577 double det = m11*m22 - m12*m21;
578 if(fabs(det) < 0.0005) {
579 /* x direction equals y direction- the image is invisible */
584 if(!b->width || !b->height) {
585 fill_solid(line, z, y, x1, x2, color_red, depth);
592 int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det);
593 int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
598 if(xx>=b->width) xx = b->width-1;
600 if(yy>=b->height) yy = b->height-1;
604 if(xx<0) xx += b->width;
605 if(yy<0) yy += b->height;
608 col = b->data[yy*b->width+xx];
611 line[x].r = ((line[x].r*ainv)>>8)+col.r;
612 line[x].g = ((line[x].g*ainv)>>8)+col.g;
613 line[x].b = ((line[x].b*ainv)>>8)+col.b;
621 typedef struct _layer {
633 static void fill(RENDERBUF*dest, RGBA*line, int*zline, int y, int x1, int x2, state_t*fillstate, U32 clipdepth)
635 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
638 layer_t*l = fillstate->layers;
640 if(x1>=x2) //zero width? nothing to do.
645 /* not filled. TODO: we should never add those in the first place */
647 printf("(not filled)");
648 } else if(l->fillid > l->p->s->numfillstyles) {
649 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->numlinestyles);
650 } else if(clipdepth) {
651 /* filled region- not used for clipping */
656 printf("(%d -> %d style %d)", x1, x2, l->fillid);
658 f = &l->p->s->fillstyles[l->fillid-1];
660 if(f->type == FILL_SOLID) {
661 /* plain color fill */
662 fill_solid(line, zline, y, x1, x2, f->color, l->p->depth);
663 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
664 /* TODO: optimize (do this in add_pixel()?) */
665 bitmap_t* b = i->bitmaps;
666 while(b && b->id != f->id_bitmap) {
670 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
671 fill_solid(line, zline, y, x1, x2, color_red, l->p->depth);
673 fill_bitmap(line, zline, y, x1, x2, &f->m, b, FILL_CLIPPED?1:0, l->p->depth, i->multiply);
676 fprintf(stderr, "Undefined fillmode: %02x\n", f->type);
681 if(clip && clipdepth) {
682 fill_clip(line, zline, y, x1, x2, clipdepth);
686 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
688 layer_t*last=0,*l = state->layers;
689 while(l && l->p->depth < depth) {
694 if(l && l->p->depth == depth)
699 static void delete_layer(state_t*state, layer_t*todel)
701 layer_t*before=todel->prev;
702 layer_t*next = todel->next;
705 state->layers = next;
711 before->next->prev = before;
714 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
717 toadd->next = state->layers;
721 toadd->next = before->next;
722 toadd->prev = before;
723 before->next = toadd;
726 toadd->next->prev = toadd;
728 static void free_layers(state_t* state)
730 layer_t*l = state->layers;
732 layer_t*next = l->next;
738 static void change_state(int y, state_t* state, renderpoint_t*p)
740 layer_t*before=0, *self=0, *after=0;
743 printf("[(%d,%d)/%d/%d-%d]", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
746 search_layer(state, p->depth, &before, &self, &after);
750 if(self->fillid<0/*??*/ || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
752 if(DEBUG&2) printf("<D>");
754 delete_layer(state, self);
756 /*both fill0 and fill1 are set- exchange the two, updating the layer */
757 if(self->fillid == p->shapeline->fillstyle0) {
758 self->fillid = p->shapeline->fillstyle1;
760 if(DEBUG&2) printf("<X>");
761 } else if(self->fillid == p->shapeline->fillstyle1) {
762 self->fillid = p->shapeline->fillstyle0;
764 if(DEBUG&2) printf("<X>");
766 /* buggy shape. keep everything as-is. */
767 if(DEBUG&2) printf("<!>");
768 //fprintf(stderr, "<line %d: bad swap>\n", y);
774 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
775 /* this is a hack- a better way would be to make sure that
776 we always get (0,32), (32, 33), (33, 0) in the right order if
777 they happen to fall on the same pixel.
778 (not: (0,32), (33, 0), (32, 33))
780 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
784 n = rfx_calloc(sizeof(layer_t));
786 if(DEBUG&2) printf("<+>");
788 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
791 add_layer(state, before, n);
795 void swf_Process(RENDERBUF*dest, U32 clipdepth)
797 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
800 if(i->ymax < i->ymin) {
801 /* shape is empty. return.
802 only, if it's a clipshape, remember the clipdepth */
804 for(y=0;y<i->height2;y++) {
805 if(clipdepth > i->lines[y].pending_clipdepth)
806 i->lines[y].pending_clipdepth = clipdepth;
809 return; //nothing (else) to do
813 /* lines outside the clip shape are not filled
814 immediately, only the highest clipdepth so far is
815 stored there. They will be clipfilled once there's
816 actually something about to happen in that line */
817 for(y=0;y<i->ymin;y++) {
818 if(clipdepth > i->lines[y].pending_clipdepth)
819 i->lines[y].pending_clipdepth = clipdepth;
821 for(y=i->ymax+1;y<i->height2;y++) {
822 if(clipdepth > i->lines[y].pending_clipdepth)
823 i->lines[y].pending_clipdepth = clipdepth;
827 for(y=i->ymin;y<=i->ymax;y++) {
829 TAG*tag = i->lines[y].points;
830 int num = i->lines[y].num;
831 renderpoint_t*points = (renderpoint_t*)tag->data;
832 RGBA*line = &i->img[i->width2*y];
833 int*zline = &i->zbuf[i->width2*y];
836 memset(&fillstate, 0, sizeof(state_t));
837 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
839 if(i->lines[y].pending_clipdepth && !clipdepth) {
840 fill_clip(line, zline, y, 0, i->width2, i->lines[y].pending_clipdepth);
841 i->lines[y].pending_clipdepth=0;
845 renderpoint_t*p = &points[n];
846 renderpoint_t*next= n<num-1?&points[n+1]:0;
848 int endx = next?next->x:i->width2;
857 /* for clipping, the inverse is filled */
858 fill_clip(line, zline, y, lastx, startx, clipdepth);
860 change_state(y, &fillstate, p);
862 fill(dest, line, zline, y, startx, endx, &fillstate, clipdepth);
863 /* if(y == 0 && startx == 232 && endx == 418) {
864 printf("ymin=%d ymax=%d\n", i->ymin, i->ymax);
866 renderpoint_t*p = &points[n];
867 printf("x=%f depth=%08x\n", p->x, p->depth);
872 if(endx == i->width2)
876 fill_clip(line, zline, y, lastx, i->width2, clipdepth);
878 free_layers(&fillstate);
881 swf_ClearTag(i->lines[y].points);
883 i->ymin = 0x7fffffff;
884 i->ymax = -0x80000000;
887 RGBA* swf_Render(RENDERBUF*dest)
889 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
890 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
892 int antialize = i->antialize;
894 if(antialize <= 1) /* no antializing */ {
895 for(y=0;y<i->height2;y++) {
896 RGBA*line = &i->img[y*i->width2];
897 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
900 RGBA**lines = (RGBA**)rfx_calloc(sizeof(RGBA*)*antialize);
901 int q = antialize*antialize;
903 for(y=0;y<i->height2;y++) {
905 ypos = y % antialize;
906 lines[ypos] = &i->img[y*i->width2];
907 if(ypos == antialize-1) {
908 RGBA*out = &img[(y / antialize)*dest->width];
911 for(x=0;x<dest->width;x++) {
912 int xpos = x*antialize;
915 for(yp=0;yp<antialize;yp++) {
916 RGBA*lp = &lines[yp][xpos];
918 for(xp=0;xp<antialize;xp++) {
948 enum {none_type, shape_type, image_type, text_type, font_type} type;
955 int compare_placements(const void *v1, const void *v2)
957 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
958 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
959 if(p1->depth != p2->depth)
960 return (int)p1->depth - (int)p2->depth;
963 return 1; // do the clip first
967 /* if(!p1->clipdepth) {
969 // !p1->clipdepth && !p2->clipdepth
970 return (int)p1->depth - (int)p2->depth;
972 // !p1->clipdepth && p2->clipdepth
973 if(p1->depth != p2->clipdepth)
974 return (int)p1->depth - (int)p2->clipdepth;
976 return 1; // do the clip first
980 // p1->clipdepth && !p2->clipdepth
981 if(p1->clipdepth != p2->depth)
982 return (int)p1->clipdepth - (int)p2->depth;
984 return -1;// do the clip first
986 if(p1->clipdepth != p2->clipdepth)
987 return (int)p1->clipdepth - (int)p2->clipdepth;
989 return (int)p1->depth - (int)p2->depth;
994 typedef struct textcallbackblock
1002 } textcallbackblock_t;
1004 static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize,
1005 int xstart, int ystart, RGBA* color)
1007 textcallbackblock_t * info = (textcallbackblock_t*)self;
1010 if(!info->idtable[fontid].obj.font) {
1011 fprintf(stderr, "Font %d unknown\n", fontid);
1014 font = info->idtable[fontid].obj.font;
1017 int x = xstart + xpos[t];
1023 p = swf_TurnPoint(p, &m);
1025 m.sx = (m.sx * fontsize) / 1024;
1026 m.sy = (m.sy * fontsize) / 1024;
1027 m.r0 = (m.r0 * fontsize) / 1024;
1028 m.r1 = (m.r1 * fontsize) / 1024;
1032 if(chars[t]<0 || chars[t]>= font->numchars) {
1033 fprintf(stderr, "Character out of range: %d\n", chars[t]);
1035 SHAPE2*shape = font->glyphs[chars[t]];
1036 shape->fillstyles[0].color = *color; //q&d
1037 /*printf("Rendering char %d (size %d, x:%d, y:%d) color:%02x%02x%02x%02x\n", chars[t], fontsize, x, y,
1038 color->a, color->r, color->g, color->b);
1039 swf_DumpMatrix(stdout, &m);
1040 swf_DumpShape(shape);*/
1041 swf_RenderShape(info->buf, shape, &m, info->cxform, info->depth, info->clipdepth);
1046 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1052 SWFPLACEOBJECT* placements;
1054 character_t* idtable = rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1055 SWFPLACEOBJECT** depthtable = rfx_calloc(sizeof(SWFPLACEOBJECT*)*65536); // depth to placeobject mapping
1057 tag = swf->firstTag;
1060 if(tag->id == ST_PLACEOBJECT ||
1061 tag->id == ST_PLACEOBJECT2) {
1066 placements = rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
1069 /* set background color */
1070 color = swf_GetSWFBackgroundColor(swf);
1071 swf_Render_SetBackgroundColor(buf, color);
1073 /* parse definitions */
1074 tag = swf->firstTag;
1076 if(swf_isDefiningTag(tag)) {
1077 int id = swf_GetDefineID(tag);
1078 idtable[id].tag = tag;
1079 idtable[id].bbox = rfx_alloc(sizeof(SRECT));
1080 *idtable[id].bbox = swf_GetDefineBBox(tag);
1082 if(swf_isShapeTag(tag)) {
1083 SHAPE2* shape = rfx_calloc(sizeof(SHAPE2));
1084 swf_ParseDefineShape(tag, shape);
1085 idtable[id].type = shape_type;
1086 idtable[id].obj.shape = shape;
1087 } else if(swf_isImageTag(tag)) {
1089 RGBA*data = swf_ExtractImage(tag, &width, &height);
1090 idtable[id].type = image_type;
1091 swf_Render_AddImage(buf, id, data, width, height);
1093 } else if(tag->id == ST_DEFINEFONT ||
1094 tag->id == ST_DEFINEFONT2) {
1097 font_t*font = rfx_calloc(sizeof(font_t));
1098 idtable[id].obj.font = font;
1099 swf_FontExtract(swf,id,&swffont);
1100 font->numchars = swffont->numchars;
1101 font->glyphs = rfx_calloc(sizeof(SHAPE2*)*font->numchars);
1102 for(t=0;t<font->numchars;t++) {
1103 if(!swffont->glyph[t].shape->fillstyle.n) {
1104 /* the actual fill color will be overwritten while rendering */
1105 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
1107 font->glyphs[t] = swf_ShapeToShape2(swffont->glyph[t].shape);
1109 swf_FontFree(swffont);
1110 idtable[id].type = font_type;
1112 } else if(tag->id == ST_DEFINEFONTINFO ||
1113 tag->id == ST_DEFINEFONTINFO2) {
1114 idtable[id].type = font_type;
1115 } else if(tag->id == ST_DEFINETEXT ||
1116 tag->id == ST_DEFINETEXT2) {
1117 idtable[id].type = text_type;
1119 } else if(tag->id == ST_PLACEOBJECT ||
1120 tag->id == ST_PLACEOBJECT2) {
1122 swf_GetPlaceObject(tag, &p);
1123 /* TODO: add move and deletion */
1124 placements[numplacements++] = p;
1125 swf_PlaceObjectFree(&p); //dirty! but it only removes items we don't need
1130 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1132 for(t=0;t<numplacements;t++) {
1133 SWFPLACEOBJECT*p = &placements[t];
1136 if(!idtable[id].tag) {
1137 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1141 if(idtable[id].type == shape_type) {
1142 //SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1143 swf_RenderShape(buf, idtable[id].obj.shape, &p->matrix, &p->cxform, p->depth, p->clipdepth);
1144 } else if(idtable[id].type == text_type) {
1145 TAG* tag = idtable[id].tag;
1146 textcallbackblock_t info;
1149 swf_SetTagPos(tag, 0);
1152 swf_GetMatrix(tag,&m);
1153 swf_MatrixJoin(&info.m, &m, &p->matrix);
1154 /*printf("Text matrix:\n");
1155 swf_DumpMatrix(stdout, &m);
1156 printf("Placement matrix:\n");
1157 swf_DumpMatrix(stdout, &p->matrix);*/
1159 info.idtable = idtable;
1160 info.depth = p->depth;
1161 info.cxform = &p->cxform;
1162 info.clipdepth = p->clipdepth;
1165 swf_ParseDefineText(tag, textcallback, &info);
1167 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1171 /* free id and depth tables again */
1172 for(t=0;t<65536;t++) {
1173 if(idtable[t].bbox) {
1174 free(idtable[t].bbox);
1177 if(idtable[t].type == shape_type) {
1178 SHAPE2* shape = idtable[t].obj.shape;
1180 swf_Shape2Free(shape); // FIXME
1181 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;
1183 } else if(idtable[t].type == font_type) {
1184 font_t* font = idtable[t].obj.font;
1188 for(t=0;t<font->numchars;t++) {
1189 swf_Shape2Free(font->glyphs[t]);
1190 free(font->glyphs[t]); font->glyphs[t] = 0;
1195 free(idtable[t].obj.font); idtable[t].obj.font = 0;