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, &mat, &s2->fillstyles[t].m);
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)
540 static void fill_solid(RGBA*line, int*z, int y, int x1, int x2, RGBA col, U32 depth)
545 int ainv = 255-col.a;
546 col.r = (col.r*col.a)>>8;
547 col.g = (col.g*col.a)>>8;
548 col.b = (col.b*col.a)>>8;
552 line[x].r = ((line[x].r*ainv)>>8)+col.r;
553 line[x].g = ((line[x].g*ainv)>>8)+col.g;
554 line[x].b = ((line[x].b*ainv)>>8)+col.b;
569 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)
573 double m11= m->sx*fmultiply/65536.0, m21= m->r1*fmultiply/65536.0;
574 double m12= m->r0*fmultiply/65536.0, m22= m->sy*fmultiply/65536.0;
575 double rx = m->tx*fmultiply/20.0;
576 double ry = m->ty*fmultiply/20.0;
578 double det = m11*m22 - m12*m21;
579 if(fabs(det) < 0.0005) {
580 /* x direction equals y direction- the image is invisible */
585 if(!b->width || !b->height) {
586 fill_solid(line, z, y, x1, x2, color_red, depth);
593 int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det);
594 int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
599 if(xx>=b->width) xx = b->width-1;
601 if(yy>=b->height) yy = b->height-1;
605 if(xx<0) xx += b->width;
606 if(yy<0) yy += b->height;
609 col = b->data[yy*b->width+xx];
612 line[x].r = ((line[x].r*ainv)>>8)+col.r;
613 line[x].g = ((line[x].g*ainv)>>8)+col.g;
614 line[x].b = ((line[x].b*ainv)>>8)+col.b;
622 typedef struct _layer {
634 static void fill(RENDERBUF*dest, RGBA*line, int*zline, int y, int x1, int x2, state_t*fillstate, U32 clipdepth)
636 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
639 layer_t*l = fillstate->layers;
641 if(x1>=x2) //zero width? nothing to do.
646 /* not filled. TODO: we should never add those in the first place */
648 printf("(not filled)");
649 } else if(l->fillid > l->p->s->numfillstyles) {
650 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->numlinestyles);
651 } else if(clipdepth) {
652 /* filled region- not used for clipping */
657 printf("(%d -> %d style %d)", x1, x2, l->fillid);
659 f = &l->p->s->fillstyles[l->fillid-1];
661 if(f->type == FILL_SOLID) {
662 /* plain color fill */
663 fill_solid(line, zline, y, x1, x2, f->color, l->p->depth);
664 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
665 /* TODO: optimize (do this in add_pixel()?) */
666 bitmap_t* b = i->bitmaps;
667 while(b && b->id != f->id_bitmap) {
671 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
672 fill_solid(line, zline, y, x1, x2, color_red, l->p->depth);
674 fill_bitmap(line, zline, y, x1, x2, &f->m, b, FILL_CLIPPED?1:0, l->p->depth, i->multiply);
677 fprintf(stderr, "Undefined fillmode: %02x\n", f->type);
682 if(clip && clipdepth) {
683 fill_clip(line, zline, y, x1, x2, clipdepth);
687 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
689 layer_t*last=0,*l = state->layers;
690 while(l && l->p->depth < depth) {
695 if(l && l->p->depth == depth)
700 static void delete_layer(state_t*state, layer_t*todel)
702 layer_t*before=todel->prev;
703 layer_t*next = todel->next;
706 state->layers = next;
712 before->next->prev = before;
715 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
718 toadd->next = state->layers;
722 toadd->next = before->next;
723 toadd->prev = before;
724 before->next = toadd;
727 toadd->next->prev = toadd;
729 static void free_layers(state_t* state)
731 layer_t*l = state->layers;
733 layer_t*next = l->next;
739 static void change_state(int y, state_t* state, renderpoint_t*p)
741 layer_t*before=0, *self=0, *after=0;
744 printf("[(%d,%d)/%d/%d-%d]", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
747 search_layer(state, p->depth, &before, &self, &after);
751 if(self->fillid<0/*??*/ || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
753 if(DEBUG&2) printf("<D>");
755 delete_layer(state, self);
757 /*both fill0 and fill1 are set- exchange the two, updating the layer */
758 if(self->fillid == p->shapeline->fillstyle0) {
759 self->fillid = p->shapeline->fillstyle1;
761 if(DEBUG&2) printf("<X>");
762 } else if(self->fillid == p->shapeline->fillstyle1) {
763 self->fillid = p->shapeline->fillstyle0;
765 if(DEBUG&2) printf("<X>");
767 /* buggy shape. keep everything as-is. */
768 if(DEBUG&2) printf("<!>");
769 //fprintf(stderr, "<line %d: bad swap>\n", y);
775 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
776 /* this is a hack- a better way would be to make sure that
777 we always get (0,32), (32, 33), (33, 0) in the right order if
778 they happen to fall on the same pixel.
779 (not: (0,32), (33, 0), (32, 33))
781 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
785 n = rfx_calloc(sizeof(layer_t));
787 if(DEBUG&2) printf("<+>");
789 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
792 add_layer(state, before, n);
796 void swf_Process(RENDERBUF*dest, U32 clipdepth)
798 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
801 if(i->ymax < i->ymin) {
802 /* shape is empty. return.
803 only, if it's a clipshape, remember the clipdepth */
805 for(y=0;y<i->height2;y++) {
806 if(clipdepth > i->lines[y].pending_clipdepth)
807 i->lines[y].pending_clipdepth = clipdepth;
810 return; //nothing (else) to do
814 /* lines outside the clip shape are not filled
815 immediately, only the highest clipdepth so far is
816 stored there. They will be clipfilled once there's
817 actually something about to happen in that line */
818 for(y=0;y<i->ymin;y++) {
819 if(clipdepth > i->lines[y].pending_clipdepth)
820 i->lines[y].pending_clipdepth = clipdepth;
822 for(y=i->ymax+1;y<i->height2;y++) {
823 if(clipdepth > i->lines[y].pending_clipdepth)
824 i->lines[y].pending_clipdepth = clipdepth;
828 for(y=i->ymin;y<=i->ymax;y++) {
830 TAG*tag = i->lines[y].points;
831 int num = i->lines[y].num;
832 renderpoint_t*points = (renderpoint_t*)tag->data;
833 RGBA*line = &i->img[i->width2*y];
834 int*zline = &i->zbuf[i->width2*y];
837 memset(&fillstate, 0, sizeof(state_t));
838 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
840 if(i->lines[y].pending_clipdepth && !clipdepth) {
841 fill_clip(line, zline, y, 0, i->width2, i->lines[y].pending_clipdepth);
842 i->lines[y].pending_clipdepth=0;
846 renderpoint_t*p = &points[n];
847 renderpoint_t*next= n<num-1?&points[n+1]:0;
849 int endx = next?next->x:i->width2;
858 /* for clipping, the inverse is filled
859 TODO: lastx!=startx only at the start of the loop,
860 so this might be moved up
862 fill_clip(line, zline, y, lastx, startx, clipdepth);
864 change_state(y, &fillstate, p);
866 fill(dest, line, zline, y, startx, endx, &fillstate, clipdepth);
867 /* if(y == 0 && startx == 232 && endx == 418) {
868 printf("ymin=%d ymax=%d\n", i->ymin, i->ymax);
870 renderpoint_t*p = &points[n];
871 printf("x=%f depth=%08x\n", p->x, p->depth);
876 if(endx == i->width2)
880 /* TODO: is lastx *ever* != i->width2 here? */
881 fill_clip(line, zline, y, lastx, i->width2, clipdepth);
883 free_layers(&fillstate);
886 swf_ClearTag(i->lines[y].points);
888 i->ymin = 0x7fffffff;
889 i->ymax = -0x80000000;
892 RGBA* swf_Render(RENDERBUF*dest)
894 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
895 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
897 int antialize = i->antialize;
899 if(antialize <= 1) /* no antializing */ {
900 for(y=0;y<i->height2;y++) {
901 RGBA*line = &i->img[y*i->width2];
902 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
905 RGBA**lines = (RGBA**)rfx_calloc(sizeof(RGBA*)*antialize);
906 int q = antialize*antialize;
908 for(y=0;y<i->height2;y++) {
910 ypos = y % antialize;
911 lines[ypos] = &i->img[y*i->width2];
912 if(ypos == antialize-1) {
913 RGBA*out = &img[(y / antialize)*dest->width];
916 for(x=0;x<dest->width;x++) {
917 int xpos = x*antialize;
920 for(yp=0;yp<antialize;yp++) {
921 RGBA*lp = &lines[yp][xpos];
923 for(xp=0;xp<antialize;xp++) {
953 enum {none_type, shape_type, image_type, text_type, font_type} type;
960 int compare_placements(const void *v1, const void *v2)
962 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
963 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
964 if(p1->depth != p2->depth)
965 return (int)p1->depth - (int)p2->depth;
968 return 1; // do the clip first
972 /* if(!p1->clipdepth) {
974 // !p1->clipdepth && !p2->clipdepth
975 return (int)p1->depth - (int)p2->depth;
977 // !p1->clipdepth && p2->clipdepth
978 if(p1->depth != p2->clipdepth)
979 return (int)p1->depth - (int)p2->clipdepth;
981 return 1; // do the clip first
985 // p1->clipdepth && !p2->clipdepth
986 if(p1->clipdepth != p2->depth)
987 return (int)p1->clipdepth - (int)p2->depth;
989 return -1;// do the clip first
991 if(p1->clipdepth != p2->clipdepth)
992 return (int)p1->clipdepth - (int)p2->clipdepth;
994 return (int)p1->depth - (int)p2->depth;
999 typedef struct textcallbackblock
1001 character_t*idtable;
1007 } textcallbackblock_t;
1009 static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize,
1010 int xstart, int ystart, RGBA* color)
1012 textcallbackblock_t * info = (textcallbackblock_t*)self;
1015 if(!info->idtable[fontid].obj.font) {
1016 fprintf(stderr, "Font %d unknown\n", fontid);
1019 font = info->idtable[fontid].obj.font;
1022 int x = xstart + xpos[t];
1028 p = swf_TurnPoint(p, &m);
1030 m.sx = (m.sx * fontsize) / 1024;
1031 m.sy = (m.sy * fontsize) / 1024;
1032 m.r0 = (m.r0 * fontsize) / 1024;
1033 m.r1 = (m.r1 * fontsize) / 1024;
1037 if(chars[t]<0 || chars[t]>= font->numchars) {
1038 fprintf(stderr, "Character out of range: %d\n", chars[t]);
1040 SHAPE2*shape = font->glyphs[chars[t]];
1041 shape->fillstyles[0].color = *color; //q&d
1042 /*printf("Rendering char %d (size %d, x:%d, y:%d) color:%02x%02x%02x%02x\n", chars[t], fontsize, x, y,
1043 color->a, color->r, color->g, color->b);
1044 swf_DumpMatrix(stdout, &m);
1045 swf_DumpShape(shape);*/
1046 swf_RenderShape(info->buf, shape, &m, info->cxform, info->depth, info->clipdepth);
1051 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1057 SWFPLACEOBJECT* placements;
1059 character_t* idtable = rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1060 SWFPLACEOBJECT** depthtable = rfx_calloc(sizeof(SWFPLACEOBJECT*)*65536); // depth to placeobject mapping
1062 tag = swf->firstTag;
1065 if(tag->id == ST_PLACEOBJECT ||
1066 tag->id == ST_PLACEOBJECT2) {
1071 placements = rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
1074 /* set background color */
1075 color = swf_GetSWFBackgroundColor(swf);
1076 swf_Render_SetBackgroundColor(buf, color);
1078 /* parse definitions */
1079 tag = swf->firstTag;
1081 if(swf_isDefiningTag(tag)) {
1082 int id = swf_GetDefineID(tag);
1083 idtable[id].tag = tag;
1084 idtable[id].bbox = rfx_alloc(sizeof(SRECT));
1085 *idtable[id].bbox = swf_GetDefineBBox(tag);
1087 if(swf_isShapeTag(tag)) {
1088 SHAPE2* shape = rfx_calloc(sizeof(SHAPE2));
1089 swf_ParseDefineShape(tag, shape);
1090 idtable[id].type = shape_type;
1091 idtable[id].obj.shape = shape;
1092 } else if(swf_isImageTag(tag)) {
1094 RGBA*data = swf_ExtractImage(tag, &width, &height);
1095 idtable[id].type = image_type;
1096 swf_Render_AddImage(buf, id, data, width, height);
1098 } else if(tag->id == ST_DEFINEFONT ||
1099 tag->id == ST_DEFINEFONT2) {
1102 font_t*font = rfx_calloc(sizeof(font_t));
1103 idtable[id].obj.font = font;
1104 swf_FontExtract(swf,id,&swffont);
1105 font->numchars = swffont->numchars;
1106 font->glyphs = rfx_calloc(sizeof(SHAPE2*)*font->numchars);
1107 for(t=0;t<font->numchars;t++) {
1108 if(!swffont->glyph[t].shape->fillstyle.n) {
1109 /* the actual fill color will be overwritten while rendering */
1110 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
1112 font->glyphs[t] = swf_ShapeToShape2(swffont->glyph[t].shape);
1114 swf_FontFree(swffont);
1115 idtable[id].type = font_type;
1117 } else if(tag->id == ST_DEFINEFONTINFO ||
1118 tag->id == ST_DEFINEFONTINFO2) {
1119 idtable[id].type = font_type;
1120 } else if(tag->id == ST_DEFINETEXT ||
1121 tag->id == ST_DEFINETEXT2) {
1122 idtable[id].type = text_type;
1124 } else if(tag->id == ST_PLACEOBJECT ||
1125 tag->id == ST_PLACEOBJECT2) {
1127 swf_GetPlaceObject(tag, &p);
1128 /* TODO: add move and deletion */
1129 placements[numplacements++] = p;
1130 swf_PlaceObjectFree(&p); //dirty! but it only frees fields we don't use
1135 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1137 for(t=0;t<numplacements;t++) {
1138 SWFPLACEOBJECT*p = &placements[t];
1141 if(!idtable[id].tag) {
1142 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1146 if(idtable[id].type == shape_type) {
1147 //SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1148 swf_RenderShape(buf, idtable[id].obj.shape, &p->matrix, &p->cxform, p->depth, p->clipdepth);
1149 } else if(idtable[id].type == text_type) {
1150 TAG* tag = idtable[id].tag;
1151 textcallbackblock_t info;
1154 swf_SetTagPos(tag, 0);
1157 swf_GetMatrix(tag,&m);
1158 swf_MatrixJoin(&info.m, &m, &p->matrix);
1159 /*printf("Text matrix:\n");
1160 swf_DumpMatrix(stdout, &m);
1161 printf("Placement matrix:\n");
1162 swf_DumpMatrix(stdout, &p->matrix);*/
1164 info.idtable = idtable;
1165 info.depth = p->depth;
1166 info.cxform = &p->cxform;
1167 info.clipdepth = p->clipdepth;
1170 swf_ParseDefineText(tag, textcallback, &info);
1172 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1176 /* free id and depth tables again */
1177 for(t=0;t<65536;t++) {
1178 if(idtable[t].bbox) {
1179 free(idtable[t].bbox);
1182 if(idtable[t].type == shape_type) {
1183 SHAPE2* shape = idtable[t].obj.shape;
1185 swf_Shape2Free(shape); // FIXME
1186 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;
1188 } else if(idtable[t].type == font_type) {
1189 font_t* font = idtable[t].obj.font;
1193 for(t=0;t<font->numchars;t++) {
1194 swf_Shape2Free(font->glyphs[t]);
1195 free(font->glyphs[t]); font->glyphs[t] = 0;
1200 free(idtable[t].obj.font); idtable[t].obj.font = 0;