optimized memory usage.
[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 #include <assert.h>
26
27 typedef struct _dummyshape
28 {
29     SHAPE2*shape;
30     //CXFORM //TODO
31     struct _dummyshape*next;
32 } dummyshape_t;
33
34 /* one bit flag: */
35 #define clip_type 0
36 #define fill_type 1
37
38 typedef struct _renderpoint
39 {
40     char type;
41     float x;
42     U32 depth;
43
44     SHAPELINE*shapeline;
45     
46     U32 clipdepth;
47     dummyshape_t*s;
48     
49 } renderpoint_t;
50
51 /* 
52     enum {clip_type, solidfill_type, texturefill_type, gradientfill_type} type;
53     float fx;
54     int x;
55     U32 depth;
56     U32 clipdepth;
57
58     // solidfill;
59     RGBA color; 
60     
61     // texturefill
62     bitmap_t* bitmap;
63
64     // gradientfill
65     gradient_t* gradient;
66
67     // texture- & gradientfill;
68     U32 x,y;
69     U32 dx,dy;
70
71 */
72
73 typedef struct _renderline
74 {
75     TAG*points; //incremented in 128 byte steps
76 } renderline_t;
77
78 typedef struct _bitmap {
79     int width;
80     int height;
81     RGBA*data;
82     int id;
83     struct _bitmap*next;
84 } bitmap_t;
85
86 typedef struct _renderbuf_internal
87 {
88     renderline_t*lines;
89     bitmap_t*bitmaps;
90     char antialize;
91     int multiply;
92     int width2,height2;
93     dummyshape_t*dshapes;
94     dummyshape_t*dshapes_next;
95     RGBA*background;
96     int background_width, background_height;
97 } renderbuf_internal;
98
99 #define DEBUG 0
100
101 static void renderpoint_write(TAG*tag, renderpoint_t*p)
102 {
103     if(tag->len == 0) {
104         swf_SetU32(tag, 1);
105     } else {
106         int num = GET32(tag->data);
107         PUT32(tag->data, num+1);
108     }
109
110     swf_SetBits(tag, p->type, 1);
111     swf_SetBits(tag, *(U32*)&p->x, 32);
112     if(p->depth & 0xffff) {
113         swf_SetBits(tag, 1, 1);
114         swf_SetBits(tag, p->depth, 32);
115     } else {
116         swf_SetBits(tag, 0, 1);
117         swf_SetBits(tag, p->depth >> 16, 16);
118     }
119     swf_SetBits(tag, *(U32*)&p->shapeline, 32);
120     if(p->type == clip_type) {
121         if(p->clipdepth & 0xffff) {
122             swf_SetBits(tag, 1, 1);
123             swf_SetBits(tag, p->clipdepth, 32);
124         } else {
125             swf_SetBits(tag, 0, 1);
126             swf_SetBits(tag, p->clipdepth >> 16, 16);
127         }
128         /* don't set s */
129     } else {
130         swf_SetBits(tag, *(U32*)&p->s, 32);
131         /* don't set clipdepth */
132     }
133 }
134 static renderpoint_t renderpoint_read(TAG*tag, int num)
135 {
136     renderpoint_t p;
137     U8 flag = 0;
138     U32 dummy = 0;
139
140     p.type = swf_GetBits(tag, 1);
141     
142     dummy = swf_GetBits(tag, 32);p.x = *(float*)&dummy;
143     flag = swf_GetBits(tag, 1);
144     if(flag) {
145         p.depth = swf_GetBits(tag, 32);
146     } else {
147         p.depth = swf_GetBits(tag, 16) << 16;
148     }
149     dummy = swf_GetBits(tag, 32);p.shapeline = *(SHAPELINE**)&dummy;
150     if(p.type == clip_type) {
151         flag = swf_GetBits(tag, 1);
152         if(flag) {
153             p.clipdepth = swf_GetBits(tag, 32);
154         } else {
155             p.clipdepth = swf_GetBits(tag, 16) << 16;
156         }
157         p.s = 0;
158     } else {
159         dummy = swf_GetBits(tag, 32);p.s = *(dummyshape_t**)&dummy;
160         p.clipdepth = 0;
161     }
162
163     return p;
164 }
165
166 static int renderpoint_num(TAG*tag)
167 {
168     if(tag->len == 0)
169         return 0;
170     return GET32(tag->data);
171 }
172
173 static renderpoint_t* renderpoint_readall(TAG*tag)
174 {
175     int num;
176     int t;
177     renderpoint_t*p;
178     swf_SetTagPos(tag, 0);
179     if(tag->len == 0)
180         num = 0;
181     else
182         num = swf_GetU32(tag);
183     p = (renderpoint_t*)rfx_alloc(num*sizeof(renderpoint_t));
184     for(t=0;t<num;t++)
185         p[t] = renderpoint_read(tag,t);
186     return p;
187 }
188
189 static inline void add_pixel(RENDERBUF*dest, float x, int y, renderpoint_t*p)
190 {
191     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
192     if(x >= i->width2 || y >= i->height2 || y<0) return;
193     p->x = x;
194     if(y<10)
195         renderpoint_write(i->lines[y].points, p);
196     else
197         renderpoint_write(i->lines[y].points, p);
198 }
199
200 /* set this to 0.777777 or something if the "both fillstyles set while not inside shape"
201    problem appears to often */
202 #define CUT 0.5
203
204 static void add_line(RENDERBUF*buf, double x1, double y1, double x2, double y2, renderpoint_t*p)
205 {
206     renderbuf_internal*i = (renderbuf_internal*)buf->internal;
207     double diffx, diffy;
208     double ny1, ny2, stepx;
209 /*    if(DEBUG&4) {
210         int l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
211         printf(" l[%d - %.2f/%.2f -> %.2f/%.2f]", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
212     }*/
213
214     y1=y1*i->multiply;
215     y2=y2*i->multiply;
216     x1=x1*i->multiply;
217     x2=x2*i->multiply;
218     
219     y1 = y1/20.0;
220     y2 = y2/20.0;
221     x1 = x1/20.0;
222     x2 = x2/20.0;
223
224     if(y2 < y1) {
225         double x;
226         double y;
227         x = x1;x1 = x2;x2=x;
228         y = y1;y1 = y2;y2=y;
229     }
230     
231     diffx = x2 - x1;
232     diffy = y2 - y1;
233     
234     ny1 = (int)(y1)+CUT;
235     ny2 = (int)(y2)+CUT;
236
237     if(ny1 < y1) {
238         ny1 = (int)(y1) + 1.0 + CUT;
239     }
240     if(ny2 >= y2) {
241         ny2 = (int)(y2) - 1.0 + CUT;
242     }
243
244     if(ny1 > ny2)
245         return;
246
247     stepx = diffx/diffy;
248     x1 = x1 + (ny1-y1)*stepx;
249     x2 = x2 + (ny2-y2)*stepx;
250
251     {
252         int posy=(int)ny1;
253         int endy=(int)ny2;
254         double posx=0;
255         double startx = x1;
256
257         while(posy<=endy) {
258             float xx = (float)(startx + posx);
259             add_pixel(buf, xx ,posy, p);
260             posx+=stepx;
261             posy++;
262         }
263     }
264 }
265 #define PI 3.14159265358979
266 static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double y2, int width, renderpoint_t*p)
267 {
268     renderbuf_internal*i = (renderbuf_internal*)buf->internal;
269
270     double dx = x2-x1;
271     double dy = y2-y1;
272     double sd;
273     double d;
274
275     int t;
276     int segments;
277     double lastx,lasty;
278     double vx,vy;
279     double xx,yy;
280   
281     /* Make sure the line is always at least one pixel wide */
282 #ifdef LINEMODE1
283     /* That's what Macromedia's Player does at least at zoom level >= 1.  */
284     width += 20;
285 #else
286     /* That's what Macromedia's Player seems to do at zoom level 0.  */
287     /* TODO: needs testing */
288     if(width<20)
289         width = 20;
290 #endif
291
292     sd = (double)dx*(double)dx+(double)dy*(double)dy;
293     d = sqrt(sd);
294
295     if(!dx && !dy) {
296         vx = 1;
297         vy = 0;
298     } else {
299         vx = ( dy/d);
300         vy = (-dx/d);
301     }
302
303     segments = width/2;
304     if(segments < 2)
305         segments = 2;
306
307     segments = 8;
308
309     vx=vx*width*0.5;
310     vy=vy*width*0.5;
311
312     xx = x2+vx;
313     yy = y2+vy;
314     add_line(buf, x1+vx, y1+vy, xx, yy, p);
315     lastx = xx;
316     lasty = yy;
317     for(t=1;t<segments;t++) {
318         double s = sin(t*PI/segments);
319         double c = cos(t*PI/segments);
320         xx = (x2 + vx*c - vy*s);
321         yy = (y2 + vx*s + vy*c);
322         add_line(buf, lastx, lasty, xx, yy, p);
323         lastx = xx;
324         lasty = yy;
325     }
326     
327     xx = (x2-vx);
328     yy = (y2-vy);
329     add_line(buf, lastx, lasty, xx, yy, p);
330     lastx = xx;
331     lasty = yy;
332     xx = (x1-vx);
333     yy = (y1-vy);
334     add_line(buf, lastx, lasty, xx, yy, p);
335     lastx = xx;
336     lasty = yy;
337     for(t=1;t<segments;t++) {
338         double s = sin(t*PI/segments);
339         double c = cos(t*PI/segments);
340         xx = (x1 - vx*c + vy*s);
341         yy = (y1 - vx*s - vy*c);
342         add_line(buf, lastx, lasty, xx, yy, p);
343         lastx = xx;
344         lasty = yy;
345     }
346     add_line(buf, lastx, lasty, (x1+vx), (y1+vy), p);
347 }
348
349 static inline void transform_point(MATRIX*m, int x, int y, int*dx, int*dy)
350 {
351     SPOINT p,d;
352     p.x = x;
353     p.y = y;
354     d = swf_TurnPoint(p, m);
355     *dx = d.x;
356     *dy = d.y;
357 }
358
359 static int compare_renderpoints(const void * _a, const void * _b)
360 {
361     renderpoint_t*a = (renderpoint_t*)_a;
362     renderpoint_t*b = (renderpoint_t*)_b;
363     if(a->x < b->x) return -1;
364     if(a->x > b->x) return 1;
365     return 0;
366 }
367
368 void swf_Render_Init(RENDERBUF*buf, int posx, int posy, int width, int height, char antialize, int multiply)
369 {
370     renderbuf_internal*i;
371     int y;
372     memset(buf, 0, sizeof(RENDERBUF));
373     buf->width = width*multiply;
374     buf->height = height*multiply;
375     buf->posx = posx;
376     buf->posy = posy;
377     buf->internal = (renderbuf_internal*)rfx_calloc(sizeof(renderbuf_internal));
378     i = (renderbuf_internal*)buf->internal;
379     i->antialize = !!antialize;
380     i->multiply = antialize?multiply*2:multiply;
381     i->height2 = antialize?2*buf->height:buf->height;
382     i->width2 = antialize?2*buf->width:buf->width;
383     i->lines = (renderline_t*)rfx_alloc(i->height2*sizeof(renderline_t));
384     for(y=0;y<i->height2;y++) {
385         i->lines[y].points = swf_InsertTag(0, 0);
386     }
387 }
388 void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height)
389 {
390     renderbuf_internal*i = (renderbuf_internal*)buf->internal;
391     RGBA*bck = (RGBA*)rfx_alloc(sizeof(RGBA)*width*height);
392     memcpy(bck, img, sizeof(RGBA)*width*height);
393     i->background = bck;
394     i->background_width = width;
395     i->background_height = height;
396 }
397 void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color)
398 {
399     swf_Render_SetBackground(buf, &color, 1, 1);
400 }
401 void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height)
402 {
403     renderbuf_internal*i = (renderbuf_internal*)buf->internal;
404
405     bitmap_t*bm = rfx_calloc(sizeof(bitmap_t));
406     bm->id = id;
407     bm->width = width;
408     bm->height = height;
409     bm->data = img;
410
411     bm->next = i->bitmaps;
412     i->bitmaps = bm;
413 }
414 void swf_Render_ClearCanvas(RENDERBUF*dest)
415 {
416     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
417     int y;
418     for(y=0;y<i->height2;y++) {
419         swf_ClearTag(i->lines[y].points);
420     }
421 }
422 void swf_Render_Delete(RENDERBUF*dest)
423 {
424     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
425     int y;
426     bitmap_t*b = i->bitmaps;
427     dummyshape_t*d = i->dshapes;
428
429     if(i->background) {
430         free(i->background);i->background=0;
431     }
432
433     /* delete line buffers */
434     for(y=0;y<i->height2;y++) {
435         swf_DeleteTag(i->lines[y].points);
436         i->lines[y].points = 0;
437     }
438
439     while(d) {
440         dummyshape_t*next = d->next;
441         swf_Shape2Free(d->shape);
442         free(d->shape);d->shape=0;
443         free(d);
444         d=next;
445     }
446     i->dshapes = 0;
447     
448     /* delete bitmaps */
449     while(b) {
450         bitmap_t*next = b->next;
451         //free(b->data);b->data=0;
452         rfx_free(b);
453         b = next;
454     }
455
456     rfx_free(i->lines); i->lines = 0;
457     rfx_free(dest->internal); dest->internal = 0;
458 }
459
460 static void swf_Render_AddShape(RENDERBUF*dest,dummyshape_t*s)
461 {
462     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
463
464     s->next = 0;
465     if(i->dshapes_next)
466         i->dshapes_next->next = s;
467     i->dshapes_next = s;
468     if(!i->dshapes) {
469         i->dshapes = s;
470     }
471 }
472
473 static SHAPE2* linestyle2fillstyle(SHAPE2*shape)
474 {
475     SHAPE2*s = rfx_calloc(sizeof(SHAPE2));
476     int t;
477     s->numfillstyles = shape->numlinestyles;
478     s->fillstyles = (FILLSTYLE*)rfx_calloc(sizeof(FILLSTYLE)*shape->numlinestyles);
479     s->lines = (SHAPELINE*)rfx_calloc(sizeof(SHAPELINE)*shape->numlinestyles);
480     for(t=0;t<shape->numlinestyles;t++) {
481         s->lines[t].fillstyle0 = t+1;
482         s->fillstyles[t].type = FILL_SOLID;
483         s->fillstyles[t].color = shape->linestyles[t].color;
484     }
485     return s;
486 }
487
488 void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth)
489 {
490     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
491     
492     SHAPELINE*line = shape->lines;
493     int x=0,y=0;
494     MATRIX mat = *m;
495     SHAPE2* lshape = 0;
496
497     renderpoint_t p, lp;
498     memset(&p, 0, sizeof(renderpoint_t));
499     memset(&lp, 0, sizeof(renderpoint_t));
500     
501     p.type = _clipdepth?clip_type:fill_type;
502     p.depth = _depth << 16;
503     p.clipdepth = _clipdepth << 16;
504
505     mat.tx -= dest->posx*20;
506     mat.ty -= dest->posy*20;
507
508     if(shape->numfillstyles) {
509         dummyshape_t*fshape = rfx_calloc(sizeof(dummyshape_t));
510         int t;
511         SHAPE2* s2 = swf_Shape2Clone(shape);
512        
513         fshape->shape = s2;
514
515         p.s = fshape;
516
517         /* multiply fillstyles matrices with placement matrix-
518            important for texture and gradient fill */
519         for(t=0;t<s2->numfillstyles;t++) {
520             MATRIX nm;
521             swf_MatrixJoin(&nm, &s2->fillstyles[t].m, &mat); //TODO: is this the right order?
522             nm.sx *= i->multiply;
523             nm.sy *= i->multiply;
524             nm.r0 *= i->multiply;
525             nm.r1 *= i->multiply;
526             nm.tx *= i->multiply;
527             nm.ty *= i->multiply;
528             s2->fillstyles[t].m = nm;
529         }
530
531         /* add this shape to the global shape list, for deallocing */
532         swf_Render_AddShape(dest, fshape);
533     }
534
535     if(shape->numlinestyles) {
536         dummyshape_t*dshape = rfx_calloc(sizeof(dummyshape_t));
537         
538         lshape = linestyle2fillstyle(shape);
539             
540         lp.type = fill_type;
541         lp.s = dshape;
542         lp.depth = (_depth << 16)+1;
543
544         dshape->shape = lshape;
545
546         /* add this shape to the global shape list, for deallocing */
547         swf_Render_AddShape(dest, dshape);
548     }
549
550     if(p.clipdepth) {
551         /* reverse shape */
552         p.shapeline = 0;
553         add_line(dest, -20, 0, -20, i->height2*20, &p);
554     }
555
556     while(line)
557     {
558         int x1,y1,x2,y2,x3,y3;
559
560         p.shapeline = line;
561
562         if(line->type == moveTo) {
563         } else if(line->type == lineTo) {
564             if(DEBUG&4) {
565                 int l;
566                 x1 = x;
567                 y1 = y;
568                 x2 = line->x;
569                 y2 = line->y;
570                 l = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
571                 printf("%d - %.2f/%.2f -> %.2f/%.2f ", l, x1/20.0, y1/20.0, x2/20.0, y2/20.0);
572             }
573
574             transform_point(&mat, x, y, &x1, &y1);
575             transform_point(&mat, line->x, line->y, &x3, &y3);
576             
577             if(line->linestyle && ! p.clipdepth) {
578                 lp.shapeline = &lshape->lines[line->linestyle-1];
579                 add_solidline(dest, x1, y1, x3, y3, shape->linestyles[line->linestyle-1].width, &lp);
580                 lp.depth++;
581             }
582             if(line->fillstyle0 || line->fillstyle1) {
583                 assert(shape->numfillstyles);
584                 add_line(dest, x1, y1, x3, y3, &p);
585             }
586             
587             if(DEBUG&4) printf("\n");
588         } else if(line->type == splineTo) {
589             int c,t,parts,qparts;
590             double xx,yy;
591             
592             transform_point(&mat, x, y, &x1, &y1);
593             transform_point(&mat, line->sx, line->sy, &x2, &y2);
594             transform_point(&mat, line->x, line->y, &x3, &y3);
595             
596             c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1);
597             xx=x1;
598             yy=y1;
599
600             parts = (int)(sqrt(c)/3);
601             if(!parts) parts = 1;
602
603             if(DEBUG&4)
604             {
605                 printf("spline %.2f/%.2f -(%.2f/%.2f)-> %.2f/%.2f (c=%d, %d parts)", 
606                         x1/20.0, y1/20.0, 
607                         x2/20.0, y2/20.0, 
608                         x3/20.0, y3/20.0, c, parts);
609             }
610
611             for(t=1;t<=parts;t++) {
612                 double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts);
613                 double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts);
614                 
615                 if(line->linestyle && ! p.clipdepth) {
616                     lp.shapeline = &lshape->lines[line->linestyle-1];
617                     add_solidline(dest, xx, yy, nx, ny, shape->linestyles[line->linestyle-1].width, &lp);
618                     lp.depth++;
619                 }
620                 if(line->fillstyle0 || line->fillstyle1) {
621                     assert(shape->numfillstyles);
622                     add_line(dest, (int)xx, (int)yy, (int)nx, (int)ny, &p);
623                 }
624
625                 xx = nx;
626                 yy = ny;
627             }
628             if(DEBUG&4) 
629                 printf("\n");
630         }
631         x = line->x;
632         y = line->y;
633         line = line->next;
634     }
635 }
636
637 typedef struct _layer {
638     int fillid;
639     U32 clipdepth;
640     renderpoint_t*p;
641     struct _layer*next;
642     struct _layer*prev;
643 } layer_t;
644
645 typedef struct {
646     layer_t*layers;
647 } state_t;
648
649 static RGBA color_red = {255,255,0,0};
650 static RGBA color_white = {255,255,255,255};
651
652 static void fill_plain(RGBA*line, int x1, int x2, RGBA col)
653 {
654     int x = x1;
655     if(col.a!=255) {
656         int ainv = 255-col.a;
657         col.r = (col.r*col.a)>>8;
658         col.g = (col.g*col.a)>>8;
659         col.b = (col.b*col.a)>>8;
660         col.a = 255;
661         do {
662             line[x].r = ((line[x].r*ainv)>>8)+col.r;
663             line[x].g = ((line[x].g*ainv)>>8)+col.g;
664             line[x].b = ((line[x].b*ainv)>>8)+col.b;
665             line[x].a = 255;
666         } while(++x<x2);
667     } else {
668         do {
669             line[x] = col;
670         } while(++x<x2);
671     }
672 }
673
674 static void fill_bitmap(RGBA*line, int y, int x1, int x2, MATRIX*m, bitmap_t*b, int clip)
675 {
676     int x = x1;
677     double m11=m->sx/65536.0, m21=m->r1/65536.0;
678     double m12=m->r0/65536.0, m22=m->sy/65536.0;
679     double rx = m->tx/20.0;
680     double ry = m->ty/20.0;
681     double det = m11*m22 - m12*m21;
682     if(fabs(det) < 0.0005) { 
683         /* x direction equals y direction- the image is invisible */
684         return;
685     }
686     det = 20.0/det;
687  
688     if(!b->width || !b->height) {
689         fill_plain(line, x1, x2, color_red);
690         return;
691     }
692
693     do {
694         RGBA col;
695         int xx = (int)((  (x - rx) * m22 - (y - ry) * m21)*det);
696         int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
697         int ainv;
698         
699         if(clip) {
700             if(xx<0) xx=0;
701             if(xx>=b->width) xx = b->width-1;
702             if(yy<0) yy=0;
703             if(yy>=b->height) yy = b->height-1;
704         } else {
705             xx %= b->width;
706             yy %= b->height;
707         }
708
709         col = b->data[yy*b->width+xx];
710         ainv = 255-col.a;
711
712         line[x].r = ((line[x].r*ainv)>>8)+col.r;
713         line[x].g = ((line[x].g*ainv)>>8)+col.g;
714         line[x].b = ((line[x].b*ainv)>>8)+col.b;
715         line[x].a = 255;
716     } while(++x<x2);
717 }
718
719 static void fill(RENDERBUF*dest, RGBA*line, int y, int x1, int x2, state_t*clipstate, state_t*fillstate)
720 {
721     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
722     U32 clipdepth;
723
724     layer_t*lc = clipstate->layers;
725     layer_t*lf = fillstate->layers;
726     layer_t*l = 0;
727
728     if(x1>=x2) //zero width? nothing to do.
729         return;
730     
731     clipdepth = 0;
732     while(lf) {
733         if(lc && (!lf || lc->p->depth < lf->p->depth)) {
734             l = lc;
735             lc = lc->next;
736         } else if(lf && (!lc || lf->p->depth < lc->p->depth)) {
737             l = lf;
738             lf = lf->next;
739         } else if(lf && lc && lf->p->depth == lc->p->depth) {
740             /* A clipshape and a fillshape at the same depth. Yuck.
741                Bug in the SWF file */
742             fprintf(stderr, "Error: Multiple use of depth %d in SWF\n", lf->p->depth);
743             l = lc;
744             lc = lc->next;
745         } else {
746             fprintf(stderr, "Internal error: %08x %08x\n", lc, lf);
747             if(lc) fprintf(stderr, "                lc->depth = %08x\n", lc->p->depth);
748             if(lf) fprintf(stderr, "                lf->depth = %08x\n", lf->p->depth);
749         }
750
751         if(l->p->depth < clipdepth) {
752             if(DEBUG&2) printf("(clipped)");
753             continue;
754         }
755         if(l->fillid < 0 /*clip*/) {
756             if(DEBUG&2) printf("(add clip %d)", l->clipdepth);
757             if(l->clipdepth > clipdepth)
758                 clipdepth = l->clipdepth;
759         } else if(l->fillid == 0) {
760             /* not filled. TODO: we should never add those in the first place */
761             if(DEBUG&2)
762                 printf("(not filled)");
763         } else if(l->fillid > l->p->s->shape->numfillstyles) {
764             fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->shape->numlinestyles);
765         } else {
766             FILLSTYLE*f;
767             if(DEBUG&2) 
768                 printf("(%d -> %d style %d)", x1, x2, l->fillid);
769
770             f = &l->p->s->shape->fillstyles[l->fillid-1];
771
772             if(f->type == FILL_SOLID) {
773                 /* plain color fill */
774                 fill_plain(line, x1, x2, f->color);
775             } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
776                 /* TODO: optimize (do this in add_pixel()?) */
777                 bitmap_t* b = i->bitmaps;
778                 while(b && b->id != f->id_bitmap) {
779                     b = b->next;
780                 }
781                 if(!b) {
782                     fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
783                     fill_plain(line, x1, x2, color_red);
784                 } else {
785                     //done in swf_RenderShape now
786                     //MATRIX m = f->m;
787                     //m.tx -= dest->posx*20;
788                     //m.ty -= dest->posy*20;
789                     //m.sx *= i->multiply;
790                     //m.sy *= i->multiply;
791                     //m.r0 *= i->multiply;
792                     //m.r1 *= i->multiply;
793                     //m.tx *= i->multiply;
794                     //m.ty *= i->multiply;
795                     fill_bitmap(line, y, x1, x2, &f->m, b, FILL_CLIPPED?1:0);
796                 }
797             }
798         }
799     }
800 }
801
802 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
803 {
804     layer_t*last=0,*l = state->layers;
805     while(l && l->p->depth < depth) {
806         last = l;
807         l = l->next;
808     }
809     *before = last;
810     if(l && l->p->depth == depth)
811         *self = l;
812     else
813         *after = l;
814 }
815 static void delete_layer(state_t*state, layer_t*todel)
816 {
817     layer_t*before=todel->prev;
818     layer_t*next = todel->next;
819     rfx_free(todel);
820     if(!before) {
821         state->layers = next;
822         if(next)
823             next->prev = 0;
824     } else {
825         before->next = next;
826         if(before->next)
827             before->next->prev = before;
828     }
829 }
830 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
831 {
832     if(!before) {
833         toadd->next = state->layers;
834         toadd->prev = 0;
835         state->layers=toadd;
836     } else {
837         toadd->next = before->next;
838         toadd->prev = before;
839         before->next = toadd;
840     }
841     if(toadd->next)
842         toadd->next->prev = toadd;
843 }
844 static void free_layers(state_t* state)
845 {
846     layer_t*l = state->layers;
847     while(l) {
848         layer_t*next = l->next;
849         rfx_free(l);
850         l = next;
851     }
852 }
853
854 static void change_state(int y, state_t* state, renderpoint_t*p)
855 {
856     layer_t*before=0, *self=0, *after=0;
857
858     if(DEBUG&2) { 
859         printf("[%s(%d,%d)/%d/%d-%d]", p->type==clip_type?"C":"F", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
860     }
861
862     search_layer(state, p->depth, &before, &self, &after);
863
864     if(self) {
865         /* shape update */
866         if(self->fillid<0 || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
867             /* filling/clipping ends */
868             if(DEBUG&2) printf("<D>");
869             
870             delete_layer(state, self);
871         } else { 
872             /*both fill0 and fill1 are set- exchange the two, updating the layer */
873             if(self->fillid == p->shapeline->fillstyle0) {
874                 self->fillid = p->shapeline->fillstyle1;
875                 self->clipdepth = 0;
876                 self->p = p;
877                 if(DEBUG&2) printf("<X>");
878             } else if(self->fillid == p->shapeline->fillstyle1) {
879                 self->fillid = p->shapeline->fillstyle0;
880                 self->clipdepth = 0;
881                 self->p = p;
882                 if(DEBUG&2) printf("<X>");
883             } else {
884                 /* buggy shape. keep everything as-is. */
885                 if(DEBUG&2) printf("<!>");
886                 //fprintf(stderr, "<line %d: bad swap>\n", y);
887             }
888         }
889         return;
890     } else {
891         layer_t* n = 0;
892         if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
893             /* this is a hack- a better way would be to make sure that
894                we always get (0,32), (32, 33), (33, 0) in the right order if
895                they happen to fall on the same pixel.
896                (not: (0,32), (33, 0), (32, 33))
897             */
898             fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
899             return;
900         }
901         
902         n = rfx_calloc(sizeof(layer_t));
903
904         if(DEBUG&2) printf("<+>");
905
906         if(p->type == clip_type) {
907             /* add clipping */
908             n->fillid = -1;
909             n->clipdepth = p->clipdepth;
910             n->p = p;
911         } else {
912             n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
913             n->clipdepth = 0;
914             n->p = p;
915         }
916
917         add_layer(state, before, n);
918     }
919 }
920
921 RGBA* swf_Render(RENDERBUF*dest)
922 {
923     renderbuf_internal*i = (renderbuf_internal*)dest->internal;
924     RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
925     int y;
926     long memory = 0;
927     RGBA * line1 = rfx_alloc(sizeof(RGBA)*i->width2);
928     RGBA * line2 = rfx_alloc(sizeof(RGBA)*i->width2);
929
930     printf("%d\n", sizeof(renderpoint_t));
931
932     for(y=0;y<i->height2;y++) {
933         TAG*tag = i->lines[y].points;
934         int n;
935         int num = renderpoint_num(tag);
936         renderpoint_t*points = renderpoint_readall(tag);
937         RGBA*line = line1;
938         state_t clipstate;
939         state_t fillstate;
940         memset(&clipstate, 0, sizeof(state_t));
941         memset(&fillstate, 0, sizeof(state_t));
942
943         if((y&1) && i->antialize)
944             line = line2;
945
946         if(!i->background) {
947             memset(line, 0, sizeof(RGBA)*i->width2);
948         } else {
949             int x,xx;
950             int xstep=i->background_width*65536/i->width2;
951             RGBA*src = &i->background[(i->background_height*y/i->height2)*i->background_width];
952             for(x=0,xx=0;x<i->width2;x++,xx+=xstep) {
953                 line[x] = src[xx>>16];
954             }
955         }
956         memory += tag->memsize;
957         qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
958         for(n=0;n<num;n++) {
959             renderpoint_t*p = &points[n];
960             renderpoint_t*next= n<num-1?&points[n+1]:0;
961             int startx = p->x;
962             int endx = next?next->x:i->width2;
963             if(endx > i->width2)
964                 endx = i->width2;
965             if(startx < 0)
966                 startx = 0;
967
968             if(p->type == clip_type)
969                 change_state(y, &clipstate, p);
970             else
971                 change_state(y, &fillstate, p);
972
973             fill(dest, line, y, startx, endx, &clipstate, &fillstate);
974             if(endx == i->width2)
975                 break;
976         }
977         free_layers(&clipstate);
978         free_layers(&fillstate);
979         if(DEBUG&2) printf("\n");
980
981         if(!i->antialize) {
982             memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
983         } else {
984             if(y&1) {
985                 int x;
986                 RGBA* p = &img[(y/2)*dest->width];
987                 for(x=0;x<dest->width;x++) {
988                     RGBA*p1 = &line1[x*2];
989                     RGBA*p2 = &line1[x*2+1];
990                     RGBA*p3 = &line2[x*2];
991                     RGBA*p4 = &line2[x*2+1];
992                     p[x].r = (p1->r + p2->r + p3->r + p4->r)/4;
993                     p[x].g = (p1->g + p2->g + p3->g + p4->g)/4;
994                     p[x].b = (p1->b + p2->b + p3->b + p4->b)/4;
995                     p[x].a = (p1->a + p2->a + p3->a + p4->a)/4;
996                 }
997             }
998         }
999         free(points);
1000     }
1001     free(line1);
1002     free(line2);
1003     
1004     if(DEBUG) printf("\nMemory used: %d\n", memory);
1005 #ifdef STATISTICS
1006     if(DEBUG) printf("Statistics:\n");
1007     if(DEBUG) printf("Average layer depth: %f\n", (double)layers/layernum);
1008 #endif
1009
1010
1011     return img;
1012 }