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 ILS2D_Draw(GF_Node *node, GF_TraverseState *tr_state) { GF_Path *path; SFVec2f *pts; SFColor col; Fixed alpha; u32 i, count, col_ind, ind, end_at; u32 linear[2], *colors; SFVec2f start, end; u32 j, num_col; GF_STENCIL grad; GF_Raster2D *raster; DrawableContext *ctx = tr_state->ctx; M_IndexedLineSet2D *ils2D = (M_IndexedLineSet2D *)node; M_Coordinate2D *coord = (M_Coordinate2D*) ils2D->coord; M_Color *color = (M_Color *) ils2D->color; end.x = end.y = 0; if (!coord->point.count) return; if (! ils2D->color) { /*no texturing*/ visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); return; } alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255; pts = coord->point.vals; if (!ils2D->colorPerVertex || (color->color.count<2) ) { count = 0; end_at = ils2D->coordIndex.count; if (!end_at) end_at = coord->point.count; ind = ils2D->coordIndex.count ? ils2D->coordIndex.vals[0] : 0; i=1; path = gf_path_new(); gf_path_add_move_to(path, pts[ind].x, pts[ind].y); for (; i<=end_at; i++) { if ((i==end_at) || (ils2D->coordIndex.count && ils2D->coordIndex.vals[i] == -1)) { /*draw current*/ col_ind = (ils2D->colorIndex.count && (ils2D->colorIndex.vals[count]>=0) ) ? (u32) ils2D->colorIndex.vals[count] : count; if (col_ind>=color->color.count) col_ind=color->color.count-1; col = color->color.vals[col_ind]; ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state); i++; if (i>=end_at) break; gf_path_reset(path); ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0)) ? (u32) ils2D->coordIndex.vals[i] : i; gf_path_add_move_to(path, pts[ind].x, pts[ind].y); if (ils2D->coordIndex.count) count++; continue; } else { ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0) ) ? (u32) ils2D->coordIndex.vals[i] : i; gf_path_add_line_to(path, pts[ind].x, pts[ind].y); } } gf_path_del(path); return; } raster = NULL; end_at = ils2D->coordIndex.count; if (!end_at) end_at = coord->point.count; count = 0; col_ind = 0; ind = 0; i=0; path = gf_path_new(); while (1) { gf_path_reset(path); ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0)) ? (u32) ils2D->coordIndex.vals[i] : i; start = pts[ind]; num_col = 1; i++; gf_path_add_move_to(path, start.x, start.y); if (ils2D->coordIndex.count) { while (ils2D->coordIndex.vals[i] != -1) { end = pts[ils2D->coordIndex.vals[i]]; gf_path_add_line_to(path, end.x, end.y); i++; num_col++; if (i >= ils2D->coordIndex.count) break; } } else { while (i<end_at) { end = pts[i]; gf_path_add_line_to(path, end.x, end.y); i++; num_col++; } } raster = tr_state->visual->compositor->rasterizer; /*use linear gradient*/ if (num_col==2) { Fixed pos[2]; grad = raster->stencil_new(raster, GF_STENCIL_LINEAR_GRADIENT); if (ils2D->colorIndex.count) { col = color->color.vals[ils2D->colorIndex.vals[col_ind]]; linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col = color->color.vals[ils2D->colorIndex.vals[col_ind+1]]; linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else if (ils2D->coordIndex.count) { col = color->color.vals[ils2D->coordIndex.vals[col_ind]]; linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col = color->color.vals[ils2D->coordIndex.vals[col_ind+1]]; linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else { col = color->color.vals[col_ind]; linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col = color->color.vals[col_ind+1]; linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } pos[0] = 0; pos[1] = FIX_ONE; raster->stencil_set_linear_gradient(grad, start.x, start.y, end.x, end.y); raster->stencil_set_gradient_interpolation(grad, pos, linear, 2); } else { grad = raster->stencil_new(raster, GF_STENCIL_VERTEX_GRADIENT); if (grad) { raster->stencil_set_vertex_path(grad, path); colors = (u32*)gf_malloc(sizeof(u32) * num_col); for (j=0; j<num_col; j++) { if (ils2D->colorIndex.count>0) { col = color->color.vals[ils2D->colorIndex.vals[col_ind+j]]; } else if (ils2D->coordIndex.count) { col = color->color.vals[ils2D->coordIndex.vals[col_ind+j]]; } else { col = color->color.vals[col_ind+j]; } colors[j] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } raster->stencil_set_vertex_colors(grad, colors, num_col); gf_free(colors); } } raster->stencil_set_matrix(grad, &ctx->transform); visual_2d_draw_path(tr_state->visual, path, ctx, NULL, grad, tr_state); if (grad) raster->stencil_delete(grad); i ++; col_ind += num_col + 1; if (i >= ils2D->coordIndex.count) break; ctx->flags &= ~CTX_PATH_STROKE; } gf_path_del(path); }
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; }
static void IFS2D_Draw(GF_Node *node, GF_TraverseState *tr_state) { u32 i, count, ci_count; u32 j, ind_col, num_col; SFVec2f center, end; SFColor col_cen; GF_STENCIL grad; u32 *colors; GF_Path *path; SFVec2f start; SFVec2f *pts; SFColor col; Fixed alpha; GF_Raster2D *raster; DrawableContext *ctx = tr_state->ctx; M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node; M_Coordinate2D *coord = (M_Coordinate2D*) ifs2D->coord; M_Color *color = (M_Color *) ifs2D->color; col.red = col.green = col.blue = 0; /*simple case, no color specified*/ if (!ifs2D->color) { 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); return; } /*if default face use first color*/ ci_count = ifs2D->coordIndex.count; pts = coord->point.vals; if (ci_count == 0) { col = (ifs2D->colorIndex.count > 0) ? color->color.vals[ifs2D->colorIndex.vals[0]] : color->color.vals[0]; alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color)) / 255; if (!alpha || !ctx->aspect.pen_props.width) { alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255; ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else { ctx->aspect.fill_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } 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); return; } /*we have color per faces so we need N path :(*/ if (! ifs2D->colorPerVertex) { path = gf_path_new(); count = 0; i = 0; while (1) { gf_path_reset(path); start = pts[ifs2D->coordIndex.vals[i]]; gf_path_add_move_to(path, start.x, start.y); i++; while (ifs2D->coordIndex.vals[i] != -1) { start = pts[ifs2D->coordIndex.vals[i]]; gf_path_add_line_to(path, start.x, start.y); i++; if (i >= ci_count) break; } /*close in ALL cases because even if the start/end points are the same the line join needs to be present*/ gf_path_close(path); col = (ifs2D->colorIndex.count > 0) ? color->color.vals[ifs2D->colorIndex.vals[count]] : color->color.vals[count]; alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color)) / 255; if (!alpha) { alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255; ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else { ctx->aspect.fill_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } visual_2d_texture_path(tr_state->visual, path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state); count++; i++; if (i >= ci_count) break; ctx->flags &= ~CTX_PATH_FILLED; ctx->flags &= ~CTX_PATH_STROKE; } gf_path_del(path); return; } /*final case, color per vertex means gradient fill/strike*/ raster = tr_state->visual->compositor->rasterizer; grad = raster->stencil_new(raster, GF_STENCIL_VERTEX_GRADIENT); /*not supported, fill default*/ if (!grad) { 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); return; } path = gf_path_new(); ind_col = 0; i = 0; while (1) { gf_path_reset(path); start = pts[ifs2D->coordIndex.vals[i]]; center = start; gf_path_add_move_to(path, start.x, start.y); num_col = 1; i+=1; while (ifs2D->coordIndex.vals[i] != -1) { end = pts[ifs2D->coordIndex.vals[i]]; gf_path_add_line_to(path, end.x, end.y); i++; center.x += end.x; center.y += end.y; num_col ++; if (i >= ci_count) break; } gf_path_close(path); num_col++; alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color) ) / 255; colors = (u32*)gf_malloc(sizeof(u32) * num_col); col_cen.blue = col_cen.red = col_cen.green = 0; for (j=0; j<num_col-1; j++) { if (ifs2D->colorIndex.count > ind_col + j) { col = color->color.vals[ifs2D->colorIndex.vals[ind_col + j]]; } else if (ci_count > ind_col + j) { col = color->color.vals[ifs2D->coordIndex.vals[ind_col + j]]; } colors[j] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col_cen.blue += col.blue; col_cen.green += col.green; col_cen.red += col.red; } colors[num_col-1] = colors[0]; if (ifs2D->colorIndex.count > ind_col) { col = color->color.vals[ifs2D->colorIndex.vals[ind_col]]; } else if (ci_count > ind_col) { col = color->color.vals[ifs2D->coordIndex.vals[ind_col]]; } col_cen.blue += col.blue; col_cen.green += col.green; col_cen.red += col.red; raster->stencil_set_vertex_path(grad, path); raster->stencil_set_vertex_colors(grad, colors, num_col); gf_free(colors); col_cen.blue /= num_col; col_cen.green /= num_col; col_cen.red /= num_col; center.x /= num_col; center.y /= num_col; raster->stencil_set_vertex_center(grad, center.x, center.y, GF_COL_ARGB_FIXED(alpha, col_cen.red, col_cen.green, col_cen.blue) ); raster->stencil_set_matrix(grad, &ctx->transform); /*draw*/ visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, grad, grad, tr_state); raster->stencil_delete(grad); //goto next point i++; ind_col += num_col + 1; if (i >= ci_count) break; grad = raster->stencil_new(raster, GF_STENCIL_VERTEX_GRADIENT); ctx->flags &= ~CTX_PATH_FILLED; ctx->flags &= ~CTX_PATH_STROKE; } gf_path_del(path); }