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].type != font_type) {
1016 fprintf(stderr, "ID %d is not a font\n", fontid);
1018 } else if(!info->idtable[fontid].obj.font) {
1019 fprintf(stderr, "Font %d unknown\n", fontid);
1022 font = info->idtable[fontid].obj.font;
1025 int x = xstart + xpos[t];
1031 p = swf_TurnPoint(p, &m);
1033 m.sx = (m.sx * fontsize) / 1024;
1034 m.sy = (m.sy * fontsize) / 1024;
1035 m.r0 = (m.r0 * fontsize) / 1024;
1036 m.r1 = (m.r1 * fontsize) / 1024;
1040 if(chars[t]<0 || chars[t]>= font->numchars) {
1041 fprintf(stderr, "Character out of range: %d\n", chars[t]);
1043 SHAPE2*shape = font->glyphs[chars[t]];
1044 shape->fillstyles[0].color = *color; //q&d
1045 /*printf("Rendering char %d (size %d, x:%d, y:%d) color:%02x%02x%02x%02x\n", chars[t], fontsize, x, y,
1046 color->a, color->r, color->g, color->b);
1047 swf_DumpMatrix(stdout, &m);
1048 swf_DumpShape(shape);*/
1049 swf_RenderShape(info->buf, shape, &m, info->cxform, info->depth, info->clipdepth);
1054 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1060 SWFPLACEOBJECT* placements;
1062 character_t* idtable = rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1063 SWFPLACEOBJECT** depthtable = rfx_calloc(sizeof(SWFPLACEOBJECT*)*65536); // depth to placeobject mapping
1065 tag = swf->firstTag;
1068 if(tag->id == ST_PLACEOBJECT ||
1069 tag->id == ST_PLACEOBJECT2) {
1074 placements = rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
1077 /* set background color */
1078 color = swf_GetSWFBackgroundColor(swf);
1079 swf_Render_SetBackgroundColor(buf, color);
1081 /* parse definitions */
1082 tag = swf->firstTag;
1084 if(swf_isDefiningTag(tag)) {
1085 int id = swf_GetDefineID(tag);
1086 idtable[id].tag = tag;
1087 idtable[id].bbox = rfx_alloc(sizeof(SRECT));
1088 *idtable[id].bbox = swf_GetDefineBBox(tag);
1090 if(swf_isShapeTag(tag)) {
1091 SHAPE2* shape = rfx_calloc(sizeof(SHAPE2));
1092 swf_ParseDefineShape(tag, shape);
1093 idtable[id].type = shape_type;
1094 idtable[id].obj.shape = shape;
1095 } else if(swf_isImageTag(tag)) {
1097 RGBA*data = swf_ExtractImage(tag, &width, &height);
1098 idtable[id].type = image_type;
1099 swf_Render_AddImage(buf, id, data, width, height);
1101 } else if(tag->id == ST_DEFINEFONT ||
1102 tag->id == ST_DEFINEFONT2) {
1105 font_t*font = rfx_calloc(sizeof(font_t));
1106 idtable[id].obj.font = font;
1107 swf_FontExtract(swf,id,&swffont);
1108 font->numchars = swffont->numchars;
1109 font->glyphs = rfx_calloc(sizeof(SHAPE2*)*font->numchars);
1110 for(t=0;t<font->numchars;t++) {
1111 if(!swffont->glyph[t].shape->fillstyle.n) {
1112 /* the actual fill color will be overwritten while rendering */
1113 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
1115 font->glyphs[t] = swf_ShapeToShape2(swffont->glyph[t].shape);
1117 swf_FontFree(swffont);
1118 idtable[id].type = font_type;
1120 } else if(tag->id == ST_DEFINEFONTINFO ||
1121 tag->id == ST_DEFINEFONTINFO2) {
1122 idtable[id].type = font_type;
1123 } else if(tag->id == ST_DEFINETEXT ||
1124 tag->id == ST_DEFINETEXT2) {
1125 idtable[id].type = text_type;
1127 } else if(tag->id == ST_PLACEOBJECT ||
1128 tag->id == ST_PLACEOBJECT2) {
1130 swf_GetPlaceObject(tag, &p);
1131 /* TODO: add move and deletion */
1132 placements[numplacements++] = p;
1133 swf_PlaceObjectFree(&p); //dirty! but it only frees fields we don't use
1138 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1140 for(t=0;t<numplacements;t++) {
1141 SWFPLACEOBJECT*p = &placements[t];
1144 if(!idtable[id].tag) {
1145 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1149 if(idtable[id].type == shape_type) {
1150 //SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1151 swf_RenderShape(buf, idtable[id].obj.shape, &p->matrix, &p->cxform, p->depth, p->clipdepth);
1152 } else if(idtable[id].type == text_type) {
1153 TAG* tag = idtable[id].tag;
1154 textcallbackblock_t info;
1157 swf_SetTagPos(tag, 0);
1160 swf_GetMatrix(tag,&m);
1161 swf_MatrixJoin(&info.m, &p->matrix, &m);
1162 /*printf("Text matrix:\n");
1163 swf_DumpMatrix(stdout, &m);
1164 printf("Placement matrix:\n");
1165 swf_DumpMatrix(stdout, &p->matrix);
1166 printf("Final matrix:\n");
1167 swf_DumpMatrix(stdout, &info.m);*/
1169 info.idtable = idtable;
1170 info.depth = p->depth;
1171 info.cxform = &p->cxform;
1172 info.clipdepth = p->clipdepth;
1175 swf_ParseDefineText(tag, textcallback, &info);
1177 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1181 /* free id and depth tables again */
1182 for(t=0;t<65536;t++) {
1183 if(idtable[t].bbox) {
1184 free(idtable[t].bbox);
1187 if(idtable[t].type == shape_type) {
1188 SHAPE2* shape = idtable[t].obj.shape;
1190 swf_Shape2Free(shape); // FIXME
1191 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;
1193 } else if(idtable[t].type == font_type) {
1194 font_t* font = idtable[t].obj.font;
1198 for(t=0;t<font->numchars;t++) {
1199 swf_Shape2Free(font->glyphs[t]);
1200 free(font->glyphs[t]); font->glyphs[t] = 0;
1205 free(idtable[t].obj.font); idtable[t].obj.font = 0;