added background color support.
[swftools.git] / lib / modules / swfrender.c
1 /* swfrender.c
2
3    functions for rendering swf content
4       
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2004 Mederra Oy <http://www.mederra.fi>
9    Copyright (c) 2004 Matthias Kramm
10  
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.
15
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.
20
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 */
24
25 typedef struct _renderpoint
26 {
27     enum {clip_type, fill_type} type;
28     float fx;
29     int x;
30     U32 depth;
31     U32 clipdepth;
32     SHAPE2*shape;
33     SHAPELINE*shapeline;
34     //CXFORM?
35 } renderpoint_t;
36
37 typedef struct _renderline
38 {
39     TAG*points; //incremented in 128 byte steps
40 } renderline_t;
41
42 typedef struct _bitmap {
43     int width;
44     int height;
45     RGBA*data;
46     int id;
47     struct _bitmap*next;
48 } bitmap_t;
49
50 typedef struct _dummyshape
51 {
52     SHAPE2*shape;
53     struct _dummyshape*next;
54 } dummyshape_t;
55
56 typedef struct _renderbuf_internal
57 {
58     renderline_t*lines;
59     bitmap_t*bitmaps;
60     char antialize;
61     int multiply;
62     int width2,height2;
63     dummyshape_t*dshapes;
64     dummyshape_t*dshapes_next;
65     RGBA*background;
66     int background_width, background_height;
67 } renderbuf_internal;
68
69 #define DEBUG 0
70
71 static inline void add_pixel(RENDERBUF*dest, float x, int y, renderpoint_t*p)
72 {
73     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
74     if(x >= i->width2 || y >= i->height2 || y<0) return;
75     p->x = (int)x;
76     p->fx = x;
77     swf_SetBlock(i->lines[y].points, (U8*)p, sizeof(renderpoint_t));
78 }
79
80 /* set this to 0.777777 or something if the "both fillstyles set while not inside shape"
81    problem appears to often */
82 #define CUT 0.5
83
84 static void add_line(RENDERBUF*buf, double x1, double y1, double x2, double y2, renderpoint_t*p, char thin)
85 {
86     renderbuf_internal*i = (renderbuf_internal*)buf->internal;
87 /*    if(DEBUG&4) {
88         int l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
89         printf(" l[%d - %.2f/%.2f -> %.2f/%.2f]", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
90     }*/
91
92     y1=y1*i->multiply;
93     y2=y2*i->multiply;
94     x1=x1*i->multiply;
95     x2=x2*i->multiply;
96     
97     y1 = y1/20.0;
98     y2 = y2/20.0;
99     x1 = x1/20.0;
100     x2 = x2/20.0;
101
102     if(y2 < y1) {
103         double x = x1;x1 = x2;x2=x;
104         double y = y1;y1 = y2;y2=y;
105     }
106     
107     double diffx = x2 - x1;
108     double diffy = y2 - y1;
109     
110     double ny1 = (int)(y1)+CUT;
111     double ny2 = (int)(y2)+CUT;
112
113     if(ny1 < y1) {
114         ny1 = (int)(y1) + 1.0 + CUT;
115     }
116     if(ny2 >= y2) {
117         ny2 = (int)(y2) - 1.0 + CUT;
118     }
119
120     if(ny1 > ny2)
121         return;
122
123     double stepx = diffx/diffy;
124     x1 = x1 + (ny1-y1)*stepx;
125     x2 = x2 + (ny2-y2)*stepx;
126
127     int posy=(int)ny1;
128     int endy=(int)ny2;
129     double posx=0;
130     double startx = x1;
131
132     while(posy<=endy) {
133         float xx = (float)(startx + posx);
134         add_pixel(buf, xx ,posy, p);
135         posx+=stepx;
136         posy++;
137     }
138 }
139 #define PI 3.14159265358979
140 static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double y2, int width, renderpoint_t*p)
141 {
142     renderbuf_internal*i = (renderbuf_internal*)buf->internal;
143
144     double dx = x2-x1;
145     double dy = y2-y1;
146     double sd;
147     double d;
148
149     int t;
150     int segments;
151     double lastx,lasty;
152     double vx,vy;
153     double xx,yy;
154    
155     /* The Flash Player does this, too. This means every line is always at least
156        one pixel wide */
157     width += 20;
158
159     sd = (double)dx*(double)dx+(double)dy*(double)dy;
160     d = sqrt(sd);
161
162     if(!dx && !dy) {
163         vx = 1;
164         vy = 0;
165     } else {
166         vx = ( dy/d);
167         vy = (-dx/d);
168     }
169
170     segments = width/2;
171     if(segments < 2)
172         segments = 2;
173
174     segments = 8;
175
176     vx=vx*width*0.5;
177     vy=vy*width*0.5;
178
179     xx = x2+vx;
180     yy = y2+vy;
181     add_line(buf, x1+vx, y1+vy, xx, yy, p, 0);
182     lastx = xx;
183     lasty = yy;
184     for(t=1;t<segments;t++) {
185         double s = sin(t*PI/segments);
186         double c = cos(t*PI/segments);
187         xx = (x2 + vx*c - vy*s);
188         yy = (y2 + vx*s + vy*c);
189         add_line(buf, lastx, lasty, xx, yy, p, 0);
190         lastx = xx;
191         lasty = yy;
192     }
193     
194     xx = (x2-vx);
195     yy = (y2-vy);
196     add_line(buf, lastx, lasty, xx, yy, p, 0);
197     lastx = xx;
198     lasty = yy;
199     xx = (x1-vx);
200     yy = (y1-vy);
201     add_line(buf, lastx, lasty, xx, yy, p, 0);
202     lastx = xx;
203     lasty = yy;
204     for(t=1;t<segments;t++) {
205         double s = sin(t*PI/segments);
206         double c = cos(t*PI/segments);
207         xx = (x1 - vx*c + vy*s);
208         yy = (y1 - vx*s - vy*c);
209         add_line(buf, lastx, lasty, xx, yy, p, 0);
210         lastx = xx;
211         lasty = yy;
212     }
213     add_line(buf, lastx, lasty, (x1+vx), (y1+vy), p, 0);
214 }
215
216 static inline void transform_point(MATRIX*m, int x, int y, int*dx, int*dy)
217 {
218     SPOINT p,d;
219     p.x = x;
220     p.y = y;
221     d = swf_TurnPoint(p, m);
222     *dx = d.x;
223     *dy = d.y;
224 }
225
226 static int compare_renderpoints(const void * _a, const void * _b)
227 {
228     renderpoint_t*a = (renderpoint_t*)_a;
229     renderpoint_t*b = (renderpoint_t*)_b;
230     if(a->fx < b->fx) return -1;
231     if(a->fx > b->fx) return 1;
232     return 0;
233 }
234
235 void swf_Render_Init(RENDERBUF*buf, int posx, int posy, int width, int height, char antialize, int multiply)
236 {
237     renderbuf_internal*i;
238     int y;
239     memset(buf, 0, sizeof(RENDERBUF));
240     buf->width = width*multiply;
241     buf->height = height*multiply;
242     buf->posx = posx;
243     buf->posy = posy;
244     buf->internal = (renderbuf_internal*)rfx_calloc(sizeof(renderbuf_internal));
245     i = (renderbuf_internal*)buf->internal;
246     i->antialize = !!antialize;
247     i->multiply = antialize?multiply*2:multiply;
248     i->height2 = antialize?2*buf->height:buf->height;
249     i->width2 = antialize?2*buf->width:buf->width;
250     i->lines = (renderline_t*)rfx_alloc(i->height2*sizeof(renderline_t));
251     for(y=0;y<i->height2;y++) {
252         i->lines[y].points = swf_InsertTag(0, 0);
253     }
254 }
255 void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height)
256 {
257     renderbuf_internal*i = (renderbuf_internal*)buf->internal;
258     RGBA*bck = (RGBA*)rfx_alloc(sizeof(RGBA)*width*height);
259     memcpy(bck, img, sizeof(RGBA)*width*height);
260     i->background = bck;
261     i->background_width = width;
262     i->background_height = height;
263 }
264 void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color)
265 {
266     swf_Render_SetBackground(buf, &color, 1, 1);
267 }
268 void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height)
269 {
270     renderbuf_internal*i = (renderbuf_internal*)buf->internal;
271
272     bitmap_t*bm = rfx_calloc(sizeof(bitmap_t));
273     bm->id = id;
274     bm->width = width;
275     bm->height = height;
276     bm->data = img;
277
278     bm->next = i->bitmaps;
279     i->bitmaps = bm;
280 }
281 void swf_Render_ClearCanvas(RENDERBUF*dest)
282 {
283     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
284     int y;
285     for(y=0;y<i->height2;y++) {
286         swf_ClearTag(i->lines[y].points);
287     }
288 }
289 void swf_Render_Delete(RENDERBUF*dest)
290 {
291     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
292     int y;
293     bitmap_t*b = i->bitmaps;
294     dummyshape_t*d = i->dshapes;
295
296     if(i->background) {
297         free(i->background);i->background=0;
298     }
299
300     /* delete line buffers */
301     for(y=0;y<i->height2;y++) {
302         swf_DeleteTag(i->lines[y].points);
303         i->lines[y].points = 0;
304     }
305
306     while(d) {
307         dummyshape_t*next = d->next;
308         swf_Shape2Free(d->shape);
309         free(d->shape);d->shape=0;
310         free(d);
311         d=next;
312     }
313     i->dshapes = 0;
314     
315     /* delete bitmaps */
316     while(b) {
317         bitmap_t*next = b->next;
318         //free(b->data);b->data=0;
319         rfx_free(b);
320         b = next;
321     }
322
323     rfx_free(i->lines); i->lines = 0;
324     rfx_free(dest->internal); dest->internal = 0;
325 }
326
327 void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth)
328 {
329     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
330     
331     SHAPELINE*line = shape->lines;
332     int x=0,y=0;
333     MATRIX mat = *m;
334     SHAPE2* lshape = 0;
335
336     renderpoint_t p, lp;
337     memset(&p, 0, sizeof(renderpoint_t));
338     memset(&lp, 0, sizeof(renderpoint_t));
339     p.type = _clipdepth?clip_type:fill_type;
340     p.shape = shape;
341     p.depth = _depth << 16;
342     p.clipdepth = _clipdepth << 16;
343     mat.tx -= dest->posx*20;
344     mat.ty -= dest->posy*20;
345
346     if(shape->numlinestyles) {
347         dummyshape_t*dshape = rfx_calloc(sizeof(dummyshape_t));
348         lshape = rfx_calloc(sizeof(SHAPE2));
349         int t;
350         lshape->numfillstyles = shape->numlinestyles;
351         lshape->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles);
352         lshape->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles);
353         for(t=0;t<shape->numlinestyles;t++) {
354             lshape->lines[t].fillstyle0 = t+1;
355             lshape->fillstyles[t].type = FILL_SOLID;
356             lshape->fillstyles[t].color = shape->linestyles[t].color;
357         }
358         lp.type = fill_type;
359         lp.shape = lshape;
360         lp.depth = p.depth+1;
361
362         /* add this shape to the global shape list, for deallocing */
363         dshape->shape = lshape;
364         i->dshapes_next = dshape;
365         if(!i->dshapes) {
366             i->dshapes = dshape;
367         }
368     }
369
370     if(p.clipdepth) {
371         /* reverse shape */
372         p.shapeline = 0;
373         add_line(dest, -20, 0, -20, i->height2*20, &p, 0);
374     }
375
376     while(line)
377     {
378         int x1,y1,x2,y2,x3,y3;
379
380         p.shapeline = line;
381
382         if(line->type == moveTo) {
383         } else if(line->type == lineTo) {
384             if(DEBUG&4) {
385                 x1 = x;
386                 y1 = y;
387                 x2 = line->x;
388                 y2 = line->y;
389                 int l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
390                 printf("%d - %.2f/%.2f -> %.2f/%.2f ", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
391             }
392
393             transform_point(&mat, x, y, &x1, &y1);
394             transform_point(&mat, line->x, line->y, &x3, &y3);
395             
396             if(line->linestyle && ! p.clipdepth) {
397                 lp.shapeline = &lshape->lines[line->linestyle-1];
398                 add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width, &lp);
399                 lp.depth++;
400             }
401             if(line->fillstyle0 || line->fillstyle1)
402                 add_line(dest, x1, y1, x3, y3, &p, 0);
403             
404             if(DEBUG&4) printf("\n");
405         } else if(line->type == splineTo) {
406             
407             transform_point(&mat, x, y, &x1, &y1);
408             transform_point(&mat, line->sx, line->sy, &x2, &y2);
409             transform_point(&mat, line->x, line->y, &x3, &y3);
410             
411             int c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1);
412             int parts,qparts;
413             int t;
414             double xx=x1,yy=y1;
415
416             parts = (int)(sqrt(c)/3);
417             if(!parts) parts = 1;
418
419             if(DEBUG&4)
420             {
421                 printf("spline %.2f/%.2f -(%.2f/%.2f)-> %.2f/%.2f (c=%d, %d parts)", 
422                         x1/20.0, y1/20.0, 
423                         x2/20.0, y2/20.0, 
424                         x3/20.0, y3/20.0, c, parts);
425             }
426
427             for(t=1;t<=parts;t++) {
428                 double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts);
429                 double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts);
430                 
431                 if(line->linestyle && ! p.clipdepth) {
432                     lp.shapeline = &lshape->lines[line->linestyle-1];
433                     add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width, &lp);
434                     lp.depth++;
435                 }
436                 if(line->fillstyle0 || line->fillstyle1)
437                     add_line(dest, (int)xx, (int)yy, (int)nx, (int)ny, &p, 0);
438
439                 xx = nx;
440                 yy = ny;
441             }
442             if(DEBUG&4) 
443                 printf("\n");
444         }
445         x = line->x;
446         y = line->y;
447         line = line->next;
448     }
449 }
450
451 typedef struct _layer {
452     int fillid;
453     U32 clipdepth;
454     renderpoint_t*p;
455     struct _layer*next;
456     struct _layer*prev;
457 } layer_t;
458
459 typedef struct {
460     layer_t*layers;
461 } state_t;
462
463 static RGBA color_red = {255,255,0,0};
464 static RGBA color_white = {255,255,255,255};
465
466 static void fill_plain(RGBA*line, int x1, int x2, RGBA col)
467 {
468     int x = x1;
469     if(col.a!=255) {
470         int ainv = 255-col.a;
471         col.r = (col.r*col.a)>>8;
472         col.g = (col.g*col.a)>>8;
473         col.b = (col.b*col.a)>>8;
474         col.a = 255;
475         do {
476             line[x].r = ((line[x].r*ainv)>>8)+col.r;
477             line[x].g = ((line[x].g*ainv)>>8)+col.g;
478             line[x].b = ((line[x].b*ainv)>>8)+col.b;
479             line[x].a = 255;
480         } while(++x<x2);
481     } else {
482         do {
483             line[x] = col;
484         } while(++x<x2);
485     }
486 }
487
488 static void fill_bitmap(RGBA*line, int y, int x1, int x2, MATRIX*m, bitmap_t*b, int clip)
489 {
490     int x = x1;
491     double m11=m->sx/65536.0, m21=m->r1/65536.0;
492     double m12=m->r0/65536.0, m22=m->sy/65536.0;
493     double rx = m->tx/20.0;
494     double ry = m->ty/20.0;
495     double det = m11*m22 - m12*m21;
496     if(fabs(det) < 0.0005) { 
497         /* x direction equals y direction- the image is invisible */
498         return;
499     }
500     det = 20.0/det;
501  
502     if(!b->width || !b->height) {
503         fill_plain(line, x1, x2, color_red);
504         return;
505     }
506
507     do {
508         int xx = (int)((  (x - rx) * m22 - (y - ry) * m21)*det);
509         int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
510         
511         if(clip) {
512             if(xx<0) xx=0;
513             if(xx>=b->width) xx = b->width-1;
514             if(yy<0) yy=0;
515             if(yy>=b->height) yy = b->height-1;
516         } else {
517             xx %= b->width;
518             yy %= b->height;
519         }
520
521         RGBA col = b->data[yy*b->width+xx];
522         int ainv = 255-col.a;
523
524         line[x].r = ((line[x].r*ainv)>>8)+col.r;
525         line[x].g = ((line[x].g*ainv)>>8)+col.g;
526         line[x].b = ((line[x].b*ainv)>>8)+col.b;
527         line[x].a = 255;
528     } while(++x<x2);
529 }
530
531 static void fill(RENDERBUF*dest, RGBA*line, int y, int x1, int x2, state_t*state)
532 {
533     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
534
535     layer_t*l = state->layers;
536
537     if(x1>=x2) //zero width? nothing to do.
538         return;
539
540     U32 clipdepth = 0;
541     while(l) {
542         if(l->p->depth < clipdepth) {
543             if(DEBUG&2) printf("(clipped)");
544             l = l->next;
545             continue;
546         }
547         if(l->fillid < 0 /*clip*/) {
548             if(DEBUG&2) printf("(add clip %d)", l->clipdepth);
549             if(l->clipdepth > clipdepth)
550                 clipdepth = l->clipdepth;
551         } else if(l->fillid == 0) {
552             /* not filled. TODO: we should never add those in the first place */
553             if(DEBUG&2)
554                 printf("(not filled)");
555         } else if(l->fillid > l->p->shape->numfillstyles) {
556             fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->shape->numlinestyles);
557         } else {
558             FILLSTYLE*f;
559             if(DEBUG&2) 
560                 printf("(%d -> %d style %d)", x1, x2, l->fillid);
561
562             f = &l->p->shape->fillstyles[l->fillid-1];
563
564             if(f->type == FILL_SOLID) {
565                 /* plain color fill */
566                 fill_plain(line, x1, x2, f->color);
567             } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
568                 /* TODO: optimize (do this in add_pixel()?) */
569                 bitmap_t* b = i->bitmaps;
570                 while(b && b->id != f->id_bitmap) {
571                     b = b->next;
572                 }
573                 if(!b) {
574                     fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
575                     fill_plain(line, x1, x2, color_red);
576                 } else {
577                     MATRIX m = f->m;
578                     m.tx -= dest->posx*20;
579                     m.ty -= dest->posy*20;
580                     m.sx *= i->multiply;
581                     m.sy *= i->multiply;
582                     m.r0 *= i->multiply;
583                     m.r1 *= i->multiply;
584                     m.tx *= i->multiply;
585                     m.ty *= i->multiply;
586                     fill_bitmap(line, y, x1, x2, &m, b, FILL_CLIPPED?1:0);
587                 }
588             }
589         }
590         l = l->next;
591     }
592 }
593
594 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
595 {
596     layer_t*last=0,*l = state->layers;
597     while(l && l->p->depth < depth) {
598         last = l;
599         l = l->next;
600     }
601     *before = last;
602     if(l && l->p->depth == depth)
603         *self = l;
604     else
605         *after = l;
606 }
607 static void delete_layer(state_t*state, layer_t*todel)
608 {
609     layer_t*before=todel->prev;
610     layer_t*next = todel->next;
611     rfx_free(todel);
612     if(!before) {
613         state->layers = next;
614         if(next)
615             next->prev = 0;
616     } else {
617         before->next = next;
618         if(before->next)
619             before->next->prev = before;
620     }
621 }
622 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
623 {
624     if(!before) {
625         toadd->next = state->layers;
626         toadd->prev = 0;
627         state->layers=toadd;
628     } else {
629         toadd->next = before->next;
630         toadd->prev = before;
631         before->next = toadd;
632     }
633     if(toadd->next)
634         toadd->next->prev = toadd;
635 }
636 static void free_layers(state_t* state)
637 {
638     layer_t*l = state->layers;
639     while(l) {
640         layer_t*next = l->next;
641         rfx_free(l);
642         l = next;
643     }
644 }
645
646 static void change_state(int y, state_t* state, renderpoint_t*p)
647 {
648     layer_t*before=0, *self=0, *after=0;
649
650     if(DEBUG&2) { 
651         printf("[%s(%d,%d)/%d/%d-%d]", p->type==clip_type?"C":"F", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
652     }
653
654     search_layer(state, p->depth, &before, &self, &after);
655
656     if(self) {
657         /* shape update */
658         if(self->fillid<0 || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
659             /* filling/clipping ends */
660             if(DEBUG&2) printf("<D>");
661             
662             delete_layer(state, self);
663         } else { 
664             /*both fill0 and fill1 are set- exchange the two, updating the layer */
665             if(self->fillid == p->shapeline->fillstyle0) {
666                 self->fillid = p->shapeline->fillstyle1;
667                 self->clipdepth = 0;
668                 self->p = p;
669                 if(DEBUG&2) printf("<X>");
670             } else if(self->fillid == p->shapeline->fillstyle1) {
671                 self->fillid = p->shapeline->fillstyle0;
672                 self->clipdepth = 0;
673                 self->p = p;
674                 if(DEBUG&2) printf("<X>");
675             } else {
676                 /* buggy shape. keep everything as-is. */
677                 if(DEBUG&2) printf("<!>");
678                 //fprintf(stderr, "<line %d: bad swap>\n", y);
679             }
680         }
681         return;
682     } else {
683         layer_t* n = 0;
684         if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
685             /* this is a hack- a better way would be to make sure that
686                we always get (0,32), (32, 33), (33, 0) in the right order if
687                they happen to fall on the same pixel.
688                (not: (0,32), (33, 0), (32, 33))
689             */
690             fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
691             return;
692         }
693         
694         n = rfx_calloc(sizeof(layer_t));
695
696         if(DEBUG&2) printf("<+>");
697
698         if(p->type == clip_type) {
699             /* add clipping */
700             n->fillid = -1;
701             n->clipdepth = p->clipdepth;
702             n->p = p;
703         } else {
704             n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
705             n->clipdepth = 0;
706             n->p = p;
707         }
708
709         add_layer(state, before, n);
710     }
711 }
712
713 RGBA* swf_Render(RENDERBUF*dest)
714 {
715     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
716     RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
717     int y;
718     long memory = 0;
719     RGBA * line1 = rfx_alloc(sizeof(RGBA)*i->width2);
720     RGBA * line2 = rfx_alloc(sizeof(RGBA)*i->width2);
721
722     for(y=0;y<i->height2;y++) {
723         TAG*tag = i->lines[y].points;
724         int n;
725         int size = sizeof(renderpoint_t);
726         int num = tag->len / size;
727         RGBA*line = line1;
728         if((y&1) && i->antialize)
729             line = line2;
730
731         state_t state;
732         memset(&state, 0, sizeof(state_t));
733
734         if(!i->background) {
735             memset(line, 0, sizeof(RGBA)*i->width2);
736         } else {
737             int x,xx;
738             int xstep=i->background_width*65536/i->width2;
739             RGBA*src = &i->background[(i->background_height*y/i->height2)*i->background_width];
740             for(x=0,xx=0;x<i->width2;x++,xx+=xstep) {
741                 line[x] = src[xx>>16];
742             }
743         }
744         memory += tag->memsize;
745         qsort(tag->data, num, size, compare_renderpoints);
746         for(n=0;n<num;n++) {
747             renderpoint_t*p = (renderpoint_t*)&tag->data[size*n];
748             renderpoint_t*next= n<num-1?(renderpoint_t*)&tag->data[size*(n+1)]:0;
749             int startx = p->x;
750             int endx = next?next->x:i->width2;
751             if(endx > i->width2)
752                 endx = i->width2;
753             if(startx < 0)
754                 startx = 0;
755
756             change_state(y, &state, p);
757
758             fill(dest, line, y, startx, endx, &state);
759             if(endx == i->width2)
760                 break;
761         }
762         free_layers(&state);
763         if(DEBUG&2) printf("\n");
764
765         if(!i->antialize) {
766             memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
767         } else {
768             if(y&1) {
769                 int x;
770                 RGBA* p = &img[(y/2)*dest->width];
771                 for(x=0;x<dest->width;x++) {
772                     RGBA*p1 = &line1[x*2];
773                     RGBA*p2 = &line1[x*2+1];
774                     RGBA*p3 = &line2[x*2];
775                     RGBA*p4 = &line2[x*2+1];
776                     p[x].r = (p1->r + p2->r + p3->r + p4->r)/4;
777                     p[x].g = (p1->g + p2->g + p3->g + p4->g)/4;
778                     p[x].b = (p1->b + p2->b + p3->b + p4->b)/4;
779                     p[x].a = (p1->a + p2->a + p3->a + p4->a)/4;
780                 }
781             }
782         }
783     }
784     free(line1);
785     free(line2);
786     
787     if(DEBUG) printf("\nMemory used: %d\n", memory);
788 #ifdef STATISTICS
789     if(DEBUG) printf("Statistics:\n");
790     if(DEBUG) printf("Average layer depth: %f\n", (double)layers/layernum);
791 #endif
792
793
794     return img;
795 }