📄 swf_shape.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / Scene Management sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/nodes_mpeg4.h>#include <gpac/utf.h>#include <gpac/internal/swf_dev.h>#ifndef GPAC_READ_ONLYSFColor get_bifs_col(u32 ARGB){ SFColor val; val.red = INT2FIX((ARGB>>16)&0xFF) / 255; val.green = INT2FIX((ARGB>>8)&0xFF) / 255; val.blue = INT2FIX((ARGB)&0xFF) / 255; return val;}Fixed get_bifs_alpha(u32 ARGB){ return INT2FIX((ARGB>>24)&0xFF) / 255;}void SWF_InsertAppearance(SWFReader *read, GF_Node *app){ M_Shape *s = (M_Shape *) SWF_NewNode(read, TAG_MPEG4_Shape); s->appearance = app; gf_node_register(app, (GF_Node *) s); SWF_InsertNode(read, (GF_Node *)s);}Bool col_equal(SFColor c1, SFColor c2){ if (c1.red != c2.red) return 0; if (c1.green != c2.green) return 0; if (c1.blue != c2.blue) return 0; return 1;}GF_Node *SWF_GetAppearance(SWFReader *read, GF_Node *parent, u32 fill_col, Fixed line_width, u32 l_col){ char szDEF[1024]; u32 ID, i; SFColor fc, lc; Fixed fill_transp, line_transp; M_Appearance *app; M_Material2D *mat; fc = get_bifs_col(fill_col); fill_transp = FIX_ONE - get_bifs_alpha(fill_col); if (fill_transp<0) fill_transp=0; lc = get_bifs_col(l_col); line_transp = FIX_ONE - get_bifs_alpha(l_col); if (line_transp<0) line_transp=0; i=0; while ((app = (M_Appearance*)gf_list_enum(read->apps, &i))) { mat = (M_Material2D *)app->material; if (!line_width) { if (mat->lineProps || !mat->filled) continue; } else { if (!mat->lineProps) continue; if (!col_equal(((M_LineProperties *)mat->lineProps)->lineColor, lc)) continue; if (((M_LineProperties *)mat->lineProps)->width != line_width) continue; } if (!mat->filled && fill_col) continue; if (mat->filled) { if (!fill_col) continue; if (mat->transparency != fill_transp) continue; if (!col_equal(mat->emissiveColor, fc)) continue; } /*OK same appearance let's go*/ gf_node_register((GF_Node *)app, parent); return (GF_Node *)app; } app = (M_Appearance *) SWF_NewNode(read, TAG_MPEG4_Appearance); app->material = SWF_NewNode(read, TAG_MPEG4_Material2D); gf_node_register(app->material, (GF_Node *)app); ((M_Material2D *)app->material)->filled = 0; if (fill_col) { ((M_Material2D *)app->material)->filled = 1; ((M_Material2D *)app->material)->emissiveColor = fc; ((M_Material2D *)app->material)->transparency = fill_transp; } if (line_width && l_col) { if (read->flags & GF_SM_SWF_SCALABLE_LINE) { M_XLineProperties *lp = (M_XLineProperties *) SWF_NewNode(read, TAG_MPEG4_XLineProperties); ((M_Material2D *)app->material)->lineProps = (GF_Node *) lp; lp->width = line_width; lp->lineColor = lc; lp->isScalable = 1; lp->transparency = line_transp; gf_node_register((GF_Node *)lp, app->material); } else { M_LineProperties *lp = (M_LineProperties *) SWF_NewNode(read, TAG_MPEG4_LineProperties); ((M_Material2D *)app->material)->lineProps = (GF_Node *) lp; lp->width = line_width; lp->lineColor = lc; gf_node_register((GF_Node *)lp, app->material); } } gf_node_register((GF_Node *)app, parent); if (read->load->swf_import_flags & GF_SM_SWF_REUSE_APPEARANCE) { sprintf(szDEF, "FILLAPP_%d", gf_list_count(read->apps)); read->load->ctx->max_node_id++; ID = read->load->ctx->max_node_id; gf_node_set_id((GF_Node *)app, ID, szDEF); SWF_InsertAppearance(read, (GF_Node *)app); gf_list_add(read->apps, app); } return (GF_Node *) app;}GF_Rect SWF_GetCenteredBounds(SWFShapeRec *srec){ GF_Rect rc; u32 i; Fixed xm, ym, xM, yM; xM = yM = FIX_MIN; xm = ym = FIX_MAX; for (i=0; i<srec->path->nbPts; i++) { if (srec->path->pts[i].x<=xm) xm = srec->path->pts[i].x; if (srec->path->pts[i].x>=xM) xM = srec->path->pts[i].x; if (srec->path->pts[i].y<=ym) ym = srec->path->pts[i].y; if (srec->path->pts[i].y>=yM) yM = srec->path->pts[i].y; } rc.width = xM-xm; rc.height = yM-ym; rc.x = xm + rc.width/2; rc.y = ym + rc.height/2; return rc;}GF_Node *SWF_GetGradient(SWFReader *read, GF_Node *parent, SWFShapeRec *srec){ Bool is_radial, has_alpha; GF_Rect rc; GF_Matrix2D mx; u32 i; MFFloat *keys; MFColor *values; GF_FieldInfo info; M_Appearance *app = (M_Appearance *) SWF_NewNode(read, TAG_MPEG4_Appearance); gf_node_register((GF_Node *)app, parent); app->material = SWF_NewNode(read, TAG_MPEG4_Material2D); gf_node_register(app->material, (GF_Node *)app); ((M_Material2D *)app->material)->filled = 1; is_radial = (srec->type==0x12) ? 1 : 0; app->texture = SWF_NewNode(read, is_radial ? TAG_MPEG4_RadialGradient : TAG_MPEG4_LinearGradient); gf_node_register((GF_Node *) app->texture, (GF_Node *) app); /*set keys*/ gf_node_get_field_by_name(app->texture, "key", &info); gf_sg_vrml_mf_alloc(info.far_ptr, info.fieldType, srec->nbGrad); keys = (MFFloat *)info.far_ptr; for (i=0; i<srec->nbGrad; i++) { keys->vals[i] = srec->grad_ratio[i]; keys->vals[i] /= 255; } /*set colors*/ gf_node_get_field_by_name(app->texture, "keyValue", &info); gf_sg_vrml_mf_alloc(info.far_ptr, info.fieldType, srec->nbGrad); values = (MFColor *)info.far_ptr; has_alpha = 0; for (i=0; i<srec->nbGrad; i++) { values->vals[i] = get_bifs_col(srec->grad_col[i]); if (get_bifs_alpha(srec->grad_col[i]) != FIX_ONE) has_alpha = 1; } /*set opacity*/ if (has_alpha) { gf_node_get_field_by_name(app->texture, "opacity", &info); gf_sg_vrml_mf_alloc(info.far_ptr, info.fieldType, srec->nbGrad); keys = (MFFloat *)info.far_ptr; for (i=0; i<srec->nbGrad; i++) { keys->vals[i] = get_bifs_alpha(srec->grad_col[i]); } /*and remove material !!*/ ((M_Material2D *)app->material)->filled = 0; ((M_Material2D *)app->material)->lineProps = SWF_NewNode(read, TAG_MPEG4_LineProperties);; ((M_LineProperties *)((M_Material2D *)app->material)->lineProps)->width = 0; gf_node_register(((M_Material2D *)app->material)->lineProps, app->material); } /* FIXME - THIS IS WRONG, don't have time to investigate how to map gradients into (u, v) space */ /*get bounds in local coord system*/ rc = SWF_GetCenteredBounds(srec); /*remove positioning*/ srec->mat.m[2] -= rc.x; srec->mat.m[5] -= rc.y; /*set positioning in TEX coords (0,1) and not shape coords*/ srec->mat.m[2] = gf_divfix(srec->mat.m[2] , rc.width); srec->mat.m[5] = gf_divfix(srec->mat.m[5], rc.height); /*remove gradient square to local shape scaling*/ gf_mx2d_init(mx); gf_mx2d_add_scale(&mx, gf_divfix(INT2FIX(32768), rc.width), gf_divfix(INT2FIX(32768), rc.height) ); gf_mx2d_add_matrix(&mx, &srec->mat); /*adjust center for radial gradient*/ if (rc.width > rc.height) { Fixed ar = gf_divfix(rc.width, rc.height); mx.m[5] += (FIX_ONE-ar)/2; } else { Fixed ar = gf_divfix(rc.height,rc.width); mx.m[2] += (FIX_ONE-ar)/2; } gf_node_get_field_by_name(app->texture, "spreadMethod", &info); *((SFInt32*)info.far_ptr) = 1; gf_node_get_field_by_name(app->texture, "transform", &info); *((GF_Node **)info.far_ptr) = SWF_GetBIFSMatrix(read, &mx); gf_node_register(*((GF_Node **)info.far_ptr), app->texture); return (GF_Node *) app;}void SWFShape_SetAppearance(SWFReader *read, SWFShape *shape, M_Shape *n, SWFShapeRec *srec, Bool is_fill){ /*get regular appearance reuse*/ if (is_fill) { switch (srec->type) { /*solid/alpha fill*/ case 0x00: n->appearance = SWF_GetAppearance(read, (GF_Node *) n, srec->solid_col, 0, 0); break; case 0x10: case 0x12: if (read->flags & GF_SM_SWF_NO_GRADIENT) { u32 col = srec->grad_col[srec->nbGrad/2]; col |= 0xFF000000; n->appearance = SWF_GetAppearance(read, (GF_Node *) n, col, 0, 0); } else { n->appearance = SWF_GetGradient(read, (GF_Node *) n, srec); } break; default: swf_report(read, GF_NOT_SUPPORTED, "Bitmap fill_style not supported"); break; } } else { n->appearance = SWF_GetAppearance(read, (GF_Node *) n, 0, srec->width, srec->solid_col); }}/*translate a flash sub shape with only one path (eg one looking style) to a BIFS Shape node*/GF_Node *SWFShapeToCurve2D(SWFReader *read, SWFShape *shape, SWFShapeRec *srec, Bool is_fill){ u32 pt_idx, i; Bool use_xcurve; void *fptr; SFVec2f ct1, ct2, ct, pt, move_orig; M_Curve2D *curve; M_Coordinate2D *points; M_Shape *n = (M_Shape *) SWF_NewNode(read, TAG_MPEG4_Shape); SWFShape_SetAppearance(read, shape, n, srec, is_fill); use_xcurve = (read->flags & GF_SM_SWF_QUAD_CURVE) ? 1 : 0; if (use_xcurve) { curve = (M_Curve2D *) SWF_NewNode(read, TAG_MPEG4_XCurve2D); } else { curve = (M_Curve2D *) SWF_NewNode(read, TAG_MPEG4_Curve2D); } points = (M_Coordinate2D *) SWF_NewNode(read, TAG_MPEG4_Coordinate2D); n->geometry = (GF_Node *) curve; gf_node_register((GF_Node *) curve, (GF_Node *)n); curve->point = (GF_Node *) points; gf_node_register((GF_Node *) points, (GF_Node *) curve); curve->fineness = FIX_ONE; assert(srec->path->nbType); pt_idx = 0; for (i=0; i<srec->path->nbType; i++) { switch (srec->path->types[i]) { /*moveTo*/ case 0: /*first moveTo implicit in BIFS*/ if (i) { gf_sg_vrml_mf_append(&curve->type, GF_SG_VRML_MFINT32, &fptr); *((SFInt32 *)fptr) = 0; } gf_sg_vrml_mf_append(&points->point, GF_SG_VRML_MFVEC2F, &fptr); ((SFVec2f *)fptr)->x = srec->path->pts[pt_idx].x; ((SFVec2f *)fptr)->y = srec->path->pts[pt_idx].y; move_orig = srec->path->pts[pt_idx]; pt_idx++; break; /*lineTo*/ case 1: gf_sg_vrml_mf_append(&curve->type, GF_SG_VRML_MFINT32, &fptr); *((SFInt32 *)fptr) = 1; gf_sg_vrml_mf_append(&points->point, GF_SG_VRML_MFVEC2F, &fptr); ((SFVec2f *)fptr)->x = srec->path->pts[pt_idx].x; ((SFVec2f *)fptr)->y = srec->path->pts[pt_idx].y; pt_idx++; break; /*curveTo*/ case 2: /*XCurve2D has quad arcs*/ if (use_xcurve) { gf_sg_vrml_mf_append(&curve->type, GF_SG_VRML_MFINT32, &fptr); *((SFInt32 *)fptr) = 7; gf_sg_vrml_mf_append(&points->point, GF_SG_VRML_MFVEC2F, &fptr); ((SFVec2f *)fptr)->x = srec->path->pts[pt_idx].x; ((SFVec2f *)fptr)->y = srec->path->pts[pt_idx].y; gf_sg_vrml_mf_append(&points->point, GF_SG_VRML_MFVEC2F, &fptr); ((SFVec2f *)fptr)->x = srec->path->pts[pt_idx+1].x; ((SFVec2f *)fptr)->y = srec->path->pts[pt_idx+1].y; pt_idx+=2; } else { gf_sg_vrml_mf_append(&curve->type, GF_SG_VRML_MFINT32, &fptr); *((SFInt32 *)fptr) = 2; /*recompute cubic from quad*/ ct.x = srec->path->pts[pt_idx].x; ct.y = srec->path->pts[pt_idx].y; pt.x = srec->path->pts[pt_idx-1].x; pt.y = srec->path->pts[pt_idx-1].y; ct1.x = pt.x + 2*(ct.x - pt.x)/3; ct1.y = pt.y + 2*(ct.y - pt.y)/3; ct.x = srec->path->pts[pt_idx+1].x; ct.y = srec->path->pts[pt_idx+1].y; ct2.x = ct1.x + (ct.x - pt.x) / 3; ct2.y = ct1.y + (ct.y - pt.y) / 3; gf_sg_vrml_mf_append(&points->point, GF_SG_VRML_MFVEC2F, &fptr); ((SFVec2f *)fptr)->x = ct1.x; ((SFVec2f *)fptr)->y = ct1.y; gf_sg_vrml_mf_append(&points->point, GF_SG_VRML_MFVEC2F, &fptr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -