예제 #1
0
void group_cache_setup(GroupCache *cache, GF_Rect *path_bounds, GF_IRect *pix_bounds, GF_Compositor *compositor, Bool for_gl)
{
	/*setup texture */
	cache->txh.compositor = compositor;
	cache->txh.height = pix_bounds->height;
	cache->txh.width = pix_bounds->width;

	cache->txh.stride = pix_bounds->width * 4;
	cache->txh.pixelformat = for_gl ? GF_PIXEL_RGBA : GF_PIXEL_ARGB;
	cache->txh.transparent = 1;

	if (cache->txh.data)
		gf_free(cache->txh.data);
#ifdef CACHE_DEBUG_ALPHA
	cache->txh.stride = pix_bounds->width * 3;
	cache->txh.pixelformat = GF_PIXEL_RGB_24;
	cache->txh.transparent = 0;
#endif

	cache->txh.data = (char *) gf_malloc (sizeof(char) * cache->txh.stride * cache->txh.height);
	memset(cache->txh.data, 0x0, sizeof(char) * cache->txh.stride * cache->txh.height);
	/*the path of drawable_cache is a rectangle one that is the the bound of the object*/
	gf_path_reset(cache->drawable->path);

	/*set a rectangle to the path
	  Attention, we want to center the cached bitmap at the center of the screen (main visual), so we use
	  the local coordinate to parameterize the path*/
	gf_path_add_rect_center(cache->drawable->path,
		path_bounds->x + path_bounds->width/2,
		path_bounds->y - path_bounds->height/2,
		path_bounds->width, path_bounds->height);
}
예제 #2
0
static void PointSet2D_Draw(GF_Node *node, GF_TraverseState *tr_state)
{
	GF_Path *path;
	Fixed alpha, w, h;
	u32 i;
	SFColor col;
	DrawableContext *ctx = tr_state->ctx;
	M_PointSet2D *ps2D = (M_PointSet2D *)node;
	M_Coordinate2D *coord = (M_Coordinate2D*) ps2D->coord;
	M_Color *color = (M_Color *) ps2D->color;

	/*never outline PS2D*/
	ctx->flags |= CTX_PATH_STROKE;
	if (!color || color->color.count<coord->point.count) {
		/*no texturing*/
		visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
		return;
	}

	get_point_size(&ctx->transform, &w, &h);

	path = gf_path_new();
	alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255;
	for (i = 0; i < coord->point.count; i++) {
		col = color->color.vals[i];
		ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
		gf_path_add_rect_center(path, coord->point.vals[i].x, coord->point.vals[i].y, w, h);
		visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state);
		gf_path_reset(path);
		ctx->flags &= ~CTX_PATH_FILLED;
	}
	gf_path_del(path);
}
예제 #3
0
static void rectangle_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
{
	/*if modified update node - we don't update for other traversing mode in order not to mess up the dirty
	rect tracking (otherwise we would miss geometry changes with same bounds)*/
	if (gf_node_dirty_get(node)) {
		drawable_reset_path(stack);
		gf_path_add_rect_center(stack->path, 0, 0, ((M_Rectangle *) node)->size.x, ((M_Rectangle *) node)->size.y);
		gf_node_dirty_clear(node, 0);
		drawable_mark_modified(stack, tr_state);
	}
}
예제 #4
0
static void DrawBackground2D_2D(DrawableContext *ctx, GF_TraverseState *tr_state)
{
	Background2DStack *stack;
	if (!ctx || !ctx->drawable || !ctx->drawable->node) return;
	stack = (Background2DStack *) gf_node_get_private(ctx->drawable->node);

	if (!ctx->bi->clip.width || !ctx->bi->clip.height) return;

	stack->flags &= ~CTX_PATH_FILLED;

	if (back_use_texture((M_Background2D *)ctx->drawable->node)) {

		if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL)) {
			/*set target rect*/
			gf_path_reset(stack->drawable->path);
			gf_path_add_rect_center(stack->drawable->path, 
								ctx->bi->unclip.x + ctx->bi->unclip.width/2,
								ctx->bi->unclip.y - ctx->bi->unclip.height/2,
								ctx->bi->unclip.width, ctx->bi->unclip.height);

			/*draw texture*/
			visual_2d_texture_path(tr_state->visual, stack->drawable->path, ctx, tr_state);
		}
		stack->flags &= ~(CTX_APP_DIRTY | CTX_TEXTURE_DIRTY);
	} else {
		
		/*direct drawing, draw without clippers */
		if (tr_state->immediate_draw) {
			/*directly clear with specified color*/
			tr_state->visual->ClearSurface(tr_state->visual, &ctx->bi->clip, ctx->aspect.fill_color);
		} else {
			u32 i;
			GF_IRect clip;
			for (i=0; i<tr_state->visual->to_redraw.count; i++) {
				/*there's an opaque region above, don't draw*/
#ifdef TRACK_OPAQUE_REGIONS
				if (tr_state->visual->draw_node_index<tr_state->visual->to_redraw.opaque_node_index[i]) continue;
#endif
				clip = ctx->bi->clip;
				gf_irect_intersect(&clip, &tr_state->visual->to_redraw.list[i]);
				if (clip.width && clip.height) {
					tr_state->visual->ClearSurface(tr_state->visual, &clip, ctx->aspect.fill_color);
				}
			}
		}
		stack->flags &= ~(CTX_APP_DIRTY | CTX_TEXTURE_DIRTY);
	}
	tr_state->visual->has_modif = 1;
}
예제 #5
0
static void draw_clipper(VisualSurface2D *surf, struct _drawable_context *ctx)
{
	GF_PenSettings clipset;
	GF_Path *clippath, *cliper;
	GF_Raster2D *r2d = surf->render->compositor->r2d;

	if (ctx->flags & CTX_IS_BACKGROUND) return;

	memset(&clipset, 0, sizeof(GF_PenSettings));
	clipset.width = 2*FIX_ONE;

	clippath = gf_path_new();
	gf_path_add_rect_center(clippath, ctx->bi->unclip.x + ctx->bi->unclip.width/2, ctx->bi->unclip.y - ctx->bi->unclip.height/2, ctx->bi->unclip.width, ctx->bi->unclip.height);
	cliper = gf_path_get_outline(clippath, clipset);
	gf_path_del(clippath);
	r2d->surface_set_matrix(surf->the_surface, NULL);
	r2d->surface_set_clipper(surf->the_surface, NULL);
	r2d->surface_set_path(surf->the_surface, cliper);
	r2d->stencil_set_brush_color(surf->the_pen, 0xFF000000);
	r2d->surface_fill(surf->the_surface, surf->the_pen);
	gf_path_del(cliper);
}
예제 #6
0
static void draw_clipper(GF_VisualManager *visual, struct _drawable_context *ctx)
{
	GF_PenSettings clipset;
	GF_Path *clippath, *cliper;
	GF_Raster2D *raster = visual->compositor->rasterizer;

	if (ctx->flags & CTX_IS_BACKGROUND) return;

	memset(&clipset, 0, sizeof(GF_PenSettings));
	clipset.width = 2*FIX_ONE;

	clippath = gf_path_new();
	gf_path_add_rect_center(clippath, ctx->bi->unclip.x + ctx->bi->unclip.width/2, ctx->bi->unclip.y - ctx->bi->unclip.height/2, ctx->bi->unclip.width, ctx->bi->unclip.height);
	cliper = gf_path_get_outline(clippath, clipset);
	gf_path_del(clippath);
	raster->surface_set_matrix(visual->raster_surface, NULL);
	raster->surface_set_clipper(visual->raster_surface, NULL);
	raster->surface_set_path(visual->raster_surface, cliper);
	raster->stencil_set_brush_color(visual->raster_brush, 0xFF000000);
	raster->surface_fill(visual->raster_surface, visual->raster_brush);
	gf_path_del(cliper);
}
예제 #7
0
u32 layer3d_setup_offscreen(GF_Node *node, Layer3DStack *st, GF_TraverseState *tr_state, Fixed width, Fixed height)
{
	GF_STENCIL stencil;
	u32 new_pixel_format, w, h;
	GF_Compositor *compositor = (GF_Compositor *)st->visual->compositor;

	if (st->unsupported) return 0;

#ifndef GPAC_USE_TINYGL
	/*no support for offscreen rendering*/
	if (!(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN)) {
		st->unsupported = 1;
		return 0;
	}
#endif

/*
	if (tr_state->visual->compositor->recompute_ar) {
		gf_node_dirty_set(node, 0, 0);
		return 0;
	}
*/

	new_pixel_format = GF_PIXEL_RGBA;
#ifndef GPAC_USE_TINYGL
//	if (!compositor_background_transparent(gf_list_get(tr_state->backgrounds, 0)) )
//		new_pixel_format = GF_PIXEL_RGB_24;

	/*in OpenGL_ES, only RGBA can be safelly used with glReadPixels*/
#ifdef GPAC_USE_OGL_ES
	new_pixel_format = GF_PIXEL_RGBA;
#else
	/*no support for alpha in offscreen rendering*/
	if (!(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA)) 
		new_pixel_format = GF_PIXEL_RGB_24;
#endif

#endif

	/*FIXME - we assume RGB+Depth+bitshape, we should check with the video out module*/
#if defined(GF_SR_USE_DEPTH) && !defined(GPAC_DISABLE_3D)
	if (st->visual->type_3d && (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_DEPTH) ) new_pixel_format = GF_PIXEL_RGBDS;
#endif
	
	w = (u32) FIX2INT(gf_ceil(width));
	h = (u32) FIX2INT(gf_ceil(height));

	/*1- some implementation of glReadPixel crash if w||h are not multiple of 4*/
	/*2- some implementation of glReadPixel don't behave properly here when texture is not a power of 2*/
	w = gf_get_next_pow2(w);
	if (w>1024) w = 1024;
	h = gf_get_next_pow2(h);
	if (h>1024) h = 1024;


	if (!w || !h) return 0;

	if (st->txh.tx_io
		&& (new_pixel_format == st->txh.pixelformat)
		&& (w == st->txh.width) 
		&& (h == st->txh.height) 
		&& (compositor->offscreen_width >= w) 
		&& (compositor->offscreen_height >= h)
	) 
		return 2;

	if (st->txh.tx_io) {
#ifdef GPAC_USE_TINYGL
		if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
#endif
		gf_sc_texture_release(&st->txh);
		if (st->txh.data) gf_free(st->txh.data);
		st->txh.data = NULL;
	}

	st->vp = gf_rect_center(INT2FIX(w), INT2FIX(h) );

	st->txh.width = w;
	st->txh.height = h;

	gf_sc_texture_allocate(&st->txh);
	st->txh.pixelformat = new_pixel_format;

	if (new_pixel_format==GF_PIXEL_RGBA) {
		st->txh.stride = w * 4;
		st->txh.transparent = 1;
	} 
	else if (new_pixel_format==GF_PIXEL_RGBDS) {
			st->txh.stride = w * 4;
			st->txh.transparent = 1;
	}
	else {
		st->txh.stride = w * 3;
		st->txh.transparent = 0;
	}

	st->visual->width = w;
	st->visual->height = h;


	stencil = compositor->rasterizer->stencil_new(compositor->rasterizer, GF_STENCIL_TEXTURE);

#ifndef GPAC_USE_TINYGL
	/*create an offscreen window for OpenGL rendering*/
	if ((compositor->offscreen_width < w) || (compositor->offscreen_height < h)) {
		GF_Err e;
		GF_Event evt;
		compositor->offscreen_width = MAX(compositor->offscreen_width, w);
		compositor->offscreen_height = MAX(compositor->offscreen_height, h);

		evt.type = GF_EVENT_VIDEO_SETUP;
		evt.setup.width = tr_state->visual->compositor->offscreen_width;
		evt.setup.height = tr_state->visual->compositor->offscreen_height;
		evt.setup.back_buffer = 0;
		evt.setup.opengl_mode = 2;
		e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
		if (e) {
			gf_sc_texture_release(&st->txh);
			st->unsupported = 1;
			return 0;
		}
		/*reload openGL ext*/
		gf_sc_load_opengl_extensions(compositor, 1);
	}
#endif
	st->txh.data = (char*)gf_malloc(sizeof(unsigned char) * st->txh.stride * st->txh.height);
	memset(st->txh.data, 0, sizeof(unsigned char) * st->txh.stride * st->txh.height);
	
	/*set stencil texture - we don't check error as an image could not be supported by the rasterizer
	but still supported by the blitter (case of RGBD/RGBDS)*/
	compositor->rasterizer->stencil_set_texture(stencil, st->txh.data, st->txh.width, st->txh.height, st->txh.stride, st->txh.pixelformat, st->txh.pixelformat, 0);

#ifdef GPAC_USE_TINYGL
	/*create TinyGL offscreen context*/
	st->tgl_ctx = ostgl_create_context(st->txh.width, st->txh.height, st->txh.transparent ? 32 : 24, &st->txh.data, 1);

	st->scale_x = st->scale_y = FIX_ONE;
#else
	st->scale_x = INT2FIX(w) / tr_state->visual->compositor->offscreen_width;
	st->scale_y = INT2FIX(h) / tr_state->visual->compositor->offscreen_height;
#endif

	gf_sc_texture_set_stencil(&st->txh, stencil);
	drawable_reset_path(st->drawable);
	gf_path_add_rect_center(st->drawable->path, 0, 0, st->clip.width, st->clip.height);
	return 1;
}
예제 #8
0
파일: svg_filters.c 프로젝트: Bevara/GPAC
/*
	This is a crude draft implementation of filter. The main drawback is that we don't cache any data.
	We should be able to check for changes in the sub-group or in the filter
*/
void svg_draw_filter(GF_Node *filter, GF_Node *node, GF_TraverseState *tr_state)
{
	GF_IRect rc1, rc2;

#ifndef GPAC_DISABLE_3D
	u32 type_3d;
#endif
	u32 prev_flags;
	GF_IRect txrc;
	Fixed scale_x, scale_y, temp_x, temp_y;
	DrawableContext *ctx, *child_ctx;
	GF_SURFACE offscreen_surface, old_surf;
	GF_Rect bounds, local_bounds, rc;
	GF_Matrix2D backup;
	SVGAllAttributes all_atts;
	GF_FilterStack *st = gf_node_get_private(filter);
	assert(tr_state->traversing_mode==TRAVERSE_SORT);

	/*store the current transform matrix, create a new one for group_cache*/
	gf_mx2d_copy(backup, tr_state->transform);
	gf_mx2d_init(tr_state->transform);

	gf_node_allow_cyclic_traverse(node);
	tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
	tr_state->bounds.width = tr_state->bounds.height = 0;
	gf_node_traverse(node, tr_state);

	local_bounds = bounds = tr_state->bounds;
	/*compute bounds in final coordinate system - this ensures that the cache has the correct anti aliasing*/
	gf_mx2d_apply_rect(&backup, &bounds);
	txrc = gf_rect_pixelize(&bounds);
	if (txrc.width%2) txrc.width++;
	if (txrc.height%2) txrc.height++;
	bounds = gf_rect_ft(&txrc);

	tr_state->traversing_mode = TRAVERSE_SORT;

	gf_mx2d_copy(tr_state->transform, backup);

	if (!bounds.width || !bounds.height) {
		return;
	}

	/*create a context */
	ctx = drawable_init_context_svg(st->drawable, tr_state);
	if (!ctx) return;

	/*setup texture */
	st->txh.height = txrc.height;
	st->txh.width = txrc.width;

	st->txh.stride = txrc.width * 4;
	st->txh.pixelformat = GF_PIXEL_ARGB;
#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) st->txh.pixelformat = GF_PIXEL_RGBA;
#endif
	st->txh.transparent = 1;

	if (st->txh.stride * st->txh.height > st->alloc_size) {
		st->alloc_size = st->txh.stride * st->txh.height;
		st->data = (u8*)gf_realloc(st->data, sizeof(u8) * st->alloc_size);
	}
	memset(st->data, 0x0, sizeof(char) * st->txh.stride * st->txh.height);
	st->txh.data = (char *) st->data;
	/*setup geometry (rectangle matching the bounds of the object)
	Warning, we want to center the cached bitmap at the center of the screen (main visual)*/
	gf_path_reset(st->drawable->path);

	gf_path_add_rect_center(st->drawable->path,
	                        bounds.x + bounds.width/2,
	                        bounds.y - bounds.height/2,
	                        bounds.width,
	                        bounds.height);


	old_surf = tr_state->visual->raster_surface;
	offscreen_surface = tr_state->visual->compositor->rasterizer->surface_new(tr_state->visual->compositor->rasterizer, tr_state->visual->center_coords);
	tr_state->visual->raster_surface = offscreen_surface;

	gf_mx2d_copy(backup, tr_state->transform);
	gf_mx2d_init(tr_state->transform);

	/*attach the buffer to visual*/
	tr_state->visual->compositor->rasterizer->surface_attach_to_buffer(offscreen_surface, st->txh.data,
	        st->txh.width,
	        st->txh.height,
	        0,
	        st->txh.stride,
	        st->txh.pixelformat);

	prev_flags = tr_state->immediate_draw;
	tr_state->immediate_draw = 1;
	tr_state->traversing_mode = TRAVERSE_SORT;
	tr_state->in_svg_filter = 1;

	/*recompute the bounds with the final scaling used*/
	scale_x = gf_divfix(bounds.width, local_bounds.width);
	scale_y = gf_divfix(bounds.height, local_bounds.height);
	gf_mx2d_init(tr_state->transform);
	gf_mx2d_add_scale(&tr_state->transform, scale_x, scale_y);

	rc = local_bounds;
	gf_mx2d_apply_rect(&tr_state->transform, &rc);

	/*centered the bitmap on the visual*/
	if (tr_state->visual->center_coords) {
		temp_x = -rc.x - rc.width/2;
		temp_y = rc.height/2 - rc.y;
	} else {
		temp_x = -rc.x;
		temp_y = rc.height - rc.y;
	}
	gf_mx2d_add_translation(&tr_state->transform, temp_x, temp_y);


	rc1 = tr_state->visual->surf_rect;
	rc2 = tr_state->visual->top_clipper;
	tr_state->visual->surf_rect.width = st->txh.width;
	tr_state->visual->surf_rect.height = st->txh.height;
	if (tr_state->visual->center_coords) {
		tr_state->visual->surf_rect.y = st->txh.height/2;
		tr_state->visual->surf_rect.x = -1 * (s32) st->txh.width/2;
	} else {
		tr_state->visual->surf_rect.y = st->txh.height;
		tr_state->visual->surf_rect.x = 0;
	}
	tr_state->visual->top_clipper = tr_state->visual->surf_rect;


#ifndef GPAC_DISABLE_3D
	type_3d = tr_state->visual->type_3d;
	tr_state->visual->type_3d=0;
#endif

	if (prev_flags) gf_node_allow_cyclic_traverse(node);
	gf_node_traverse(node, tr_state);

	child_ctx = ctx->next;
	while (child_ctx && child_ctx->drawable) {
		drawable_reset_bounds(child_ctx->drawable, tr_state->visual);
		child_ctx->drawable = NULL;
		child_ctx = child_ctx->next;
	}
	tr_state->visual->cur_context = ctx;


	/*restore state and destroy whatever needs to be cleaned*/
	tr_state->in_svg_filter = 0;
	tr_state->immediate_draw = prev_flags;
	tr_state->visual->compositor->rasterizer->surface_delete(offscreen_surface);
	tr_state->visual->raster_surface = old_surf;
	tr_state->traversing_mode = TRAVERSE_SORT;
	tr_state->visual->surf_rect = rc1;
	tr_state->visual->top_clipper = rc2;
#ifndef GPAC_DISABLE_3D
	tr_state->visual->type_3d = type_3d ;
#endif

	/*update texture*/
	st->txh.transparent = 1;
	st->txh.flags |= GF_SR_TEXTURE_NO_GL_FLIP;
	gf_sc_texture_set_data(&st->txh);
#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d)
		gf_sc_texture_push_image(&st->txh, 0, 0);
	else
#endif
		gf_sc_texture_push_image(&st->txh, 0, 1);

	ctx->flags |= CTX_NO_ANTIALIAS;
	ctx->aspect.fill_color = 0;
	ctx->aspect.line_color = 0xFF000000;
	ctx->aspect.fill_texture = &st->txh;
	ctx->flags |= CTX_TEXTURE_DIRTY;

	/*get the filter region*/
	bounds = local_bounds;
	gf_svg_flatten_attributes((SVG_Element *)filter, &all_atts);
	if (!all_atts.filterUnits || (*all_atts.filterUnits==SVG_GRADIENTUNITS_OBJECT)) {
		Fixed v;
		v = all_atts.x ? all_atts.x->value : INT2FIX(-10);
		bounds.x += gf_mulfix(v, bounds.width);
		v = all_atts.y ? all_atts.y->value : INT2FIX(-10);
		bounds.y += gf_mulfix(v, bounds.height);
		v = all_atts.width ? all_atts.width->value : INT2FIX(120);
		bounds.width = gf_mulfix(v, bounds.width);
		v = all_atts.height ? all_atts.height->value : INT2FIX(120);
		bounds.height = gf_mulfix(v, bounds.height);
	} else {
		bounds.x = all_atts.x ? all_atts.x->value : 0;
		bounds.y = all_atts.y ? all_atts.y->value : 0;
		bounds.width = all_atts.width ? all_atts.x->value : bounds.width;
		bounds.height = all_atts.x ? all_atts.x->value : 120;
	}
	gf_mx2d_apply_rect(&backup, &bounds);

	svg_filter_apply(filter, &st->txh, &bounds);


#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		if (!st->drawable->mesh) {
			st->drawable->mesh = new_mesh();
			mesh_from_path(st->drawable->mesh, st->drawable->path);
		}
		visual_3d_draw_from_context(tr_state->ctx, tr_state);
		ctx->drawable = NULL;
		return;
	}
#endif

	/*we computed the texture in final screen coordinate, so use the identity matrix for the context*/
	gf_mx2d_init(tr_state->transform);
	drawable_finalize_sort(ctx, tr_state, NULL);
	gf_mx2d_copy(tr_state->transform, backup);
}
예제 #9
0
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);
}
예제 #10
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;
}
예제 #11
0
static void DrawBackground2D_2D(DrawableContext *ctx, GF_TraverseState *tr_state)
{
	Bool clear_all = GF_TRUE;
	u32 color;
	Bool use_texture;
	Bool is_offscreen = GF_FALSE;
	Background2DStack *stack;
	if (!ctx || !ctx->drawable || !ctx->drawable->node) return;
	stack = (Background2DStack *) gf_node_get_private(ctx->drawable->node);

	if (!ctx->bi->clip.width || !ctx->bi->clip.height) return;

	stack->flags &= ~CTX_PATH_FILLED;
	color = ctx->aspect.fill_color;

	use_texture = back_use_texture((M_Background2D *)ctx->drawable->node);
	if (!use_texture && !tr_state->visual->is_attached) {
		use_texture = 1;
		stack->txh.data = stack->col_tx;
		stack->txh.width = 2;
		stack->txh.height = 2;
		stack->txh.stride = 6;
		stack->txh.pixelformat = GF_PIXEL_RGB_24;
	}

	if (use_texture) {

		if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx)) {
			/*set target rect*/
			gf_path_reset(stack->drawable->path);
			gf_path_add_rect_center(stack->drawable->path,
			                        ctx->bi->unclip.x + ctx->bi->unclip.width/2,
			                        ctx->bi->unclip.y - ctx->bi->unclip.height/2,
			                        ctx->bi->unclip.width, ctx->bi->unclip.height);

			/*draw texture*/
			visual_2d_texture_path(tr_state->visual, stack->drawable->path, ctx, tr_state);
		}
		//a quick hack, if texture not ready return (we don't have direct notification of this through the above functions
#ifndef GPAC_DISABLE_3D
		if (tr_state->visual->compositor->hybrid_opengl && !stack->txh.tx_io) 
			return;
#endif

		stack->flags &= ~(CTX_APP_DIRTY | CTX_TEXTURE_DIRTY);
		tr_state->visual->has_modif = 1;
#ifndef GPAC_DISABLE_3D
		//in opengl auto mode we still have to clear the canvas
		if (!tr_state->immediate_draw && !tr_state->visual->offscreen && tr_state->visual->compositor->hybrid_opengl) {
			clear_all = GF_FALSE;
			is_offscreen = GF_TRUE;
			color &= 0x00FFFFFF;
		} else
#endif
			return;
	}


#ifndef GPAC_DISABLE_3D
	if (ctx->flags & CTX_BACKROUND_NOT_LAYER) {
		if (clear_all && !tr_state->visual->offscreen && tr_state->visual->compositor->hybrid_opengl) {
			compositor_2d_hybgl_clear_surface(tr_state->visual, NULL, color, GF_FALSE);
			is_offscreen = GF_TRUE;
			color &= 0x00FFFFFF;
			//we may need to clear the canvas for immediate mode
		}
	} else {
		is_offscreen = GF_TRUE;
	}
#endif
	/*direct drawing, draw without clippers */
	if (tr_state->immediate_draw
	   ) {
		/*directly clear with specified color*/
		if (clear_all)
			tr_state->visual->ClearSurface(tr_state->visual, &ctx->bi->clip, color, is_offscreen);
	} else {
		u32 i;
		GF_IRect clip;
		for (i=0; i<tr_state->visual->to_redraw.count; i++) {
			/*there's an opaque region above, don't draw*/
#ifdef TRACK_OPAQUE_REGIONS
			if (tr_state->visual->draw_node_index < tr_state->visual->to_redraw.list[i].opaque_node_index) continue;
#endif
			clip = ctx->bi->clip;
			gf_irect_intersect(&clip, &tr_state->visual->to_redraw.list[i].rect);
			if (clip.width && clip.height) {
				tr_state->visual->ClearSurface(tr_state->visual, &clip, color, is_offscreen);
			}
		}
	}
	stack->flags &= ~(CTX_APP_DIRTY | CTX_TEXTURE_DIRTY);
	tr_state->visual->has_modif = 1;
}