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 */
108 #define CUT 0.77887789
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;
214 segments = (int)(width/2);
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 = (bitmap_t*)rfx_calloc(sizeof(bitmap_t));
337 bm->data = (RGBA*)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 = (SHAPE2*)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((float)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 || f->type == (FILL_TILED|2) || f->type == (FILL_CLIPPED|2)) {
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, /*clipped?*/f->type&1, 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))
780 Notice: Weird fill styles appear if linestyles are involved, too.
782 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
786 n = (layer_t*)rfx_calloc(sizeof(layer_t));
788 if(DEBUG&2) printf("<+>");
790 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
793 add_layer(state, before, n);
797 void swf_Process(RENDERBUF*dest, U32 clipdepth)
799 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
802 if(i->ymax < i->ymin) {
803 /* shape is empty. return.
804 only, if it's a clipshape, remember the clipdepth */
806 for(y=0;y<i->height2;y++) {
807 if(clipdepth > i->lines[y].pending_clipdepth)
808 i->lines[y].pending_clipdepth = clipdepth;
811 return; //nothing (else) to do
815 /* lines outside the clip shape are not filled
816 immediately, only the highest clipdepth so far is
817 stored there. They will be clipfilled once there's
818 actually something about to happen in that line */
819 for(y=0;y<i->ymin;y++) {
820 if(clipdepth > i->lines[y].pending_clipdepth)
821 i->lines[y].pending_clipdepth = clipdepth;
823 for(y=i->ymax+1;y<i->height2;y++) {
824 if(clipdepth > i->lines[y].pending_clipdepth)
825 i->lines[y].pending_clipdepth = clipdepth;
829 for(y=i->ymin;y<=i->ymax;y++) {
831 TAG*tag = i->lines[y].points;
832 int num = i->lines[y].num;
833 renderpoint_t*points = (renderpoint_t*)tag->data;
834 RGBA*line = &i->img[i->width2*y];
835 int*zline = &i->zbuf[i->width2*y];
838 memset(&fillstate, 0, sizeof(state_t));
839 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
843 printf("%f (%d/%d) %d\n", points[n].x,
844 points[n].shapeline->fillstyle0,
845 points[n].shapeline->fillstyle1,
846 points[n].shapeline->linestyle);
850 if(i->lines[y].pending_clipdepth && !clipdepth) {
851 fill_clip(line, zline, y, 0, i->width2, i->lines[y].pending_clipdepth);
852 i->lines[y].pending_clipdepth=0;
856 renderpoint_t*p = &points[n];
857 renderpoint_t*next= n<num-1?&points[n+1]:0;
858 int startx = (int)p->x;
859 int endx = (int)(next?next->x:i->width2);
868 /* for clipping, the inverse is filled
869 TODO: lastx!=startx only at the start of the loop,
870 so this might be moved up
872 fill_clip(line, zline, y, lastx, startx, clipdepth);
874 change_state(y, &fillstate, p);
876 fill(dest, line, zline, y, startx, endx, &fillstate, clipdepth);
877 /* if(y == 0 && startx == 232 && endx == 418) {
878 printf("ymin=%d ymax=%d\n", i->ymin, i->ymax);
880 renderpoint_t*p = &points[n];
881 printf("x=%f depth=%08x\n", p->x, p->depth);
886 if(endx == i->width2)
890 /* TODO: is lastx *ever* != i->width2 here? */
891 fill_clip(line, zline, y, lastx, i->width2, clipdepth);
893 free_layers(&fillstate);
896 swf_ClearTag(i->lines[y].points);
898 i->ymin = 0x7fffffff;
899 i->ymax = -0x80000000;
902 RGBA* swf_Render(RENDERBUF*dest)
904 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
905 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
907 int antialize = i->antialize;
909 if(antialize <= 1) /* no antializing */ {
910 for(y=0;y<i->height2;y++) {
911 RGBA*line = &i->img[y*i->width2];
912 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
915 RGBA**lines = (RGBA**)rfx_calloc(sizeof(RGBA*)*antialize);
916 int q = antialize*antialize;
918 for(y=0;y<i->height2;y++) {
920 ypos = y % antialize;
921 lines[ypos] = &i->img[y*i->width2];
922 if(ypos == antialize-1) {
923 RGBA*out = &img[(y / antialize)*dest->width];
926 for(x=0;x<dest->width;x++) {
927 int xpos = x*antialize;
930 for(yp=0;yp<antialize;yp++) {
931 RGBA*lp = &lines[yp][xpos];
933 for(xp=0;xp<antialize;xp++) {
959 enum CHARACTER_TYPE {none_type, shape_type, image_type, text_type, font_type, sprite_type};
964 enum CHARACTER_TYPE type;
971 int compare_placements(const void *v1, const void *v2)
973 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
974 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
975 if(p1->depth != p2->depth)
976 return (int)p1->depth - (int)p2->depth;
979 return 1; // do the clip first
983 /* if(!p1->clipdepth) {
985 // !p1->clipdepth && !p2->clipdepth
986 return (int)p1->depth - (int)p2->depth;
988 // !p1->clipdepth && p2->clipdepth
989 if(p1->depth != p2->clipdepth)
990 return (int)p1->depth - (int)p2->clipdepth;
992 return 1; // do the clip first
996 // p1->clipdepth && !p2->clipdepth
997 if(p1->clipdepth != p2->depth)
998 return (int)p1->clipdepth - (int)p2->depth;
1000 return -1;// do the clip first
1002 if(p1->clipdepth != p2->clipdepth)
1003 return (int)p1->clipdepth - (int)p2->clipdepth;
1005 return (int)p1->depth - (int)p2->depth;
1010 typedef struct textcallbackblock
1012 character_t*idtable;
1018 } textcallbackblock_t;
1020 static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize,
1021 int xstart, int ystart, RGBA* color)
1023 textcallbackblock_t * info = (textcallbackblock_t*)self;
1026 if(info->idtable[fontid].type != font_type) {
1027 fprintf(stderr, "ID %d is not a font\n", fontid);
1029 } else if(!info->idtable[fontid].obj.font) {
1030 fprintf(stderr, "Font %d unknown\n", fontid);
1033 font = info->idtable[fontid].obj.font;
1036 int x = xstart + xpos[t];
1042 p = swf_TurnPoint(p, &m);
1044 m.sx = (m.sx * fontsize) / 1024;
1045 m.sy = (m.sy * fontsize) / 1024;
1046 m.r0 = (m.r0 * fontsize) / 1024;
1047 m.r1 = (m.r1 * fontsize) / 1024;
1051 if(chars[t]<0 || chars[t]>= font->numchars) {
1052 fprintf(stderr, "Character out of range: %d\n", chars[t]);
1054 SHAPE2*shape = font->glyphs[chars[t]];
1055 shape->fillstyles[0].color = *color; //q&d
1056 /*printf("Rendering char %d (size %d, x:%d, y:%d) color:%02x%02x%02x%02x\n", chars[t], fontsize, x, y,
1057 color->a, color->r, color->g, color->b);
1058 swf_DumpMatrix(stdout, &m);
1059 swf_DumpShape(shape);*/
1060 swf_RenderShape(info->buf, shape, &m, info->cxform, info->depth, info->clipdepth);
1065 static void renderFromTag(RENDERBUF*buf, character_t*idtable, TAG*firstTag, MATRIX*m)
1068 int numplacements = 0;
1069 SWFPLACEOBJECT* placements;
1074 if(tag->id == ST_PLACEOBJECT ||
1075 tag->id == ST_PLACEOBJECT2) {
1078 if(tag->id == ST_SHOWFRAME || tag->id == ST_END)
1082 placements = (SWFPLACEOBJECT*)rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
1087 if(swf_isPlaceTag(tag)) {
1089 swf_GetPlaceObject(tag, &p);
1090 /* TODO: add move and deletion */
1091 placements[numplacements++] = p;
1092 swf_PlaceObjectFree(&p); //dirty! but it only frees fields we don't use
1094 if(tag->id == ST_SHOWFRAME || tag->id == ST_END)
1099 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1102 for(t=0;t<numplacements;t++) {
1103 SWFPLACEOBJECT*p = &placements[t];
1106 swf_MatrixJoin(&m2, m, &p->matrix);
1108 if(!idtable[id].tag) {
1109 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1113 if(idtable[id].type == shape_type) {
1114 //SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1115 swf_RenderShape(buf, idtable[id].obj.shape, &m2, &p->cxform, p->depth, p->clipdepth);
1116 } else if(idtable[id].type == sprite_type) {
1117 swf_UnFoldSprite(idtable[id].tag);
1118 renderFromTag(buf, idtable, idtable[id].tag->next, &m2);
1119 swf_FoldSprite(idtable[id].tag);
1120 } else if(idtable[id].type == text_type) {
1121 TAG* tag = idtable[id].tag;
1122 textcallbackblock_t info;
1125 swf_SetTagPos(tag, 0);
1128 swf_GetMatrix(tag,&mt);
1129 swf_MatrixJoin(&info.m, &m2, &mt);
1130 /*printf("Text matrix:\n");
1131 swf_DumpMatrix(stdout, &m);
1132 printf("Placement matrix:\n");
1133 swf_DumpMatrix(stdout, &p->matrix);
1134 printf("Final matrix:\n");
1135 swf_DumpMatrix(stdout, &info.m);*/
1137 info.idtable = idtable;
1138 info.depth = p->depth;
1139 info.cxform = &p->cxform;
1140 info.clipdepth = p->clipdepth;
1143 swf_ParseDefineText(tag, textcallback, &info);
1145 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1152 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1160 character_t* idtable = (character_t*)rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1162 /* set background color */
1163 color = swf_GetSWFBackgroundColor(swf);
1164 swf_Render_SetBackgroundColor(buf, color);
1166 /* parse definitions */
1167 tag = swf->firstTag;
1169 if(swf_isDefiningTag(tag)) {
1170 int id = swf_GetDefineID(tag);
1171 idtable[id].tag = tag;
1172 idtable[id].bbox = (SRECT*)rfx_alloc(sizeof(SRECT));
1173 *idtable[id].bbox = swf_GetDefineBBox(tag);
1175 if(swf_isShapeTag(tag)) {
1176 SHAPE2* shape = (SHAPE2*)rfx_calloc(sizeof(SHAPE2));
1177 swf_ParseDefineShape(tag, shape);
1178 idtable[id].type = shape_type;
1179 idtable[id].obj.shape = shape;
1180 } else if(swf_isImageTag(tag)) {
1182 RGBA*data = swf_ExtractImage(tag, &width, &height);
1183 idtable[id].type = image_type;
1184 swf_Render_AddImage(buf, id, data, width, height);
1186 } else if(tag->id == ST_DEFINEFONT ||
1187 tag->id == ST_DEFINEFONT2) {
1190 font_t*font = (font_t*)rfx_calloc(sizeof(font_t));
1191 idtable[id].obj.font = font;
1192 swf_FontExtract(swf,id,&swffont);
1193 font->numchars = swffont->numchars;
1194 font->glyphs = (SHAPE2**)rfx_calloc(sizeof(SHAPE2*)*font->numchars);
1195 for(t=0;t<font->numchars;t++) {
1196 if(!swffont->glyph[t].shape->fillstyle.n) {
1197 /* the actual fill color will be overwritten while rendering */
1198 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
1200 font->glyphs[t] = swf_ShapeToShape2(swffont->glyph[t].shape);
1202 swf_FontFree(swffont);
1203 idtable[id].type = font_type;
1205 } else if(tag->id == ST_DEFINEFONTINFO ||
1206 tag->id == ST_DEFINEFONTINFO2) {
1207 idtable[id].type = font_type;
1208 } else if(tag->id == ST_DEFINETEXT ||
1209 tag->id == ST_DEFINETEXT2) {
1210 idtable[id].type = text_type;
1211 } else if(tag->id == ST_DEFINESPRITE) {
1212 idtable[id].type = sprite_type;
1218 swf_GetMatrix(0, &m);
1219 renderFromTag(buf, idtable, swf->firstTag, &m);
1221 /* free id and depth tables again */
1222 for(t=0;t<65536;t++) {
1223 if(idtable[t].bbox) {
1224 free(idtable[t].bbox);
1227 if(idtable[t].type == shape_type) {
1228 SHAPE2* shape = idtable[t].obj.shape;
1230 swf_Shape2Free(shape); // FIXME
1231 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;
1233 } else if(idtable[t].type == font_type) {
1234 font_t* font = idtable[t].obj.font;
1238 for(t=0;t<font->numchars;t++) {
1239 swf_Shape2Free(font->glyphs[t]);
1240 free(font->glyphs[t]); font->glyphs[t] = 0;
1245 free(idtable[t].obj.font); idtable[t].obj.font = 0;