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 int inline clamp(int v)
571 if(v>255) return 255;
575 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)
579 double m11= m->sx*fmultiply/65536.0, m21= m->r1*fmultiply/65536.0;
580 double m12= m->r0*fmultiply/65536.0, m22= m->sy*fmultiply/65536.0;
581 double rx = m->tx*fmultiply/20.0;
582 double ry = m->ty*fmultiply/20.0;
584 double det = m11*m22 - m12*m21;
585 if(fabs(det) < 0.0005) {
586 /* x direction equals y direction- the image is invisible */
591 if(!b->width || !b->height) {
592 fill_solid(line, z, y, x1, x2, color_red, depth);
599 int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det);
600 int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
605 if(xx>=b->width) xx = b->width-1;
607 if(yy>=b->height) yy = b->height-1;
611 if(xx<0) xx += b->width;
612 if(yy<0) yy += b->height;
615 col = b->data[yy*b->width+xx];
618 line[x].r = clamp(((line[x].r*ainv)>>8)+col.r);
619 line[x].g = clamp(((line[x].g*ainv)>>8)+col.g);
620 line[x].b = clamp(((line[x].b*ainv)>>8)+col.b);
628 static void fill_gradient(RGBA*line, int*z, int y, int x1, int x2, MATRIX*m, GRADIENT*g, int type, U32 depth, double fmultiply)
632 double m11= m->sx*fmultiply/80, m21= m->r1*fmultiply/80;
633 double m12= m->r0*fmultiply/80, m22= m->sy*fmultiply/80;
634 double rx = m->tx*fmultiply/20.0;
635 double ry = m->ty*fmultiply/20.0;
637 double det = m11*m22 - m12*m21;
638 if(fabs(det) < 0.0005) {
639 /* x direction equals y direction- the image is invisible */
645 RGBA oldcol = g->rgba[0];
646 int r0 = g->ratios[0]*2;
650 for(t=1;t<g->num;t++) {
651 int r1 = g->ratios[t]*2;
652 RGBA newcol = g->rgba[t];
655 //printf("%d %d->%d %02x%02x%02x%02x->%02x%02x%02x%02x\n",
656 // t, r0, r1, oldcol.r,oldcol.g,oldcol.b,oldcol.a,
657 // newcol.r,newcol.g,newcol.b,newcol.a);
658 double f = 1.0 / (r1-r0);
663 palette[r0].r = oldcol.r*p0 + newcol.r*p1;
664 palette[r0].g = oldcol.g*p0 + newcol.g*p1;
665 palette[r0].b = oldcol.b*p0 + newcol.b*p1;
666 palette[r0].a = oldcol.a*p0 + newcol.a*p1;
678 double xx = ( (x - rx) * m22 - (y - ry) * m21)*det;
679 double yy = (- (x - rx) * m12 + (y - ry) * m11)*det;
683 if(type == FILL_LINEAR) {
689 col = palette[xr+256];
691 int xr = sqrt(xx*xx+yy*yy)*511;
699 line[x].r = clamp(((line[x].r*ainv)>>8)+col.r);
700 line[x].g = clamp(((line[x].g*ainv)>>8)+col.g);
701 line[x].b = clamp(((line[x].b*ainv)>>8)+col.b);
709 typedef struct _layer {
721 static void fill(RENDERBUF*dest, RGBA*line, int*zline, int y, int x1, int x2, state_t*fillstate, U32 clipdepth)
723 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
726 layer_t*l = fillstate->layers;
728 if(x1>=x2) //zero width? nothing to do.
733 /* not filled. TODO: we should never add those in the first place */
735 printf("(not filled)");
736 } else if(l->fillid > l->p->s->numfillstyles) {
737 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->numlinestyles);
738 } else if(clipdepth) {
739 /* filled region- not used for clipping */
744 printf("(%d -> %d style %d)", x1, x2, l->fillid);
746 f = &l->p->s->fillstyles[l->fillid-1];
748 if(f->type == FILL_SOLID) {
749 /* plain color fill */
750 fill_solid(line, zline, y, x1, x2, f->color, l->p->depth);
751 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED || f->type == (FILL_TILED|2) || f->type == (FILL_CLIPPED|2)) {
752 /* TODO: optimize (do this in add_pixel()?) */
753 bitmap_t* b = i->bitmaps;
754 while(b && b->id != f->id_bitmap) {
758 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
759 fill_solid(line, zline, y, x1, x2, color_red, l->p->depth);
761 fill_bitmap(line, zline, y, x1, x2, &f->m, b, /*clipped?*/f->type&1, l->p->depth, i->multiply);
763 } else if(f->type == FILL_LINEAR || f->type == FILL_RADIAL) {
764 fill_gradient(line, zline, y, x1, x2, &f->m, &f->gradient, f->type, l->p->depth, i->multiply);
766 fprintf(stderr, "Undefined fillmode: %02x\n", f->type);
771 if(clip && clipdepth) {
772 fill_clip(line, zline, y, x1, x2, clipdepth);
776 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
778 layer_t*last=0,*l = state->layers;
779 while(l && l->p->depth < depth) {
784 if(l && l->p->depth == depth)
789 static void delete_layer(state_t*state, layer_t*todel)
791 layer_t*before=todel->prev;
792 layer_t*next = todel->next;
795 state->layers = next;
801 before->next->prev = before;
804 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
807 toadd->next = state->layers;
811 toadd->next = before->next;
812 toadd->prev = before;
813 before->next = toadd;
816 toadd->next->prev = toadd;
818 static void free_layers(state_t* state)
820 layer_t*l = state->layers;
822 layer_t*next = l->next;
828 static void change_state(int y, state_t* state, renderpoint_t*p)
830 layer_t*before=0, *self=0, *after=0;
833 printf("[(%d,%d)/%d/%d-%d]", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
836 search_layer(state, p->depth, &before, &self, &after);
840 if(self->fillid<0/*??*/ || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
842 if(DEBUG&2) printf("<D>");
844 delete_layer(state, self);
846 /*both fill0 and fill1 are set- exchange the two, updating the layer */
847 if(self->fillid == p->shapeline->fillstyle0) {
848 self->fillid = p->shapeline->fillstyle1;
850 if(DEBUG&2) printf("<X>");
851 } else if(self->fillid == p->shapeline->fillstyle1) {
852 self->fillid = p->shapeline->fillstyle0;
854 if(DEBUG&2) printf("<X>");
856 /* buggy shape. keep everything as-is. */
857 if(DEBUG&2) printf("<!>");
858 //fprintf(stderr, "<line %d: bad swap>\n", y);
864 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
865 /* this is a hack- a better way would be to make sure that
866 we always get (0,32), (32, 33), (33, 0) in the right order if
867 they happen to fall on the same pixel.
868 (not: (0,32), (33, 0), (32, 33))
869 Notice: Weird fill styles appear if linestyles are involved, too.
871 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
875 n = (layer_t*)rfx_calloc(sizeof(layer_t));
877 if(DEBUG&2) printf("<+>");
879 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
882 add_layer(state, before, n);
886 void swf_Process(RENDERBUF*dest, U32 clipdepth)
888 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
891 if(i->ymax < i->ymin) {
892 /* shape is empty. return.
893 only, if it's a clipshape, remember the clipdepth */
895 for(y=0;y<i->height2;y++) {
896 if(clipdepth > i->lines[y].pending_clipdepth)
897 i->lines[y].pending_clipdepth = clipdepth;
900 return; //nothing (else) to do
904 /* lines outside the clip shape are not filled
905 immediately, only the highest clipdepth so far is
906 stored there. They will be clipfilled once there's
907 actually something about to happen in that line */
908 for(y=0;y<i->ymin;y++) {
909 if(clipdepth > i->lines[y].pending_clipdepth)
910 i->lines[y].pending_clipdepth = clipdepth;
912 for(y=i->ymax+1;y<i->height2;y++) {
913 if(clipdepth > i->lines[y].pending_clipdepth)
914 i->lines[y].pending_clipdepth = clipdepth;
918 for(y=i->ymin;y<=i->ymax;y++) {
920 TAG*tag = i->lines[y].points;
921 int num = i->lines[y].num;
922 renderpoint_t*points = (renderpoint_t*)tag->data;
923 RGBA*line = &i->img[i->width2*y];
924 int*zline = &i->zbuf[i->width2*y];
927 memset(&fillstate, 0, sizeof(state_t));
928 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
932 printf("%f (%d/%d) %d\n", points[n].x,
933 points[n].shapeline->fillstyle0,
934 points[n].shapeline->fillstyle1,
935 points[n].shapeline->linestyle);
939 if(i->lines[y].pending_clipdepth && !clipdepth) {
940 fill_clip(line, zline, y, 0, i->width2, i->lines[y].pending_clipdepth);
941 i->lines[y].pending_clipdepth=0;
945 renderpoint_t*p = &points[n];
946 renderpoint_t*next= n<num-1?&points[n+1]:0;
947 int startx = (int)p->x;
948 int endx = (int)(next?next->x:i->width2);
957 /* for clipping, the inverse is filled
958 TODO: lastx!=startx only at the start of the loop,
959 so this might be moved up
961 fill_clip(line, zline, y, lastx, startx, clipdepth);
963 change_state(y, &fillstate, p);
965 fill(dest, line, zline, y, startx, endx, &fillstate, clipdepth);
966 /* if(y == 0 && startx == 232 && endx == 418) {
967 printf("ymin=%d ymax=%d\n", i->ymin, i->ymax);
969 renderpoint_t*p = &points[n];
970 printf("x=%f depth=%08x\n", p->x, p->depth);
975 if(endx == i->width2)
979 /* TODO: is lastx *ever* != i->width2 here? */
980 fill_clip(line, zline, y, lastx, i->width2, clipdepth);
982 free_layers(&fillstate);
985 swf_ClearTag(i->lines[y].points);
987 i->ymin = 0x7fffffff;
988 i->ymax = -0x80000000;
991 RGBA* swf_Render(RENDERBUF*dest)
993 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
994 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
996 int antialize = i->antialize;
998 if(antialize <= 1) /* no antializing */ {
999 for(y=0;y<i->height2;y++) {
1000 RGBA*line = &i->img[y*i->width2];
1001 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
1004 RGBA**lines = (RGBA**)rfx_calloc(sizeof(RGBA*)*antialize);
1005 int q = antialize*antialize;
1007 for(y=0;y<i->height2;y++) {
1009 ypos = y % antialize;
1010 lines[ypos] = &i->img[y*i->width2];
1011 if(ypos == antialize-1) {
1012 RGBA*out = &img[(y / antialize)*dest->width];
1015 for(x=0;x<dest->width;x++) {
1016 int xpos = x*antialize;
1018 U32 r=0,g=0,b=0,a=0;
1019 for(yp=0;yp<antialize;yp++) {
1020 RGBA*lp = &lines[yp][xpos];
1022 for(xp=0;xp<antialize;xp++) {
1048 enum CHARACTER_TYPE {none_type, shape_type, image_type, text_type, font_type, sprite_type};
1053 enum CHARACTER_TYPE type;
1060 int compare_placements(const void *v1, const void *v2)
1062 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
1063 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
1064 if(p1->depth != p2->depth)
1065 return (int)p1->depth - (int)p2->depth;
1068 return 1; // do the clip first
1072 /* if(!p1->clipdepth) {
1073 if(!p2->clipdepth) {
1074 // !p1->clipdepth && !p2->clipdepth
1075 return (int)p1->depth - (int)p2->depth;
1077 // !p1->clipdepth && p2->clipdepth
1078 if(p1->depth != p2->clipdepth)
1079 return (int)p1->depth - (int)p2->clipdepth;
1081 return 1; // do the clip first
1084 if(!p2->clipdepth) {
1085 // p1->clipdepth && !p2->clipdepth
1086 if(p1->clipdepth != p2->depth)
1087 return (int)p1->clipdepth - (int)p2->depth;
1089 return -1;// do the clip first
1091 if(p1->clipdepth != p2->clipdepth)
1092 return (int)p1->clipdepth - (int)p2->clipdepth;
1094 return (int)p1->depth - (int)p2->depth;
1099 typedef struct textcallbackblock
1101 character_t*idtable;
1107 } textcallbackblock_t;
1109 static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize,
1110 int xstart, int ystart, RGBA* color)
1112 textcallbackblock_t * info = (textcallbackblock_t*)self;
1115 if(info->idtable[fontid].type != font_type) {
1116 fprintf(stderr, "ID %d is not a font\n", fontid);
1118 } else if(!info->idtable[fontid].obj.font) {
1119 fprintf(stderr, "Font %d unknown\n", fontid);
1122 font = info->idtable[fontid].obj.font;
1125 int x = xstart + xpos[t];
1131 p = swf_TurnPoint(p, &m);
1133 m.sx = (m.sx * fontsize) / 1024;
1134 m.sy = (m.sy * fontsize) / 1024;
1135 m.r0 = (m.r0 * fontsize) / 1024;
1136 m.r1 = (m.r1 * fontsize) / 1024;
1140 if(chars[t]<0 || chars[t]>= font->numchars) {
1141 fprintf(stderr, "Character out of range: %d\n", chars[t]);
1143 SHAPE2*shape = font->glyphs[chars[t]];
1144 shape->fillstyles[0].color = *color; //q&d
1145 /*printf("Rendering char %d (size %d, x:%d, y:%d) color:%02x%02x%02x%02x\n", chars[t], fontsize, x, y,
1146 color->a, color->r, color->g, color->b);
1147 swf_DumpMatrix(stdout, &m);
1148 swf_DumpShape(shape);*/
1149 swf_RenderShape(info->buf, shape, &m, info->cxform, info->depth, info->clipdepth);
1154 static void renderFromTag(RENDERBUF*buf, character_t*idtable, TAG*firstTag, MATRIX*m)
1157 int numplacements = 0;
1158 SWFPLACEOBJECT* placements;
1163 if(tag->id == ST_PLACEOBJECT ||
1164 tag->id == ST_PLACEOBJECT2) {
1167 if(tag->id == ST_SHOWFRAME || tag->id == ST_END)
1171 placements = (SWFPLACEOBJECT*)rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
1176 if(swf_isPlaceTag(tag)) {
1178 swf_GetPlaceObject(tag, &p);
1179 /* TODO: add move and deletion */
1180 placements[numplacements++] = p;
1181 swf_PlaceObjectFree(&p); //dirty! but it only frees fields we don't use
1183 if(tag->id == ST_SHOWFRAME || tag->id == ST_END)
1188 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1191 for(t=0;t<numplacements;t++) {
1192 SWFPLACEOBJECT*p = &placements[t];
1195 swf_MatrixJoin(&m2, m, &p->matrix);
1197 if(!idtable[id].tag) {
1198 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1202 if(idtable[id].type == shape_type) {
1203 //SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1204 swf_RenderShape(buf, idtable[id].obj.shape, &m2, &p->cxform, p->depth, p->clipdepth);
1205 } else if(idtable[id].type == sprite_type) {
1206 swf_UnFoldSprite(idtable[id].tag);
1207 renderFromTag(buf, idtable, idtable[id].tag->next, &m2);
1208 swf_FoldSprite(idtable[id].tag);
1209 } else if(idtable[id].type == text_type) {
1210 TAG* tag = idtable[id].tag;
1211 textcallbackblock_t info;
1214 swf_SetTagPos(tag, 0);
1217 swf_GetMatrix(tag,&mt);
1218 swf_MatrixJoin(&info.m, &m2, &mt);
1219 /*printf("Text matrix:\n");
1220 swf_DumpMatrix(stdout, &m);
1221 printf("Placement matrix:\n");
1222 swf_DumpMatrix(stdout, &p->matrix);
1223 printf("Final matrix:\n");
1224 swf_DumpMatrix(stdout, &info.m);*/
1226 info.idtable = idtable;
1227 info.depth = p->depth;
1228 info.cxform = &p->cxform;
1229 info.clipdepth = p->clipdepth;
1232 swf_ParseDefineText(tag, textcallback, &info);
1234 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1241 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1249 character_t* idtable = (character_t*)rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1251 /* set background color */
1252 color = swf_GetSWFBackgroundColor(swf);
1253 swf_Render_SetBackgroundColor(buf, color);
1255 /* parse definitions */
1256 tag = swf->firstTag;
1258 if(swf_isDefiningTag(tag)) {
1259 int id = swf_GetDefineID(tag);
1260 idtable[id].tag = tag;
1261 idtable[id].bbox = (SRECT*)rfx_alloc(sizeof(SRECT));
1262 *idtable[id].bbox = swf_GetDefineBBox(tag);
1264 if(swf_isShapeTag(tag)) {
1265 SHAPE2* shape = (SHAPE2*)rfx_calloc(sizeof(SHAPE2));
1266 swf_ParseDefineShape(tag, shape);
1267 idtable[id].type = shape_type;
1268 idtable[id].obj.shape = shape;
1269 } else if(swf_isImageTag(tag)) {
1271 RGBA*data = swf_ExtractImage(tag, &width, &height);
1272 idtable[id].type = image_type;
1273 swf_Render_AddImage(buf, id, data, width, height);
1275 } else if(tag->id == ST_DEFINEFONT ||
1276 tag->id == ST_DEFINEFONT2) {
1279 font_t*font = (font_t*)rfx_calloc(sizeof(font_t));
1280 idtable[id].obj.font = font;
1281 swf_FontExtract(swf,id,&swffont);
1282 font->numchars = swffont->numchars;
1283 font->glyphs = (SHAPE2**)rfx_calloc(sizeof(SHAPE2*)*font->numchars);
1284 for(t=0;t<font->numchars;t++) {
1285 if(!swffont->glyph[t].shape->fillstyle.n) {
1286 /* the actual fill color will be overwritten while rendering */
1287 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
1289 font->glyphs[t] = swf_ShapeToShape2(swffont->glyph[t].shape);
1291 swf_FontFree(swffont);
1292 idtable[id].type = font_type;
1294 } else if(tag->id == ST_DEFINEFONTINFO ||
1295 tag->id == ST_DEFINEFONTINFO2) {
1296 idtable[id].type = font_type;
1297 } else if(tag->id == ST_DEFINETEXT ||
1298 tag->id == ST_DEFINETEXT2) {
1299 idtable[id].type = text_type;
1300 } else if(tag->id == ST_DEFINESPRITE) {
1301 idtable[id].type = sprite_type;
1307 swf_GetMatrix(0, &m);
1308 renderFromTag(buf, idtable, swf->firstTag, &m);
1310 /* free id and depth tables again */
1311 for(t=0;t<65536;t++) {
1312 if(idtable[t].bbox) {
1313 free(idtable[t].bbox);
1316 if(idtable[t].type == shape_type) {
1317 SHAPE2* shape = idtable[t].obj.shape;
1319 swf_Shape2Free(shape); // FIXME
1320 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;
1322 } else if(idtable[t].type == font_type) {
1323 font_t* font = idtable[t].obj.font;
1327 for(t=0;t<font->numchars;t++) {
1328 swf_Shape2Free(font->glyphs[t]);
1329 free(font->glyphs[t]); font->glyphs[t] = 0;
1334 free(idtable[t].obj.font); idtable[t].obj.font = 0;