コード例 #1
0
ファイル: mpeg4_grouping_2d.c プロジェクト: Bevara/GPAC
static void traverse_transform(GF_Node *node, Transform2DStack *stack, GF_TraverseState *tr_state)
{
	if (stack->is_null) return;

	/*note we don't clear dirty flag, this is done in traversing*/
	if (stack->is_identity) {
		group_2d_traverse(node, (GroupingNode2D *)stack, tr_state);
	}
#ifndef GPAC_DISABLE_3D
	else if (tr_state->visual->type_3d) {
		GF_Matrix mx_bckup;
		gf_mx_copy(mx_bckup, tr_state->model_matrix);

		gf_mx_add_matrix_2d(&tr_state->model_matrix, &stack->mat);
		group_2d_traverse(node, (GroupingNode2D *)stack, tr_state);
		gf_mx_copy(tr_state->model_matrix, mx_bckup);
	}
#endif
	else {
		GF_Matrix2D bckup;
		gf_mx2d_copy(bckup, tr_state->transform);
		gf_mx2d_pre_multiply(&tr_state->transform, &stack->mat);

		group_2d_traverse(node, (GroupingNode2D *)stack, tr_state);

		gf_mx2d_copy(tr_state->transform, bckup);
	}

	if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
		gf_mx2d_apply_rect(&stack->mat, &tr_state->bounds);
	}
}
コード例 #2
0
ファイル: hardcoded_protos.c プロジェクト: dragonlucian/gpac
static void TraverseDepthGroup(GF_Node *node, void *rs, Bool is_destroy)
{
#ifdef GF_SR_USE_DEPTH
	Fixed depth_gain, depth_offset;
#endif

	DepthGroupStack *stack = (DepthGroupStack *)gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *) rs;

	if (is_destroy) {
		gf_free(stack);
		return;
	}

	if (tr_state->traversing_mode==TRAVERSE_SORT) {
		if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {

			gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
			/*flag is not set for PROTO*/
			gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, 0);
		}
	}
	DepthGroup_GetNode(node, &stack->dg);


#ifdef GF_SR_USE_DEPTH
	depth_gain = tr_state->depth_gain;
	depth_offset = tr_state->depth_offset;

	// new offset is multiplied by parent gain and added to parent offset
	tr_state->depth_offset = gf_mulfix(stack->dg.depth_offset, tr_state->depth_gain) + tr_state->depth_offset;

	// gain is multiplied by parent gain
	tr_state->depth_gain = gf_mulfix(tr_state->depth_gain, stack->dg.depth_gain);
#endif

#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		GF_Matrix mx_bckup, mx;

		gf_mx_copy(mx_bckup, tr_state->model_matrix);
		gf_mx_init(mx);
		mx.m[14] = gf_mulfix(stack->dg.depth_offset, tr_state->visual->compositor->depth_gl_scale);
		gf_mx_add_matrix(&tr_state->model_matrix, &mx);
		group_2d_traverse((GF_Node *)&stack->dg, (GroupingNode2D*)stack, tr_state);
		gf_mx_copy(tr_state->model_matrix, mx_bckup);

	} else
#endif
	{

		group_2d_traverse((GF_Node *)&stack->dg, (GroupingNode2D*)stack, tr_state);
	}

#ifdef GF_SR_USE_DEPTH
	tr_state->depth_gain = depth_gain;
	tr_state->depth_offset = depth_offset;
#endif
}
コード例 #3
0
ファイル: mpeg4_grouping_2d.c プロジェクト: bigbensk/gpac
/*ColorTransform*/
static void TraverseColorTransform(GF_Node *node, void *rs, Bool is_destroy)
{
	Bool c_changed;
	M_ColorTransform *tr = (M_ColorTransform *)node;
	ColorTransformStack *ptr = (ColorTransformStack  *)gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *) rs;
	Bool prev_inv;

	if (is_destroy) {
		gf_sc_check_focus_upon_destroy(node);
		group_2d_destroy(node, (GroupingNode2D*)ptr);
		gf_free(ptr);
		return;
	}
	if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
		group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state);
		return;
	}

	prev_inv = tr_state->invalidate_all;
	c_changed = 0;
	if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
		gf_cmx_set(&ptr->cmat, 
			tr->mrr , tr->mrg, tr->mrb, tr->mra, tr->tr, 
			tr->mgr , tr->mgg, tr->mgb, tr->mga, tr->tg, 
			tr->mbr, tr->mbg, tr->mbb, tr->mba, tr->tb, 
			tr->mar, tr->mag, tr->mab, tr->maa, tr->ta); 
		c_changed = 1;
		gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
	}

	if ((tr_state->traversing_mode==TRAVERSE_SORT) 
		&& !tr->maa && !tr->mar && !tr->mag && !tr->mab && !tr->ta)
		return; 

	/*if modified redraw all nodes*/
	if (c_changed) tr_state->invalidate_all = 1;

	/*note we don't clear dirty flag, this is done in traversing*/
	if (ptr->cmat.identity) {
		group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state);
	} else {
		GF_ColorMatrix gf_cmx_bck;
		gf_cmx_copy(&gf_cmx_bck, &tr_state->color_mat);
		gf_cmx_multiply(&tr_state->color_mat, &ptr->cmat);


		group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state);
		/*restore traversing state*/
		gf_cmx_copy(&tr_state->color_mat, &gf_cmx_bck);
	}
	tr_state->invalidate_all = prev_inv;
}
コード例 #4
0
ファイル: hardcoded_protos.c プロジェクト: dragonlucian/gpac
static void TraverseStyleGroup(GF_Node *node, void *rs, Bool is_destroy)
{
	Bool set = 0;
	StyleGroupStack *stack = (StyleGroupStack *)gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *) rs;

	if (is_destroy) {
		gf_free(stack);
		return;
	}

	if (tr_state->traversing_mode==TRAVERSE_SORT) {
		if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {

			gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
			/*flag is not set for PROTO*/
			gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, 0);
		}
	}
	StyleGroup_GetNode(node, &stack->sg);

	if (!tr_state->override_appearance) {
		set = 1;
		tr_state->override_appearance = stack->sg.appearance;
	}
	group_2d_traverse((GF_Node *)&stack->sg, (GroupingNode2D*)stack, tr_state);

	if (set) {
		tr_state->override_appearance = NULL;
	}
}
コード例 #5
0
ファイル: mpeg4_grouping_3d.c プロジェクト: ARSekkat/gpac
static void TraverseGroup(GF_Node *node, void *rs, Bool is_destroy)
{
	GroupingNode2D *group = (GroupingNode2D *) gf_node_get_private(node);
	if (is_destroy) {
		gf_sc_check_focus_upon_destroy(node);
		gf_free(group);
	} else {
		group_2d_traverse(node, group, (GF_TraverseState*)rs);
	}
}
コード例 #6
0
ファイル: mpeg4_grouping_2d.c プロジェクト: bigbensk/gpac
static void TraverseOrderedGroup(GF_Node *node, void *rs, Bool is_destroy)
{
	u32 i, count;
	struct og_pos *priorities;
	Bool invalidate_backup;
	OrderedGroupStack *stack = (OrderedGroupStack *) gf_node_get_private(node);
	M_OrderedGroup *og = (M_OrderedGroup *) node;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;

	if (is_destroy) {
		gf_sc_check_focus_upon_destroy(node);
		group_2d_destroy(node, (GroupingNode2D*)stack);
		if (stack->positions) gf_free(stack->positions);
		gf_free(stack);
		return;
	}

	if (!og->order.count || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) ) {
		gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
		group_2d_traverse(node, (GroupingNode2D*)stack, tr_state);
		return;
	}

	invalidate_backup = tr_state->invalidate_all;
	/*check whether the OrderedGroup node has changed*/
	if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
		if (stack->positions) gf_free(stack->positions);
		count = gf_node_list_get_count(og->children);
		priorities = (struct og_pos*)gf_malloc(sizeof(struct og_pos)*count);
		for (i=0; i<count; i++) {
			priorities[i].position = i;
			priorities[i].priority = (i<og->order.count) ? og->order.vals[i] : 0;
		}
		qsort(priorities, count, sizeof(struct og_pos), compare_priority);

		stack->positions = (u32*)gf_malloc(sizeof(u32) * count);
		for (i=0; i<count; i++) stack->positions[i] = priorities[i].position;
		gf_free(priorities);
		
		tr_state->invalidate_all = 1;
		gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
	}
	group_2d_traverse_with_order(node, (GroupingNode2D*)stack, tr_state, stack->positions);
	tr_state->invalidate_all = invalidate_backup;
}
コード例 #7
0
ファイル: mpeg4_sensors.c プロジェクト: JamesLinus/gpac
static void TraverseAnchor(GF_Node *node, void *rs, Bool is_destroy)
{
	AnchorStack *st = (AnchorStack *) gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;

	if (is_destroy) {
		mpeg4_sensor_deleted(node, &st->hdl);
		gf_sc_check_focus_upon_destroy(node);
		if (st->sensors) gf_list_del(st->sensors);
		gf_free(st);
		return;
	}

	if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
		MFURL *url = NULL;
		switch (gf_node_get_tag(node)) {
		case TAG_MPEG4_Anchor:
			url = & ((M_Anchor *)node)->url;
			break;
#ifndef GPAC_DISABLE_X3D
		case TAG_X3D_Anchor:
			url = & ((X_Anchor *)node)->url;
			break;
#endif
		}
		st->enabled = 0;
		if (url && url->count && url->vals[0].url && strlen(url->vals[0].url) )
			st->enabled = 1;

		if (!tr_state->visual->compositor->user->EventProc) {
			st->enabled = 0;
		}
		gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
	}

	group_2d_traverse(node, (GroupingNode2D*)st, tr_state);
}
コード例 #8
0
ファイル: hardcoded_protos.c プロジェクト: jnorthrup/gpac
static void TraverseUntransform(GF_Node *node, void *rs, Bool is_destroy)
{
    UntransformStack *stack = (UntransformStack *)gf_node_get_private(node);
    GF_TraverseState *tr_state = (GF_TraverseState *) rs;

    if (is_destroy) {
        gf_free(stack);
        return;
    }

    if (tr_state->traversing_mode==TRAVERSE_SORT) {
        if (gf_node_dirty_get(node)) {
            Untransform_GetNode(node, &stack->untr); /*lets place it below*/
            gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
        }
    }

#ifndef GPAC_DISABLE_3D
    if (tr_state->visual->type_3d) {
        GF_Matrix mx_model;
        GF_Camera backup_cam;

        if (!tr_state->camera) return;

        gf_mx_copy(mx_model, tr_state->model_matrix);
        gf_mx_init(tr_state->model_matrix);

        memcpy(&backup_cam, tr_state->camera, sizeof(GF_Camera));


        camera_invalidate(tr_state->camera);
        tr_state->camera->is_3D=0;
        tr_state->camera->flags |= CAM_NO_LOOKAT;
        tr_state->camera->end_zoom = FIX_ONE;
        camera_update(tr_state->camera, NULL, 1);


        if (tr_state->traversing_mode == TRAVERSE_SORT) {
            visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_PROJECTION);
            visual_3d_matrix_load(tr_state->visual, tr_state->camera->projection.m);
            visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_MODELVIEW);
            visual_3d_matrix_load(tr_state->visual, tr_state->camera->modelview.m);

            visual_3d_set_viewport(tr_state->visual, tr_state->camera->vp);

            gf_node_traverse_children((GF_Node *)&stack->untr, tr_state);

            gf_mx_copy(tr_state->model_matrix, mx_model);
            memcpy(tr_state->camera, &backup_cam, sizeof(GF_Camera));

            visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_PROJECTION);
            visual_3d_matrix_load(tr_state->visual, tr_state->camera->projection.m);
            visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_MODELVIEW);
            visual_3d_matrix_load(tr_state->visual, tr_state->camera->modelview.m);

            visual_3d_set_viewport(tr_state->visual, tr_state->camera->vp);
        } else if (tr_state->traversing_mode == TRAVERSE_PICK) {
            Fixed prev_dist = tr_state->visual->compositor->hit_square_dist;
            GF_Ray r = tr_state->ray;
            tr_state->ray.orig.x = INT2FIX(tr_state->pick_x);
            tr_state->ray.orig.y = INT2FIX(tr_state->pick_y);
            tr_state->ray.orig.z = 0;
            tr_state->ray.dir.x = 0;
            tr_state->ray.dir.y = 0;
            tr_state->ray.dir.z = -FIX_ONE;
            tr_state->visual->compositor->hit_square_dist=0;

            gf_node_traverse_children((GF_Node *)&stack->untr, tr_state);

            gf_mx_copy(tr_state->model_matrix, mx_model);
            memcpy(tr_state->camera, &backup_cam, sizeof(GF_Camera));
            tr_state->ray = r;

            /*nothing picked, restore previous pick*/
            if (!tr_state->visual->compositor->hit_square_dist)
                tr_state->visual->compositor->hit_square_dist = prev_dist;

        } else {
            gf_node_traverse_children((GF_Node *)&stack->untr, tr_state);

            gf_mx_copy(tr_state->model_matrix, mx_model);
            memcpy(tr_state->camera, &backup_cam, sizeof(GF_Camera));
        }

    } else
#endif
    {
        GF_Matrix2D mx2d_backup;
        gf_mx2d_copy(mx2d_backup, tr_state->transform);
        gf_mx2d_init(tr_state->transform);

        group_2d_traverse((GF_Node *)&stack->untr, (GroupingNode2D *)stack, tr_state);

        gf_mx2d_copy(tr_state->transform, mx2d_backup);


    }
}
コード例 #9
0
ファイル: hardcoded_protos.c プロジェクト: jnorthrup/gpac
static void TraverseOffscreenGroup(GF_Node *node, void *rs, Bool is_destroy)
{
    OffscreenGroupStack *stack = (OffscreenGroupStack *)gf_node_get_private(node);
    GF_TraverseState *tr_state = (GF_TraverseState *) rs;

    if (is_destroy) {
        if (stack->cache) group_cache_del(stack->cache);
        gf_free(stack);
        return;
    }

    if (tr_state->traversing_mode==TRAVERSE_SORT) {
        if (!stack->detached && (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY)) {
            OffscreenGroup_GetNode(node, &stack->og);

            if (stack->og.offscreen) {
                stack->flags |= GROUP_IS_CACHED | GROUP_PERMANENT_CACHE;
                if (!stack->cache) {
                    stack->cache = group_cache_new(tr_state->visual->compositor, (GF_Node*)&stack->og);
                }
                stack->cache->opacity = stack->og.opacity;
                stack->cache->drawable->flags |= DRAWABLE_HAS_CHANGED;
            } else {
                if (stack->cache) group_cache_del(stack->cache);
                stack->cache = NULL;
                stack->flags &= ~(GROUP_IS_CACHED|GROUP_PERMANENT_CACHE);
            }
            gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
            /*flag is not set for PROTO*/
            gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, 0);
        }
        if (stack->cache) {
            if (stack->detached)
                gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);

            tr_state->subscene_not_over = 0;
            group_cache_traverse((GF_Node *)&stack->og, stack->cache, tr_state, stack->cache->force_recompute, 1, stack->detached ? 1 : 0);

            if (gf_node_dirty_get(node)) {
                gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
            } else if ((stack->og.offscreen==2) && !stack->detached && !tr_state->subscene_not_over && stack->cache->txh.width && stack->cache->txh.height) {
                GF_FieldInfo field;
                if (gf_node_get_field(node, 0, &field) == GF_OK) {
                    gf_node_unregister_children(node, *(GF_ChildNodeItem **) field.far_ptr);
                    *(GF_ChildNodeItem **) field.far_ptr = NULL;
                    stack->detached = 1;
                }
                if (gf_node_get_field(node, 3, &field) == GF_OK) {
                    *(SFBool *) field.far_ptr = 1;
                    //gf_node_event_out(node, 3);
                }
            }
        } else {
            group_2d_traverse((GF_Node *)&stack->og, (GroupingNode2D*)stack, tr_state);
        }
    }
    /*draw mode*/
    else if (stack->cache && (tr_state->traversing_mode == TRAVERSE_DRAW_2D)) {
        /*draw it*/
        group_cache_draw(stack->cache, tr_state);
        gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
    } else if (!stack->detached) {
        group_2d_traverse((GF_Node *)&stack->og, (GroupingNode2D*)stack, tr_state);
    } else {
        if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
            tr_state->bounds = stack->bounds;
        }
        else if (tr_state->traversing_mode == TRAVERSE_PICK) {
            vrml_drawable_pick(stack->cache->drawable, tr_state);
        }
    }
}
コード例 #10
0
ファイル: mpeg4_layer_2d.c プロジェクト: golgol7777/gpac
static void TraverseLayer2D(GF_Node *node, void *rs, Bool is_destroy)
{
	GF_List *oldb, *oldv;
	GF_Node *viewport;
	GF_Node *back;
	Bool prev_layer;
	GF_Matrix2D backup;
	SFVec2f prev_vp;

#ifndef GPAC_DISABLE_3D
	GF_Matrix mx3d;
	GF_List *oldf, *oldn;
	GF_List *node_list_backup;
	GF_Rect prev_clipper;
	Bool had_clip;
#endif
	
	M_Layer2D *l = (M_Layer2D *)node;
	Layer2DStack *st = (Layer2DStack *) gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *) rs;
	
	if (is_destroy) {
		gf_list_del(st->backs);
		gf_list_del(st->views);
		group_2d_destroy(node, (GroupingNode2D*)st);
		gf_free(st);
		return;
	}

	/*layers can only be used in a 2D context*/
#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d && tr_state->camera->is_3D) return;
#endif

	/*layer2D maintains its own stacks*/
	oldb = tr_state->backgrounds;
	oldv = tr_state->viewpoints;
	tr_state->backgrounds = st->backs;
	tr_state->viewpoints = st->views;
	prev_layer = tr_state->is_layer;
	tr_state->is_layer = 1;
#ifndef GPAC_DISABLE_3D
	oldf = tr_state->fogs;
	oldn = tr_state->navigations;
	tr_state->fogs = tr_state->navigations = NULL;
#endif

	l2d_CheckBindables(node, tr_state, st->first);

	back = (GF_Node*)gf_list_get(st->backs, 0);

	viewport = (GF_Node*)gf_list_get(st->views, 0);

	if ((tr_state->traversing_mode == TRAVERSE_SORT) || (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS)) {
		/*override group bounds*/
		visual_get_size_info(tr_state, &st->clip.width, &st->clip.height);
		/*setup bounds in local coord system*/
		if (l->size.x>=0) st->clip.width = l->size.x;
		if (l->size.y>=0) st->clip.height = l->size.y;
		st->clip = gf_rect_center(st->clip.width, st->clip.height);
		st->bounds = st->clip;
	}
	
	prev_vp = tr_state->vp_size;
	tr_state->vp_size.x = st->clip.width;
	tr_state->vp_size.y = st->clip.height;

	switch (tr_state->traversing_mode) {
	case TRAVERSE_SORT:
#ifndef GPAC_DISABLE_3D
		if (tr_state->visual->type_3d) {
			tr_state->layer_clipper = compositor_2d_update_clipper(tr_state, st->clip, &had_clip, &prev_clipper, 1);

			visual_3d_matrix_push(tr_state->visual);
			gf_mx_copy(mx3d, tr_state->model_matrix);

			/*setup clipping*/
			visual_3d_set_clipper_2d(tr_state->visual, tr_state->layer_clipper);
			
			/*apply background BEFORE viewport*/
			if (back) {
				tr_state->traversing_mode = TRAVERSE_BINDABLE;
				gf_bbox_from_rect(&tr_state->bbox, &st->clip);
				gf_node_traverse(back, tr_state);
			}

			/*sort all children without transform, and use current transform when flushing contexts*/
			gf_mx_init(tr_state->model_matrix);

			/*apply viewport*/
			if (viewport) {
				tr_state->traversing_mode = TRAVERSE_BINDABLE;
				tr_state->bounds = st->clip;
				gf_node_traverse(viewport, tr_state);
				visual_3d_matrix_add(tr_state->visual, tr_state->model_matrix.m);
			}


			node_list_backup = tr_state->visual->alpha_nodes_to_draw;
			tr_state->visual->alpha_nodes_to_draw = gf_list_new();
			tr_state->traversing_mode = TRAVERSE_SORT;
			/*reset cull flag*/
			tr_state->cull_flag = 0;
			group_2d_traverse(node, (GroupingNode2D *)st, tr_state);

			visual_3d_flush_contexts(tr_state->visual, tr_state);
			tr_state->traversing_mode = TRAVERSE_SORT;

			assert(!gf_list_count(tr_state->visual->alpha_nodes_to_draw));
			gf_list_del(tr_state->visual->alpha_nodes_to_draw);
			tr_state->visual->alpha_nodes_to_draw = node_list_backup;

			
			visual_3d_matrix_pop(tr_state->visual);
			gf_mx_copy(tr_state->model_matrix, mx3d);

			visual_3d_reset_clipper_2d(tr_state->visual);

			tr_state->has_layer_clip = had_clip;
			if (had_clip) {
				tr_state->layer_clipper = prev_clipper;
				visual_3d_set_clipper_2d(tr_state->visual, tr_state->layer_clipper);
			}
		} else 
#endif
		{
			GF_IRect prev_clip;
			GF_Rect rc;

			gf_mx2d_copy(backup, tr_state->transform);

			prev_clip = tr_state->visual->top_clipper;
			rc = st->clip;
			
			/*get clipper in world coordinate*/
			gf_mx2d_apply_rect(&tr_state->transform, &rc);

			if (viewport) {
				tr_state->traversing_mode = TRAVERSE_BINDABLE;
				tr_state->bounds = st->clip;
				gf_node_traverse(viewport, tr_state);
#if VIEWPORT_CLIPS
				/*move viewport box in world coordinate*/
				gf_mx2d_apply_rect(&backup, &tr_state->bounds);
				/*and intersect with layer clipper*/
				rect_intersect(&rc, &tr_state->bounds);
#endif
			}

			tr_state->visual->top_clipper = gf_rect_pixelize(&rc);
			gf_irect_intersect(&tr_state->visual->top_clipper, &prev_clip);
			tr_state->traversing_mode = TRAVERSE_SORT;

			if (tr_state->visual->top_clipper.width && tr_state->visual->top_clipper.height) {
				if (back && Bindable_GetIsBound(back) ) {
					DrawableContext *ctx;

					ctx = b2d_get_context((M_Background2D*) back, st->backs);
					gf_mx2d_init(ctx->transform);
					ctx->bi->clip = tr_state->visual->top_clipper;
					ctx->bi->unclip = rc;

					if (tr_state->immediate_draw) {
						tr_state->ctx = ctx;
						tr_state->traversing_mode = TRAVERSE_DRAW_2D;
						gf_node_traverse(back, tr_state);
						tr_state->traversing_mode = TRAVERSE_SORT;
						tr_state->ctx = NULL;
					} else {
						DrawableContext *back_ctx = visual_2d_get_drawable_context(tr_state->visual);

						gf_node_traverse(back, tr_state);

						back_ctx->flags = ctx->flags;
						back_ctx->flags &= ~CTX_IS_TRANSPARENT;
						back_ctx->flags |= CTX_IS_BACKGROUND;
						back_ctx->aspect = ctx->aspect;
						back_ctx->drawable = ctx->drawable;
						drawable_check_bounds(back_ctx, tr_state->visual);
						back_ctx->bi->clip = ctx->bi->clip;
						back_ctx->bi->unclip = ctx->bi->unclip;
					}
					/*keep track of node drawn*/
					if (!(ctx->drawable->flags & DRAWABLE_REGISTERED_WITH_VISUAL) ) {
						struct _drawable_store *it;
						GF_SAFEALLOC(it, struct _drawable_store);
						it->drawable = ctx->drawable;
						if (tr_state->visual->last_prev_entry) {
							tr_state->visual->last_prev_entry->next = it;
							tr_state->visual->last_prev_entry = it;
						} else {
							tr_state->visual->prev_nodes = tr_state->visual->last_prev_entry = it;
						}
						GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Layer2D] Registering new drawn node %s on visual\n", gf_node_get_class_name(it->drawable->node)));
						ctx->drawable->flags |= DRAWABLE_REGISTERED_WITH_VISUAL;
					}
				}

				group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
			}
			tr_state->visual->top_clipper = prev_clip;
			gf_mx2d_copy(tr_state->transform, backup);
		}
		break;
		
		/*check picking - we must fall in our 2D clipper*/
	case TRAVERSE_PICK:
		if (gf_sc_pick_in_clipper(tr_state, &st->clip)) {
		
#ifndef GPAC_DISABLE_3D
			if (tr_state->visual->type_3d) {
				/*apply viewport*/
				if (viewport) {
					gf_mx_copy(mx3d, tr_state->model_matrix);
					tr_state->traversing_mode = TRAVERSE_BINDABLE;
					tr_state->bounds = st->clip;
					gf_node_traverse(viewport, tr_state);
					tr_state->traversing_mode = TRAVERSE_PICK;
					group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
					gf_mx_copy(tr_state->model_matrix, mx3d);
				} else {
					group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
				}
			} else 
#endif
			{
				if (viewport) {
					gf_mx2d_copy(backup, tr_state->transform);
					tr_state->traversing_mode = TRAVERSE_BINDABLE;
					tr_state->bounds = st->clip;
					gf_node_traverse(viewport, tr_state);
					tr_state->traversing_mode = TRAVERSE_PICK;
					group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
					gf_mx2d_copy(tr_state->transform, backup);
				} else {
					group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
				}
			}	
		}
		break;
	case TRAVERSE_GET_BOUNDS:
		if (tr_state->for_node) {
			group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
		} else {
			tr_state->bounds = st->clip;
#ifndef GPAC_DISABLE_3D
			gf_bbox_from_rect(&tr_state->bbox, &st->clip);
#endif
		}
		break;

	case TRAVERSE_DRAW_2D:
		group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
		break;

#ifndef GPAC_DISABLE_3D
	/*drawing a layer means drawing all sub-elements as a whole (no depth sorting with parents)*/
	case TRAVERSE_DRAW_3D:
		assert(0);
		break;
#endif
	}
	
	/*restore traversing state*/
	tr_state->vp_size = prev_vp;
	tr_state->backgrounds = oldb;
	tr_state->viewpoints = oldv;
	tr_state->is_layer = prev_layer;
#ifndef GPAC_DISABLE_3D
	tr_state->fogs = oldf;
	tr_state->navigations = oldn;
#endif

	/*in case we missed bindables*/
	if (st->first) {
		st->first = 0;
		gf_sc_invalidate(tr_state->visual->compositor, NULL);
	}
}