/*TransformMatrix2D*/ static void RenderTransformMatrix2D(GF_Node *node, void *rs, Bool is_destroy) { GF_Matrix2D bckup; M_TransformMatrix2D *tr = (M_TransformMatrix2D*)node; Transform2DStack *ptr = (Transform2DStack *) gf_node_get_private(node); RenderEffect2D *eff = (RenderEffect2D *)rs; if (is_destroy) { DeleteGroupingNode2D((GroupingNode2D *)ptr); free(ptr); return; } if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { TM2D_GetMatrix(node, &ptr->mat); if ((tr->mxx==FIX_ONE) && (tr->mxy==0) && (tr->tx==0) && (tr->myx==0) && (tr->myy==FIX_ONE) && (tr->ty==0) ) ptr->is_identity = 1; else ptr->is_identity = 0; } /*note we don't clear dirty flag, this is done in traversing*/ if (ptr->is_identity) { group2d_traverse((GroupingNode2D *)ptr, tr->children, eff); } else { gf_mx2d_copy(bckup, eff->transform); gf_mx2d_copy(eff->transform, ptr->mat); gf_mx2d_add_matrix(&eff->transform, &bckup); group2d_traverse((GroupingNode2D *)ptr, tr->children, eff); gf_mx2d_copy(eff->transform, bckup); } }
void VS2D_TexturePathText(VisualSurface2D *surf, DrawableContext *txt_ctx, GF_Path *path, GF_Rect *object_bounds, GF_HWTEXTURE hwtx, GF_Rect *gf_sr_texture_bounds) { Fixed sS, sT; GF_Matrix2D gf_mx2d_txt; GF_Rect rc, orig_rc; u8 alpha, r, g, b; GF_ColorMatrix cmat; GF_Raster2D *r2d = surf->render->compositor->r2d; VS2D_SetOptions(surf->render, surf->the_surface, 0, 1); /*get original bounds*/ orig_rc = *object_bounds; rc = *gf_sr_texture_bounds; /*get scaling ratio so that active texture view is stretched to original bounds (std 2D shape texture mapping in MPEG4)*/ sS = gf_divfix(orig_rc.width, rc.width); sT = gf_divfix(orig_rc.height, rc.height); gf_mx2d_init(gf_mx2d_txt); gf_mx2d_add_scale(&gf_mx2d_txt, sS, sT); /*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*/ gf_mx2d_add_matrix(&gf_mx2d_txt, &txt_ctx->transform); /*set path transform, except for background2D node which is directly build in the final coord system*/ r2d->stencil_set_matrix(hwtx, &gf_mx2d_txt); alpha = GF_COL_A(txt_ctx->aspect.fill_color); r = GF_COL_R(txt_ctx->aspect.fill_color); g = GF_COL_G(txt_ctx->aspect.fill_color); b = GF_COL_B(txt_ctx->aspect.fill_color); /*if col do a cxmatrix*/ if (!r && !g && !b) { r2d->stencil_set_texture_alpha(hwtx, alpha); } else { r2d->stencil_set_texture_alpha(hwtx, 0xFF); memset(cmat.m, 0, sizeof(Fixed) * 20); cmat.m[4] = INT2FIX(r)/255; cmat.m[9] = INT2FIX(g)/255; cmat.m[14] = INT2FIX(b)/255; cmat.m[18] = INT2FIX(alpha)/255; cmat.identity = 0; r2d->stencil_set_color_matrix(hwtx, &cmat); } r2d->surface_set_matrix(surf->the_surface, &txt_ctx->transform); /*push path*/ r2d->surface_set_path(surf->the_surface, path); VS2D_DoFill(surf, txt_ctx, hwtx); r2d->surface_set_path(surf->the_surface, NULL); txt_ctx->flags |= CTX_PATH_FILLED; }
static void RenderTransform2D(GF_Node *node, void *rs, Bool is_destroy) { GF_Matrix2D bckup; M_Transform2D *tr = (M_Transform2D *)node; Transform2DStack *ptr = (Transform2DStack *)gf_node_get_private(node); RenderEffect2D *eff; if (is_destroy) { DeleteGroupingNode2D((GroupingNode2D *)ptr); free(ptr); return; } eff = (RenderEffect2D *) rs; if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { gf_mx2d_init(ptr->mat); ptr->is_identity = 1; if ((tr->scale.x != FIX_ONE) || (tr->scale.y != FIX_ONE)) { gf_mx2d_add_scale_at(&ptr->mat, tr->scale.x, tr->scale.y, 0, 0, tr->scaleOrientation); ptr->is_identity = 0; } if (tr->rotationAngle) { gf_mx2d_add_rotation(&ptr->mat, tr->center.x, tr->center.y, tr->rotationAngle); ptr->is_identity = 0; } if (tr->translation.x || tr->translation.y) { ptr->is_identity = 0; gf_mx2d_add_translation(&ptr->mat, tr->translation.x, tr->translation.y); } } /*note we don't clear dirty flag, this is done in traversing*/ if (ptr->is_identity) { group2d_traverse((GroupingNode2D *)ptr, tr->children, eff); } else { gf_mx2d_copy(bckup, eff->transform); gf_mx2d_copy(eff->transform, ptr->mat); gf_mx2d_add_matrix(&eff->transform, &bckup); group2d_traverse((GroupingNode2D *)ptr, tr->children, eff); gf_mx2d_copy(eff->transform, bckup); } }
GF_Err evg_surface_fill(GF_SURFACE _this, GF_STENCIL stencil) { GF_Rect rc; GF_Matrix2D mat, st_mat; Bool restore_filter; EVGSurface *surf = (EVGSurface *)_this; EVGStencil *sten = (EVGStencil *)stencil; if (!surf || !stencil) return GF_BAD_PARAM; if (!surf->ftoutline.n_points) return GF_OK; surf->sten = sten; /*setup ft raster calllbacks*/ if (!setup_grey_callback(surf)) return GF_OK; /* surf->ftparams.gray_spans = gray_spans_stub; */ get_surface_world_matrix(surf, &mat); restore_filter = 0; /*get path frame for texture convertion */ if (sten->type != GF_STENCIL_SOLID) { rc = surf->path_bounds; gf_mx2d_apply_rect(&mat, &rc); rc.x = rc.y = 0; /*assign target frame and matrix*/ sten->frame = rc; gf_mx2d_copy(sten->pmat, surf->mat); gf_mx2d_inverse(&sten->pmat); gf_mx2d_copy(st_mat, sten->smat); gf_mx2d_init(sten->smat); switch (sten->type) { case GF_STENCIL_TEXTURE: if (! ((EVG_Texture *)sten)->pixels) return GF_BAD_PARAM; if (((EVG_Texture *)sten)->mod & GF_TEXTURE_FLIP) { if (!surf->center_coords) gf_mx2d_add_scale(&sten->smat, FIX_ONE, -FIX_ONE); } else { if (surf->center_coords) gf_mx2d_add_scale(&sten->smat, FIX_ONE, -FIX_ONE); } evg_set_texture_active(sten); gf_mx2d_add_matrix(&sten->smat, &st_mat); gf_mx2d_add_matrix(&sten->smat, &mat); gf_mx2d_inverse(&sten->smat); evg_bmp_init(sten); if (((EVG_Texture *)sten)->filter == GF_TEXTURE_FILTER_DEFAULT) { restore_filter = 1; ((EVG_Texture *)sten)->filter = surf->texture_filter; } break; case GF_STENCIL_LINEAR_GRADIENT: { EVG_LinearGradient *lin = (EVG_LinearGradient *)sten; gf_mx2d_add_matrix(&sten->smat, &st_mat); gf_mx2d_add_matrix(&sten->smat, &mat); gf_mx2d_inverse(&sten->smat); /*and finalize matrix in gradient coord system*/ gf_mx2d_add_matrix(&sten->smat, &lin->vecmat); gf_mx2d_add_scale(&sten->smat, INT2FIX(1<<EVGGRADIENTBITS), INT2FIX(1<<EVGGRADIENTBITS)); } break; case GF_STENCIL_RADIAL_GRADIENT: { EVG_RadialGradient *rad = (EVG_RadialGradient*)sten; gf_mx2d_copy(sten->smat, st_mat); gf_mx2d_add_matrix(&sten->smat, &mat); gf_mx2d_inverse(&sten->smat); gf_mx2d_add_translation(&sten->smat, -rad->center.x, -rad->center.y); gf_mx2d_add_scale(&sten->smat, gf_invfix(rad->radius.x), gf_invfix(rad->radius.y)); rad->d_f.x = gf_divfix(rad->focus.x - rad->center.x, rad->radius.x); rad->d_f.y = gf_divfix(rad->focus.y - rad->center.y, rad->radius.y); /*init*/ evg_radial_init(rad); } break; } } if (surf->useClipper) { surf->ftparams.clip_xMin = surf->clipper.x; surf->ftparams.clip_yMin = surf->clipper.y; surf->ftparams.clip_xMax = (surf->clipper.x + surf->clipper.width); surf->ftparams.clip_yMax = (surf->clipper.y + surf->clipper.height); } else { surf->ftparams.clip_xMin = 0; surf->ftparams.clip_yMin = 0; surf->ftparams.clip_xMax = (surf->width); surf->ftparams.clip_yMax = (surf->height); } /*and call the raster*/ evg_raster_render(surf->raster, &surf->ftparams); /*restore stencil matrix*/ if (sten->type != GF_STENCIL_SOLID) { gf_mx2d_copy(sten->smat, st_mat); if (restore_filter) ((EVG_Texture *)sten)->filter = GF_TEXTURE_FILTER_DEFAULT; } surf->sten = 0L; return GF_OK; }
void gf_sc_get_nodes_bounds(GF_Node *self, GF_ChildNodeItem *children, GF_TraverseState *tr_state, s32 *child_idx) { u32 i; SFVec2f size; GF_Rect rc; GF_Matrix2D cur_mx; if (tr_state->abort_bounds_traverse) { if (self == tr_state->for_node) { gf_mx2d_pre_multiply(&tr_state->mx_at_node, &tr_state->transform); } tr_state->abort_bounds_traverse=0; gf_sc_get_nodes_bounds(self, children, tr_state, child_idx); tr_state->abort_bounds_traverse=1; return; } if (!children) return; size.x = size.y = -FIX_ONE; #ifndef GPAC_DISABLE_VRML switch (gf_node_get_tag(self)) { case TAG_MPEG4_Layer2D: size = ((M_Layer2D *)self)->size; break; case TAG_MPEG4_Layer3D: size = ((M_Layer3D *)self)->size; break; case TAG_MPEG4_Form: size = ((M_Form *)self)->size; break; } #endif if ((size.x>=0) && (size.y>=0)) { tr_state->bounds = gf_rect_center(size.x, size.y); return; } gf_mx2d_copy(cur_mx, tr_state->transform); rc = gf_rect_center(0,0); i = 0; while (children) { if (child_idx && (i != (u32) *child_idx)) { children = children->next; continue; } gf_mx2d_init(tr_state->transform); tr_state->bounds = gf_rect_center(0,0); /*we hit the target node*/ if (children->node == tr_state->for_node) tr_state->abort_bounds_traverse = 1; gf_node_traverse(children->node, tr_state); if (tr_state->abort_bounds_traverse) { gf_mx2d_add_matrix(&tr_state->mx_at_node, &cur_mx); return; } gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds); gf_rect_union(&rc, &tr_state->bounds); children = children->next; if (child_idx) break; } #ifndef GPAC_DISABLE_SVG if (gf_node_get_tag(self)==TAG_SVG_use) { GF_FieldInfo info; if (gf_node_get_attribute_by_tag(self, TAG_XLINK_ATT_href, 0, 0, &info)==GF_OK) { GF_Node *iri = ((XMLRI*)info.far_ptr)->target; if (iri) { gf_mx2d_init(tr_state->transform); tr_state->bounds = gf_rect_center(0,0); /*we hit the target node*/ if (iri == tr_state->for_node) tr_state->abort_bounds_traverse = 1; gf_node_traverse(iri, tr_state); if (tr_state->abort_bounds_traverse) { gf_mx2d_pre_multiply(&tr_state->mx_at_node, &cur_mx); return; } gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds); gf_rect_union(&rc, &tr_state->bounds); } } } #endif gf_mx2d_copy(tr_state->transform, cur_mx); if (self != tr_state->for_node) { gf_mx2d_apply_rect(&tr_state->transform, &rc); } tr_state->bounds = rc; }
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; }
static void svg_recompute_viewport_transformation(GF_Node *node, SVGsvgStack *stack, GF_TraverseState *tr_state, SVGAllAttributes *atts) { GF_Matrix2D mx; SVG_ViewBox ext_vb, *vb; SVG_PreserveAspectRatio par; Fixed scale, vp_w, vp_h; Fixed parent_width, parent_height, doc_width, doc_height; /*canvas size negociation has already been done when attaching the scene to the compositor*/ if (atts->width && (atts->width->type==SVG_NUMBER_PERCENTAGE) ) { parent_width = gf_mulfix(tr_state->vp_size.x, atts->width->value/100); doc_width = 0; } else if (!stack->root_svg) { doc_width = parent_width = atts->width ? atts->width->value : 0; } else { parent_width = tr_state->vp_size.x; doc_width = atts->width ? atts->width->value : 0; } if (atts->height && (atts->height->type==SVG_NUMBER_PERCENTAGE) ) { parent_height = gf_mulfix(tr_state->vp_size.y, atts->height->value/100); doc_height = 0; } else if (!stack->root_svg) { doc_height = parent_height = atts->height ? atts->height->value : 0; } else { parent_height = tr_state->vp_size.y; doc_height = atts->height ? atts->height->value : 0; } stack->vp = stack->parent_vp = tr_state->vp_size; vb = atts->viewBox; gf_mx2d_init(mx); if (stack->root_svg) { const char *frag_uri = gf_scene_get_fragment_uri(node); if (frag_uri) { /*SVGView*/ if (!strncmp(frag_uri, "svgView", 7)) { if (!strncmp(frag_uri, "svgView(viewBox(", 16)) { Float x, y, w, h; sscanf(frag_uri, "svgView(viewBox(%f,%f,%f,%f))", &x, &y, &w, &h); ext_vb.x = FLT2FIX(x); ext_vb.y = FLT2FIX(y); ext_vb.width = FLT2FIX(w); ext_vb.height = FLT2FIX(h); ext_vb.is_set = 1; vb = &ext_vb; } else if (!strncmp(frag_uri, "svgView(transform(", 18)) { Bool ret = gf_svg_parse_transformlist(&mx, (char *) frag_uri+18); if (!ret) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error parsing SVG View transform component: %s\n", frag_uri+18)); } } } /*fragID*/ else { GF_Node *target = gf_sg_find_node_by_name(gf_node_get_graph(node), (char *) frag_uri); if (target) { GF_Matrix2D mx; GF_TraverseState bounds_state; memset(&bounds_state, 0, sizeof(bounds_state)); bounds_state.traversing_mode = TRAVERSE_GET_BOUNDS; bounds_state.visual = tr_state->visual; bounds_state.for_node = target; bounds_state.svg_props = tr_state->svg_props; gf_mx2d_init(bounds_state.transform); gf_mx2d_init(bounds_state.mx_at_node); gf_mx_init(tr_state->visual->compositor->hit_world_to_local); gf_sc_get_nodes_bounds(node, ((GF_ParentNode *)node)->children, &bounds_state, NULL); gf_mx2d_from_mx(&mx, &tr_state->visual->compositor->hit_world_to_local); gf_mx2d_apply_rect(&mx, &bounds_state.bounds); ext_vb.x = bounds_state.bounds.x; ext_vb.y = bounds_state.bounds.y-bounds_state.bounds.height; ext_vb.width = bounds_state.bounds.width; ext_vb.height = bounds_state.bounds.height; ext_vb.is_set = 1; vb = &ext_vb; } } } } gf_mx2d_init(stack->viewbox_mx); if (!vb) { if (!doc_width || !doc_height) { gf_mx2d_copy(stack->viewbox_mx, mx); return; } /*width/height were specified in the doc, use them to compute a dummy viewbox*/ ext_vb.x = 0; ext_vb.y = 0; ext_vb.width = doc_width; ext_vb.height = doc_height; ext_vb.is_set = 1; vb = &ext_vb; } if ((vb->width<=0) || (vb->height<=0) ) { gf_mx2d_copy(stack->viewbox_mx, mx); return; } stack->vp.x = vb->width; stack->vp.y = vb->height; /*setup default*/ par.defer = 0; par.meetOrSlice = SVG_MEETORSLICE_MEET; par.align = SVG_PRESERVEASPECTRATIO_XMIDYMID; /*use parent (animation, image) viewport settings*/ if (tr_state->parent_anim_atts) { if (tr_state->parent_anim_atts->preserveAspectRatio) { if (tr_state->parent_anim_atts->preserveAspectRatio->defer) { if (atts->preserveAspectRatio) par = *atts->preserveAspectRatio; } else { par = *tr_state->parent_anim_atts->preserveAspectRatio; } } } /*use current viewport settings*/ else if (atts->preserveAspectRatio) { par = *atts->preserveAspectRatio; } if (par.meetOrSlice==SVG_MEETORSLICE_MEET) { if (gf_divfix(parent_width, vb->width) > gf_divfix(parent_height, vb->height)) { scale = gf_divfix(parent_height, vb->height); vp_w = gf_mulfix(vb->width, scale); vp_h = parent_height; } else { scale = gf_divfix(parent_width, vb->width); vp_w = parent_width; vp_h = gf_mulfix(vb->height, scale); } } else { if (gf_divfix(parent_width, vb->width) < gf_divfix(parent_height, vb->height)) { scale = gf_divfix(parent_height, vb->height); vp_w = gf_mulfix(vb->width, scale); vp_h = parent_height; } else { scale = gf_divfix(parent_width, vb->width); vp_w = parent_width; vp_h = gf_mulfix(vb->height, scale); } } if (par.align==SVG_PRESERVEASPECTRATIO_NONE) { stack->viewbox_mx.m[0] = gf_divfix(parent_width, vb->width); stack->viewbox_mx.m[4] = gf_divfix(parent_height, vb->height); stack->viewbox_mx.m[2] = - gf_muldiv(vb->x, parent_width, vb->width); stack->viewbox_mx.m[5] = - gf_muldiv(vb->y, parent_height, vb->height); } else { Fixed dx, dy; stack->viewbox_mx.m[0] = stack->viewbox_mx.m[4] = scale; stack->viewbox_mx.m[2] = - gf_mulfix(vb->x, scale); stack->viewbox_mx.m[5] = - gf_mulfix(vb->y, scale); dx = dy = 0; switch (par.align) { case SVG_PRESERVEASPECTRATIO_XMINYMIN: break; case SVG_PRESERVEASPECTRATIO_XMIDYMIN: dx = ( parent_width - vp_w) / 2; break; case SVG_PRESERVEASPECTRATIO_XMAXYMIN: dx = parent_width - vp_w; break; case SVG_PRESERVEASPECTRATIO_XMINYMID: dy = ( parent_height - vp_h) / 2; break; case SVG_PRESERVEASPECTRATIO_XMIDYMID: dx = ( parent_width - vp_w) / 2; dy = ( parent_height - vp_h) / 2; break; case SVG_PRESERVEASPECTRATIO_XMAXYMID: dx = parent_width - vp_w; dy = ( parent_height - vp_h) / 2; break; case SVG_PRESERVEASPECTRATIO_XMINYMAX: dy = parent_height - vp_h; break; case SVG_PRESERVEASPECTRATIO_XMIDYMAX: dx = (parent_width - vp_w) / 2; dy = parent_height - vp_h; break; case SVG_PRESERVEASPECTRATIO_XMAXYMAX: dx = parent_width - vp_w; dy = parent_height - vp_h; break; } gf_mx2d_add_translation(&stack->viewbox_mx, dx, dy); stack->dx = dx; stack->dy = dy; stack->vpw = vp_w; stack->vph = vp_h; /*we need a clipper*/ if (stack->root_svg && !tr_state->parent_anim_atts && (par.meetOrSlice==SVG_MEETORSLICE_SLICE)) { GF_Rect rc; rc.width = parent_width; rc.height = parent_height; if (!stack->root_svg) { rc.x = 0; rc.y = parent_height; gf_mx2d_apply_rect(&stack->viewbox_mx, &rc); } else { rc.x = dx; rc.y = dy + parent_height; } // tr_state->visual->top_clipper = gf_rect_pixelize(&rc); } } gf_mx2d_add_matrix(&stack->viewbox_mx, &mx); }
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; }
void visual_2d_texture_path_text(GF_VisualManager *visual, DrawableContext *txt_ctx, GF_Path *path, GF_Rect *object_bounds, GF_TextureHandler *txh, GF_TraverseState *tr_state) { GF_STENCIL stencil; Fixed sS, sT; GF_Matrix2D gf_mx2d_txt; GF_Rect orig_rc; u8 alpha, r, g, b; GF_ColorMatrix cmat; GF_Raster2D *raster; if (! visual->CheckAttached(visual) ) return; raster = visual->compositor->rasterizer; stencil = gf_sc_texture_get_stencil(txh); if (!stencil) return; visual_2d_set_options(visual->compositor, visual->raster_surface, 0, 1); /*get original bounds*/ orig_rc = *object_bounds; /*get scaling ratio so that active texture view is stretched to original bounds (std 2D shape texture mapping in MPEG4)*/ sS = gf_divfix(orig_rc.width, INT2FIX(txh->width)); sT = gf_divfix(orig_rc.height, INT2FIX(txh->height)); gf_mx2d_init(gf_mx2d_txt); gf_mx2d_add_scale(&gf_mx2d_txt, sS, sT); /*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*/ gf_mx2d_add_matrix(&gf_mx2d_txt, &txt_ctx->transform); /*set path transform, except for background2D node which is directly build in the final coord system*/ raster->stencil_set_matrix(stencil, &gf_mx2d_txt); alpha = GF_COL_A(txt_ctx->aspect.fill_color); r = GF_COL_R(txt_ctx->aspect.fill_color); g = GF_COL_G(txt_ctx->aspect.fill_color); b = GF_COL_B(txt_ctx->aspect.fill_color); /*if col do a cxmatrix*/ if (!r && !g && !b) { raster->stencil_set_alpha(stencil, alpha); } else { raster->stencil_set_alpha(stencil, 0xFF); memset(cmat.m, 0, sizeof(Fixed) * 20); cmat.m[4] = INT2FIX(r)/255; cmat.m[9] = INT2FIX(g)/255; cmat.m[14] = INT2FIX(b)/255; cmat.m[18] = INT2FIX(alpha)/255; cmat.identity = 0; raster->stencil_set_color_matrix(stencil, &cmat); } raster->surface_set_matrix(visual->raster_surface, &txt_ctx->transform); txh->flags |= GF_SR_TEXTURE_USED; /*push path*/ raster->surface_set_path(visual->raster_surface, path); visual_2d_fill_path(visual, txt_ctx, stencil, tr_state, 0); raster->surface_set_path(visual->raster_surface, NULL); txt_ctx->flags |= CTX_PATH_FILLED; }