3 #include "../gfxdevice.h"
4 #include "../gfxsource.h"
5 #include "../gfxtools.h"
12 typedef struct _map16_t
17 typedef struct _swf_page_internal
20 } swf_page_internal_t;
22 typedef struct _swf_doc_internal
36 typedef struct _character
44 typedef struct _placement
51 typedef struct _sprite
64 typedef struct _render render_t;
67 static void placement_free(placement_t*p)
69 swf_PlaceObjectFree(&p->po);
73 //---- object/depth handling ----
77 map16_t*map = rfx_calloc(sizeof(map16_t));
78 /* TODO: replace this by a more sophisticated data structure */
79 map->ids = (void**)rfx_calloc(sizeof(character_t)*65536);
82 character_t*map16_get_id(map16_t*map, int id)
88 void map16_free(map16_t*map)
92 void map16_add_id(map16_t*map, int nr, void*id)
95 fprintf(stderr, "Warning: ID %d defined more than once\n", nr);
98 void map16_remove_id(map16_t*map, int nr)
102 void map16_enumerate(map16_t*map, void (*f)(void*self, int id, void*data), void*self)
105 for(t=0;t<65536;t++) {
107 f(self, t, map->ids[t]);
111 //---- conversion stuff ----
113 static void convertMatrix(MATRIX*from, gfxmatrix_t*to)
115 to->m00 = from->sx / 65536.0; to->m10 = from->r1 / 65536.0;
116 to->m01 = from->r0 / 65536.0; to->m11 = from->sy / 65536.0;
117 to->tx = from->tx/20.0;
118 to->ty = from->ty/20.0;
121 static void convertCXForm(CXFORM*from, gfxcxform_t*to)
123 memset(to, 0, sizeof(gfxcxform_t));
124 to->aa = from->a0 / 256.0;
125 to->rr = from->r0 / 256.0;
126 to->gg = from->g0 / 256.0;
127 to->bb = from->b0 / 256.0;
134 static gfxgradient_t* convertGradient(GRADIENT*from)
136 gfxgradient_t*g = rfx_calloc(from->num * sizeof(gfxgradient_t));
138 for(t=0;t<from->num;t++) {
139 g[t].pos = from->ratios[t] / 255.0;
140 g[t].color = *(gfxcolor_t*)&from->rgba[t];
149 gfxline_t* swfline_to_gfxline(SHAPELINE*line, int linestyle, int fillstyle0)
152 SCOORD x=0,y=0,xx=0,yy=0;
154 gfxdrawer_target_gfxline(&d);
155 if(line && line->type != moveTo) {
156 fprintf(stderr, "Warning: Shape doesn't start with a moveTo\n");
158 xx = line?line->x+1:0;
160 if(line->fillstyle0 == fillstyle0 ||
161 line->fillstyle1 == fillstyle0 ||
162 line->linestyle == linestyle) {
163 if(line->type == lineTo) {
164 if(xx!=x || yy!=y) d.moveTo(&d, x/20.0,y/20.0);
165 d.lineTo(&d, line->x/20.0,line->y/20.0);
168 } else if(line->type == splineTo) {
169 if(xx!=x || yy!=y) d.moveTo(&d, x/20.0,y/20.0);
170 d.splineTo(&d, line->sx/20.0, line->sy/20.0, line->x/20.0,line->y/20.0);
184 //---- bitmap handling ----
186 static gfximage_t* gfximage_new(RGBA*data, int width, int height)
188 gfximage_t* b = (gfximage_t*)rfx_calloc(sizeof(gfximage_t));
189 b->data = (gfxcolor_t*)data;
195 static gfximage_t* findimage(render_t*r, U16 id)
197 character_t*c = (character_t*)map16_get_id(r->id2char, id);
198 assert(c && c->type == TYPE_BITMAP);
199 gfximage_t*img = (gfximage_t*)c->data;
202 sprintf(filename, "bitmap%d.png", id);
203 writePNG(filename, (unsigned char*)img->data, img->width, img->height);
204 printf("saving bitmap %d to %s\n", id, filename);*/
208 //---- shape handling ----
210 static void renderFilled(render_t*r, gfxline_t*line, FILLSTYLE*f, CXFORM*cx, MATRIX*po_m)
212 if(f->type == FILL_SOLID) {
213 gfxcolor_t c = *(gfxcolor_t*)&f->color;
214 r->device->fill(r->device, line, &c);
215 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
216 gfximage_t* img = findimage(r, f->id_bitmap);
219 convertCXForm(cx, &gfxcx);
221 swf_MatrixJoin(&m2, po_m, &f->m);
222 convertMatrix(&m2, &m);
223 m.m00/=20.0; m.m10/=20.0;
224 m.m01/=20.0; m.m11/=20.0;
225 /* TODO: handle clipped */
226 r->device->fillbitmap(r->device, line, img, &m, &gfxcx);
227 } else if(f->type == FILL_LINEAR || f->type == FILL_RADIAL) {
231 //swf_MatrixJoin(&m2, po_m, &f->m);
233 double z = f->type==FILL_RADIAL?4:4;
234 m.m00 = m2->sx/z/20.0; m.m10 = m2->r1/z/20.0;
235 m.m01 = m2->r0/z/20.0; m.m11 = m2->sy/z/20.0;
239 g = convertGradient(&f->gradient);
240 r->device->fillgradient(r->device, line, g, f->type == FILL_LINEAR ? gfxgradient_linear : gfxgradient_radial, &m);
245 //---- font handling ----
253 typedef struct textcallbackblock
257 } textcallbackblock_t;
259 static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize,
260 int xstart, int ystart, RGBA* color)
262 textcallbackblock_t * info = (textcallbackblock_t*)self;
265 character_t*cfont = map16_get_id(info->r->id2char, fontid);
267 fprintf(stderr, "Font %d unknown\n", fontid);
270 if(cfont->type != TYPE_FONT) {
271 fprintf(stderr, "ID %d is not a font\n", fontid);
277 int x = xstart + xpos[t];
283 p = swf_TurnPoint(p, &m);
285 m.sx = (m.sx * fontsize) / 1024;
286 m.sy = (m.sy * fontsize) / 1024;
287 m.r0 = (m.r0 * fontsize) / 1024;
288 m.r1 = (m.r1 * fontsize) / 1024;
293 convertMatrix(&m, &gm);
295 if(chars[t]<0 || chars[t]>= font->numchars) {
296 fprintf(stderr, "Character out of range: %d\n", chars[t]);
298 gfxline_t*line = gfxline_clone(font->glyphs[chars[t]]);
299 gfxline_transform(line, &gm);
303 renderFilled(info->r, line, &f, 0, 0);
310 //---- tag handling ----
312 static map16_t* extractDefinitions(SWF*swf)
314 map16_t*map = map16_new();
315 TAG*tag = swf->firstTag;
319 if(swf_isDefiningTag(tag)) {
320 id = swf_GetDefineID(tag);
323 if(tag->id == ST_DEFINESPRITE) {
324 character_t*c = rfx_calloc(sizeof(character_t));
325 sprite_t*s = rfx_calloc(sizeof(sprite_t));
326 swf_SetTagPos(tag, 0);
327 swf_GetU16(tag); //id
328 s->frameCount = swf_GetU16(tag); //frameno
330 c->type = TYPE_SPRITE;
332 map16_add_id(map, id, c);
334 else if(tag->id == ST_DEFINESHAPE ||
335 tag->id == ST_DEFINESHAPE2 ||
336 tag->id == ST_DEFINESHAPE3) {
337 character_t*c = rfx_calloc(sizeof(character_t));
339 c->type = TYPE_SHAPE;
340 map16_add_id(map, id, c);
342 else if(tag->id == ST_DEFINEFONT ||
343 tag->id == ST_DEFINEFONT2 ||
344 tag->id == ST_DEFINEFONT3) {
345 character_t*c = rfx_calloc(sizeof(character_t));
347 font_t*font = (font_t*)rfx_calloc(sizeof(font_t));
348 swf_FontExtract(swf, id, &swffont);
349 font->numchars = swffont->numchars;
350 font->glyphs = (gfxline_t**)rfx_calloc(sizeof(gfxline_t*)*font->numchars);
352 RGBA color_white = {255,255,255,255};
353 for(t=0;t<font->numchars;t++) {
354 if(!swffont->glyph[t].shape->fillstyle.n) {
355 swf_ShapeAddSolidFillStyle(swffont->glyph[t].shape, &color_white);
357 SHAPE2*s2 = swf_ShapeToShape2(swffont->glyph[t].shape);
358 font->glyphs[t] = swfline_to_gfxline(s2->lines, 0, 1);
359 if(tag->id==ST_DEFINEFONT3) {
360 gfxmatrix_t m = {1/20.0,0,0, 0,1/20.0,0};
361 gfxline_transform(font->glyphs[t], &m);
365 swf_FontFree(swffont);
370 map16_add_id(map, id, c);
372 else if(tag->id == ST_DEFINETEXT ||
373 tag->id == ST_DEFINETEXT2) {
374 character_t*c = rfx_calloc(sizeof(character_t));
378 map16_add_id(map, id, c);
380 else if(tag->id == ST_DEFINEBITSJPEG ||
381 tag->id == ST_DEFINEBITSJPEG2 ||
382 tag->id == ST_DEFINEBITSJPEG3 ||
383 tag->id == ST_DEFINEBITSLOSSLESS ||
384 tag->id == ST_DEFINEBITSLOSSLESS2) {
385 character_t*c = rfx_calloc(sizeof(character_t));
387 void*data = swf_ExtractImage(tag, &width, &height);
388 gfximage_t*b = gfximage_new(data, width, height);
390 c->type = TYPE_BITMAP;
392 map16_add_id(map, id, c);
400 void swf_FreeTaglist(TAG*tag)
404 TAG * tnew = tag->next;
412 static void increaseAge(void*self, int id, void*data)
414 placement_t*p = (placement_t*)data;
418 static map16_t* extractFrame(TAG*startTag, int frame_to_extract)
420 map16_t*depthmap = map16_new();
425 SWF*swf = rfx_calloc(sizeof(SWF));
426 swf->firstTag = startTag;
428 for(;tag;tag = tag->next) {
429 if(tag->id == ST_DEFINESPRITE) {
430 while(tag->id != ST_END)
434 if(tag->id == ST_PLACEOBJECT ||
435 tag->id == ST_PLACEOBJECT2) {
436 placement_t* p = rfx_calloc(sizeof(placement_t));
438 p->startFrame = frame;
439 swf_GetPlaceObject(tag, &p->po);
441 placement_t*old = (placement_t*)map16_get_id(depthmap, p->po.depth);
442 p->po.id = old->po.id;
443 map16_remove_id(depthmap, p->po.depth);
446 map16_add_id(depthmap, p->po.depth, p);
449 if(tag->id == ST_REMOVEOBJECT ||
450 tag->id == ST_REMOVEOBJECT2) {
451 U16 depth = swf_GetDepth(tag);
452 map16_remove_id(depthmap, depth);
454 if(tag->id == ST_SHOWFRAME || tag->id == ST_END || !tag->next) {
455 if(frame == frame_to_extract) {
458 if(tag->id == ST_SHOWFRAME) {
460 map16_enumerate(depthmap, increaseAge, 0);
463 if(tag->id == ST_END)
469 // ---- rendering ----
471 void swf_ShapeApplyMatrix(SHAPE2*shape, MATRIX*m)
475 RGBA swf_ColorTransform(RGBA*color, CXFORM*cx)
478 dest.r = (cx->r0*color->r + cx->r1*256) >> 8;
479 dest.g = (cx->g0*color->g + cx->g1*256) >> 8;
480 dest.b = (cx->b0*color->b + cx->b1*256) >> 8;
481 dest.a = (cx->a0*color->a + cx->a1*256) >> 8;
485 void renderOutline(render_t*r, gfxline_t*line, LINESTYLE*l, CXFORM*cx)
487 RGBA c = swf_ColorTransform(&l->color, cx);
488 gfxcoord_t width = l->width/20.0;
489 r->device->stroke(r->device, line, width, (gfxcolor_t*)&c, gfx_capRound, gfx_joinRound, 0.0);
492 void swf_ApplyMatrixToShape(SHAPE2*shape, MATRIX*m)
494 SHAPELINE*line = shape->lines;
497 p.x = line->x; p.y = line->y;
498 p = swf_TurnPoint(p, m);
499 line->x = p.x; line->y = p.y;
504 static void renderCharacter(render_t*r, placement_t*p, character_t*c)
506 if(c->type == TYPE_SHAPE) {
508 swf_ParseDefineShape(c->tag, &shape);
510 swf_MatrixJoin(&m, &r->m, &p->po.matrix);
511 swf_ApplyMatrixToShape(&shape, &m);
512 SHAPELINE*line = shape.lines;
514 for(t=1;t<=shape.numfillstyles;t++) {
516 line = swfline_to_gfxline(shape.lines, -1, t);
518 if(!p->po.clipdepth) {
519 renderFilled(r, line, &shape.fillstyles[t-1], &p->po.cxform, &p->po.matrix);
521 r->device->startclip(r->device, line);
522 r->clips_waiting[p->po.clipdepth]++;
526 /*line = swfline_to_gfxline(shape.lines, -1, -1, t);
527 if(line) renderFilled(r, line, &shape.fillstyles[t-1], &p->po.cxform);
528 gfxline_free(line);*/
530 for(t=1;t<=shape.numlinestyles;t++) {
531 gfxline_t*line = swfline_to_gfxline(shape.lines, t, -1);
532 if(line) renderOutline(r, line, &shape.linestyles[t-1], &p->po.cxform);
535 } else if(c->type == TYPE_TEXT) {
537 textcallbackblock_t info;
539 swf_SetTagPos(tag, 0);
542 swf_GetMatrix(tag,&mt);
544 swf_MatrixJoin(&mt2, &r->m, &mt);
545 swf_MatrixJoin(&info.m, &mt2, &p->po.matrix);
547 swf_ParseDefineText(tag, textcallback, &info);
553 static void placeObject(void*self, int id, void*data)
555 render_t*r = (render_t*)self;
556 placement_t*p = (placement_t*)data;
557 character_t*c = map16_get_id(r->id2char, p->po.id);
559 fprintf(stderr, "Error: ID %d unknown\n", p->po.id);
562 if(c->type == TYPE_SPRITE) {
563 int*old_clips_waiting = r->clips_waiting;
564 r->clips_waiting = rfx_calloc(sizeof(r->clips_waiting[0])*65536);
566 sprite_t* s = (sprite_t*)c->data;
568 map16_t* depths = extractFrame(c->tag->next, s->frameCount>0? p->age % s->frameCount : 0);
569 map16_enumerate(depths, placeObject, r);
572 for(t=0;t<65536;t++) {
574 for(i=0; i<r->clips_waiting[t]; i++) {
575 r->device->endclip(r->device);
578 free(r->clips_waiting);
579 r->clips_waiting = old_clips_waiting;
582 renderCharacter(r, p, c);
585 void swfpage_destroy(gfxpage_t*swf_page)
587 swf_page_internal_t*i= (swf_page_internal_t*)swf_page->internal;
588 free(swf_page->internal);swf_page->internal = 0;
589 free(swf_page);swf_page=0;
592 void swfpage_render(gfxpage_t*page, gfxdevice_t*output)
594 swf_page_internal_t*i = (swf_page_internal_t*)page->internal;
595 swf_doc_internal_t*pi = (swf_doc_internal_t*)page->parent->internal;
596 map16_t* depths = extractFrame(pi->swf.firstTag, i->frame);
598 r.id2char = pi->id2char;
602 r.clips_waiting = malloc(sizeof(r.clips_waiting[0])*65536);
603 memset(r.clips_waiting, 0, sizeof(r.clips_waiting[0])*65536);
606 for(t=0;t<65536;t++) {
608 placeObject(&r, t, depths->ids[t]);
611 for(i=0; i<r.clips_waiting[t]; i++) {
612 output->endclip(output);
615 free(r.clips_waiting);
618 void swfpage_rendersection(gfxpage_t*page, gfxdevice_t*output, gfxcoord_t x, gfxcoord_t y, gfxcoord_t _x1, gfxcoord_t _y1, gfxcoord_t _x2, gfxcoord_t _y2)
620 swf_doc_internal_t*pi = (swf_doc_internal_t*)page->parent->internal;
622 swfpage_render(page,output);
625 void swf_doc_destroy(gfxdocument_t*gfx)
627 swf_doc_internal_t*i= (swf_doc_internal_t*)gfx->internal;
628 swf_FreeTags(&i->swf);
629 free(gfx->internal);gfx->internal=0;
633 void swf_doc_setparameter(gfxdocument_t*gfx, const char*name, const char*value)
635 swf_doc_internal_t*i= (swf_doc_internal_t*)gfx->internal;
638 gfxpage_t* swf_doc_getpage(gfxdocument_t*doc, int page)
640 swf_doc_internal_t*di= (swf_doc_internal_t*)doc->internal;
641 if(page < 1 || page > doc->num_pages)
644 gfxpage_t* swf_page = (gfxpage_t*)malloc(sizeof(gfxpage_t));
645 swf_page_internal_t*pi= (swf_page_internal_t*)malloc(sizeof(swf_page_internal_t));
646 memset(pi, 0, sizeof(swf_page_internal_t));
650 swf_page->internal = pi;
651 swf_page->destroy = swfpage_destroy;
652 swf_page->render = swfpage_render;
653 swf_page->rendersection = swfpage_rendersection;
654 swf_page->width = di->width;
655 swf_page->height = di->height;
656 swf_page->parent = doc;
661 void swf_setparameter(gfxsource_t*src, const char*name, const char*value)
663 msg("<verbose> setting parameter %s to \"%s\"", name, value);
666 gfxdocument_t*swf_open(gfxsource_t*src, const char*filename)
668 gfxdocument_t*swf_doc = (gfxdocument_t*)malloc(sizeof(gfxdocument_t));
669 memset(swf_doc, 0, sizeof(gfxdocument_t));
670 swf_doc_internal_t*i= (swf_doc_internal_t*)malloc(sizeof(swf_doc_internal_t));
671 memset(i, 0, sizeof(swf_doc_internal_t));
682 f = open(filename,O_RDONLY|O_BINARY);
684 perror("Couldn't open file: ");
687 if FAILED(swf_ReadSWF(f,&i->swf)) {
688 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
692 swf_UnFoldAll(&i->swf);
694 i->id2char = extractDefinitions(&i->swf);
695 i->width = (i->swf.movieSize.xmax - i->swf.movieSize.xmin) / 20;
696 i->height = (i->swf.movieSize.ymax - i->swf.movieSize.ymin) / 20;
698 swf_GetMatrix(0, &i->m);
699 i->m.tx = -i->swf.movieSize.xmin;
700 i->m.ty = -i->swf.movieSize.ymin;
702 swf_doc->num_pages = i->swf.frameCount;
703 swf_doc->internal = i;
705 swf_doc->destroy = swf_doc_destroy;
706 swf_doc->setparameter = swf_doc_setparameter;
707 swf_doc->getpage = swf_doc_getpage;
712 static void swf_destroy(gfxsource_t*src)
714 memset(src, 0, sizeof(*src));
719 gfxsource_t*gfxsource_swf_create()
721 gfxsource_t*src = (gfxsource_t*)malloc(sizeof(gfxsource_t));
722 memset(src, 0, sizeof(gfxsource_t));
723 src->setparameter = swf_setparameter;
724 src->open = swf_open;
725 src->destroy = swf_destroy;