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 */
28 #include "../rfxswf.h"
34 typedef struct _renderpoint
45 enum {clip_type, solidfill_type, texturefill_type, gradientfill_type} type;
60 // texture- & gradientfill;
66 typedef struct _renderline
68 TAG*points; //incremented in 128 byte steps
70 U32 pending_clipdepth;
73 typedef struct _bitmap {
81 typedef struct _renderbuf_internal
97 static inline void add_pixel(RENDERBUF*dest, float x, int y, renderpoint_t*p)
99 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
100 if(x >= i->width2 || y >= i->height2 || y<0) return;
102 if(y<i->ymin) i->ymin = y;
103 if(y>i->ymax) i->ymax = y;
106 swf_SetBlock(i->lines[y].points, (U8*)p, sizeof(renderpoint_t));
109 /* set this to 0.777777 or something if the "both fillstyles set while not inside shape"
110 problem appears to often */
111 #define CUT 0.77887789
113 #define INT(x) ((int)((x)+16)-16)
115 static void add_line(RENDERBUF*buf, double x1, double y1, double x2, double y2, renderpoint_t*p)
117 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
119 double ny1, ny2, stepx;
121 int l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
122 printf(" l[%d - %.2f/%.2f -> %.2f/%.2f]\n", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
124 assert(p->shapeline);
150 ny1 = INT(y1) + 1.0 + CUT;
153 ny2 = INT(y2) - 1.0 + CUT;
160 x1 = x1 + (ny1-y1)*stepx;
161 x2 = x2 + (ny2-y2)*stepx;
170 float xx = (float)(startx + posx);
171 add_pixel(buf, xx ,posy, p);
177 #define PI 3.14159265358979
178 static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double y2, double width, renderpoint_t*p)
180 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
193 /* Make sure the line is always at least one pixel wide */
195 /* That's what Macromedia's Player does at least at zoom level >= 1. */
198 /* That's what Macromedia's Player seems to do at zoom level 0. */
199 /* TODO: needs testing */
201 /* TODO: how does this interact with scaling? */
202 if(width * i->multiply < 20)
203 width = 20 / i->multiply;
206 sd = (double)dx*(double)dx+(double)dy*(double)dy;
217 segments = (int)(width/2);
228 add_line(buf, x1+vx, y1+vy, xx, yy, p);
231 for(t=1;t<segments;t++) {
232 double s = sin(t*PI/segments);
233 double c = cos(t*PI/segments);
234 xx = (x2 + vx*c - vy*s);
235 yy = (y2 + vx*s + vy*c);
236 add_line(buf, lastx, lasty, xx, yy, p);
243 add_line(buf, lastx, lasty, xx, yy, p);
248 add_line(buf, lastx, lasty, xx, yy, p);
251 for(t=1;t<segments;t++) {
252 double s = sin(t*PI/segments);
253 double c = cos(t*PI/segments);
254 xx = (x1 - vx*c + vy*s);
255 yy = (y1 - vx*s - vy*c);
256 add_line(buf, lastx, lasty, xx, yy, p);
260 add_line(buf, lastx, lasty, (x1+vx), (y1+vy), p);
263 static inline void transform_point(MATRIX*m, int x, int y, int*dx, int*dy)
268 d = swf_TurnPoint(p, m);
273 static int compare_renderpoints(const void * _a, const void * _b)
275 renderpoint_t*a = (renderpoint_t*)_a;
276 renderpoint_t*b = (renderpoint_t*)_b;
277 if(a->x < b->x) return -1;
278 if(a->x > b->x) return 1;
282 void swf_Render_Init(RENDERBUF*buf, int posx, int posy, int width, int height, int antialize, int multiply)
284 renderbuf_internal*i;
286 memset(buf, 0, sizeof(RENDERBUF));
287 buf->width = width*multiply;
288 buf->height = height*multiply;
291 buf->internal = (renderbuf_internal*)rfx_calloc(sizeof(renderbuf_internal));
292 i = (renderbuf_internal*)buf->internal;
295 i->antialize = antialize;
296 i->multiply = multiply*antialize;
297 i->height2 = antialize*buf->height;
298 i->width2 = antialize*buf->width;
299 i->lines = (renderline_t*)rfx_alloc(i->height2*sizeof(renderline_t));
300 for(y=0;y<i->height2;y++) {
301 memset(&i->lines[y], 0, sizeof(renderline_t));
302 i->lines[y].points = swf_InsertTag(0, 0);
305 i->zbuf = (int*)rfx_calloc(sizeof(int)*i->width2*i->height2);
306 i->img = (RGBA*)rfx_calloc(sizeof(RGBA)*i->width2*i->height2);
308 i->ymin = 0x7fffffff;
309 i->ymax = -0x80000000;
311 void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height)
313 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
315 int xstep=width*65536/i->width2;
316 int ystep=height*65536/i->height2;
318 fprintf(stderr, "rfxswf: Warning: swf_Render_SetBackground() called after drawing shapes\n");
320 for(y=0,yy=0;y<i->height2;y++,yy+=ystep) {
321 RGBA*src = &img[(yy>>16) * width];
322 RGBA*line = &i->img[y * i->width2];
323 for(x=0,xx=0;x<i->width2;x++,xx+=xstep) {
324 line[x] = src[xx>>16];
328 void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color)
330 swf_Render_SetBackground(buf, &color, 1, 1);
332 void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height)
334 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
336 bitmap_t*bm = (bitmap_t*)rfx_calloc(sizeof(bitmap_t));
340 bm->data = (RGBA*)rfx_alloc(width*height*4);
341 memcpy(bm->data, img, width*height*4);
343 bm->next = i->bitmaps;
346 void swf_Render_ClearCanvas(RENDERBUF*dest)
348 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
350 for(y=0;y<i->height2;y++) {
351 swf_ClearTag(i->lines[y].points);
353 memset(i->zbuf, 0, sizeof(int)*i->width2*i->height2);
354 memset(i->img, 0, sizeof(RGBA)*i->width2*i->height2);
356 void swf_Render_Delete(RENDERBUF*dest)
358 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
360 bitmap_t*b = i->bitmaps;
366 /* delete line buffers */
367 for(y=0;y<i->height2;y++) {
368 swf_DeleteTag(0, i->lines[y].points);
369 i->lines[y].points = 0;
374 bitmap_t*next = b->next;
375 free(b->data);b->data=0;
380 rfx_free(i->lines); i->lines = 0;
381 rfx_free(dest->internal); dest->internal = 0;
384 static SHAPE2* linestyle2fillstyle(SHAPE2*shape)
386 SHAPE2*s = (SHAPE2*)rfx_calloc(sizeof(SHAPE2));
388 s->numfillstyles = shape->numlinestyles;
389 s->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles);
390 s->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles);
391 for(t=0;t<shape->numlinestyles;t++) {
392 s->lines[t].fillstyle0 = t+1;
393 s->fillstyles[t].type = FILL_SOLID;
394 s->fillstyles[t].color = shape->linestyles[t].color;
399 void swf_Process(RENDERBUF*dest, U32 clipdepth);
401 double matrixsize(MATRIX*m)
403 double l1 = sqrt((m->sx /65536.0) * (m->sx /65536.0) + (m->r0 /65536.0) * (m->r0/65536.0) );
404 double l2 = sqrt((m->r1 /65536.0) * (m->r1 /65536.0) + (m->sy /65536.0) * (m->sy/65536.0) );
408 void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth)
410 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
419 double widthmultiply = matrixsize(m);
421 memset(&p, 0, sizeof(renderpoint_t));
422 memset(&lp, 0, sizeof(renderpoint_t));
424 clipdepth = _clipdepth? _clipdepth << 16 | 0xffff : 0;
425 p.depth = _depth << 16;
427 mat.tx -= dest->posx*20;
428 mat.ty -= dest->posy*20;
430 s2 = swf_Shape2Clone(shape);
432 if(shape->numfillstyles) {
435 /* multiply fillstyles matrices with placement matrix-
436 important for texture and gradient fill */
437 for(t=0;t<s2->numfillstyles;t++) {
439 swf_MatrixJoin(&nm, &mat, &s2->fillstyles[t].m);
440 /*nm.sx *= i->multiply;
441 nm.sy *= i->multiply;
442 nm.r0 *= i->multiply;
443 nm.r1 *= i->multiply;
444 nm.tx *= i->multiply;
445 nm.ty *= i->multiply;*/
446 s2->fillstyles[t].m = nm;
450 if(shape->numlinestyles) {
451 lshape = linestyle2fillstyle(shape);
453 lp.depth = (_depth << 16)+1;
459 int x1,y1,x2,y2,x3,y3;
461 if(line->type == moveTo) {
462 } else if(line->type == lineTo) {
463 transform_point(&mat, x, y, &x1, &y1);
464 transform_point(&mat, line->x, line->y, &x3, &y3);
466 if(line->linestyle && ! clipdepth) {
467 lp.shapeline = &lshape->lines[line->linestyle-1];
468 add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width * widthmultiply, &lp);
471 if(line->fillstyle0 || line->fillstyle1) {
472 assert(shape->numfillstyles);
474 add_line(dest, x1, y1, x3, y3, &p);
476 } else if(line->type == splineTo) {
477 int c,t,parts,qparts;
480 transform_point(&mat, x, y, &x1, &y1);
481 transform_point(&mat, line->sx, line->sy, &x2, &y2);
482 transform_point(&mat, line->x, line->y, &x3, &y3);
484 c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1);
488 parts = (int)(sqrt((float)c)/3);
489 if(!parts) parts = 1;
491 for(t=1;t<=parts;t++) {
492 double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts);
493 double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts);
495 if(line->linestyle && ! clipdepth) {
496 lp.shapeline = &lshape->lines[line->linestyle-1];
497 add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width * widthmultiply, &lp);
500 if(line->fillstyle0 || line->fillstyle1) {
501 assert(shape->numfillstyles);
503 add_line(dest, xx, yy, nx, ny, &p);
515 swf_Process(dest, clipdepth);
518 swf_Shape2Free(s2);rfx_free(s2);s2=0;
521 swf_Shape2Free(lshape);rfx_free(lshape);lshape=0;
526 static RGBA color_red = {255,255,0,0};
527 static RGBA color_white = {255,255,255,255};
528 static RGBA color_black = {255,0,0,0};
530 static void fill_clip(RGBA*line, int*z, int y, int x1, int x2, U32 depth)
543 static void fill_solid(RGBA*line, int*z, int y, int x1, int x2, RGBA col, U32 depth)
548 int ainv = 255-col.a;
549 col.r = (col.r*col.a)>>8;
550 col.g = (col.g*col.a)>>8;
551 col.b = (col.b*col.a)>>8;
555 line[x].r = ((line[x].r*ainv)>>8)+col.r;
556 line[x].g = ((line[x].g*ainv)>>8)+col.g;
557 line[x].b = ((line[x].b*ainv)>>8)+col.b;
572 static int inline clamp(int v)
574 if(v>255) return 255;
578 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)
582 double m11= m->sx*fmultiply/65536.0, m21= m->r1*fmultiply/65536.0;
583 double m12= m->r0*fmultiply/65536.0, m22= m->sy*fmultiply/65536.0;
584 double rx = m->tx*fmultiply/20.0;
585 double ry = m->ty*fmultiply/20.0;
587 double det = m11*m22 - m12*m21;
588 if(fabs(det) < 0.0005) {
589 /* x direction equals y direction- the image is invisible */
594 if(!b->width || !b->height) {
595 fill_solid(line, z, y, x1, x2, color_red, depth);
602 int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det);
603 int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
608 if(xx>=b->width) xx = b->width-1;
610 if(yy>=b->height) yy = b->height-1;
614 if(xx<0) xx += b->width;
615 if(yy<0) yy += b->height;
618 col = b->data[yy*b->width+xx];
621 line[x].r = clamp(((line[x].r*ainv)>>8)+col.r);
622 line[x].g = clamp(((line[x].g*ainv)>>8)+col.g);
623 line[x].b = clamp(((line[x].b*ainv)>>8)+col.b);
631 static void fill_gradient(RGBA*line, int*z, int y, int x1, int x2, MATRIX*m, GRADIENT*g, int type, U32 depth, double fmultiply)
635 double m11= m->sx*fmultiply/80, m21= m->r1*fmultiply/80;
636 double m12= m->r0*fmultiply/80, m22= m->sy*fmultiply/80;
637 double rx = m->tx*fmultiply/20.0;
638 double ry = m->ty*fmultiply/20.0;
640 double det = m11*m22 - m12*m21;
641 if(fabs(det) < 0.0005) {
642 /* x direction equals y direction- the image is invisible */
648 RGBA oldcol = g->rgba[0];
649 int r0 = g->ratios[0]*2;
653 for(t=1;t<g->num;t++) {
654 int r1 = g->ratios[t]*2;
655 RGBA newcol = g->rgba[t];
658 //printf("%d %d->%d %02x%02x%02x%02x->%02x%02x%02x%02x\n",
659 // t, r0, r1, oldcol.r,oldcol.g,oldcol.b,oldcol.a,
660 // newcol.r,newcol.g,newcol.b,newcol.a);
661 double f = 1.0 / (r1-r0);
666 palette[r0].r = oldcol.r*p0 + newcol.r*p1;
667 palette[r0].g = oldcol.g*p0 + newcol.g*p1;
668 palette[r0].b = oldcol.b*p0 + newcol.b*p1;
669 palette[r0].a = oldcol.a*p0 + newcol.a*p1;
681 double xx = ( (x - rx) * m22 - (y - ry) * m21)*det;
682 double yy = (- (x - rx) * m12 + (y - ry) * m11)*det;
686 if(type == FILL_LINEAR) {
692 col = palette[xr+256];
694 int xr = sqrt(xx*xx+yy*yy)*511;
702 line[x].r = clamp(((line[x].r*ainv)>>8)+col.r);
703 line[x].g = clamp(((line[x].g*ainv)>>8)+col.g);
704 line[x].b = clamp(((line[x].b*ainv)>>8)+col.b);
712 typedef struct _layer {
724 static void fill(RENDERBUF*dest, RGBA*line, int*zline, int y, int x1, int x2, state_t*fillstate, U32 clipdepth)
726 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
729 layer_t*l = fillstate->layers;
731 if(x1>=x2) //zero width? nothing to do.
736 /* not filled. TODO: we should never add those in the first place */
738 printf("(not filled)");
739 } else if(l->fillid > l->p->s->numfillstyles) {
740 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->numlinestyles);
741 } else if(clipdepth) {
742 /* filled region- not used for clipping */
747 printf("(%d -> %d style %d)", x1, x2, l->fillid);
749 f = &l->p->s->fillstyles[l->fillid-1];
751 if(f->type == FILL_SOLID) {
752 /* plain color fill */
753 fill_solid(line, zline, y, x1, x2, f->color, l->p->depth);
754 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED || f->type == (FILL_TILED|2) || f->type == (FILL_CLIPPED|2)) {
755 /* TODO: optimize (do this in add_pixel()?) */
756 bitmap_t* b = i->bitmaps;
757 while(b && b->id != f->id_bitmap) {
761 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
762 fill_solid(line, zline, y, x1, x2, color_red, l->p->depth);
764 fill_bitmap(line, zline, y, x1, x2, &f->m, b, /*clipped?*/f->type&1, l->p->depth, i->multiply);
766 } else if(f->type == FILL_LINEAR || f->type == FILL_RADIAL) {
767 fill_gradient(line, zline, y, x1, x2, &f->m, &f->gradient, f->type, l->p->depth, i->multiply);
769 fprintf(stderr, "Undefined fillmode: %02x\n", f->type);
774 if(clip && clipdepth) {
775 fill_clip(line, zline, y, x1, x2, clipdepth);
779 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
781 layer_t*last=0,*l = state->layers;
782 while(l && l->p->depth < depth) {
787 if(l && l->p->depth == depth)
792 static void delete_layer(state_t*state, layer_t*todel)
794 layer_t*before=todel->prev;
795 layer_t*next = todel->next;
798 state->layers = next;
804 before->next->prev = before;
807 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
810 toadd->next = state->layers;
814 toadd->next = before->next;
815 toadd->prev = before;
816 before->next = toadd;
819 toadd->next->prev = toadd;
821 static void free_layers(state_t* state)
823 layer_t*l = state->layers;
825 layer_t*next = l->next;
831 static void change_state(int y, state_t* state, renderpoint_t*p)
833 layer_t*before=0, *self=0, *after=0;
836 printf("[(%f,%d)/%d/%d-%d]", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
839 search_layer(state, p->depth, &before, &self, &after);
843 if(self->fillid<0/*??*/ || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
845 if(DEBUG&2) printf("<D>");
847 delete_layer(state, self);
849 /*both fill0 and fill1 are set- exchange the two, updating the layer */
850 if(self->fillid == p->shapeline->fillstyle0) {
851 self->fillid = p->shapeline->fillstyle1;
853 if(DEBUG&2) printf("<X>");
854 } else if(self->fillid == p->shapeline->fillstyle1) {
855 self->fillid = p->shapeline->fillstyle0;
857 if(DEBUG&2) printf("<X>");
859 /* buggy shape. keep everything as-is. */
860 if(DEBUG&2) printf("<!>");
861 //fprintf(stderr, "<line %d: bad swap>\n", y);
867 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
868 /* this is a hack- a better way would be to make sure that
869 we always get (0,32), (32, 33), (33, 0) in the right order if
870 they happen to fall on the same pixel.
871 (not: (0,32), (33, 0), (32, 33))
872 Notice: Weird fill styles appear if linestyles are involved, too.
874 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
878 n = (layer_t*)rfx_calloc(sizeof(layer_t));
880 if(DEBUG&2) printf("<+>");
882 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
885 add_layer(state, before, n);
889 void swf_Process(RENDERBUF*dest, U32 clipdepth)
891 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
894 if(i->ymax < i->ymin) {
895 /* shape is empty. return.
896 only, if it's a clipshape, remember the clipdepth */
898 for(y=0;y<i->height2;y++) {
899 if(clipdepth > i->lines[y].pending_clipdepth)
900 i->lines[y].pending_clipdepth = clipdepth;
903 return; //nothing (else) to do
907 /* lines outside the clip shape are not filled
908 immediately, only the highest clipdepth so far is
909 stored there. They will be clipfilled once there's
910 actually something about to happen in that line */
911 for(y=0;y<i->ymin;y++) {
912 if(clipdepth > i->lines[y].pending_clipdepth)
913 i->lines[y].pending_clipdepth = clipdepth;
915 for(y=i->ymax+1;y<i->height2;y++) {
916 if(clipdepth > i->lines[y].pending_clipdepth)
917 i->lines[y].pending_clipdepth = clipdepth;
921 for(y=i->ymin;y<=i->ymax;y++) {
923 TAG*tag = i->lines[y].points;
924 int num = i->lines[y].num;
925 renderpoint_t*points = (renderpoint_t*)tag->data;
926 RGBA*line = &i->img[i->width2*y];
927 int*zline = &i->zbuf[i->width2*y];
930 memset(&fillstate, 0, sizeof(state_t));
931 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
935 printf("%f (%d/%d) %d\n", points[n].x,
936 points[n].shapeline->fillstyle0,
937 points[n].shapeline->fillstyle1,
938 points[n].shapeline->linestyle);
942 if(i->lines[y].pending_clipdepth && !clipdepth) {
943 fill_clip(line, zline, y, 0, i->width2, i->lines[y].pending_clipdepth);
944 i->lines[y].pending_clipdepth=0;
948 renderpoint_t*p = &points[n];
949 renderpoint_t*next= n<num-1?&points[n+1]:0;
950 int startx = (int)p->x;
951 int endx = (int)(next?next->x:i->width2);
960 /* for clipping, the inverse is filled
961 TODO: lastx!=startx only at the start of the loop,
962 so this might be moved up
964 fill_clip(line, zline, y, lastx, startx, clipdepth);
966 change_state(y, &fillstate, p);
968 fill(dest, line, zline, y, startx, endx, &fillstate, clipdepth);
969 /* if(y == 0 && startx == 232 && endx == 418) {
970 printf("ymin=%d ymax=%d\n", i->ymin, i->ymax);
972 renderpoint_t*p = &points[n];
973 printf("x=%f depth=%08x\n", p->x, p->depth);
978 if(endx == i->width2)
982 /* TODO: is lastx *ever* != i->width2 here? */
983 fill_clip(line, zline, y, lastx, i->width2, clipdepth);
985 free_layers(&fillstate);
988 swf_ClearTag(i->lines[y].points);
990 i->ymin = 0x7fffffff;
991 i->ymax = -0x80000000;
994 RGBA* swf_Render(RENDERBUF*dest)
996 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
997 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
999 int antialize = i->antialize;
1001 if(antialize <= 1) /* no antializing */ {
1002 for(y=0;y<i->height2;y++) {
1003 RGBA*line = &i->img[y*i->width2];
1004 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
1007 RGBA**lines = (RGBA**)rfx_calloc(sizeof(RGBA*)*antialize);
1008 int q = antialize*antialize;
1010 for(y=0;y<i->height2;y++) {
1012 ypos = y % antialize;
1013 lines[ypos] = &i->img[y*i->width2];
1014 if(ypos == antialize-1) {
1015 RGBA*out = &img[(y / antialize)*dest->width];
1018 for(x=0;x<dest->width;x++) {
1019 int xpos = x*antialize;
1021 U32 r=0,g=0,b=0,a=0;
1022 for(yp=0;yp<antialize;yp++) {
1023 RGBA*lp = &lines[yp][xpos];
1025 for(xp=0;xp<antialize;xp++) {
1051 enum CHARACTER_TYPE {none_type, shape_type, image_type, text_type, edittext_type, font_type, sprite_type};
1056 enum CHARACTER_TYPE type;
1063 int compare_placements(const void *v1, const void *v2)
1065 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
1066 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
1067 if(p1->depth != p2->depth)
1068 return (int)p1->depth - (int)p2->depth;
1071 return 1; // do the clip first
1075 /* if(!p1->clipdepth) {
1076 if(!p2->clipdepth) {
1077 // !p1->clipdepth && !p2->clipdepth
1078 return (int)p1->depth - (int)p2->depth;
1080 // !p1->clipdepth && p2->clipdepth
1081 if(p1->depth != p2->clipdepth)
1082 return (int)p1->depth - (int)p2->clipdepth;
1084 return 1; // do the clip first
1087 if(!p2->clipdepth) {
1088 // p1->clipdepth && !p2->clipdepth
1089 if(p1->clipdepth != p2->depth)
1090 return (int)p1->clipdepth - (int)p2->depth;
1092 return -1;// do the clip first
1094 if(p1->clipdepth != p2->clipdepth)
1095 return (int)p1->clipdepth - (int)p2->clipdepth;
1097 return (int)p1->depth - (int)p2->depth;
1102 typedef struct textcallbackblock
1104 character_t*idtable;
1110 } textcallbackblock_t;
1112 static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize,
1113 int xstart, int ystart, RGBA* color)
1115 textcallbackblock_t * info = (textcallbackblock_t*)self;
1118 if(info->idtable[fontid].type != font_type) {
1119 fprintf(stderr, "ID %d is not a font\n", fontid);
1121 } else if(!info->idtable[fontid].obj.font) {
1122 fprintf(stderr, "Font %d unknown\n", fontid);
1125 font = info->idtable[fontid].obj.font;
1128 int x = xstart + xpos[t];
1134 p = swf_TurnPoint(p, &m);
1136 m.sx = (m.sx * fontsize) / 1024;
1137 m.sy = (m.sy * fontsize) / 1024;
1138 m.r0 = (m.r0 * fontsize) / 1024;
1139 m.r1 = (m.r1 * fontsize) / 1024;
1143 if(chars[t]<0 || chars[t]>= font->numchars) {
1144 fprintf(stderr, "Character out of range: %d\n", chars[t]);
1146 SHAPE2*shape = font->glyphs[chars[t]];
1147 shape->fillstyles[0].color = *color; //q&d
1148 /*printf("Rendering char %d (size %d, x:%d, y:%d) color:%02x%02x%02x%02x\n", chars[t], fontsize, x, y,
1149 color->a, color->r, color->g, color->b);
1150 swf_DumpMatrix(stdout, &m);
1151 swf_DumpShape(shape);*/
1152 swf_RenderShape(info->buf, shape, &m, info->cxform, info->depth, info->clipdepth);
1157 static void renderFromTag(RENDERBUF*buf, character_t*idtable, TAG*firstTag, MATRIX*m)
1160 int numplacements = 0;
1161 SWFPLACEOBJECT* placements;
1166 if(tag->id == ST_PLACEOBJECT ||
1167 tag->id == ST_PLACEOBJECT2) {
1170 if(tag->id == ST_SHOWFRAME || tag->id == ST_END)
1174 placements = (SWFPLACEOBJECT*)rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
1179 if(swf_isPlaceTag(tag)) {
1181 swf_GetPlaceObject(tag, &p);
1182 /* TODO: add move and deletion */
1183 placements[numplacements++] = p;
1184 swf_PlaceObjectFree(&p); //dirty! but it only frees fields we don't use
1186 if(tag->id == ST_SHOWFRAME || tag->id == ST_END)
1191 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1194 for(t=0;t<numplacements;t++) {
1195 SWFPLACEOBJECT*p = &placements[t];
1198 swf_MatrixJoin(&m2, m, &p->matrix);
1200 if(!idtable[id].tag) {
1201 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1205 if(idtable[id].type == shape_type) {
1206 //SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1207 swf_RenderShape(buf, idtable[id].obj.shape, &m2, &p->cxform, p->depth, p->clipdepth);
1208 } else if(idtable[id].type == sprite_type) {
1209 swf_UnFoldSprite(idtable[id].tag);
1210 renderFromTag(buf, idtable, idtable[id].tag->next, &m2);
1211 swf_FoldSprite(idtable[id].tag);
1212 } else if(idtable[id].type == text_type) {
1213 TAG* tag = idtable[id].tag;
1214 textcallbackblock_t info;
1217 swf_SetTagPos(tag, 0);
1220 swf_GetMatrix(tag,&mt);
1221 swf_MatrixJoin(&info.m, &m2, &mt);
1222 /*printf("Text matrix:\n");
1223 swf_DumpMatrix(stdout, &m);
1224 printf("Placement matrix:\n");
1225 swf_DumpMatrix(stdout, &p->matrix);
1226 printf("Final matrix:\n");
1227 swf_DumpMatrix(stdout, &info.m);*/
1229 info.idtable = idtable;
1230 info.depth = p->depth;
1231 info.cxform = &p->cxform;
1232 info.clipdepth = p->clipdepth;
1235 swf_ParseDefineText(tag, textcallback, &info);
1236 } else if(idtable[id].type == edittext_type) {
1237 TAG* tag = idtable[id].tag;
1238 U16 flags = swf_GetBits(tag, 16);
1239 if(flags & ET_HASTEXT) {
1240 fprintf(stderr, "edittext not supported yet (id %d)\n", id);
1243 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1250 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1256 swf_OptimizeTagOrder(swf);
1259 character_t* idtable = (character_t*)rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1261 /* set background color */
1262 color = swf_GetSWFBackgroundColor(swf);
1263 swf_Render_SetBackgroundColor(buf, color);
1265 /* parse definitions */
1266 tag = swf->firstTag;
1268 if(swf_isDefiningTag(tag)) {
1269 int id = swf_GetDefineID(tag);
1270 idtable[id].tag = tag;
1271 idtable[id].bbox = (SRECT*)rfx_alloc(sizeof(SRECT));
1272 *idtable[id].bbox = swf_GetDefineBBox(tag);
1274 if(swf_isShapeTag(tag)) {
1275 SHAPE2* shape = (SHAPE2*)rfx_calloc(sizeof(SHAPE2));
1276 swf_ParseDefineShape(tag, shape);
1277 idtable[id].type = shape_type;
1278 idtable[id].obj.shape = shape;
1279 } else if(swf_isImageTag(tag)) {
1281 RGBA*data = swf_ExtractImage(tag, &width, &height);
1282 idtable[id].type = image_type;
1283 swf_Render_AddImage(buf, id, data, width, height);
1285 } else if(tag->id == ST_DEFINEFONT ||
1286 tag->id == ST_DEFINEFONT2) {
1289 font_t*font = (font_t*)rfx_calloc(sizeof(font_t));
1290 idtable[id].obj.font = font;
1291 swf_FontExtract(swf,id,&swffont);
1292 font->numchars = swffont->numchars;
1293 font->glyphs = (SHAPE2**)rfx_calloc(sizeof(SHAPE2*)*font->numchars);
1294 for(t=0;t<font->numchars;t++) {
1295 if(!swffont->glyph[t].shape->fillstyle.n) {
1296 /* the actual fill color will be overwritten while rendering */
1297 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
1299 font->glyphs[t] = swf_ShapeToShape2(swffont->glyph[t].shape);
1301 swf_FontFree(swffont);
1302 idtable[id].type = font_type;
1304 } else if(tag->id == ST_DEFINEFONTINFO ||
1305 tag->id == ST_DEFINEFONTINFO2) {
1306 idtable[id].type = font_type;
1307 } else if(tag->id == ST_DEFINETEXT ||
1308 tag->id == ST_DEFINETEXT2) {
1309 idtable[id].type = text_type;
1310 } else if(tag->id == ST_DEFINESPRITE) {
1311 idtable[id].type = sprite_type;
1312 } else if(tag->id == ST_DEFINEEDITTEXT) {
1313 idtable[id].type = edittext_type;
1319 swf_GetMatrix(0, &m);
1320 renderFromTag(buf, idtable, swf->firstTag, &m);
1322 /* free id and depth tables again */
1323 for(t=0;t<65536;t++) {
1324 if(idtable[t].bbox) {
1325 free(idtable[t].bbox);
1328 if(idtable[t].type == shape_type) {
1329 SHAPE2* shape = idtable[t].obj.shape;
1331 swf_Shape2Free(shape); // FIXME
1332 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;
1334 } else if(idtable[t].type == font_type) {
1335 font_t* font = idtable[t].obj.font;
1339 for(t=0;t<font->numchars;t++) {
1340 swf_Shape2Free(font->glyphs[t]);
1341 free(font->glyphs[t]); font->glyphs[t] = 0;
1346 free(idtable[t].obj.font); idtable[t].obj.font = 0;