static void VS2D_DrawGradient(VisualSurface2D *surf, GF_Path *path, GF_TextureHandler *txh, struct _drawable_context *ctx) { GF_Rect rc; GF_Matrix2D g_mat, txt_mat; GF_Raster2D *r2d = surf->render->compositor->r2d; if (!txh) txh = ctx->h_texture; gf_path_get_bounds(path, &rc); if (!rc.width || !rc.height || !txh->hwtx) return; txh->compute_gradient_matrix(txh, &rc, &g_mat); if (ctx->flags & CTX_HAS_APPEARANCE) { get_gf_sr_texture_transform(ctx->appear, txh, &txt_mat, (txh == ctx->h_texture) ? 0 : 1, INT2FIX(txh->width), INT2FIX(txh->height)); gf_mx2d_add_matrix(&g_mat, &txt_mat); } gf_mx2d_add_matrix(&g_mat, &ctx->transform); r2d->stencil_set_matrix(txh->hwtx, &g_mat); r2d->stencil_set_color_matrix(txh->hwtx, ctx->col_mat); r2d->surface_set_matrix(surf->the_surface, &ctx->transform); r2d->surface_set_path(surf->the_surface, path); VS2D_DoFill(surf, ctx, txh->hwtx); r2d->surface_set_path(surf->the_surface, NULL); ctx->flags |= CTX_PATH_FILLED; }
GF_Err evg_surface_set_path(GF_SURFACE _this, GF_Path *gp) { #ifndef INLINE_POINT_CONVERSION u32 i; GF_Point2D pt; #endif EVGSurface *surf = (EVGSurface *)_this; if (!surf) return GF_BAD_PARAM; if (!gp || !gp->n_points) { surf->ftoutline.n_points = 0; surf->ftoutline.n_contours = 0; return GF_OK; } gf_path_flatten(gp); surf->ftoutline.n_points = gp->n_points; surf->ftoutline.n_contours = gp->n_contours; surf->ftoutline.tags = gp->tags; surf->ftoutline.contours = (s32*) gp->contours; /*store path bounds for gradient/textures*/ gf_path_get_bounds(gp, &surf->path_bounds); /*invert Y (ft uses min Y)*/ surf->path_bounds.y -= surf->path_bounds.height; surf->ftoutline.flags = 0; if (gp->flags & GF_PATH_FILL_ZERO_NONZERO) surf->ftoutline.flags = GF_PATH_FILL_ZERO_NONZERO; #ifdef INLINE_POINT_CONVERSION surf->ftoutline.n_points = gp->n_points; surf->ftoutline.points = gp->points; surf->ftparams.mx = &surf->mat; #else if (surf->pointlen < gp->n_points) { surf->points = gf_realloc(surf->points, sizeof(EVG_Vector) * gp->n_points); if (surf->points == NULL) { surf->pointlen = 0; return GF_OUT_OF_MEM; } surf->pointlen = gp->n_points; } surf->ftoutline.points = surf->points; for (i=0; i<gp->n_points; i++) { pt = gp->points[i]; gf_mx2d_apply_point(&surf->mat, &pt); #ifdef GPAC_FIXED_POINT surf->points[i].x = pt.x; surf->points[i].y = pt.y; #else /*move to 16.16 representation*/ surf->points[i].x = (u32) (pt.x * 0x10000L); surf->points[i].y = (u32) (pt.y * 0x10000L); #endif } #endif return GF_OK; }
static void TraverseILS2D(GF_Node *node, void *rs, Bool is_destroy) { DrawableContext *ctx; M_IndexedLineSet2D *ils2D = (M_IndexedLineSet2D *)node; Drawable *stack = (Drawable *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { drawable_node_del(node); return; } if (!ils2D->coord) return; ils2d_check_changes(node, stack, tr_state); switch (tr_state->traversing_mode) { case TRAVERSE_DRAW_2D: ILS2D_Draw(node, tr_state); return; #ifndef GPAC_DISABLE_3D case TRAVERSE_DRAW_3D: if (!stack->mesh) { stack->mesh = new_mesh(); mesh_new_ils(stack->mesh, ils2D->coord, &ils2D->coordIndex, ils2D->color, &ils2D->colorIndex, ils2D->colorPerVertex, 0); } if (ils2D->color) { DrawAspect2D asp; memset(&asp, 0, sizeof(DrawAspect2D)); drawable_get_aspect_2d_mpeg4(node, &asp, tr_state); visual_3d_mesh_strike(tr_state, stack->mesh, asp.pen_props.width, asp.line_scale, asp.pen_props.dash); } else { visual_3d_draw_2d(stack, tr_state); } return; #endif case TRAVERSE_PICK: vrml_drawable_pick(stack, tr_state); return; case TRAVERSE_GET_BOUNDS: gf_path_get_bounds(stack->path, &tr_state->bounds); return; case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) return; #endif ctx = drawable_init_context_mpeg4(stack, tr_state); if (!ctx) return; /*ILS2D are NEVER filled*/ ctx->aspect.fill_color &= 0x00FFFFFF; drawable_finalize_sort(ctx, tr_state, NULL); return; default: return; } }
static void TraversePointSet2D(GF_Node *node, void *rs, Bool is_destroy) { DrawableContext *ctx; M_PointSet2D *ps2D = (M_PointSet2D *)node; Drawable *stack = (Drawable *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { drawable_node_del(node); return; } if (!ps2D->coord) return; pointset2d_check_changes(node, stack, tr_state); switch (tr_state->traversing_mode) { case TRAVERSE_DRAW_2D: PointSet2D_Draw(node, tr_state); return; #ifndef GPAC_DISABLE_3D case TRAVERSE_DRAW_3D: { DrawAspect2D asp; if (!stack->mesh) { stack->mesh = new_mesh(); mesh_new_ps(stack->mesh, ps2D->coord, ps2D->color); } memset(&asp, 0, sizeof(DrawAspect2D)); drawable_get_aspect_2d_mpeg4(node, &asp, tr_state); visual_3d_set_material_2d_argb(tr_state->visual, asp.fill_color); visual_3d_mesh_paint(tr_state, stack->mesh); return; } #endif case TRAVERSE_GET_BOUNDS: gf_path_get_bounds(stack->path, &tr_state->bounds); return; case TRAVERSE_PICK: return; case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) return; #endif ctx = drawable_init_context_mpeg4(stack, tr_state); if (!ctx) return; drawable_finalize_sort(ctx, tr_state, NULL); break; default: return; } }
static void visual_2d_draw_gradient(GF_VisualManager *visual, GF_Path *path, GF_TextureHandler *txh, struct _drawable_context *ctx, GF_TraverseState *tr_state, GF_Matrix2D *ext_mx, GF_Rect *orig_bounds) { GF_Rect rc; GF_STENCIL stencil; GF_Matrix2D g_mat; GF_Raster2D *raster = visual->compositor->rasterizer; if (!txh) txh = ctx->aspect.fill_texture; gf_path_get_bounds(path, &rc); if (!rc.width || !rc.height || !txh->tx_io) return; if (orig_bounds) { txh->compute_gradient_matrix(txh, orig_bounds, &g_mat, 0); } else { txh->compute_gradient_matrix(txh, &rc, &g_mat, 0); } stencil = gf_sc_texture_get_stencil(txh); if (!stencil) return; #ifndef GPAC_DISABLE_VRML if (ctx->flags & CTX_HAS_APPEARANCE) { GF_Matrix2D txt_mat; visual_2d_get_texture_transform(ctx->appear, txh, &txt_mat, (txh == ctx->aspect.fill_texture) ? 0 : 1, INT2FIX(txh->width), INT2FIX(txh->height)); gf_mx2d_add_matrix(&g_mat, &txt_mat); } #endif /*move to bottom-left corner of bounds */ if (ext_mx) gf_mx2d_add_matrix(&g_mat, ext_mx); if (orig_bounds) gf_mx2d_add_translation(&g_mat, (orig_bounds->x), (orig_bounds->y - orig_bounds->height)); gf_mx2d_add_matrix(&g_mat, &ctx->transform); raster->stencil_set_matrix(stencil, &g_mat); raster->stencil_set_color_matrix(stencil, ctx->col_mat); /*MPEG-4/VRML context or no fill info*/ if (ctx->flags & CTX_HAS_APPEARANCE || !ctx->aspect.fill_color) raster->stencil_set_alpha(stencil, 0xFF); else raster->stencil_set_alpha(stencil, GF_COL_A(ctx->aspect.fill_color) ); raster->surface_set_matrix(visual->raster_surface, &ctx->transform); txh->flags |= GF_SR_TEXTURE_USED; raster->surface_set_path(visual->raster_surface, path); visual_2d_fill_path(visual, ctx, stencil, tr_state, 0); raster->surface_set_path(visual->raster_surface, NULL); ctx->flags |= CTX_PATH_FILLED; }
static void TraverseArc2D(GF_Node *node, void *rs, Bool is_destroy) { DrawableContext *ctx; Drawable *stack = (Drawable *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { drawable_node_del(node); return; } arc2d_check_changes(node, stack, tr_state); switch (tr_state->traversing_mode) { #ifndef GPAC_DISABLE_3D case TRAVERSE_DRAW_3D: if (!stack->mesh) { stack->mesh = new_mesh(); if (gf_node_get_tag(node)==TAG_X3D_Arc2D) { mesh_get_outline(stack->mesh, stack->path); } else { mesh_from_path(stack->mesh, stack->path); } } visual_3d_draw_2d(stack, tr_state); return; #endif case TRAVERSE_GET_BOUNDS: gf_path_get_bounds(stack->path, &tr_state->bounds); #ifndef GPAC_DISABLE_3D gf_bbox_from_rect(&tr_state->bbox, &tr_state->bounds); #endif return; case TRAVERSE_PICK: vrml_drawable_pick(stack, tr_state); return; case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) return; #endif ctx = drawable_init_context_mpeg4(stack, tr_state); if (!ctx) return; drawable_finalize_sort(ctx, tr_state, NULL); return; } }
static void TraverseIndexedCurve2D(GF_Node *node, void *rs, Bool is_destroy) { DrawableContext *ctx; IndexedCurve2D ic2d; GF_TraverseState *tr_state = (GF_TraverseState *)rs; Drawable *stack = (Drawable *)gf_node_get_private(node); if (is_destroy) { drawable_node_del(node); return; } if (gf_node_dirty_get(node)) { if (!IndexedCurve2D_GetNode(node, &ic2d)) return; curve2d_check_changes((GF_Node*) &ic2d, stack, tr_state, &ic2d.index); } switch (tr_state->traversing_mode) { #ifndef GPAC_DISABLE_3D case TRAVERSE_DRAW_3D: if (!stack->mesh) { stack->mesh = new_mesh(); mesh_from_path(stack->mesh, stack->path); } visual_3d_draw_2d(stack, tr_state); return; #endif case TRAVERSE_PICK: vrml_drawable_pick(stack, tr_state); return; case TRAVERSE_GET_BOUNDS: gf_path_get_bounds(stack->path, &tr_state->bounds); return; case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) return; #endif ctx = drawable_init_context_mpeg4(stack, tr_state); if (!ctx) return; drawable_finalize_sort(ctx, tr_state, NULL); return; } }
static void svg_sani_DrawablePostRender(Drawable *cs, SVG_SANI_TransformableElement *elt, RenderEffect2D *eff, Bool rectangular, Fixed path_length) { GF_FieldInfo info; GF_Matrix2D backup_matrix; DrawableContext *ctx; if (eff->traversing_mode == TRAVERSE_GET_BOUNDS) { gf_node_get_field_by_name(cs->node, "display", &info); if (*(SVG_Display *)info.far_ptr == SVG_DISPLAY_NONE) gf_path_get_bounds(cs->path, &eff->bounds); return; } gf_node_get_field_by_name(cs->node, "display", &info); if (*(SVG_Display *)info.far_ptr == SVG_DISPLAY_NONE) return; gf_node_get_field_by_name(cs->node, "visibility", &info); if (*(SVG_Visibility *)info.far_ptr == SVG_VISIBILITY_HIDDEN) return; gf_svg_sani_apply_local_transformation(eff, (GF_Node *)elt, &backup_matrix); gf_node_get_field_by_name(cs->node, "fill-rule", &info); if (*(SVG_FillRule *)info.far_ptr == SVG_FILLRULE_NONZERO) cs->path->flags |= GF_PATH_FILL_ZERO_NONZERO; else cs->path->flags &= ~GF_PATH_FILL_ZERO_NONZERO; ctx = svg_sani_drawable_init_context(cs, eff); if (ctx) { if (rectangular) { if (ctx->h_texture && ctx->h_texture->transparent) {} else if (GF_COL_A(ctx->aspect.fill_color) != 0xFF) {} else if (ctx->transform.m[1] || ctx->transform.m[3]) {} else { ctx->flags &= ~CTX_IS_TRANSPARENT; } } if (path_length) ctx->aspect.pen_props.path_length = path_length; drawable_finalize_render(ctx, eff, NULL); } gf_svg_sani_restore_parent_transformation(eff, &backup_matrix); }
static void compositor_2d_draw_rectangle(GF_TraverseState *tr_state) { DrawableContext *ctx = tr_state->ctx; if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->data #ifndef GPAC_DISABLE_3D && !tr_state->visual->compositor->hybrid_opengl #endif ) { Bool res; /*get image size WITHOUT line size or antialias margin*/ if ( !(ctx->flags & CTX_NO_ANTIALIAS) ) { GF_Rect orig_unclip; GF_IRect orig_clip; orig_unclip = ctx->bi->unclip; orig_clip = ctx->bi->clip; gf_path_get_bounds(ctx->drawable->path, &ctx->bi->unclip); gf_mx2d_apply_rect(&ctx->transform, &ctx->bi->unclip); ctx->bi->clip = gf_rect_pixelize(&ctx->bi->unclip); gf_irect_intersect(&ctx->bi->clip, &orig_clip); res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL); /*strike path*/ ctx->bi->unclip = orig_unclip; ctx->bi->clip = orig_clip; if (res) { ctx->flags |= CTX_PATH_FILLED; visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); } } else { res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL); } /*if failure retry with raster*/ if (res) return; } visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); }
static void TraverseCircle(GF_Node *node, void *rs, Bool is_destroy) { DrawableContext *ctx; Drawable *stack = (Drawable *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { drawable_node_del(node); return; } circle_check_changes(node, stack, tr_state); switch (tr_state->traversing_mode) { #ifndef GPAC_DISABLE_3D case TRAVERSE_DRAW_3D: if (!stack->mesh) { Fixed a = ((M_Circle *) node)->radius * 2; stack->mesh = new_mesh(); mesh_new_ellipse(stack->mesh, a, a, tr_state->visual->compositor->high_speed); } visual_3d_draw_2d(stack, tr_state); return; #endif case TRAVERSE_GET_BOUNDS: gf_path_get_bounds(stack->path, &tr_state->bounds); return; case TRAVERSE_PICK: vrml_drawable_pick(stack, tr_state); return; case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) return; #endif ctx = drawable_init_context_mpeg4(stack, tr_state); if (!ctx) return; drawable_finalize_sort(ctx, tr_state, NULL); return; } }
static void TraverseDisk2D(GF_Node *node, void *rs, Bool is_destroy) { DrawableContext *ctx; Drawable *stack = (Drawable *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { drawable_node_del(node); return; } disk2d_check_changes(node, stack, tr_state); switch (tr_state->traversing_mode) { #ifndef GPAC_DISABLE_3D case TRAVERSE_DRAW_3D: if (!stack->mesh) { stack->mesh = new_mesh(); /*FIXME - enable it with OpenGL-ES*/ mesh_from_path(stack->mesh, stack->path); } visual_3d_draw_2d(stack, tr_state); return; #endif case TRAVERSE_GET_BOUNDS: gf_path_get_bounds(stack->path, &tr_state->bounds); return; case TRAVERSE_PICK: vrml_drawable_pick(stack, tr_state); return; case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) return; #endif ctx = drawable_init_context_mpeg4(stack, tr_state); if (!ctx) return; drawable_finalize_sort(ctx, tr_state, NULL); return; } }
void visual_2d_texture_path_extended(GF_VisualManager *visual, GF_Path *path, GF_TextureHandler *txh, struct _drawable_context *ctx, GF_Rect *orig_bounds, GF_Matrix2D *ext_mx, GF_TraverseState *tr_state) { Fixed sS, sT; u32 tx_tile; GF_STENCIL tx_raster; GF_Matrix2D mx_texture; GF_Rect orig_rc; GF_Raster2D *raster; if (! visual->CheckAttached(visual) ) return; raster = visual->compositor->rasterizer; if (!txh) txh = ctx->aspect.fill_texture; if (!txh) return; if (!txh->tx_io) { gf_node_dirty_set(txh->owner, 0, 1); txh->needs_refresh=1; return; } /*this is gradient draw*/ if (txh->compute_gradient_matrix) { visual_2d_draw_gradient(visual, path, txh, ctx, tr_state, ext_mx, orig_bounds); return; } #ifndef GPAC_DISABLE_3D if (visual->compositor->hybrid_opengl) { visual_2d_texture_path_opengl_auto(visual, path, txh, ctx, orig_bounds, ext_mx, tr_state); return; } #endif if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) { GF_Window src, dst; visual_2d_fill_path(visual, ctx, NULL, tr_state, 0); /*if texture not ready, update the size before computing output rectangles */ if (!txh->width || !txh->height) { gf_mo_get_visual_info(txh->stream, &txh->width, &txh->height, &txh->stride, &txh->pixel_ar, &txh->pixelformat, &txh->is_flipped); /*in case the node is an MPEG-4 bitmap, force stack rebuild at next frame */ gf_node_dirty_set(ctx->drawable->node, GF_SG_NODE_DIRTY, 1); } if (compositor_texture_rectangles(visual, txh, &ctx->bi->clip, &ctx->bi->unclip, &src, &dst, NULL, NULL)) { if (txh->stream && gf_mo_set_position(txh->stream, &src, &dst)) { gf_mo_get_visual_info(txh->stream, &txh->width, &txh->height, &txh->stride, &txh->pixel_ar, &txh->pixelformat, &txh->is_flipped); /*force dirty flag to get called again*/ gf_node_dirty_set(ctx->drawable->node, GF_SG_NODE_DIRTY, 1); gf_sc_next_frame_state(visual->compositor, GF_SC_DRAW_FRAME); } } return; } if (!gf_sc_texture_push_image(txh, 0, 1)) return; tx_raster = gf_sc_texture_get_stencil(txh); /*setup quality even for background (since quality concerns images)*/ visual_2d_set_options(visual->compositor, visual->raster_surface, ctx->flags & CTX_IS_TEXT, ctx->flags & CTX_NO_ANTIALIAS); /*get original bounds*/ if (orig_bounds) { orig_rc = *orig_bounds; } else { gf_path_get_bounds(path, &orig_rc); } /*get scaling ratio so that active texture view is stretched to original bounds (std 2D shape texture mapping in MPEG4)*/ sS = orig_rc.width / txh->width; sT = orig_rc.height / txh->height; gf_mx2d_init(mx_texture); gf_mx2d_add_scale(&mx_texture, sS, sT); #ifndef GPAC_DISABLE_VRML /*apply texture transform*/ if (ctx->flags & CTX_HAS_APPEARANCE) { GF_Matrix2D tex_trans; visual_2d_get_texture_transform(ctx->appear, txh, &tex_trans, (txh == ctx->aspect.fill_texture) ? 0 : 1, txh->width * sS, txh->height * sT); gf_mx2d_add_matrix(&mx_texture, &tex_trans); } #endif /*move to bottom-left corner of bounds */ gf_mx2d_add_translation(&mx_texture, (orig_rc.x), (orig_rc.y - orig_rc.height)); if (ext_mx) gf_mx2d_add_matrix(&mx_texture, ext_mx); /*move to final coordinate system (except background which is built directly in final coord system)*/ if (!(ctx->flags & CTX_IS_BACKGROUND) ) gf_mx2d_add_matrix(&mx_texture, &ctx->transform); /*set path transform*/ raster->stencil_set_matrix(tx_raster, &mx_texture); tx_tile = 0; if (txh->flags & GF_SR_TEXTURE_REPEAT_S) tx_tile |= GF_TEXTURE_REPEAT_S; if (txh->flags & GF_SR_TEXTURE_REPEAT_T) tx_tile |= GF_TEXTURE_REPEAT_T; if (ctx->flags & CTX_FLIPED_COORDS) tx_tile |= GF_TEXTURE_FLIP; raster->stencil_set_tiling(tx_raster, (GF_TextureTiling) tx_tile); if (!(ctx->flags & CTX_IS_BACKGROUND) ) { u8 a = GF_COL_A(ctx->aspect.fill_color); if (!a) a = GF_COL_A(ctx->aspect.line_color); /*texture alpha scale is the original material transparency, NOT the one after color transform*/ raster->stencil_set_alpha(tx_raster, a ); raster->stencil_set_color_matrix(tx_raster, ctx->col_mat); raster->surface_set_matrix(visual->raster_surface, &ctx->transform); } else { raster->surface_set_matrix(visual->raster_surface, NULL); } txh->flags |= GF_SR_TEXTURE_USED; /*push path & draw*/ raster->surface_set_path(visual->raster_surface, path); visual_2d_fill_path(visual, ctx, tx_raster, tr_state, 0); raster->surface_set_path(visual->raster_surface, NULL); ctx->flags |= CTX_PATH_FILLED; }
static void build_shape(FSStack *st, GF_Node *node) { GF_FieldInfo field; MFVec2f *coords; MFInt32 *com, *widthIndex, *lineIndex, *fillIndex, *coordIndex; MFFloat *widths; MFColor *colors; u32 wi, li, fi, ci, command, i, has_ci; FSItem *fill_item, *line_item; Fixed w; SFVec2f cur, pt, ct1={0,0}, ct2, *pts; GF_Rect rc; u32 line_col, fill_col; Bool need_line, need_fill; /*get all fields*/ gf_node_get_field(node, 0, &field); coords = field.far_ptr; gf_node_get_field(node, 1, &field); com = field.far_ptr; gf_node_get_field(node, 2, &field); widths = field.far_ptr; gf_node_get_field(node, 3, &field); colors = field.far_ptr; gf_node_get_field(node, 4, &field); widthIndex = field.far_ptr; gf_node_get_field(node, 5, &field); lineIndex = field.far_ptr; gf_node_get_field(node, 6, &field); fillIndex = field.far_ptr; gf_node_get_field(node, 7, &field); coordIndex = field.far_ptr; wi = li = fi = ci = 0; w = 0; st->max_width = 0; cur.x = cur.y = 0; fill_item = line_item = NULL; need_line = need_fill = 0; cur.x = cur.y = 0; has_ci = coordIndex->count ? 1 : 0; pts = coords->vals; line_col = fill_col = 0; /*implicit commands: 0 1 2 3*/ /* if (widthIndex->count) { w = (widthIndex->vals[wi]==-1) ? 0 : widths->vals[widthIndex->vals[wi]]; if (!w) { need_line = 0; line_item = NULL; } else { need_line = 1; if (st->max_width<w) st->max_width = w; } wi++; } if (lineIndex->count) { if (w) { line_col = SFCOL_MAKE_ARGB(colors->vals[lineIndex->vals[li]]); need_line = 1; } li++; } if (fillIndex->count) { if (fillIndex->vals[fi]==-1) { fill_col = 0; fill_item = NULL; } else { fill_col = SFCOL_MAKE_ARGB(colors->vals[fillIndex->vals[fi]]); need_fill = 1; } fi++; } if (!coordIndex->count) return; cur = coords->vals[coordIndex->vals[ci]]; ci++; */ for (command=0; command<com->count; command++) { switch (com->vals[command]) { /*set line width*/ case 0: if (wi >= widthIndex->count) return; w = (widthIndex->vals[wi]==-1) ? 0 : widths->vals[widthIndex->vals[wi]]; if (!w) line_item = NULL; else { need_line = 1; if (st->max_width<w) st->max_width = w; } wi++; break; /*set line color*/ case 1: if (li > lineIndex->count) return; if (w) { line_col = SFCOL_MAKE_ARGB(colors->vals[lineIndex->vals[li]]); need_line = 1; } li++; break; /*set fill color*/ case 2: if (fi >= fillIndex->count) return; if (fillIndex->vals[fi]==-1) { fill_col = 0; fill_item = NULL; } else { fill_col = SFCOL_MAKE_ARGB(colors->vals[fillIndex->vals[fi]]); need_fill = 1; } fi++; break; /*moveTo*/ case 3: if ((has_ci && ci >= coordIndex->count) || (!has_ci && ci >= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); need_line = 0; } if (has_ci) { pt = pts[coordIndex->vals[ci]]; } else { pt = pts[ci]; } if (fill_item) gf_path_add_move_to(fill_item->path, pt.x, pt.y); if (line_item) gf_path_add_move_to(line_item->path, pt.x, pt.y); ct1 = pt; cur = pt; ci++; break; /*lineTo*/ case 4: if ((has_ci && ci >= coordIndex->count) || (!has_ci && ci >= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); gf_path_add_move_to(fill_item->path, cur.x, cur.y); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); gf_path_add_move_to(line_item->path, cur.x, cur.y); need_line = 0; } if (has_ci) { pt = pts[coordIndex->vals[ci]]; } else { pt = pts[ci]; } if (fill_item) gf_path_add_line_to(fill_item->path, pt.x, pt.y); if (line_item) gf_path_add_line_to(line_item->path, pt.x, pt.y); cur = pt; ci++; break; /*cubic curveTo*/ case 5: if ((has_ci && ci + 2 >= coordIndex->count) || (!has_ci && ci + 2>= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); gf_path_add_move_to(fill_item->path, cur.x, cur.y); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); gf_path_add_move_to(line_item->path, cur.x, cur.y); need_line = 0; } if (has_ci) { ct1 = pts[coordIndex->vals[ci]]; ct2 = pts[coordIndex->vals[ci+1]]; pt = pts[coordIndex->vals[ci+2]]; } else { ct1 = pts[ci]; ct2 = pts[ci+1]; pt = pts[ci+2]; } if (fill_item) gf_path_add_cubic_to(fill_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y); if (line_item) gf_path_add_cubic_to(line_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y); ct1 = ct2; cur = pt; ci += 3; break; /*cubic nextCurveTo*/ case 6: if ((has_ci && ci + 1 >= coordIndex->count) || (!has_ci && ci + 1>= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); gf_path_add_move_to(fill_item->path, cur.x, cur.y); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); gf_path_add_move_to(line_item->path, cur.x, cur.y); need_line = 0; } ct1.x = 2*cur.x - ct1.x; ct1.y = 2*cur.y - ct1.y; if (has_ci) { ct2 = pts[coordIndex->vals[ci]]; pt = pts[coordIndex->vals[ci+1]]; } else { ct2 = pts[ci]; pt = pts[ci+1]; } if (fill_item) gf_path_add_cubic_to(fill_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y); if (line_item) gf_path_add_cubic_to(line_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y); ct1 = ct2; cur = pt; ci += 2; break; /*quadratic CurveTo*/ case 7: if ((has_ci && ci + 1 >= coordIndex->count) || (!has_ci && ci + 1>= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); gf_path_add_move_to(fill_item->path, cur.x, cur.y); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); gf_path_add_move_to(line_item->path, cur.x, cur.y); need_line = 0; } if (has_ci) { ct1 = pts[coordIndex->vals[ci]]; pt = pts[coordIndex->vals[ci+1]]; } else { ct1 = pts[ci]; pt = pts[ci+1]; } if (fill_item) gf_path_add_quadratic_to(fill_item->path, ct1.x, ct1.y, pt.x, pt.y); if (line_item) gf_path_add_quadratic_to(line_item->path, ct1.x, ct1.y, pt.x, pt.y); cur = pt; ci += 2; break; /*quadratic nextCurveTo*/ case 8: if ((has_ci && ci >= coordIndex->count) || (!has_ci && ci >= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); gf_path_add_move_to(fill_item->path, cur.x, cur.y); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); gf_path_add_move_to(line_item->path, cur.x, cur.y); need_line = 0; } ct1.x = 2*cur.x - ct1.x; ct1.y = 2*cur.y - ct1.y; if (has_ci) { pt = pts[coordIndex->vals[ci]]; } else { pt = pts[ci]; } if (fill_item) gf_path_add_quadratic_to(fill_item->path, ct1.x, ct1.y, pt.x, pt.y); if (line_item) gf_path_add_quadratic_to(line_item->path, ct1.x, ct1.y, pt.x, pt.y); cur = pt; ci += 2; break; /*close*/ case 9: if (fill_item) gf_path_close(fill_item->path); if (line_item) gf_path_close(line_item->path); break; } } /*compute bounds*/ st->bounds.width = st->bounds.height = 0; for (i=0; i<gf_list_count(st->items); i++) { line_item = gf_list_get(st->items, i); gf_path_get_bounds(line_item->path, &rc); gf_rect_union(&st->bounds, &rc); } }
static void TraversePlanarExtrusion(GF_Node *node, void *rs, Bool is_destroy) { PlanarExtrusion plane_ext; Drawable *stack_2d; u32 i, j, k; MFVec3f spine_vec; SFVec3f d; Fixed spine_len; GF_Rect bounds; GF_Path *geo, *spine; GF_TraverseState *tr_state = (GF_TraverseState *)rs; Drawable3D *stack = (Drawable3D *)gf_node_get_private(node); if (is_destroy) { drawable_3d_del(node); return; } if (!PlanarExtrusion_GetNode(node, &plane_ext)) return; if (!plane_ext.geometry || !plane_ext.spine) return; if (gf_node_dirty_get(node)) { u32 cur, nb_pts; u32 mode = tr_state->traversing_mode; geo = spine = NULL; tr_state->traversing_mode = TRAVERSE_GET_BOUNDS; gf_node_traverse(plane_ext.geometry, tr_state); gf_node_traverse(plane_ext.spine, tr_state); tr_state->traversing_mode = mode; switch (gf_node_get_tag(plane_ext.geometry) ) { case TAG_MPEG4_Circle: case TAG_MPEG4_Ellipse: case TAG_MPEG4_Rectangle: case TAG_MPEG4_Curve2D: case TAG_MPEG4_XCurve2D: case TAG_MPEG4_IndexedFaceSet2D: case TAG_MPEG4_IndexedLineSet2D: stack_2d = (Drawable*)gf_node_get_private(plane_ext.geometry); if (stack_2d) geo = stack_2d->path; break; default: return; } switch (gf_node_get_tag(plane_ext.spine) ) { case TAG_MPEG4_Circle: case TAG_MPEG4_Ellipse: case TAG_MPEG4_Rectangle: case TAG_MPEG4_Curve2D: case TAG_MPEG4_XCurve2D: case TAG_MPEG4_IndexedFaceSet2D: case TAG_MPEG4_IndexedLineSet2D: stack_2d = (Drawable*)gf_node_get_private(plane_ext.spine); if (stack_2d) spine = stack_2d->path; break; default: return; } if (!geo || !spine) return; mesh_reset(stack->mesh); gf_path_flatten(spine); gf_path_get_bounds(spine, &bounds); gf_path_flatten(geo); gf_path_get_bounds(geo, &bounds); cur = 0; for (i=0; i<spine->n_contours; i++) { nb_pts = 1 + spine->contours[i] - cur; spine_vec.vals = NULL; gf_sg_vrml_mf_alloc(&spine_vec, GF_SG_VRML_MFVEC3F, nb_pts); spine_len = 0; for (j=cur; j<nb_pts; j++) { spine_vec.vals[j].x = spine->points[j].x; spine_vec.vals[j].y = spine->points[j].y; spine_vec.vals[j].z = 0; if (j) { gf_vec_diff(d, spine_vec.vals[j], spine_vec.vals[j-1]); spine_len += gf_vec_len(d); } } cur += nb_pts; if (!plane_ext.orientation->count && !plane_ext.scale->count) { mesh_extrude_path_ext(stack->mesh, geo, &spine_vec, plane_ext.creaseAngle, bounds.x, bounds.y-bounds.height, bounds.width, bounds.height, plane_ext.beginCap, plane_ext.endCap, NULL, NULL, plane_ext.txAlongSpine); } /*interpolate orientation and scale along subpath line*/ else { MFRotation ori; MFVec2f scale; Fixed cur_len, frac; ori.vals = NULL; gf_sg_vrml_mf_alloc(&ori, GF_SG_VRML_MFROTATION, nb_pts); scale.vals = NULL; gf_sg_vrml_mf_alloc(&scale, GF_SG_VRML_MFVEC2F, nb_pts); cur_len = 0; if (!plane_ext.orientation->count) ori.vals[0].y = FIX_ONE; if (!plane_ext.scale->count) scale.vals[0].x = scale.vals[0].y = FIX_ONE; for (j=0; j<nb_pts; j++) { if (j) { gf_vec_diff(d, spine_vec.vals[j], spine_vec.vals[j-1]); cur_len += gf_vec_len(d); ori.vals[j] = ori.vals[j-1]; scale.vals[j] = scale.vals[j-1]; } if (plane_ext.orientation->count && (plane_ext.orientation->count == plane_ext.orientationKeys->count)) { frac = gf_divfix(cur_len , spine_len); if (frac < plane_ext.orientationKeys->vals[0]) ori.vals[j] = plane_ext.orientation->vals[0]; else if (frac >= plane_ext.orientationKeys->vals[plane_ext.orientationKeys->count-1]) ori.vals[j] = plane_ext.orientation->vals[plane_ext.orientationKeys->count-1]; else { for (k=1; k<plane_ext.orientationKeys->count; k++) { Fixed kDiff = plane_ext.orientationKeys->vals[k] - plane_ext.orientationKeys->vals[k-1]; if (!kDiff) continue; if (frac < plane_ext.orientationKeys->vals[k-1]) continue; if (frac > plane_ext.orientationKeys->vals[k]) continue; frac = gf_divfix(frac - plane_ext.orientationKeys->vals[k-1], kDiff); break; } ori.vals[j] = gf_sg_sfrotation_interpolate(plane_ext.orientation->vals[k-1], plane_ext.orientation->vals[k], frac); } } if (plane_ext.scale->count == plane_ext.scaleKeys->count) { frac = gf_divfix(cur_len , spine_len); if (frac <= plane_ext.scaleKeys->vals[0]) scale.vals[j] = plane_ext.scale->vals[0]; else if (frac >= plane_ext.scaleKeys->vals[plane_ext.scaleKeys->count-1]) scale.vals[j] = plane_ext.scale->vals[plane_ext.scale->count-1]; else { for (k=1; k<plane_ext.scaleKeys->count; k++) { Fixed kDiff = plane_ext.scaleKeys->vals[k] - plane_ext.scaleKeys->vals[k-1]; if (!kDiff) continue; if (frac < plane_ext.scaleKeys->vals[k-1]) continue; if (frac > plane_ext.scaleKeys->vals[k]) continue; frac = gf_divfix(frac - plane_ext.scaleKeys->vals[k-1], kDiff); break; } scale.vals[j].x = gf_mulfix(plane_ext.scale->vals[k].x - plane_ext.scale->vals[k-1].x, frac) + plane_ext.scale->vals[k-1].x; scale.vals[j].y = gf_mulfix(plane_ext.scale->vals[k].y - plane_ext.scale->vals[k-1].y, frac) + plane_ext.scale->vals[k-1].y; } } } mesh_extrude_path_ext(stack->mesh, geo, &spine_vec, plane_ext.creaseAngle, bounds.x, bounds.y-bounds.height, bounds.width, bounds.height, plane_ext.beginCap, plane_ext.endCap, &ori, &scale, plane_ext.txAlongSpine); gf_sg_vrml_mf_reset(&ori, GF_SG_VRML_MFROTATION); gf_sg_vrml_mf_reset(&scale, GF_SG_VRML_MFVEC2F); } gf_sg_vrml_mf_reset(&spine_vec, GF_SG_VRML_MFVEC3F); } mesh_update_bounds(stack->mesh); gf_mesh_build_aabbtree(stack->mesh); } if (tr_state->traversing_mode==TRAVERSE_DRAW_3D) { visual_3d_draw(tr_state, stack->mesh); } else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) { tr_state->bbox = stack->mesh->bounds; } }
Bool svg_drawable_is_over(Drawable *drawable, Fixed x, Fixed y, DrawAspect2D *asp, GF_TraverseState *tr_state, GF_Rect *glyph_rc) { Bool check_fill, check_stroke, check_over, check_outline, check_vis, inside; GF_Rect rc; u8 ptr_evt; ptr_evt = *tr_state->svg_props->pointer_events; if (ptr_evt==SVG_POINTEREVENTS_NONE) { return 0; } if (glyph_rc) { rc = *glyph_rc; } else { gf_path_get_bounds(drawable->path, &rc); } inside = ( (x >= rc.x) && (y <= rc.y) && (x <= rc.x + rc.width) && (y >= rc.y - rc.height) ) ? 1 : 0; if (ptr_evt==SVG_POINTEREVENTS_BOUNDINGBOX) return inside; check_fill = check_stroke = check_over = check_outline = check_vis = 0; /* check_vis: if set, return FALSE when visible property is not "visible" check_fill: if 1, checks whether point is over path, if 2, checks if the path is painted (even with fill-opacity=0) before check_stroke: if 1, checks whether point is over path outline, if 2, checks if the path outline is painted (even with stroke-opacity=0) before */ switch (ptr_evt) { case SVG_POINTEREVENTS_VISIBLE: check_vis = 1; check_fill = 1; check_stroke = 1; break; case SVG_POINTEREVENTS_VISIBLEFILL: check_vis = 1; check_fill = 1; break; case SVG_POINTEREVENTS_VISIBLESTROKE: check_vis = 1; check_stroke = 1; break; case SVG_POINTEREVENTS_VISIBLEPAINTED: check_vis = 1; check_fill = 2; check_stroke = 2; break; case SVG_POINTEREVENTS_FILL: check_fill = 1; break; case SVG_POINTEREVENTS_STROKE: check_stroke = 1; break; case SVG_POINTEREVENTS_ALL: check_fill = 1; check_stroke = 1; break; case SVG_POINTEREVENTS_PAINTED: check_fill = 2; check_stroke = 2; break; default: return 0; } /*!!watchout!! asp2D.width is 0 if stroke not visible due to painting properties - we must override this for picking*/ if (check_stroke==1) { asp->pen_props.width = tr_state->svg_props->stroke_width ? tr_state->svg_props->stroke_width->value : 0; } if (!asp->pen_props.width) check_stroke = 0; if (check_stroke) { /*rough estimation of stroke bounding box to avoid fetching the stroke each time*/ if (!inside) { Fixed width = asp->pen_props.width; rc.x -= width; rc.y += width; rc.width += 2*width; rc.height += 2*width; inside = ( (x >= rc.x) && (y <= rc.y) && (x <= rc.x + rc.width) && (y >= rc.y - rc.height) ) ? 1 : 0; if (!inside) return 0; } } else if (!inside) { return 0; } if (check_vis) { if (*tr_state->svg_props->visibility!=SVG_VISIBILITY_VISIBLE) return 0; } if (check_fill) { /*painted or don't care about fill*/ if ((check_fill!=2) || asp->fill_texture || asp->fill_color) { if (glyph_rc) return 1; /*point is over path*/ if (gf_path_point_over(drawable->path, x, y)) return 1; } } if (check_stroke) { StrikeInfo2D *si; /*not painted or don't care about stroke*/ if ((check_stroke!=2) || asp->line_texture || asp->line_color) { if (glyph_rc) return 1; si = drawable_get_strikeinfo(tr_state->visual->compositor, drawable, asp, tr_state->appear, NULL, 0, NULL); /*point is over outline*/ if (si && si->outline && gf_path_point_over(si->outline, x, y)) return 1; } } return 0; }
static void svg_traverse_bitmap(GF_Node *node, void *rs, Bool is_destroy) { Fixed cx, cy, angle; /*video stack is just an extension of image stack, type-casting is OK*/ SVG_video_stack *stack = (SVG_video_stack*)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; SVGPropertiesPointers backup_props; u32 backup_flags; GF_Matrix2D backup_matrix; GF_Matrix mx_3d; DrawableContext *ctx; SVGAllAttributes all_atts; if (is_destroy) { gf_sc_texture_destroy(&stack->txh); gf_sg_mfurl_del(stack->txurl); drawable_del(stack->graph); if (stack->audio) { gf_node_unregister(stack->audio, NULL); } gf_free(stack); return; } /*TRAVERSE_DRAW is NEVER called in 3D mode*/ if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) { SVG_Draw_bitmap(tr_state); return; } else if (tr_state->traversing_mode==TRAVERSE_PICK) { svg_drawable_pick(node, stack->graph, tr_state); return; } /*flatten attributes and apply animations + inheritance*/ gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!compositor_svg_traverse_base(node, &all_atts, (GF_TraverseState *)rs, &backup_props, &backup_flags)) return; if (gf_node_dirty_get(node) & GF_SG_SVG_XLINK_HREF_DIRTY) { gf_term_get_mfurl_from_xlink(node, &stack->txurl); stack->txh.width = stack->txh.height = 0; /*remove associated audio if any*/ if (stack->audio) { svg_audio_smil_evaluate_ex(NULL, 0, SMIL_TIMING_EVAL_REMOVE, stack->audio, stack->txh.owner); gf_node_unregister(stack->audio, NULL); stack->audio = NULL; } stack->audio_dirty = GF_TRUE; if (stack->txurl.count) svg_play_texture(stack, &all_atts); gf_node_dirty_clear(node, GF_SG_SVG_XLINK_HREF_DIRTY); } if (gf_node_dirty_get(node)) { /*do not clear dirty state until the image is loaded*/ if (stack->txh.width) { gf_node_dirty_clear(node, 0); SVG_Build_Bitmap_Graph((SVG_video_stack*)gf_node_get_private(node), tr_state); } } if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { if (!compositor_svg_is_display_off(tr_state->svg_props)) { gf_path_get_bounds(stack->graph->path, &tr_state->bounds); compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) { GF_Matrix2D mx; tr_state->bounds.width = INT2FIX(stack->txh.width); tr_state->bounds.height = INT2FIX(stack->txh.height); tr_state->bounds.x = cx - tr_state->bounds.width/2; tr_state->bounds.y = cy + tr_state->bounds.height/2; gf_mx2d_init(mx); gf_mx2d_add_rotation(&mx, 0, 0, angle); gf_mx2d_apply_rect(&mx, &tr_state->bounds); } else { gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } } else if (tr_state->traversing_mode == TRAVERSE_SORT) { if (!compositor_svg_is_display_off(tr_state->svg_props) && ( *(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN) ) { GF_Matrix mx_bck; Bool restore_mx = GF_FALSE; compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); ctx = drawable_init_context_svg(stack->graph, tr_state); if (!ctx || !ctx->aspect.fill_texture ) return; if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) { drawable_reset_path(stack->graph); gf_path_add_rect_center(stack->graph->path, cx, cy, INT2FIX(stack->txh.width), INT2FIX(stack->txh.height)); gf_mx2d_copy(mx_bck, tr_state->transform); restore_mx = GF_TRUE; gf_mx2d_init(tr_state->transform); gf_mx2d_add_rotation(&tr_state->transform, cx, cy, angle); } /*even if set this is not true*/ ctx->aspect.pen_props.width = 0; ctx->flags |= CTX_NO_ANTIALIAS; /*if rotation, transparent*/ ctx->flags &= ~CTX_IS_TRANSPARENT; if (ctx->transform.m[1] || ctx->transform.m[3]) { ctx->flags |= CTX_IS_TRANSPARENT; ctx->flags &= ~CTX_NO_ANTIALIAS; } else if (ctx->aspect.fill_texture->transparent) ctx->flags |= CTX_IS_TRANSPARENT; else if (tr_state->svg_props->opacity && (tr_state->svg_props->opacity->type==SVG_NUMBER_VALUE) && (tr_state->svg_props->opacity->value!=FIX_ONE)) { ctx->flags = CTX_IS_TRANSPARENT; ctx->aspect.fill_color = GF_COL_ARGB(FIX2INT(0xFF * tr_state->svg_props->opacity->value), 0, 0, 0); } #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { if (!stack->graph->mesh) { stack->graph->mesh = new_mesh(); mesh_from_path(stack->graph->mesh, stack->graph->path); } compositor_3d_draw_bitmap(stack->graph, &ctx->aspect, tr_state, 0, 0, FIX_ONE, FIX_ONE); ctx->drawable = NULL; } else #endif { drawable_finalize_sort(ctx, tr_state, NULL); } if (restore_mx) gf_mx2d_copy(tr_state->transform, mx_bck); compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } } if (stack->audio) svg_traverse_audio_ex(stack->audio, rs, GF_FALSE, tr_state->svg_props); memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; }
static void svg_drawable_traverse(GF_Node *node, void *rs, Bool is_destroy, void (*rebuild_path)(GF_Node *, Drawable *, SVGAllAttributes *), Bool is_svg_rect, Bool is_svg_path) { GF_Matrix2D backup_matrix; GF_Matrix mx_3d; DrawableContext *ctx; SVGPropertiesPointers backup_props; u32 backup_flags; Drawable *drawable = (Drawable *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; SVGAllAttributes all_atts; if (is_destroy) { #if USE_GF_PATH /* The path is the same as the one in the SVG node, don't delete it here */ if (is_svg_path) drawable->path = NULL; #endif drawable_node_del(node); return; } assert(tr_state->traversing_mode!=TRAVERSE_DRAW_2D); if (tr_state->traversing_mode==TRAVERSE_PICK) { svg_drawable_pick(node, drawable, tr_state); return; } /*flatten attributes and apply animations + inheritance*/ gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!compositor_svg_traverse_base(node, &all_atts, (GF_TraverseState *)rs, &backup_props, &backup_flags)) return; /* Recreates the path (i.e the shape) only if the node is dirty */ if (gf_node_dirty_get(node) & GF_SG_SVG_GEOMETRY_DIRTY) { /*the rebuild function is responsible for cleaning the path*/ rebuild_path(node, drawable, &all_atts); gf_node_dirty_clear(node, GF_SG_SVG_GEOMETRY_DIRTY); drawable_mark_modified(drawable, tr_state); } if (drawable->path) { if (*(tr_state->svg_props->fill_rule)==GF_PATH_FILL_ZERO_NONZERO) { if (!(drawable->path->flags & GF_PATH_FILL_ZERO_NONZERO)) { drawable->path->flags |= GF_PATH_FILL_ZERO_NONZERO; drawable_mark_modified(drawable, tr_state); } } else { if (drawable->path->flags & GF_PATH_FILL_ZERO_NONZERO) { drawable->path->flags &= ~GF_PATH_FILL_ZERO_NONZERO; drawable_mark_modified(drawable, tr_state); } } } if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { if (! compositor_svg_is_display_off(tr_state->svg_props)) { DrawAspect2D asp; gf_path_get_bounds(drawable->path, &tr_state->bounds); if (!tr_state->ignore_strike) { memset(&asp, 0, sizeof(DrawAspect2D)); drawable_get_aspect_2d_svg(node, &asp, tr_state); if (asp.pen_props.width) { StrikeInfo2D *si = drawable_get_strikeinfo(tr_state->visual->compositor, drawable, &asp, NULL, drawable->path, 0, NULL); if (si && si->outline) { gf_path_get_bounds(si->outline, &tr_state->bounds); } } } compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, NULL); if (!tr_state->abort_bounds_traverse) gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds); gf_sc_get_nodes_bounds(node, NULL, tr_state, NULL); compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, NULL); } } else if (tr_state->traversing_mode == TRAVERSE_SORT) { /*reset our flags - this may break reuse of nodes and change-detection in dirty-rect algo */ gf_node_dirty_clear(node, 0); if (!compositor_svg_is_display_off(tr_state->svg_props) && ( *(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN) ) { compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); ctx = drawable_init_context_svg(drawable, tr_state); if (ctx) { if (is_svg_rect) { if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->transparent) {} else if (GF_COL_A(ctx->aspect.fill_color) != 0xFF) {} else if (ctx->transform.m[1] || ctx->transform.m[3]) {} else { ctx->flags &= ~CTX_IS_TRANSPARENT; if (!ctx->aspect.pen_props.width) ctx->flags |= CTX_NO_ANTIALIAS; } } if (all_atts.pathLength && all_atts.pathLength->type==SVG_NUMBER_VALUE) ctx->aspect.pen_props.path_length = all_atts.pathLength->value; #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { if (!drawable->mesh) { drawable->mesh = new_mesh(); if (drawable->path) mesh_from_path(drawable->mesh, drawable->path); } visual_3d_draw_from_context(ctx, tr_state); ctx->drawable = NULL; } else #endif { drawable_finalize_sort(ctx, tr_state, NULL); } } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } } memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; }
static GF_Glyph *gdip_load_glyph(GF_FontReader *dr, u32 glyph_name) { GF_Rect bounds; GF_Glyph *glyph; GpPath *path_tmp; GpStringFormat *fmt; GpMatrix *mat; Float est_advance_h; unsigned short str[4]; int i; FontPriv *ctx = (FontPriv *)dr->udta; if (!ctx->font) return NULL; RectF rc; rc.X = rc.Y = 0; rc.Width = rc.Height = 0; GdipCreateStringFormat(StringFormatFlagsNoWrap | StringFormatFlagsNoFitBlackBox | StringFormatFlagsMeasureTrailingSpaces, LANG_NEUTRAL, &fmt); GdipSetStringFormatAlign(fmt, StringAlignmentNear); GdipCreatePath(FillModeAlternate, &path_tmp); if (glyph_name==0x20) { est_advance_h = ctx->whitespace_width; } else { /*to compute first glyph alignment (say 'x', we figure out its bounding full box by using the '_' char as wrapper (eg, "_x_") then the bounding box starting from xMin of the glyph ('x_'). The difference between both will give us a good approx of the glyph alignment*/ str[0] = glyph_name; str[1] = (unsigned short) '_'; str[2] = (unsigned short) 0; GdipAddPathString(path_tmp, (const WCHAR *)str, -1, ctx->font, ctx->font_style, ctx->em_size, &rc, fmt); GdipGetPathWorldBounds(path_tmp, &rc, NULL, NULL); est_advance_h = rc.Width - ctx->underscore_width; } GdipResetPath(path_tmp); str[0] = glyph_name; str[1] = (unsigned short) 0; rc.X = rc.Y = 0; rc.Width = rc.Height = 0; GdipAddPathString(path_tmp, (const WCHAR *)str, -1, ctx->font, ctx->font_style, ctx->em_size, &rc, fmt); GdipGetPathWorldBounds(path_tmp, &rc, NULL, NULL); /*flip so that we are in a font coordinate system - also move back the glyph to x=0 and y=baseline, GdiPlus doesn't do so*/ GdipCreateMatrix(&mat); GdipTranslateMatrix(mat, - rc.X, -ctx->ascent, MatrixOrderAppend); GdipScaleMatrix(mat, 1, -1, MatrixOrderAppend); GdipTransformPath(path_tmp, mat); GdipDeleteMatrix(mat); /*start enum*/ s32 count; GdipGetPointCount(path_tmp, &count); GpPointF *pts = new GpPointF[count]; BYTE *types = new BYTE[count]; GdipGetPathTypes(path_tmp, types, count); GdipGetPathPoints(path_tmp, pts, count); GF_SAFEALLOC(glyph, GF_Glyph); GF_SAFEALLOC(glyph->path, GF_Path); for (i=0; i<count; ) { BOOL closed = 0; s32 sub_type; sub_type = types[i] & PathPointTypePathTypeMask; if (sub_type == PathPointTypeStart) { gf_path_add_move_to(glyph->path, FLT2FIX(pts[i].X), FLT2FIX(pts[i].Y)); i++; } else if (sub_type == PathPointTypeLine) { gf_path_add_line_to(glyph->path, FLT2FIX(pts[i].X), FLT2FIX(pts[i].Y)); if (types[i] & PathPointTypeCloseSubpath) gf_path_close(glyph->path); i++; } else if (sub_type == PathPointTypeBezier) { assert(i+2<=count); gf_path_add_cubic_to(glyph->path, FLT2FIX(pts[i].X), FLT2FIX(pts[i].Y), FLT2FIX(pts[i+1].X), FLT2FIX(pts[i+1].Y), FLT2FIX(pts[i+2].X), FLT2FIX(pts[i+2].Y)); if (types[i+2] & PathPointTypeCloseSubpath) gf_path_close(glyph->path); i += 3; } else { assert(0); break; } } delete [] pts; delete [] types; GdipDeleteStringFormat(fmt); GdipDeletePath(path_tmp); glyph->ID = glyph_name; glyph->utf_name = glyph_name; glyph->vert_advance = (s32) (ctx->ascent-ctx->descent); glyph->horiz_advance = (s32) est_advance_h; gf_path_get_bounds(glyph->path, &bounds); glyph->width = FIX2INT(bounds.width); glyph->height = FIX2INT(bounds.height); return glyph; }
static void SVG_Build_Bitmap_Graph(SVG_video_stack *stack, GF_TraverseState *tr_state) { u32 tag; GF_Rect rc, new_rc; Fixed x, y, width, height, txwidth, txheight; Fixed rectx, recty, rectwidth, rectheight; SVGAllAttributes atts; SVG_PreserveAspectRatio pAR; SVG_Element *e = (SVG_Element *)stack->graph->node; gf_svg_flatten_attributes(e, &atts); tag = gf_node_get_tag(stack->graph->node); switch (tag) { case TAG_SVG_image: case TAG_SVG_video: x = (atts.x ? atts.x->value : 0); y = (atts.y ? atts.y->value : 0); width = (atts.width ? atts.width->value : 0); height = (atts.height ? atts.height->value : 0); break; default: return; } if (!width || !height) return; txheight = INT2FIX(stack->txh.height); txwidth = INT2FIX(stack->txh.width); if (!txwidth || !txheight) return; if (!atts.preserveAspectRatio) { pAR.defer = GF_FALSE; pAR.meetOrSlice = SVG_MEETORSLICE_MEET; pAR.align = SVG_PRESERVEASPECTRATIO_XMIDYMID; } else { pAR = *atts.preserveAspectRatio; } if (pAR.defer) { /* TODO */ rectwidth = width; rectheight = height; rectx = x+rectwidth/2; recty = y+rectheight/2; } else { if (pAR.align==SVG_PRESERVEASPECTRATIO_NONE) { rectwidth = width; rectheight = height; rectx = x+rectwidth/2; recty = y+rectheight/2; } else { Fixed scale, scale_w, scale_h; scale_w = gf_divfix(width, txwidth); scale_h = gf_divfix(height, txheight); if (pAR.meetOrSlice==SVG_MEETORSLICE_MEET) { if (scale_w > scale_h) { scale = scale_h; rectwidth = gf_mulfix(txwidth, scale); rectheight = height; } else { scale = scale_w; rectwidth = width; rectheight = gf_mulfix(txheight, scale); } } else { if (scale_w < scale_h) { scale = scale_h; rectwidth = gf_mulfix(txwidth, scale); rectheight = height; } else { scale = scale_w; rectwidth = width; rectheight = gf_mulfix(txheight, scale); } } rectx = x + rectwidth/2; recty = y + rectheight/2; switch (pAR.align) { case SVG_PRESERVEASPECTRATIO_XMINYMIN: break; case SVG_PRESERVEASPECTRATIO_XMIDYMIN: rectx += (width - rectwidth)/ 2; break; case SVG_PRESERVEASPECTRATIO_XMAXYMIN: rectx += width - rectwidth; break; case SVG_PRESERVEASPECTRATIO_XMINYMID: recty += (height - rectheight)/ 2; break; case SVG_PRESERVEASPECTRATIO_XMIDYMID: rectx += (width - rectwidth)/ 2; recty += (height - rectheight) / 2; break; case SVG_PRESERVEASPECTRATIO_XMAXYMID: rectx += width - rectwidth; recty += ( txheight - rectheight) / 2; break; case SVG_PRESERVEASPECTRATIO_XMINYMAX: recty += height - rectheight; break; case SVG_PRESERVEASPECTRATIO_XMIDYMAX: rectx += (width - rectwidth)/ 2; recty += height - rectheight; break; case SVG_PRESERVEASPECTRATIO_XMAXYMAX: rectx += width - rectwidth; recty += height - rectheight; break; } } } gf_path_get_bounds(stack->graph->path, &rc); drawable_reset_path(stack->graph); gf_path_add_rect_center(stack->graph->path, rectx, recty, rectwidth, rectheight); gf_path_get_bounds(stack->graph->path, &new_rc); if (!gf_rect_equal(rc, new_rc)) drawable_mark_modified(stack->graph, tr_state); else if (stack->txh.flags & GF_SR_TEXTURE_PRIVATE_MEDIA) drawable_mark_modified(stack->graph, tr_state); gf_node_dirty_clear(stack->graph->node, GF_SG_SVG_GEOMETRY_DIRTY); }
void VS2D_TexturePathIntern(VisualSurface2D *surf, GF_Path *path, GF_TextureHandler *txh, struct _drawable_context *ctx) { Fixed sS, sT; u32 tx_tile; GF_Matrix2D gf_mx2d_txt, gf_sr_texture_transform; GF_Rect rc, orig_rc; GF_Raster2D *r2d = surf->render->compositor->r2d; if (!txh) txh = ctx->h_texture; if (!txh || !txh->hwtx) return; /*this is gradient draw*/ if (txh->compute_gradient_matrix) { VS2D_DrawGradient(surf, path, txh, ctx); return; } /*setup quality even for background (since quality concerns images)*/ VS2D_SetOptions(surf->render, surf->the_surface, ctx->flags & CTX_IS_TEXT, ctx->flags & CTX_NO_ANTIALIAS); /*get original bounds*/ gf_path_get_bounds(path, &orig_rc); /*get active texture window in pixels*/ rc.width = INT2FIX(txh->width); rc.height = INT2FIX(txh->height); /*get scaling ratio so that active texture view is stretched to original bounds (std 2D shape texture mapping in MPEG4)*/ sS = orig_rc.width / txh->width; sT = orig_rc.height / txh->height; gf_mx2d_init(gf_mx2d_txt); gf_mx2d_add_scale(&gf_mx2d_txt, sS, sT); /*apply texture transform*/ get_gf_sr_texture_transform(ctx->appear, txh, &gf_sr_texture_transform, (txh == ctx->h_texture) ? 0 : 1, txh->width * sS, txh->height * sT); gf_mx2d_add_matrix(&gf_mx2d_txt, &gf_sr_texture_transform); /*move to bottom-left corner of bounds */ gf_mx2d_add_translation(&gf_mx2d_txt, (orig_rc.x), (orig_rc.y - orig_rc.height)); /*move to final coordinate system (except background which is built directly in final coord system)*/ if (!(ctx->flags & CTX_IS_BACKGROUND) ) gf_mx2d_add_matrix(&gf_mx2d_txt, &ctx->transform); /*set path transform, except for background2D node which is directly build in the final coord system*/ r2d->stencil_set_matrix(txh->hwtx, &gf_mx2d_txt); tx_tile = 0; if (txh->flags & GF_SR_TEXTURE_REPEAT_S) tx_tile |= GF_TEXTURE_REPEAT_S; if (txh->flags & GF_SR_TEXTURE_REPEAT_T) tx_tile |= GF_TEXTURE_REPEAT_T; r2d->stencil_set_tiling(txh->hwtx, (GF_TextureTiling) tx_tile); if (!(ctx->flags & CTX_IS_BACKGROUND) ) { u8 a = GF_COL_A(ctx->aspect.fill_color); if (!a) a = GF_COL_A(ctx->aspect.line_color); /*texture alpha scale is the original material transparency, NOT the one after color transform*/ r2d->stencil_set_texture_alpha(txh->hwtx, a ); r2d->stencil_set_color_matrix(txh->hwtx, ctx->col_mat); r2d->surface_set_matrix(surf->the_surface, &ctx->transform); } else { r2d->surface_set_matrix(surf->the_surface, NULL); } /*push path & draw*/ r2d->surface_set_path(surf->the_surface, path); VS2D_DoFill(surf, ctx, txh->hwtx); r2d->surface_set_path(surf->the_surface, NULL); ctx->flags |= CTX_PATH_FILLED; }
void compositor_init_svg_glyph(GF_Compositor *compositor, GF_Node *node) { u16 utf_name[20]; u8 *utf8; u32 len; GF_Rect rc; GF_Glyph *glyph; GF_Font *font; SVG_GlyphStack *st; SVGAllAttributes atts; GF_Node *node_font = gf_node_get_parent(node, 0); /*locate the font node*/ if (node_font) node_font = gf_node_get_parent(node, 0); if (!node_font || (gf_node_get_tag(node_font)!=TAG_SVG_font) ) return; font = gf_node_get_private(node_font); if (!font) return; gf_svg_flatten_attributes((SVG_Element*)node, &atts); if (gf_node_get_tag(node)==TAG_SVG_missing_glyph) { GF_SAFEALLOC(st, SVG_GlyphStack); goto reg_common; } /*we must have unicode specified*/ if (!atts.unicode) return; GF_SAFEALLOC(st, SVG_GlyphStack); utf8 = (u8 *) *atts.unicode; len = gf_utf8_mbstowcs(utf_name, 200, (const char **) &utf8); /*this is a single glyph*/ if (len==1) { st->glyph.utf_name = utf_name[0]; st->uni_len = 1; } else { st->glyph.utf_name = (u32) (PTR_TO_U_CAST st); st->unicode = gf_malloc(sizeof(u16)*len); st->uni_len = len; memcpy(st->unicode, utf_name, sizeof(u16)*len); } reg_common: st->glyph.ID = (u32) (PTR_TO_U_CAST st); st->font = font; st->glyph.horiz_advance = font->max_advance_h; if (atts.horiz_adv_x) st->glyph.horiz_advance = FIX2INT( gf_ceil(atts.horiz_adv_x->value) ); if (atts.d) { st->glyph.path = atts.d; gf_path_get_bounds(atts.d, &rc); st->glyph.width = FIX2INT( gf_ceil(rc.width) ); st->glyph.height = FIX2INT( gf_ceil(rc.height) ); } st->glyph.vert_advance = st->glyph.height; if (!st->glyph.vert_advance) st->glyph.vert_advance = font->max_advance_v; /*register glyph*/ if (!font->glyph) { font->glyph = &st->glyph; } else { glyph = font->glyph; while (glyph->next) glyph = glyph->next; glyph->next = &st->glyph; } gf_node_set_private(node, st); gf_node_set_callback_function(node, svg_traverse_glyph); }
static void TraverseRectangle(GF_Node *node, void *rs, Bool is_destroy) { DrawableContext *ctx; Drawable *stack = (Drawable *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { drawable_node_del(node); return; } rectangle_check_changes(node, stack, tr_state); switch (tr_state->traversing_mode) { case TRAVERSE_DRAW_2D: compositor_2d_draw_rectangle(tr_state); return; #ifndef GPAC_DISABLE_3D case TRAVERSE_DRAW_3D: if (!stack->mesh) { stack->mesh = new_mesh(); mesh_new_rectangle(stack->mesh, ((M_Rectangle *) node)->size, NULL, 0); } visual_3d_draw_2d(stack, tr_state); return; #endif case TRAVERSE_PICK: vrml_drawable_pick(stack, tr_state); return; case TRAVERSE_GET_BOUNDS: gf_path_get_bounds(stack->path, &tr_state->bounds); return; case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) return; #endif break; default: return; } ctx = drawable_init_context_mpeg4(stack, tr_state); if (!ctx) return; /*if rotated, object is transparent (doesn't fill bounds) and antialias must be used*/ if (tr_state->transform.m[1] || tr_state->transform.m[3]) { } else { /*if alpha or not filled, transparent*/ if (ctx->aspect.fill_color && (GF_COL_A(ctx->aspect.fill_color) != 0xFF)) { } /*if texture transparent, transparent*/ else if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->transparent) { } /*TODO check matrix for alpha*/ else if (!tr_state->color_mat.identity) { } /*otherwise, not transparent*/ else { ctx->flags &= ~CTX_IS_TRANSPARENT; } /*if no line width, we skip antialiasing*/ if (!ctx->aspect.pen_props.width) ctx->flags |= CTX_NO_ANTIALIAS; } drawable_finalize_sort(ctx, tr_state, NULL); }
static void TraverseTriangleSet2D(GF_Node *node, void *rs, Bool is_destroy) { DrawableContext *ctx; Drawable *stack = (Drawable *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { drawable_node_del(node); return; } triangleset2d_check_changes(node, stack, tr_state); switch (tr_state->traversing_mode) { #ifndef GPAC_DISABLE_3D case TRAVERSE_DRAW_3D: if (!stack->mesh) { SFColorRGBA col; u32 i, count, idx; GF_Vertex v1, v2, v3; X_TriangleSet2D *p = (X_TriangleSet2D *)node; stack->mesh = new_mesh(); stack->mesh->mesh_type = MESH_TRIANGLES; col.red = col.green = col.blue = 0; col.alpha = FIX_ONE; v1.color = MESH_MAKE_COL(col); v1.normal.x = v1.normal.y = 0; v1.normal.z = MESH_NORMAL_UNIT; v1.pos.z = 0; v3 = v2 = v1; count = p->vertices.count; while (count%3) count--; for (i=0; i<count; i+=3) { idx = stack->mesh->v_count; v1.pos.x = p->vertices.vals[i].x; v1.pos.y = p->vertices.vals[i].y; v2.pos.x = p->vertices.vals[i+1].x; v2.pos.y = p->vertices.vals[i+1].y; v3.pos.x = p->vertices.vals[i+2].x; v3.pos.y = p->vertices.vals[i+2].y; mesh_set_vertex_vx(stack->mesh, &v1); mesh_set_vertex_vx(stack->mesh, &v2); mesh_set_vertex_vx(stack->mesh, &v3); gf_vec_diff(v2.pos, v2.pos, v1.pos); gf_vec_diff(v3.pos, v3.pos, v1.pos); v1.pos = gf_vec_cross(v2.pos, v3.pos); if (v1.pos.z<0) { mesh_set_triangle(stack->mesh, idx, idx+2, idx+1); } else { mesh_set_triangle(stack->mesh, idx, idx+1, idx+2); } } stack->mesh->flags |= MESH_IS_2D; mesh_update_bounds(stack->mesh); } visual_3d_draw_2d(stack, tr_state); return; #endif case TRAVERSE_GET_BOUNDS: gf_path_get_bounds(stack->path, &tr_state->bounds); return; case TRAVERSE_PICK: vrml_drawable_pick(stack, tr_state); return; case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) return; #endif ctx = drawable_init_context_mpeg4(stack, tr_state); if (!ctx) return; drawable_finalize_sort(ctx, tr_state, NULL); return; } }
GF_EXPORT Bool gf_path_point_over(GF_Path *gp, Fixed x, Fixed y) { u32 i, *contour, start_idx; s32 wn; GF_Point2D start, s, e, pt; GF_Rect rc; /*check if not in bounds*/ gf_path_get_bounds(gp, &rc); if ((x<rc.x) || (y>rc.y) || (x>rc.x+rc.width) || (y<rc.y-rc.height)) return 0; if (!gp || (gp->n_points<2)) return 0; pt.x = x; pt.y = y; wn = 0; s = start = gp->points[0]; start_idx = 0; contour = gp->contours; for (i=1; i<gp->n_points; ) { switch (gp->tags[i]) { case GF_PATH_CURVE_ON: case GF_PATH_CLOSE: e = gp->points[i]; if (s.y<=pt.y) { if (e.y>pt.y) { if (isLeft(s, e, pt) > 0) wn++; } } else if (e.y<=pt.y) { if (isLeft(s, e, pt) < 0) wn--; } s = e; i++; break; case GF_PATH_CURVE_CONIC: { GF_Point2D *ctl, *end, c1, c2; ctl = &gp->points[i]; end = &gp->points[i+1]; c1.x = s.x + 2*(ctl->x - s.x) / 3; c1.y = s.y + 2*(ctl->y - s.y) / 3; c2.x = c1.x + (end->x - s.x) / 3; c2.y = c1.y + (end->y - s.y) / 3; gf_subdivide_cubic_hit_test(x, y, s.x, s.y, c1.x, c1.y, c2.x, c2.y, end->x, end->y, &wn); s = *end; } i+=2; break; case GF_PATH_CURVE_CUBIC: gf_subdivide_cubic_hit_test(x, y, s.x, s.y, gp->points[i].x, gp->points[i].y, gp->points[i+1].x, gp->points[i+1].y, gp->points[i+2].x, gp->points[i+2].y, &wn); s = gp->points[i+2]; i+=3; break; } /*end of subpath*/ if (*contour==i-1) { /*close path if needed, but don't test for lines...*/ if ((i-start_idx > 2) && (pt.y<s.y)) { if ((start.x != s.x) || (start.y != s.y)) { e = start; if (s.x<=pt.x) { if (e.y>pt.y) { if (isLeft(s, e, pt) > 0) wn++; } } else if (e.y<=pt.y) { if (isLeft(s, e, pt) < 0) wn--; } } } if ( i < gp->n_points ) s = start = gp->points[i]; i++; } } if (gp->flags & GF_PATH_FILL_ZERO_NONZERO) return wn ? 1 : 0; return wn%2 ? 1 : 0; }
static void TraverseIFS2D(GF_Node *node, void *rs, Bool is_destroy) { DrawableContext *ctx; M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node; Drawable *stack = (Drawable *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { drawable_node_del(node); return; } if (!ifs2D->coord) return; ifs2d_check_changes(node, stack, tr_state); switch (tr_state->traversing_mode) { case TRAVERSE_DRAW_2D: IFS2D_Draw(node, tr_state); return; #ifndef GPAC_DISABLE_3D case TRAVERSE_DRAW_3D: { DrawAspect2D asp; if (!stack->mesh) { stack->mesh = new_mesh(); mesh_new_ifs2d(stack->mesh, node); } memset(&asp, 0, sizeof(DrawAspect2D)); drawable_get_aspect_2d_mpeg4(node, &asp, tr_state); if (ifs2D->color && !GF_COL_A(asp.fill_color) ) { /*use special func to disable outline recompute and handle recompute ourselves*/ StrikeInfo2D *si = drawable_get_strikeinfo(tr_state->visual->compositor, stack, &asp, tr_state->appear, NULL, 0, tr_state); if (!si->mesh_outline) { si->mesh_outline = new_mesh(); mesh_new_ils(si->mesh_outline, ifs2D->coord, &ifs2D->coordIndex, ifs2D->color, &ifs2D->colorIndex, ifs2D->colorPerVertex, 1); } visual_3d_mesh_strike(tr_state, si->mesh_outline, asp.pen_props.width, asp.line_scale, asp.pen_props.dash); } else { visual_3d_draw_2d_with_aspect(stack, tr_state, &asp); } return; } #endif case TRAVERSE_PICK: vrml_drawable_pick(stack, tr_state); return; case TRAVERSE_GET_BOUNDS: gf_path_get_bounds(stack->path, &tr_state->bounds); return; case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) return; #endif ctx = drawable_init_context_mpeg4(stack, tr_state); if (!ctx) return; drawable_finalize_sort(ctx, tr_state, NULL); return; } }