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;
}
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;
}