X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fmodules%2Fswfrender.c;h=db1a2d1a76a77597a2291c654a788f3833a16a91;hp=e3236aff6a107de9e23b4790e75a0d2fc5332631;hb=90e82ae6c7f404670088aba9bebd012ce90ba932;hpb=7bda0c12d1c74bcb179cad18bb49fcb2257c2a98 diff --git a/lib/modules/swfrender.c b/lib/modules/swfrender.c index e3236af..db1a2d1 100644 --- a/lib/modules/swfrender.c +++ b/lib/modules/swfrender.c @@ -22,18 +22,49 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include + +typedef struct _dummyshape +{ + SHAPE2*shape; + //CXFORM //TODO + struct _dummyshape*next; +} dummyshape_t; + typedef struct _renderpoint { enum {clip_type, fill_type} type; - float fx; + float fx; //for sorting int x; U32 depth; U32 clipdepth; - SHAPE2*shape; SHAPELINE*shapeline; - //CXFORM? + + dummyshape_t*s; } renderpoint_t; +/* + enum {clip_type, solidfill_type, texturefill_type, gradientfill_type} type; + float fx; + int x; + U32 depth; + U32 clipdepth; + + // solidfill; + RGBA color; + + // texturefill + bitmap_t* bitmap; + + // gradientfill + gradient_t* gradient; + + // texture- & gradientfill; + U32 x,y; + U32 dx,dy; + +*/ + typedef struct _renderline { TAG*points; //incremented in 128 byte steps @@ -54,6 +85,10 @@ typedef struct _renderbuf_internal char antialize; int multiply; int width2,height2; + dummyshape_t*dshapes; + dummyshape_t*dshapes_next; + RGBA*background; + int background_width, background_height; } renderbuf_internal; #define DEBUG 0 @@ -66,71 +101,71 @@ static inline void add_pixel(RENDERBUF*dest, float x, int y, renderpoint_t*p) p->fx = x; swf_SetBlock(i->lines[y].points, (U8*)p, sizeof(renderpoint_t)); } -static void add_line(RENDERBUF*buf, double x1, int y1, double x2, int y2, renderpoint_t*p, char thin) + +/* set this to 0.777777 or something if the "both fillstyles set while not inside shape" + problem appears to often */ +#define CUT 0.5 + +static void add_line(RENDERBUF*buf, double x1, double y1, double x2, double y2, renderpoint_t*p) { renderbuf_internal*i = (renderbuf_internal*)buf->internal; + double diffx, diffy; + double ny1, ny2, stepx; /* if(DEBUG&4) { int l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); printf(" l[%d - %.2f/%.2f -> %.2f/%.2f]", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0); }*/ - /* SCALE DOWN */ - y1*=i->multiply; - y2*=i->multiply; - x1*=i->multiply; - x2*=i->multiply; - - y1/=20; - y2/=20; + y1=y1*i->multiply; + y2=y2*i->multiply; + x1=x1*i->multiply; + x2=x2*i->multiply; - int diffy = y2 - y1; - int starty = y1; - int posy=0; - double diffx = x2 - x1; - double stepx; - double startx = x1; - double posx=0; - - if(diffy<0) { - startx = x2; - starty = y2; - diffx = -diffx; - diffy = -diffy; + y1 = y1/20.0; + y2 = y2/20.0; + x1 = x1/20.0; + x2 = x2/20.0; + + if(y2 < y1) { + double x; + double y; + x = x1;x1 = x2;x2=x; + y = y1;y1 = y2;y2=y; } + + diffx = x2 - x1; + diffy = y2 - y1; + + ny1 = (int)(y1)+CUT; + ny2 = (int)(y2)+CUT; - if(diffy == 0) { - if(thin) { - stepx = diffx; - } else { - return; - } - } else { - stepx = diffx / diffy; + if(ny1 < y1) { + ny1 = (int)(y1) + 1.0 + CUT; } - - if(thin) - diffy++; - - while(posy= y2) { + ny2 = (int)(y2) - 1.0 + CUT; + } + + if(ny1 > ny2) + return; + + stepx = diffx/diffy; + x1 = x1 + (ny1-y1)*stepx; + x2 = x2 + (ny2-y2)*stepx; + + { + int posy=(int)ny1; + int endy=(int)ny2; + double posx=0; + double startx = x1; + + while(posy<=endy) { + float xx = (float)(startx + posx); + add_pixel(buf, xx ,posy, p); + posx+=stepx; + posy++; + } } - return; } #define PI 3.14159265358979 static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double y2, int width, renderpoint_t*p) @@ -144,21 +179,21 @@ static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double int t; int segments; - double lastx; + double lastx,lasty; double vx,vy; - double xx; - - int lasty; - int yy; - - /* The Flash Player does this, too. This means every line is always at least - one pixel wide */ + double xx,yy; + + /* Make sure the line is always at least one pixel wide */ +#define LINEMODE1 +#ifdef LINEMODE1 + /* That's what Macromedia's Player does at least at zoom level >= 1. */ width += 20; - - /*if(width<=20) { - add_line(buf, x1, y1, x2, y2, p, 1); - return; - }*/ +#else + /* That's what Macromedia's Player seems to do at zoom level 0. */ + /* TODO: needs testing */ + if(width<20) + width = 20; +#endif sd = (double)dx*(double)dx+(double)dy*(double)dy; d = sqrt(sd); @@ -181,40 +216,40 @@ static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double vy=vy*width*0.5; xx = x2+vx; - yy = (int)(y2+vy); - add_line(buf, x1+vx, (int)(y1+vy), xx, yy, p, 0); + yy = y2+vy; + add_line(buf, x1+vx, y1+vy, xx, yy, p); lastx = xx; lasty = yy; for(t=1;tposy = posy; buf->internal = (renderbuf_internal*)rfx_calloc(sizeof(renderbuf_internal)); i = (renderbuf_internal*)buf->internal; - i->antialize = antialize; + i->antialize = !!antialize; i->multiply = antialize?multiply*2:multiply; i->height2 = antialize?2*buf->height:buf->height; i->width2 = antialize?2*buf->width:buf->width; @@ -256,6 +291,19 @@ void swf_Render_Init(RENDERBUF*buf, int posx, int posy, int width, int height, c i->lines[y].points = swf_InsertTag(0, 0); } } +void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height) +{ + renderbuf_internal*i = (renderbuf_internal*)buf->internal; + RGBA*bck = (RGBA*)rfx_alloc(sizeof(RGBA)*width*height); + memcpy(bck, img, sizeof(RGBA)*width*height); + i->background = bck; + i->background_width = width; + i->background_height = height; +} +void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color) +{ + swf_Render_SetBackground(buf, &color, 1, 1); +} void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height) { renderbuf_internal*i = (renderbuf_internal*)buf->internal; @@ -282,12 +330,26 @@ void swf_Render_Delete(RENDERBUF*dest) renderbuf_internal*i = (renderbuf_internal*)dest->internal; int y; bitmap_t*b = i->bitmaps; + dummyshape_t*d = i->dshapes; + + if(i->background) { + free(i->background);i->background=0; + } /* delete line buffers */ for(y=0;yheight2;y++) { swf_DeleteTag(i->lines[y].points); i->lines[y].points = 0; } + + while(d) { + dummyshape_t*next = d->next; + swf_Shape2Free(d->shape); + free(d->shape);d->shape=0; + free(d); + d=next; + } + i->dshapes = 0; /* delete bitmaps */ while(b) { @@ -301,6 +363,34 @@ void swf_Render_Delete(RENDERBUF*dest) rfx_free(dest->internal); dest->internal = 0; } +static void swf_Render_AddShape(RENDERBUF*dest,dummyshape_t*s) +{ + renderbuf_internal*i = (renderbuf_internal*)dest->internal; + + s->next = 0; + if(i->dshapes_next) + i->dshapes_next->next = s; + i->dshapes_next = s; + if(!i->dshapes) { + i->dshapes = s; + } +} + +static SHAPE2* linestyle2fillstyle(SHAPE2*shape) +{ + SHAPE2*s = rfx_calloc(sizeof(SHAPE2)); + int t; + s->numfillstyles = shape->numlinestyles; + s->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles); + s->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles); + for(t=0;tnumlinestyles;t++) { + s->lines[t].fillstyle0 = t+1; + s->fillstyles[t].type = FILL_SOLID; + s->fillstyles[t].color = shape->linestyles[t].color; + } + return s; +} + void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth) { renderbuf_internal*i = (renderbuf_internal*)dest->internal; @@ -313,34 +403,60 @@ void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _dept renderpoint_t p, lp; memset(&p, 0, sizeof(renderpoint_t)); memset(&lp, 0, sizeof(renderpoint_t)); + p.type = _clipdepth?clip_type:fill_type; - p.shape = shape; p.depth = _depth << 16; p.clipdepth = _clipdepth << 16; + mat.tx -= dest->posx*20; mat.ty -= dest->posy*20; - if(shape->numlinestyles) { - /* TODO: free this again */ - lshape = rfx_calloc(sizeof(SHAPE2)); + if(shape->numfillstyles) { + dummyshape_t*fshape = rfx_calloc(sizeof(dummyshape_t)); int t; - lshape->numfillstyles = shape->numlinestyles; - lshape->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles); - lshape->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles); - for(t=0;tnumlinestyles;t++) { - lshape->lines[t].fillstyle0 = t+1; - lshape->fillstyles[t].type = FILL_SOLID; - lshape->fillstyles[t].color = shape->linestyles[t].color; + SHAPE2* s2 = swf_Shape2Clone(shape); + + fshape->shape = s2; + + p.s = fshape; + + /* multiply fillstyles matrices with placement matrix- + important for texture and gradient fill */ + for(t=0;tnumfillstyles;t++) { + MATRIX nm; + swf_MatrixJoin(&nm, &s2->fillstyles[t].m, &mat); //TODO: is this the right order? + nm.sx *= i->multiply; + nm.sy *= i->multiply; + nm.r0 *= i->multiply; + nm.r1 *= i->multiply; + nm.tx *= i->multiply; + nm.ty *= i->multiply; + s2->fillstyles[t].m = nm; } + + /* add this shape to the global shape list, for deallocing */ + swf_Render_AddShape(dest, fshape); + } + + if(shape->numlinestyles) { + dummyshape_t*dshape = rfx_calloc(sizeof(dummyshape_t)); + + lshape = linestyle2fillstyle(shape); + lp.type = fill_type; - lp.shape = lshape; - lp.depth = p.depth+1; + lp.s = dshape; + lp.depth = (_depth << 16)+1; + + dshape->shape = lshape; + + /* add this shape to the global shape list, for deallocing */ + swf_Render_AddShape(dest, dshape); } if(p.clipdepth) { /* reverse shape */ p.shapeline = 0; - add_line(dest, -20, 0, -20, i->height2*20, &p, 0); + add_line(dest, -20, 0, -20, i->height2*20, &p); } while(line) @@ -352,11 +468,12 @@ void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _dept if(line->type == moveTo) { } else if(line->type == lineTo) { if(DEBUG&4) { + int l; x1 = x; y1 = y; x2 = line->x; y2 = line->y; - int l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); + l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); printf("%d - %.2f/%.2f -> %.2f/%.2f ", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0); } @@ -368,22 +485,25 @@ void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _dept add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width, &lp); lp.depth++; } - if(line->fillstyle0 || line->fillstyle1) - add_line(dest, x1, y1, x3, y3, &p, 0); + if(line->fillstyle0 || line->fillstyle1) { + assert(shape->numfillstyles); + add_line(dest, x1, y1, x3, y3, &p); + } if(DEBUG&4) printf("\n"); } else if(line->type == splineTo) { + int c,t,parts,qparts; + double xx,yy; transform_point(&mat, x, y, &x1, &y1); transform_point(&mat, line->sx, line->sy, &x2, &y2); transform_point(&mat, line->x, line->y, &x3, &y3); - int c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1); - int parts,qparts; - int t; - double xx=x1,yy=y1; + c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1); + xx=x1; + yy=y1; - parts = (int)(sqrt(c)/2); + parts = (int)(sqrt(c)/3); if(!parts) parts = 1; if(DEBUG&4) @@ -403,8 +523,10 @@ void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _dept add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width, &lp); lp.depth++; } - if(line->fillstyle0 || line->fillstyle1) - add_line(dest, (int)xx, (int)yy, (int)nx, (int)ny, &p, 0); + if(line->fillstyle0 || line->fillstyle1) { + assert(shape->numfillstyles); + add_line(dest, (int)xx, (int)yy, (int)nx, (int)ny, &p); + } xx = nx; yy = ny; @@ -468,23 +590,30 @@ static void fill_bitmap(RGBA*line, int y, int x1, int x2, MATRIX*m, bitmap_t*b, return; } det = 20.0/det; - + + if(!b->width || !b->height) { + fill_plain(line, x1, x2, color_red); + return; + } + do { + RGBA col; int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det); int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det); + int ainv; if(clip) { - if(xx<0 || xx>=b->width || yy<0 || yy>=b->height) { - //line[x] = color_red; - continue; - } + if(xx<0) xx=0; + if(xx>=b->width) xx = b->width-1; + if(yy<0) yy=0; + if(yy>=b->height) yy = b->height-1; } else { xx %= b->width; yy %= b->height; } - RGBA col = b->data[yy*b->width+xx]; - int ainv = 255-col.a; + col = b->data[yy*b->width+xx]; + ainv = 255-col.a; line[x].r = ((line[x].r*ainv)>>8)+col.r; line[x].g = ((line[x].g*ainv)>>8)+col.g; @@ -496,13 +625,14 @@ static void fill_bitmap(RGBA*line, int y, int x1, int x2, MATRIX*m, bitmap_t*b, static void fill(RENDERBUF*dest, RGBA*line, int y, int x1, int x2, state_t*state) { renderbuf_internal*i = (renderbuf_internal*)dest->internal; + U32 clipdepth; layer_t*l = state->layers; if(x1>=x2) //zero width? nothing to do. return; - U32 clipdepth = 0; + clipdepth = 0; while(l) { if(l->p->depth < clipdepth) { if(DEBUG&2) printf("(clipped)"); @@ -517,14 +647,14 @@ static void fill(RENDERBUF*dest, RGBA*line, int y, int x1, int x2, state_t*state /* not filled. TODO: we should never add those in the first place */ if(DEBUG&2) printf("(not filled)"); - } else if(l->fillid > l->p->shape->numfillstyles) { - fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->shape->numlinestyles); + } else if(l->fillid > l->p->s->shape->numfillstyles) { + fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->shape->numlinestyles); } else { FILLSTYLE*f; if(DEBUG&2) printf("(%d -> %d style %d)", x1, x2, l->fillid); - f = &l->p->shape->fillstyles[l->fillid-1]; + f = &l->p->s->shape->fillstyles[l->fillid-1]; if(f->type == FILL_SOLID) { /* plain color fill */ @@ -539,16 +669,17 @@ static void fill(RENDERBUF*dest, RGBA*line, int y, int x1, int x2, state_t*state fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap); fill_plain(line, x1, x2, color_red); } else { - MATRIX m = f->m; - m.tx -= dest->posx*20; - m.ty -= dest->posy*20; - m.sx *= i->multiply; - m.sy *= i->multiply; - m.r0 *= i->multiply; - m.r1 *= i->multiply; - m.tx *= i->multiply; - m.ty *= i->multiply; - fill_bitmap(line, y, x1, x2, &m, b, FILL_CLIPPED?1:0); + //done in swf_RenderShape now + //MATRIX m = f->m; + //m.tx -= dest->posx*20; + //m.ty -= dest->posy*20; + //m.sx *= i->multiply; + //m.sy *= i->multiply; + //m.r0 *= i->multiply; + //m.r1 *= i->multiply; + //m.tx *= i->multiply; + //m.ty *= i->multiply; + fill_bitmap(line, y, x1, x2, &f->m, b, FILL_CLIPPED?1:0); } } } @@ -690,13 +821,23 @@ RGBA* swf_Render(RENDERBUF*dest) int size = sizeof(renderpoint_t); int num = tag->len / size; RGBA*line = line1; + state_t state; + memset(&state, 0, sizeof(state_t)); + if((y&1) && i->antialize) line = line2; - state_t state; - memset(&state, 0, sizeof(state_t)); - memset(line, 0, sizeof(RGBA)*i->width2); + if(!i->background) { + memset(line, 0, sizeof(RGBA)*i->width2); + } else { + int x,xx; + int xstep=i->background_width*65536/i->width2; + RGBA*src = &i->background[(i->background_height*y/i->height2)*i->background_width]; + for(x=0,xx=0;xwidth2;x++,xx+=xstep) { + line[x] = src[xx>>16]; + } + } memory += tag->memsize; qsort(tag->data, num, size, compare_renderpoints); for(n=0;n