1 #include "../gfxdevice.h"
2 #include "../gfxsource.h"
3 #include "../gfxtools.h"
9 typedef struct _map16_t
14 typedef struct _swf_page_internal
17 } swf_page_internal_t;
19 typedef struct _swf_doc_internal
34 typedef struct _character
42 typedef struct _placement
49 typedef struct _sprite
54 static void placement_free(placement_t*p)
56 swf_PlaceObjectFree(&p->po);
60 //---- object/depth handling ----
64 map16_t*map = rfx_calloc(sizeof(map16_t));
65 /* TODO: replace this by a more sophisticated data structure */
66 map->ids = (void**)rfx_calloc(sizeof(character_t)*65536);
69 character_t*map16_get_id(map16_t*map, int id)
75 void map16_free(map16_t*map)
79 void map16_add_id(map16_t*map, int nr, void*id)
82 fprintf(stderr, "Warning: ID %d defined more than once\n");
85 void map16_remove_id(map16_t*map, int nr)
89 void map16_enumerate(map16_t*map, void (*f)(void*self, int id, void*data), void*self)
92 for(t=0;t<65536;t++) {
94 f(self, t, map->ids[t]);
99 //---- bitmap handling ----
101 typedef struct _bitmap
107 bitmap_t* bitmap_new(RGBA*data, int width, int height)
109 bitmap_t* b = (bitmap_t*)rfx_calloc(sizeof(bitmap_t));
116 void bitmap_free(bitmap_t*b)
125 static map16_t* extractDefinitions(SWF*swf)
127 map16_t*map = map16_new();
128 TAG*tag = swf->firstTag;
132 if(swf_isDefiningTag(tag)) {
133 id = swf_GetDefineID(tag);
136 if(tag->id == ST_DEFINESPRITE) {
137 character_t*c = rfx_calloc(sizeof(character_t));
138 sprite_t*s = rfx_calloc(sizeof(sprite_t));
139 swf_SetTagPos(tag, 0);
140 swf_GetU16(tag); //id
141 s->frameCount = swf_GetU16(tag); //frameno
143 c->type = TYPE_SPRITE;
145 map16_add_id(map, id, c);
147 else if(tag->id == ST_DEFINESHAPE ||
148 tag->id == ST_DEFINESHAPE2 ||
149 tag->id == ST_DEFINESHAPE3) {
150 character_t*c = rfx_calloc(sizeof(character_t));
152 c->type = TYPE_SHAPE;
153 map16_add_id(map, id, c);
155 else if(tag->id == ST_DEFINEFONT ||
156 tag->id == ST_DEFINEFONT2) {
157 character_t*c = rfx_calloc(sizeof(character_t));
159 swf_FontExtract(swf, id, &font);
163 map16_add_id(map, id, c);
165 else if(tag->id == ST_DEFINEBITSJPEG ||
166 tag->id == ST_DEFINEBITSJPEG2 ||
167 tag->id == ST_DEFINEBITSJPEG3 ||
168 tag->id == ST_DEFINEBITSLOSSLESS ||
169 tag->id == ST_DEFINEBITSLOSSLESS2) {
170 character_t*c = rfx_calloc(sizeof(character_t));
172 void*data = swf_ExtractImage(tag, &width, &height);
173 bitmap_t*b = bitmap_new(data, width, height);
175 c->type = TYPE_BITMAP;
177 map16_add_id(map, id, c);
185 void swf_FreeTaglist(TAG*tag)
189 TAG * tnew = tag->next;
197 static void increaseAge(void*self, int id, void*data)
199 placement_t*p = (placement_t*)data;
203 static map16_t* extractFrame(TAG*startTag, int frame_to_extract)
205 map16_t*depthmap = map16_new();
209 for(;tag;tag = tag->next) {
210 if(tag->id == ST_END)
212 if(tag->id == ST_DEFINESPRITE) {
213 while(tag->id != ST_END)
217 if(tag->id == ST_PLACEOBJECT ||
218 tag->id == ST_PLACEOBJECT2) {
219 placement_t* p = rfx_calloc(sizeof(placement_t));
221 p->startFrame = frame;
222 swf_GetPlaceObject(tag, &p->po);
224 placement_t*old = (placement_t*)map16_get_id(depthmap, p->po.depth);
225 p->po.id = old->po.id;
226 map16_remove_id(depthmap, p->po.depth);
229 map16_add_id(depthmap, p->po.depth, p);
232 if(tag->id == ST_REMOVEOBJECT ||
233 tag->id == ST_REMOVEOBJECT2) {
234 U16 depth = swf_GetDepth(tag);
235 map16_remove_id(depthmap, depth);
237 if(tag->id == ST_SHOWFRAME || tag->id == ST_END) {
238 if(frame == frame_to_extract) {
241 if(tag->id == ST_SHOWFRAME) {
243 map16_enumerate(depthmap, increaseAge, 0);
247 fprintf(stderr, "gfxsource_swf: frame %d not found\n", frame_to_extract);
251 // ---- render handling ----
253 typedef struct _render
261 static void stopClippings(int from, render_t*r)
264 for(t=from;t<r->clips;t++)
265 r->device->endclip(r->device);
269 gfxline_t* swfline_to_gfxline(SHAPELINE*line, int linestyle, int fillstyle0)
274 gfxdrawer_target_gfxline(&d);
275 if(line->type != moveTo) {
276 fprintf(stderr, "Warning: Shape doesn't start with a moveTo\n");
279 if(line->fillstyle0 == fillstyle0 || line->fillstyle1 == fillstyle0 ||
280 line->linestyle == linestyle) {
281 if(line->type == lineTo) {
282 d.moveTo(&d, x/20.0,y/20.0);
283 d.lineTo(&d, line->x/20.0,line->y/20.0);
284 } else if(line->type == splineTo) {
285 d.moveTo(&d, x/20.0,y/20.0);
286 d.splineTo(&d, line->sx/20.0, line->sy/20.0, line->x/20.0,line->y/20.0);
297 void swf_ShapeApplyMatrix(SHAPE2*shape, MATRIX*m)
301 static void convertMatrix(MATRIX*from, gfxmatrix_t*to)
303 to->m00 = from->sx / 65536.0; to->m10 = from->r1 / 65536.0;
304 to->m01 = from->r0 / 65536.0; to->m11 = from->sy / 65536.0;
305 to->tx = from->tx/20.0;
306 to->ty = from->ty/20.0;
309 static void convertCXForm(CXFORM*from, gfxcxform_t*to)
311 memset(to, 0, sizeof(gfxcxform_t));
312 to->aa = from->a0 / 256.0;
313 to->rr = from->r0 / 256.0;
314 to->gg = from->g0 / 256.0;
315 to->bb = from->b0 / 256.0;
322 static gfxgradient_t* convertGradient(GRADIENT*from)
324 gfxgradient_t*g = rfx_calloc(from->num * sizeof(gfxgradient_t));
326 for(t=0;t<from->num;t++) {
327 g[t].pos = from->ratios[t] / 255.0;
328 g[t].color = *(gfxcolor_t*)&from->rgba[t];
337 gfximage_t* findimage(render_t*r)
342 static void renderFilled(render_t*r, gfxline_t*line, FILLSTYLE*f, CXFORM*cx)
344 if(f->type == FILL_SOLID) {
345 gfxcolor_t c = *(gfxcolor_t*)&f->color;
346 r->device->fill(r->device, line, &c);
347 } else if(f->type == FILL_TILED || f->type == FILL_CLIPPED) {
348 gfximage_t* img = findimage(r);
351 convertCXForm(cx, &gfxcx);
352 convertMatrix(&f->m, &m);
353 /* TODO: handle clipped */
354 r->device->fillbitmap(r->device, line, img, &m, &gfxcx);
355 } else if(f->type == FILL_LINEAR || f->type == FILL_RADIAL) {
358 convertMatrix(&f->m, &m);
359 g = convertGradient(&f->gradient);
360 r->device->fillgradient(r->device, line, g, f->type == FILL_LINEAR ? gfxgradient_linear : gfxgradient_radial, &m);
365 RGBA swf_ColorTransform(RGBA*color, CXFORM*cx)
368 dest.r = (cx->r0*color->r + cx->r1*256) >> 8;
369 dest.g = (cx->g0*color->g + cx->g1*256) >> 8;
370 dest.b = (cx->b0*color->b + cx->b1*256) >> 8;
371 dest.a = (cx->a0*color->a + cx->a1*256) >> 8;
375 void renderOutline(render_t*r, gfxline_t*line, LINESTYLE*l, CXFORM*cx)
377 RGBA c = swf_ColorTransform(&l->color, cx);
378 gfxcoord_t width = l->width/20.0;
379 r->device->stroke(r->device, line, width, (gfxcolor_t*)&c, gfx_capRound, gfx_joinRound, 0.0);
382 void swf_ApplyMatrixToShape(SHAPE2*shape, MATRIX*m)
384 SHAPELINE*line = shape->lines;
387 p.x = line->x; p.y = line->y;
388 p = swf_TurnPoint(p, m);
389 line->x = p.x; line->y = p.y;
394 static void renderCharacter(render_t*r, placement_t*p, character_t*c)
396 if(c->type == TYPE_SHAPE) {
398 swf_ParseDefineShape(c->tag, &shape);
400 swf_MatrixJoin(&m, &r->m, &p->po.matrix);
401 swf_ApplyMatrixToShape(&shape, &m);
402 SHAPELINE*line = shape.lines;
404 for(t=1;t<=shape.numfillstyles;t++) {
406 line = swfline_to_gfxline(shape.lines, -1, t);
408 if(!p->po.clipdepth) {
409 renderFilled(r, line, &shape.fillstyles[t-1], &p->po.cxform);
411 r->device->startclip(r->device, line);
416 /*line = swfline_to_gfxline(shape.lines, -1, -1, t);
417 if(line) renderFilled(r, line, &shape.fillstyles[t-1], &p->po.cxform);
418 gfxline_free(line);*/
420 for(t=1;t<=shape.numlinestyles;t++) {
421 gfxline_t*line = swfline_to_gfxline(shape.lines, t, -1);
422 if(line) renderOutline(r, line, &shape.linestyles[t-1], &p->po.cxform);
430 static void placeObject(void*self, int id, void*data)
432 render_t*r = (render_t*)self;
433 placement_t*p = (placement_t*)data;
434 character_t*c = map16_get_id(r->id2char, p->po.id);
436 fprintf(stderr, "Error: ID %d unknown\n", p->po.id);
438 if(c->type == TYPE_SPRITE) {
439 int oldclip = r->clips;
440 sprite_t* s = (sprite_t*)c->data;
441 map16_t* depths = extractFrame(c->tag, p->age % s->frameCount);
442 map16_enumerate(depths, placeObject, r);
443 stopClippings(oldclip, r);
446 renderCharacter(r, p, c);
449 void swfpage_destroy(gfxpage_t*swf_page)
451 swf_page_internal_t*i= (swf_page_internal_t*)swf_page->internal;
452 free(swf_page->internal);swf_page->internal = 0;
453 free(swf_page);swf_page=0;
456 void swfpage_render(gfxpage_t*page, gfxdevice_t*output)
458 swf_page_internal_t*i = (swf_page_internal_t*)page->internal;
459 swf_doc_internal_t*pi = (swf_doc_internal_t*)page->parent->internal;
460 map16_t* depths = extractFrame(pi->swf.firstTag, i->frame);
462 r.id2char = pi->id2char;
466 map16_enumerate(depths, placeObject, &r);
469 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)
471 swf_doc_internal_t*pi = (swf_doc_internal_t*)page->parent->internal;
473 swfpage_render(page,output);
476 void swf_doc_destroy(gfxdocument_t*gfx)
478 swf_doc_internal_t*i= (swf_doc_internal_t*)gfx->internal;
479 swf_FreeTags(&i->swf);
480 free(gfx->internal);gfx->internal=0;
484 void swf_doc_set_parameter(gfxdocument_t*gfx, char*name, char*value)
486 swf_doc_internal_t*i= (swf_doc_internal_t*)gfx->internal;
489 gfxpage_t* swf_doc_getpage(gfxdocument_t*doc, int page)
491 swf_doc_internal_t*di= (swf_doc_internal_t*)doc->internal;
492 if(page < 1 || page > doc->num_pages)
495 gfxpage_t* swf_page = (gfxpage_t*)malloc(sizeof(gfxpage_t));
496 swf_page_internal_t*pi= (swf_page_internal_t*)malloc(sizeof(swf_page_internal_t));
497 memset(pi, 0, sizeof(swf_page_internal_t));
501 swf_page->internal = pi;
502 swf_page->destroy = swfpage_destroy;
503 swf_page->render = swfpage_render;
504 swf_page->rendersection = swfpage_rendersection;
505 swf_page->width = di->width;
506 swf_page->height = di->height;
507 swf_page->parent = doc;
512 void swf_set_parameter(char*name, char*value)
514 msg("<verbose> setting parameter %s to \"%s\"", name, value);
517 gfxdocument_t*swf_open(char*filename)
519 gfxdocument_t*swf_doc = (gfxdocument_t*)malloc(sizeof(gfxdocument_t));
520 memset(swf_doc, 0, sizeof(gfxdocument_t));
521 swf_doc_internal_t*i= (swf_doc_internal_t*)malloc(sizeof(swf_doc_internal_t));
522 memset(i, 0, sizeof(swf_doc_internal_t));
533 f = open(filename,O_RDONLY|O_BINARY);
535 perror("Couldn't open file: ");
538 if FAILED(swf_ReadSWF(f,&i->swf)) {
539 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
543 swf_UnFoldAll(&i->swf);
545 i->id2char = extractDefinitions(&i->swf);
546 i->width = (i->swf.movieSize.xmax - i->swf.movieSize.xmin) / 20;
547 i->height = (i->swf.movieSize.ymax - i->swf.movieSize.ymin) / 20;
549 swf_GetMatrix(0, &i->m);
550 i->m.tx = -i->swf.movieSize.xmin;
551 i->m.ty = -i->swf.movieSize.ymin;
553 swf_doc->num_pages = i->swf.frameCount;
554 swf_doc->internal = i;
556 swf_doc->destroy = swf_doc_destroy;
557 swf_doc->set_parameter = swf_doc_set_parameter;
558 swf_doc->getpage = swf_doc_getpage;
563 gfxsource_t*gfxsource_swf_create()
565 gfxsource_t*src = (gfxsource_t*)malloc(sizeof(gfxsource_t));
566 memset(src, 0, sizeof(gfxsource_t));
567 src->set_parameter = swf_set_parameter;
568 src->open = swf_open;