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 #include <stdio.h>
27 #include <stdlib.h>
28 #include "../rfxswf.h"
29
30 /* one bit flag: */
31 #define clip_type 0
32 #define fill_type 1
33
34 typedef struct _renderpoint
35 {
36 float x;
37 U32 depth;
38
39 SHAPELINE*shapeline;
40 SHAPE2*s;
41
42 } renderpoint_t;
43
44 /*
45 enum {clip_type, solidfill_type, texturefill_type, gradientfill_type} type;
46 float fx;
47 int x;
48 U32 depth;
49 U32 clipdepth;
50
51 // solidfill;
52 RGBA color;
53
54 // texturefill
55 bitmap_t* bitmap;
56
57 // gradientfill
58 gradient_t* gradient;
59
60 // texture- & gradientfill;
61 U32 x,y;
62 U32 dx,dy;
63
64 */
65
66 typedef struct _renderline
67 {
68 TAG*points; //incremented in 128 byte steps
69 int num;
70 U32 pending_clipdepth;
71 } renderline_t;
72
73 typedef struct _bitmap {
74 int width;
75 int height;
76 RGBA*data;
77 int id;
78 struct _bitmap*next;
79 } bitmap_t;
80
81 typedef struct _renderbuf_internal
82 {
83 renderline_t*lines;
84 bitmap_t*bitmaps;
85 int antialize;
86 int multiply;
87 int width2,height2;
88 int shapes;
89 int ymin, ymax;
90
91 RGBA* img;
92 int* zbuf;
93 } renderbuf_internal;
94
95 #define DEBUG 0
96
add_pixel(RENDERBUF * dest,float x,int y,renderpoint_t * p)97 static inline void add_pixel(RENDERBUF*dest, float x, int y, renderpoint_t*p)
98 {
99 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
100 if(x >= i->width2 || y >= i->height2 || y<0) return;
101 p->x = x;
102 if(y<i->ymin) i->ymin = y;
103 if(y>i->ymax) i->ymax = y;
104
105 i->lines[y].num++;
106 swf_SetBlock(i->lines[y].points, (U8*)p, sizeof(renderpoint_t));
107 }
108
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
112
113 #define INT(x) ((int)((x)+16)-16)
114
add_line(RENDERBUF * buf,double x1,double y1,double x2,double y2,renderpoint_t * p)115 static void add_line(RENDERBUF*buf, double x1, double y1, double x2, double y2, renderpoint_t*p)
116 {
117 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
118 double diffx, diffy;
119 double ny1, ny2, stepx;
120 /* if(DEBUG&4) {
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);
123 }*/
124 assert(p->shapeline);
125
126 y1=y1*i->multiply;
127 y2=y2*i->multiply;
128 x1=x1*i->multiply;
129 x2=x2*i->multiply;
130
131 y1 = y1/20.0;
132 y2 = y2/20.0;
133 x1 = x1/20.0;
134 x2 = x2/20.0;
135
136 if(y2 < y1) {
137 double x;
138 double y;
139 x = x1;x1 = x2;x2=x;
140 y = y1;y1 = y2;y2=y;
141 }
142
143 diffx = x2 - x1;
144 diffy = y2 - y1;
145
146 ny1 = INT(y1)+CUT;
147 ny2 = INT(y2)+CUT;
148
149 if(ny1 < y1) {
150 ny1 = INT(y1) + 1.0 + CUT;
151 }
152 if(ny2 >= y2) {
153 ny2 = INT(y2) - 1.0 + CUT;
154 }
155
156 if(ny1 > ny2)
157 return;
158
159 stepx = diffx/diffy;
160 x1 = x1 + (ny1-y1)*stepx;
161 x2 = x2 + (ny2-y2)*stepx;
162
163 {
164 int posy=INT(ny1);
165 int endy=INT(ny2);
166 double posx=0;
167 double startx = x1;
168
169 while(posy<=endy) {
170 float xx = (float)(startx + posx);
171 add_pixel(buf, xx ,posy, p);
172 posx+=stepx;
173 posy++;
174 }
175 }
176 }
177 #define PI 3.14159265358979
add_solidline(RENDERBUF * buf,double x1,double y1,double x2,double y2,double width,renderpoint_t * p)178 static void add_solidline(RENDERBUF*buf, double x1, double y1, double x2, double y2, double width, renderpoint_t*p)
179 {
180 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
181
182 double dx = x2-x1;
183 double dy = y2-y1;
184 double sd;
185 double d;
186
187 int t;
188 int segments;
189 double lastx,lasty;
190 double vx,vy;
191 double xx,yy;
192
193 /* Make sure the line is always at least one pixel wide */
194 #ifdef LINEMODE1
195 /* That's what Macromedia's Player does at least at zoom level >= 1. */
196 width += 20;
197 #else
198 /* That's what Macromedia's Player seems to do at zoom level 0. */
199 /* TODO: needs testing */
200
201 /* TODO: how does this interact with scaling? */
202 if(width * i->multiply < 20)
203 width = 20 / i->multiply;
204 #endif
205
206 sd = (double)dx*(double)dx+(double)dy*(double)dy;
207 d = sqrt(sd);
208
209 if(!dx && !dy) {
210 vx = 1;
211 vy = 0;
212 } else {
213 vx = ( dy/d);
214 vy = (-dx/d);
215 }
216
217 segments = (int)(width/2);
218 if(segments < 2)
219 segments = 2;
220
221 segments = 8;
222
223 vx=vx*width*0.5;
224 vy=vy*width*0.5;
225
226 xx = x2+vx;
227 yy = y2+vy;
228 add_line(buf, x1+vx, y1+vy, xx, yy, p);
229 lastx = xx;
230 lasty = yy;
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);
237 lastx = xx;
238 lasty = yy;
239 }
240
241 xx = (x2-vx);
242 yy = (y2-vy);
243 add_line(buf, lastx, lasty, xx, yy, p);
244 lastx = xx;
245 lasty = yy;
246 xx = (x1-vx);
247 yy = (y1-vy);
248 add_line(buf, lastx, lasty, xx, yy, p);
249 lastx = xx;
250 lasty = yy;
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);
257 lastx = xx;
258 lasty = yy;
259 }
260 add_line(buf, lastx, lasty, (x1+vx), (y1+vy), p);
261 }
262
transform_point(MATRIX * m,int x,int y,int * dx,int * dy)263 static inline void transform_point(MATRIX*m, int x, int y, int*dx, int*dy)
264 {
265 SPOINT p,d;
266 p.x = x;
267 p.y = y;
268 d = swf_TurnPoint(p, m);
269 *dx = d.x;
270 *dy = d.y;
271 }
272
compare_renderpoints(const void * _a,const void * _b)273 static int compare_renderpoints(const void * _a, const void * _b)
274 {
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;
279 return 0;
280 }
281
swf_Render_Init(RENDERBUF * buf,int posx,int posy,int width,int height,int antialize,int multiply)282 void swf_Render_Init(RENDERBUF*buf, int posx, int posy, int width, int height, int antialize, int multiply)
283 {
284 renderbuf_internal*i;
285 int y;
286 memset(buf, 0, sizeof(RENDERBUF));
287 buf->width = width*multiply;
288 buf->height = height*multiply;
289 buf->posx = posx;
290 buf->posy = posy;
291 buf->internal = (renderbuf_internal*)rfx_calloc(sizeof(renderbuf_internal));
292 i = (renderbuf_internal*)buf->internal;
293 if(antialize < 1)
294 antialize = 1;
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);
303 i->lines[y].num = 0;
304 }
305 i->zbuf = (int*)rfx_calloc(sizeof(int)*i->width2*i->height2);
306 i->img = (RGBA*)rfx_calloc(sizeof(RGBA)*i->width2*i->height2);
307 i->shapes = 0;
308 i->ymin = 0x7fffffff;
309 i->ymax = -0x80000000;
310 }
swf_Render_SetBackground(RENDERBUF * buf,RGBA * img,int width,int height)311 void swf_Render_SetBackground(RENDERBUF*buf, RGBA*img, int width, int height)
312 {
313 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
314 int x,xx,y,yy;
315 int xstep=width*65536/i->width2;
316 int ystep=height*65536/i->height2;
317 if(i->shapes) {
318 fprintf(stderr, "rfxswf: Warning: swf_Render_SetBackground() called after drawing shapes\n");
319 }
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];
325 }
326 }
327 }
swf_Render_SetBackgroundColor(RENDERBUF * buf,RGBA color)328 void swf_Render_SetBackgroundColor(RENDERBUF*buf, RGBA color)
329 {
330 swf_Render_SetBackground(buf, &color, 1, 1);
331 }
swf_Render_AddImage(RENDERBUF * buf,U16 id,RGBA * img,int width,int height)332 void swf_Render_AddImage(RENDERBUF*buf, U16 id, RGBA*img, int width, int height)
333 {
334 renderbuf_internal*i = (renderbuf_internal*)buf->internal;
335
336 bitmap_t*bm = (bitmap_t*)rfx_calloc(sizeof(bitmap_t));
337 bm->id = id;
338 bm->width = width;
339 bm->height = height;
340 bm->data = (RGBA*)rfx_alloc(width*height*4);
341 memcpy(bm->data, img, width*height*4);
342
343 bm->next = i->bitmaps;
344 i->bitmaps = bm;
345 }
swf_Render_ClearCanvas(RENDERBUF * dest)346 void swf_Render_ClearCanvas(RENDERBUF*dest)
347 {
348 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
349 int y;
350 for(y=0;y<i->height2;y++) {
351 swf_ClearTag(i->lines[y].points);
352 }
353 memset(i->zbuf, 0, sizeof(int)*i->width2*i->height2);
354 memset(i->img, 0, sizeof(RGBA)*i->width2*i->height2);
355 }
swf_Render_Delete(RENDERBUF * dest)356 void swf_Render_Delete(RENDERBUF*dest)
357 {
358 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
359 int y;
360 bitmap_t*b = i->bitmaps;
361
362 /* delete canvas */
363 rfx_free(i->zbuf);
364 rfx_free(i->img);
365
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;
370 }
371
372 /* delete bitmaps */
373 while(b) {
374 bitmap_t*next = b->next;
375 free(b->data);b->data=0;
376 rfx_free(b);
377 b = next;
378 }
379
380 rfx_free(i->lines); i->lines = 0;
381 rfx_free(dest->internal); dest->internal = 0;
382 }
383
linestyle2fillstyle(SHAPE2 * shape)384 static SHAPE2* linestyle2fillstyle(SHAPE2*shape)
385 {
386 SHAPE2*s = (SHAPE2*)rfx_calloc(sizeof(SHAPE2));
387 int t;
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;
395 }
396 return s;
397 }
398
399 void swf_Process(RENDERBUF*dest, U32 clipdepth);
400
matrixsize(MATRIX * m)401 double matrixsize(MATRIX*m)
402 {
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) );
405 return sqrt(l1*l2);
406 }
407
swf_RenderShape(RENDERBUF * dest,SHAPE2 * shape,MATRIX * m,CXFORM * c,U16 _depth,U16 _clipdepth)408 void swf_RenderShape(RENDERBUF*dest, SHAPE2*shape, MATRIX*m, CXFORM*c, U16 _depth,U16 _clipdepth)
409 {
410 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
411
412 SHAPELINE*line;
413 int x=0,y=0;
414 MATRIX mat = *m;
415 SHAPE2* s2 = 0;
416 SHAPE2* lshape = 0;
417 renderpoint_t p, lp;
418 U32 clipdepth;
419 double widthmultiply = matrixsize(m);
420
421 memset(&p, 0, sizeof(renderpoint_t));
422 memset(&lp, 0, sizeof(renderpoint_t));
423
424 clipdepth = _clipdepth? _clipdepth << 16 | 0xffff : 0;
425 p.depth = _depth << 16;
426
427 mat.tx -= dest->posx*20;
428 mat.ty -= dest->posy*20;
429
430 s2 = swf_Shape2Clone(shape);
431 line = s2->lines;
432 if(shape->numfillstyles) {
433 int t;
434 p.s = s2;
435 /* multiply fillstyles matrices with placement matrix-
436 important for texture and gradient fill */
437 for(t=0;t<s2->numfillstyles;t++) {
438 MATRIX nm;
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;
447 }
448 }
449
450 if(shape->numlinestyles) {
451 lshape = linestyle2fillstyle(shape);
452 lp.s = lshape;
453 lp.depth = (_depth << 16)+1;
454 }
455
456
457 while(line)
458 {
459 int x1,y1,x2,y2,x3,y3;
460
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);
465
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);
469 lp.depth++;
470 }
471 if(line->fillstyle0 || line->fillstyle1) {
472 assert(shape->numfillstyles);
473 p.shapeline = line;
474 add_line(dest, x1, y1, x3, y3, &p);
475 }
476 } else if(line->type == splineTo) {
477 int c,t,parts,qparts;
478 double xx,yy;
479
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);
483
484 c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1);
485 xx=x1;
486 yy=y1;
487
488 parts = (int)(sqrt((float)c)/3);
489 if(!parts) parts = 1;
490
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);
494
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);
498 lp.depth++;
499 }
500 if(line->fillstyle0 || line->fillstyle1) {
501 assert(shape->numfillstyles);
502 p.shapeline = line;
503 add_line(dest, xx, yy, nx, ny, &p);
504 }
505
506 xx = nx;
507 yy = ny;
508 }
509 }
510 x = line->x;
511 y = line->y;
512 line = line->next;
513 }
514
515 swf_Process(dest, clipdepth);
516
517 if(s2) {
518 swf_Shape2Free(s2);rfx_free(s2);s2=0;
519 }
520 if(lshape) {
521 swf_Shape2Free(lshape);rfx_free(lshape);lshape=0;
522 }
523
524 }
525
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};
529
fill_clip(RGBA * line,int * z,int y,int x1,int x2,U32 depth)530 static void fill_clip(RGBA*line, int*z, int y, int x1, int x2, U32 depth)
531 {
532 int x = x1;
533 if(x1>=x2)
534 return;
535 do {
536 if(depth > z[x]) {
537 z[x] = depth;
538 }
539 } while(++x<x2);
540 }
541
542
fill_solid(RGBA * line,int * z,int y,int x1,int x2,RGBA col,U32 depth)543 static void fill_solid(RGBA*line, int*z, int y, int x1, int x2, RGBA col, U32 depth)
544 {
545 int x = x1;
546
547 if(col.a!=255) {
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;
552 col.a = 255;
553 do {
554 if(depth >= z[x]) {
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;
558 line[x].a = 255;
559 z[x] = depth;
560 }
561 } while(++x<x2);
562 } else {
563 do {
564 if(depth >= z[x]) {
565 line[x] = col;
566 z[x] = depth;
567 }
568 } while(++x<x2);
569 }
570 }
571
clamp(int v)572 static int inline clamp(int v)
573 {
574 if(v>255) return 255;
575 else return v;
576 }
577
fill_bitmap(RGBA * line,int * z,int y,int x1,int x2,MATRIX * m,bitmap_t * b,int clipbitmap,U32 depth,double fmultiply)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)
579 {
580 int x = x1;
581
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;
586
587 double det = m11*m22 - m12*m21;
588 if(fabs(det) < 0.0005) {
589 /* x direction equals y direction- the image is invisible */
590 return;
591 }
592 det = 20.0/det;
593
594 if(!b->width || !b->height) {
595 fill_solid(line, z, y, x1, x2, color_red, depth);
596 return;
597 }
598
599 do {
600 if(depth >= z[x]) {
601 RGBA col;
602 int xx = (int)(( (x - rx) * m22 - (y - ry) * m21)*det);
603 int yy = (int)((- (x - rx) * m12 + (y - ry) * m11)*det);
604 int ainv;
605
606 if(clipbitmap) {
607 if(xx<0) xx=0;
608 if(xx>=b->width) xx = b->width-1;
609 if(yy<0) yy=0;
610 if(yy>=b->height) yy = b->height-1;
611 } else {
612 xx %= b->width;
613 yy %= b->height;
614 if(xx<0) xx += b->width;
615 if(yy<0) yy += b->height;
616 }
617
618 col = b->data[yy*b->width+xx];
619 ainv = 255-col.a;
620
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);
624 line[x].a = 255;
625
626 z[x] = depth;
627 }
628 } while(++x<x2);
629 }
630
fill_gradient(RGBA * line,int * z,int y,int x1,int x2,MATRIX * m,GRADIENT * g,int type,U32 depth,double fmultiply)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)
632 {
633 int x = x1;
634
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;
639
640 double det = m11*m22 - m12*m21;
641 if(fabs(det) < 0.0005) {
642 /* x direction equals y direction- the image is invisible */
643 return;
644 }
645 det = 1.0/det;
646
647 RGBA palette[512];
648 RGBA oldcol = g->rgba[0];
649 int r0 = g->ratios[0]*2;
650 int t;
651 for(t=0;t<r0;t++)
652 palette[t] = oldcol;
653 for(t=1;t<g->num;t++) {
654 int r1 = g->ratios[t]*2;
655 RGBA newcol = g->rgba[t];
656 if(r0 == r1)
657 continue;
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);
662 double p0 = 1;
663 double p1 = 0;
664 int s;
665 for(;r0<=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;
670 p0 -= f;
671 p1 += f;
672 }
673 oldcol = newcol;
674 }
675 for(t=r0;t<512;t++)
676 palette[t] = oldcol;
677
678 do {
679 if(depth >= z[x]) {
680 RGBA col;
681 double xx = ( (x - rx) * m22 - (y - ry) * m21)*det;
682 double yy = (- (x - rx) * m12 + (y - ry) * m11)*det;
683
684 if(type == FILL_LINEAR) {
685 int xr = xx*256;
686 if(xr<-256)
687 xr = -256;
688 if(xr>255)
689 xr = 255;
690 col = palette[xr+256];
691 } else {
692 int xr = sqrt(xx*xx+yy*yy)*511;
693 if(xr<0)
694 xr = 0;
695 if(xr>511)
696 xr = 511;
697 col = palette[xr];
698 }
699 int ainv;
700 ainv = 255-col.a;
701 line[x].r = clamp(((line[x].r*ainv)>>8)+col.r);
702 line[x].g = clamp(((line[x].g*ainv)>>8)+col.g);
703 line[x].b = clamp(((line[x].b*ainv)>>8)+col.b);
704 line[x].a = 255;
705
706 z[x] = depth;
707 }
708 } while(++x<x2);
709 }
710
711 typedef struct _layer {
712 int fillid;
713 renderpoint_t*p;
714 struct _layer*next;
715 struct _layer*prev;
716 } layer_t;
717
718 typedef struct {
719 layer_t*layers;
720 } state_t;
721
722
fill(RENDERBUF * dest,RGBA * line,int * zline,int y,int x1,int x2,state_t * fillstate,U32 clipdepth)723 static void fill(RENDERBUF*dest, RGBA*line, int*zline, int y, int x1, int x2, state_t*fillstate, U32 clipdepth)
724 {
725 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
726 int clip=1;
727
728 layer_t*l = fillstate->layers;
729
730 if(x1>=x2) //zero width? nothing to do.
731 return;
732
733 while(l) {
734 if(l->fillid == 0) {
735 /* not filled. TODO: we should never add those in the first place */
736 if(DEBUG&2)
737 printf("(not filled)");
738 } else if(l->fillid > l->p->s->numfillstyles) {
739 fprintf(stderr, "Fill style out of bounds (%d>%d)", l->fillid, l->p->s->numlinestyles);
740 } else if(clipdepth) {
741 /* filled region- not used for clipping */
742 clip = 0;
743 } else {
744 FILLSTYLE*f;
745 if(DEBUG&2)
746 printf("(%d -> %d style %d)", x1, x2, l->fillid);
747
748 f = &l->p->s->fillstyles[l->fillid-1];
749
750 if(f->type == FILL_SOLID) {
751 /* plain color fill */
752 fill_solid(line, zline, y, x1, x2, f->color, l->p->depth);
753 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED || f->type == (FILL_TILED|2) || f->type == (FILL_CLIPPED|2)) {
754 /* TODO: optimize (do this in add_pixel()?) */
755 bitmap_t* b = i->bitmaps;
756 while(b && b->id != f->id_bitmap) {
757 b = b->next;
758 }
759 if(!b) {
760 fprintf(stderr, "Shape references unknown bitmap %d\n", f->id_bitmap);
761 fill_solid(line, zline, y, x1, x2, color_red, l->p->depth);
762 } else {
763 fill_bitmap(line, zline, y, x1, x2, &f->m, b, /*clipped?*/f->type&1, l->p->depth, i->multiply);
764 }
765 } else if(f->type == FILL_LINEAR || f->type == FILL_RADIAL) {
766 fill_gradient(line, zline, y, x1, x2, &f->m, &f->gradient, f->type, l->p->depth, i->multiply);
767 } else {
768 fprintf(stderr, "Undefined fillmode: %02x\n", f->type);
769 }
770 }
771 l = l->next;
772 }
773 if(clip && clipdepth) {
774 fill_clip(line, zline, y, x1, x2, clipdepth);
775 }
776 }
777
search_layer(state_t * state,int depth,layer_t ** before,layer_t ** self,layer_t ** after)778 static void search_layer(state_t*state, int depth, layer_t**before, layer_t**self, layer_t**after)
779 {
780 layer_t*last=0,*l = state->layers;
781 while(l && l->p->depth < depth) {
782 last = l;
783 l = l->next;
784 }
785 *before = last;
786 if(l && l->p->depth == depth)
787 *self = l;
788 else
789 *after = l;
790 }
delete_layer(state_t * state,layer_t * todel)791 static void delete_layer(state_t*state, layer_t*todel)
792 {
793 layer_t*before=todel->prev;
794 layer_t*next = todel->next;
795 rfx_free(todel);
796 if(!before) {
797 state->layers = next;
798 if(next)
799 next->prev = 0;
800 } else {
801 before->next = next;
802 if(before->next)
803 before->next->prev = before;
804 }
805 }
add_layer(state_t * state,layer_t * before,layer_t * toadd)806 static void add_layer(state_t*state, layer_t*before, layer_t*toadd)
807 {
808 if(!before) {
809 toadd->next = state->layers;
810 toadd->prev = 0;
811 state->layers=toadd;
812 } else {
813 toadd->next = before->next;
814 toadd->prev = before;
815 before->next = toadd;
816 }
817 if(toadd->next)
818 toadd->next->prev = toadd;
819 }
free_layers(state_t * state)820 static void free_layers(state_t* state)
821 {
822 layer_t*l = state->layers;
823 while(l) {
824 layer_t*next = l->next;
825 rfx_free(l);
826 l = next;
827 }
828 }
829
change_state(int y,state_t * state,renderpoint_t * p)830 static void change_state(int y, state_t* state, renderpoint_t*p)
831 {
832 layer_t*before=0, *self=0, *after=0;
833
834 if(DEBUG&2) {
835 printf("[(%f,%d)/%d/%d-%d]", p->x, y, p->depth, p->shapeline->fillstyle0, p->shapeline->fillstyle1);
836 }
837
838 search_layer(state, p->depth, &before, &self, &after);
839
840 if(self) {
841 /* shape update */
842 if(self->fillid<0/*??*/ || !p->shapeline->fillstyle0 || !p->shapeline->fillstyle1) {
843 /* filling ends */
844 if(DEBUG&2) printf("<D>");
845
846 delete_layer(state, self);
847 } else {
848 /*both fill0 and fill1 are set- exchange the two, updating the layer */
849 if(self->fillid == p->shapeline->fillstyle0) {
850 self->fillid = p->shapeline->fillstyle1;
851 self->p = p;
852 if(DEBUG&2) printf("<X>");
853 } else if(self->fillid == p->shapeline->fillstyle1) {
854 self->fillid = p->shapeline->fillstyle0;
855 self->p = p;
856 if(DEBUG&2) printf("<X>");
857 } else {
858 /* buggy shape. keep everything as-is. */
859 if(DEBUG&2) printf("<!>");
860 //fprintf(stderr, "<line %d: bad swap>\n", y);
861 }
862 }
863 return;
864 } else {
865 layer_t* n = 0;
866 if(p->shapeline && p->shapeline->fillstyle0 && p->shapeline->fillstyle1) {
867 /* this is a hack- a better way would be to make sure that
868 we always get (0,32), (32, 33), (33, 0) in the right order if
869 they happen to fall on the same pixel.
870 (not: (0,32), (33, 0), (32, 33))
871 Notice: Weird fill styles appear if linestyles are involved, too.
872 */
873 fprintf(stderr, "<line %d: both fillstyles set while not inside shape>\n", y);
874 return;
875 }
876
877 n = (layer_t*)rfx_calloc(sizeof(layer_t));
878
879 if(DEBUG&2) printf("<+>");
880
881 n->fillid = p->shapeline->fillstyle0 ? p->shapeline->fillstyle0 : p->shapeline->fillstyle1;
882 n->p = p;
883
884 add_layer(state, before, n);
885 }
886 }
887
swf_Process(RENDERBUF * dest,U32 clipdepth)888 void swf_Process(RENDERBUF*dest, U32 clipdepth)
889 {
890 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
891 int y;
892
893 if(i->ymax < i->ymin) {
894 /* shape is empty. return.
895 only, if it's a clipshape, remember the clipdepth */
896 if(clipdepth) {
897 for(y=0;y<i->height2;y++) {
898 if(clipdepth > i->lines[y].pending_clipdepth)
899 i->lines[y].pending_clipdepth = clipdepth;
900 }
901 }
902 return; //nothing (else) to do
903 }
904
905 if(clipdepth) {
906 /* lines outside the clip shape are not filled
907 immediately, only the highest clipdepth so far is
908 stored there. They will be clipfilled once there's
909 actually something about to happen in that line */
910 for(y=0;y<i->ymin;y++) {
911 if(clipdepth > i->lines[y].pending_clipdepth)
912 i->lines[y].pending_clipdepth = clipdepth;
913 }
914 for(y=i->ymax+1;y<i->height2;y++) {
915 if(clipdepth > i->lines[y].pending_clipdepth)
916 i->lines[y].pending_clipdepth = clipdepth;
917 }
918 }
919
920 for(y=i->ymin;y<=i->ymax;y++) {
921 int n;
922 TAG*tag = i->lines[y].points;
923 int num = i->lines[y].num;
924 renderpoint_t*points = (renderpoint_t*)tag->data;
925 RGBA*line = &i->img[i->width2*y];
926 int*zline = &i->zbuf[i->width2*y];
927 int lastx = 0;
928 state_t fillstate;
929 memset(&fillstate, 0, sizeof(state_t));
930 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
931 /* resort points */
932 /*if(y==884) {
933 for(n=0;n<num;n++) {
934 printf("%f (%d/%d) %d\n", points[n].x,
935 points[n].shapeline->fillstyle0,
936 points[n].shapeline->fillstyle1,
937 points[n].shapeline->linestyle);
938 }
939 }*/
940
941 if(i->lines[y].pending_clipdepth && !clipdepth) {
942 fill_clip(line, zline, y, 0, i->width2, i->lines[y].pending_clipdepth);
943 i->lines[y].pending_clipdepth=0;
944 }
945
946 for(n=0;n<num;n++) {
947 renderpoint_t*p = &points[n];
948 renderpoint_t*next= n<num-1?&points[n+1]:0;
949 int startx = (int)p->x;
950 int endx = (int)(next?next->x:i->width2);
951 if(endx > i->width2)
952 endx = i->width2;
953 if(startx < 0)
954 startx = 0;
955 if(endx < 0)
956 endx = 0;
957
958 if(clipdepth) {
959 /* for clipping, the inverse is filled
960 TODO: lastx!=startx only at the start of the loop,
961 so this might be moved up
962 */
963 fill_clip(line, zline, y, lastx, startx, clipdepth);
964 }
965 change_state(y, &fillstate, p);
966
967 fill(dest, line, zline, y, startx, endx, &fillstate, clipdepth);
968 /* if(y == 0 && startx == 232 && endx == 418) {
969 printf("ymin=%d ymax=%d\n", i->ymin, i->ymax);
970 for(n=0;n<num;n++) {
971 renderpoint_t*p = &points[n];
972 printf("x=%f depth=%08x\n", p->x, p->depth);
973 }
974 }*/
975
976 lastx = endx;
977 if(endx == i->width2)
978 break;
979 }
980 if(clipdepth) {
981 /* TODO: is lastx *ever* != i->width2 here? */
982 fill_clip(line, zline, y, lastx, i->width2, clipdepth);
983 }
984 free_layers(&fillstate);
985
986 i->lines[y].num = 0;
987 swf_ClearTag(i->lines[y].points);
988 }
989 i->ymin = 0x7fffffff;
990 i->ymax = -0x80000000;
991 }
992
swf_Render(RENDERBUF * dest)993 RGBA* swf_Render(RENDERBUF*dest)
994 {
995 renderbuf_internal*i = (renderbuf_internal*)dest->internal;
996 RGBA* img = (RGBA*)rfx_alloc(sizeof(RGBA)*dest->width*dest->height);
997 int y;
998 int antialize = i->antialize;
999
1000 if(antialize <= 1) /* no antializing */ {
1001 for(y=0;y<i->height2;y++) {
1002 RGBA*line = &i->img[y*i->width2];
1003 memcpy(&img[y*dest->width], line, sizeof(RGBA)*dest->width);
1004 }
1005 } else {
1006 RGBA**lines = (RGBA**)rfx_calloc(sizeof(RGBA*)*antialize);
1007 int q = antialize*antialize;
1008 int ypos = 0;
1009 for(y=0;y<i->height2;y++) {
1010 int n;
1011 ypos = y % antialize;
1012 lines[ypos] = &i->img[y*i->width2];
1013 if(ypos == antialize-1) {
1014 RGBA*out = &img[(y / antialize)*dest->width];
1015 int x;
1016 int r,g,b,a;
1017 for(x=0;x<dest->width;x++) {
1018 int xpos = x*antialize;
1019 int yp;
1020 U32 r=0,g=0,b=0,a=0;
1021 for(yp=0;yp<antialize;yp++) {
1022 RGBA*lp = &lines[yp][xpos];
1023 int xp;
1024 for(xp=0;xp<antialize;xp++) {
1025 RGBA*p = &lp[xp];
1026 r += p->r;
1027 g += p->g;
1028 b += p->b;
1029 a += p->a;
1030 }
1031 }
1032 out[x].r = r / q;
1033 out[x].g = g / q;
1034 out[x].b = b / q;
1035 out[x].a = a / q;
1036 }
1037 }
1038 }
1039 rfx_free(lines);
1040 }
1041 return img;
1042 }
1043
1044 typedef struct
1045 {
1046 int numchars;
1047 SHAPE2**glyphs;
1048 } font_t;
1049
1050 enum CHARACTER_TYPE {none_type, shape_type, image_type, text_type, edittext_type, font_type, sprite_type};
1051 typedef struct
1052 {
1053 TAG*tag;
1054 SRECT*bbox;
1055 enum CHARACTER_TYPE type;
1056 union {
1057 SHAPE2*shape;
1058 font_t*font;
1059 } obj;
1060 } character_t;
1061
compare_placements(const void * v1,const void * v2)1062 int compare_placements(const void *v1, const void *v2)
1063 {
1064 SWFPLACEOBJECT*p1 = (SWFPLACEOBJECT*)v1;
1065 SWFPLACEOBJECT*p2 = (SWFPLACEOBJECT*)v2;
1066 if(p1->depth != p2->depth)
1067 return (int)p1->depth - (int)p2->depth;
1068 else
1069 if(p2->clipdepth)
1070 return 1; // do the clip first
1071 else
1072 return -1;
1073
1074 /* if(!p1->clipdepth) {
1075 if(!p2->clipdepth) {
1076 // !p1->clipdepth && !p2->clipdepth
1077 return (int)p1->depth - (int)p2->depth;
1078 } else {
1079 // !p1->clipdepth && p2->clipdepth
1080 if(p1->depth != p2->clipdepth)
1081 return (int)p1->depth - (int)p2->clipdepth;
1082 else
1083 return 1; // do the clip first
1084 }
1085 } else {
1086 if(!p2->clipdepth) {
1087 // p1->clipdepth && !p2->clipdepth
1088 if(p1->clipdepth != p2->depth)
1089 return (int)p1->clipdepth - (int)p2->depth;
1090 else
1091 return -1;// do the clip first
1092 } else {
1093 if(p1->clipdepth != p2->clipdepth)
1094 return (int)p1->clipdepth - (int)p2->clipdepth;
1095 else
1096 return (int)p1->depth - (int)p2->depth;
1097 }
1098 }*/
1099 }
1100
1101 typedef struct textcallbackblock
1102 {
1103 character_t*idtable;
1104 U16 depth;
1105 U16 clipdepth;
1106 CXFORM* cxform;
1107 MATRIX m;
1108 RENDERBUF*buf;
1109 } textcallbackblock_t;
1110
textcallback(void * self,int * chars,int * xpos,int nr,int fontid,int fontsize,int xstart,int ystart,RGBA * color)1111 static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize,
1112 int xstart, int ystart, RGBA* color)
1113 {
1114 textcallbackblock_t * info = (textcallbackblock_t*)self;
1115 font_t*font = 0;
1116 int t;
1117 if(info->idtable[fontid].type != font_type) {
1118 fprintf(stderr, "ID %d is not a font\n", fontid);
1119 return;
1120 } else if(!info->idtable[fontid].obj.font) {
1121 fprintf(stderr, "Font %d unknown\n", fontid);
1122 return;
1123 } else {
1124 font = info->idtable[fontid].obj.font;
1125 }
1126 for(t=0;t<nr;t++) {
1127 int x = xstart + xpos[t];
1128 int y = ystart;
1129 MATRIX m = info->m;
1130 SPOINT p;
1131
1132 p.x = x; p.y = y;
1133 p = swf_TurnPoint(p, &m);
1134
1135 m.sx = (m.sx * fontsize) / 1024;
1136 m.sy = (m.sy * fontsize) / 1024;
1137 m.r0 = (m.r0 * fontsize) / 1024;
1138 m.r1 = (m.r1 * fontsize) / 1024;
1139 m.tx = p.x;
1140 m.ty = p.y;
1141
1142 if(chars[t]<0 || chars[t]>= font->numchars) {
1143 fprintf(stderr, "Character out of range: %d\n", chars[t]);
1144 } else {
1145 SHAPE2*shape = font->glyphs[chars[t]];
1146 shape->fillstyles[0].color = *color; //q&d
1147 /*printf("Rendering char %d (size %d, x:%d, y:%d) color:%02x%02x%02x%02x\n", chars[t], fontsize, x, y,
1148 color->a, color->r, color->g, color->b);
1149 swf_DumpMatrix(stdout, &m);
1150 swf_DumpShape(shape);*/
1151 swf_RenderShape(info->buf, shape, &m, info->cxform, info->depth, info->clipdepth);
1152 }
1153 }
1154 }
1155
renderFromTag(RENDERBUF * buf,character_t * idtable,TAG * firstTag,MATRIX * m)1156 static void renderFromTag(RENDERBUF*buf, character_t*idtable, TAG*firstTag, MATRIX*m)
1157 {
1158 TAG*tag = 0;
1159 int numplacements = 0;
1160 SWFPLACEOBJECT* placements;
1161
1162 tag = firstTag;
1163 numplacements = 0;
1164 while(tag) {
1165 if(tag->id == ST_PLACEOBJECT ||
1166 tag->id == ST_PLACEOBJECT2) {
1167 numplacements++;
1168 }
1169 if(tag->id == ST_SHOWFRAME || tag->id == ST_END)
1170 break;
1171 tag = tag->next;
1172 }
1173 placements = (SWFPLACEOBJECT*)rfx_calloc(sizeof(SWFPLACEOBJECT)*numplacements);
1174 numplacements = 0;
1175
1176 tag = firstTag;
1177 while(tag) {
1178 if(swf_isPlaceTag(tag)) {
1179 SWFPLACEOBJECT p;
1180 swf_GetPlaceObject(tag, &p);
1181 /* TODO: add move and deletion */
1182 placements[numplacements++] = p;
1183 swf_PlaceObjectFree(&p); //dirty! but it only frees fields we don't use
1184 }
1185 if(tag->id == ST_SHOWFRAME || tag->id == ST_END)
1186 break;
1187 tag = tag->next;
1188 }
1189
1190 qsort(placements, numplacements, sizeof(SWFPLACEOBJECT), compare_placements);
1191
1192 int t;
1193 for(t=0;t<numplacements;t++) {
1194 SWFPLACEOBJECT*p = &placements[t];
1195 int id = p->id;
1196 MATRIX m2;
1197 swf_MatrixJoin(&m2, m, &p->matrix);
1198
1199 if(!idtable[id].tag) {
1200 fprintf(stderr, "rfxswf: Id %d is unknown\n", id);
1201 continue;
1202 }
1203
1204 if(idtable[id].type == shape_type) {
1205 //SRECT sbbox = swf_TurnRect(*idtable[id].bbox, &p->matrix);
1206 swf_RenderShape(buf, idtable[id].obj.shape, &m2, &p->cxform, p->depth, p->clipdepth);
1207 } else if(idtable[id].type == sprite_type) {
1208 swf_UnFoldSprite(idtable[id].tag);
1209 renderFromTag(buf, idtable, idtable[id].tag->next, &m2);
1210 swf_FoldSprite(idtable[id].tag);
1211 } else if(idtable[id].type == text_type) {
1212 TAG* tag = idtable[id].tag;
1213 textcallbackblock_t info;
1214 MATRIX mt;
1215
1216 swf_SetTagPos(tag, 0);
1217 swf_GetU16(tag);
1218 swf_GetRect(tag,0);
1219 swf_GetMatrix(tag,&mt);
1220 swf_MatrixJoin(&info.m, &m2, &mt);
1221 /*printf("Text matrix:\n");
1222 swf_DumpMatrix(stdout, &m);
1223 printf("Placement matrix:\n");
1224 swf_DumpMatrix(stdout, &p->matrix);
1225 printf("Final matrix:\n");
1226 swf_DumpMatrix(stdout, &info.m);*/
1227
1228 info.idtable = idtable;
1229 info.depth = p->depth;
1230 info.cxform = &p->cxform;
1231 info.clipdepth = p->clipdepth;
1232 info.buf = buf;
1233
1234 swf_ParseDefineText(tag, textcallback, &info);
1235 } else if(idtable[id].type == edittext_type) {
1236 TAG* tag = idtable[id].tag;
1237 U16 flags = swf_GetBits(tag, 16);
1238 if(flags & ET_HASTEXT) {
1239 fprintf(stderr, "edittext not supported yet (id %d)\n", id);
1240 }
1241 } else {
1242 fprintf(stderr, "Unknown/Unsupported Object Type for id %d: %s\n", id, swf_TagGetName(idtable[id].tag));
1243 }
1244 }
1245
1246 free(placements);
1247 }
1248
swf_RenderSWF(RENDERBUF * buf,SWF * swf)1249 void swf_RenderSWF(RENDERBUF*buf, SWF*swf)
1250 {
1251 TAG*tag;
1252 int t;
1253 RGBA color;
1254
1255 swf_OptimizeTagOrder(swf);
1256 swf_FoldAll(swf);
1257
1258 character_t* idtable = (character_t*)rfx_calloc(sizeof(character_t)*65536); // id to character mapping
1259
1260 /* set background color */
1261 color = swf_GetSWFBackgroundColor(swf);
1262 swf_Render_SetBackgroundColor(buf, color);
1263
1264 /* parse definitions */
1265 tag = swf->firstTag;
1266 while(tag) {
1267 if(swf_isDefiningTag(tag)) {
1268 int id = swf_GetDefineID(tag);
1269 idtable[id].tag = tag;
1270 idtable[id].bbox = (SRECT*)rfx_alloc(sizeof(SRECT));
1271 *idtable[id].bbox = swf_GetDefineBBox(tag);
1272
1273 if(swf_isShapeTag(tag)) {
1274 SHAPE2* shape = (SHAPE2*)rfx_calloc(sizeof(SHAPE2));
1275 swf_ParseDefineShape(tag, shape);
1276 idtable[id].type = shape_type;
1277 idtable[id].obj.shape = shape;
1278 } else if(swf_isImageTag(tag)) {
1279 int width,height;
1280 RGBA*data = swf_ExtractImage(tag, &width, &height);
1281 idtable[id].type = image_type;
1282 swf_Render_AddImage(buf, id, data, width, height);
1283 free(data);
1284 } else if(tag->id == ST_DEFINEFONT ||
1285 tag->id == ST_DEFINEFONT2) {
1286 int t;
1287 SWFFONT*swffont;
1288 font_t*font = (font_t*)rfx_calloc(sizeof(font_t));
1289 idtable[id].obj.font = font;
1290 swf_FontExtract(swf,id,&swffont);
1291 font->numchars = swffont->numchars;
1292 font->glyphs = (SHAPE2**)rfx_calloc(sizeof(SHAPE2*)*font->numchars);
1293 for(t=0;t<font->numchars;t++) {
1294 if(!swffont->glyph[t].shape->fillstyle.n) {
1295 /* the actual fill color will be overwritten while rendering */
1296 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
1297 }
1298 font->glyphs[t] = swf_ShapeToShape2(swffont->glyph[t].shape);
1299 }
1300 swf_FontFree(swffont);
1301 idtable[id].type = font_type;
1302
1303 } else if(tag->id == ST_DEFINEFONTINFO ||
1304 tag->id == ST_DEFINEFONTINFO2) {
1305 idtable[id].type = font_type;
1306 } else if(tag->id == ST_DEFINETEXT ||
1307 tag->id == ST_DEFINETEXT2) {
1308 idtable[id].type = text_type;
1309 } else if(tag->id == ST_DEFINESPRITE) {
1310 idtable[id].type = sprite_type;
1311 } else if(tag->id == ST_DEFINEEDITTEXT) {
1312 idtable[id].type = edittext_type;
1313 }
1314 }
1315 tag = tag->next;
1316 }
1317 MATRIX m;
1318 swf_GetMatrix(0, &m);
1319 renderFromTag(buf, idtable, swf->firstTag, &m);
1320
1321 /* free id and depth tables again */
1322 for(t=0;t<65536;t++) {
1323 if(idtable[t].bbox) {
1324 free(idtable[t].bbox);
1325 idtable[t].bbox=0;
1326 }
1327 if(idtable[t].type == shape_type) {
1328 SHAPE2* shape = idtable[t].obj.shape;
1329 if(shape) {
1330 swf_Shape2Free(shape); // FIXME
1331 free(idtable[t].obj.shape);idtable[t].obj.shape = 0;
1332 }
1333 } else if(idtable[t].type == font_type) {
1334 font_t* font = idtable[t].obj.font;
1335 if(font) {
1336 if(font->glyphs) {
1337 int t;
1338 for(t=0;t<font->numchars;t++) {
1339 swf_Shape2Free(font->glyphs[t]);
1340 free(font->glyphs[t]); font->glyphs[t] = 0;
1341 }
1342 free(font->glyphs);
1343 font->glyphs = 0;
1344 }
1345 free(idtable[t].obj.font); idtable[t].obj.font = 0;
1346 font = 0;
1347 }
1348 }
1349 }
1350 free(idtable);
1351 }
1352
1353