Exemplo n.º 1
0
static void TraverseFog(GF_Node *node, void *rs, Bool is_destroy)
{
	Fixed density, vrange;
	SFVec3f start, end;
	ViewStack *vp_st;
	M_Viewpoint *vp;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	M_Fog *fog = (M_Fog *) node;
	ViewStack *st = (ViewStack *) gf_node_get_private(node);

	if (is_destroy) {
		DestroyViewStack(node);
		return;
	}

	if (!tr_state->fogs) return;

	/*first traverse, bound if needed*/
	if (gf_list_find(tr_state->fogs, node) < 0) {
		gf_list_add(tr_state->fogs, node);
		if (gf_list_get(tr_state->fogs, 0) == fog) {
			if (!fog->isBound) Bindable_SetIsBound(node, 1);
		}
		assert(gf_list_find(st->reg_stacks, tr_state->fogs)==-1);
		gf_list_add(st->reg_stacks, tr_state->fogs);

		gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
		/*in any case don't draw the first time*/
		gf_sc_invalidate(tr_state->visual->compositor, NULL);
		return;
	}
	/*not evaluating, return*/
	if (tr_state->traversing_mode != TRAVERSE_BINDABLE) {
		if ((tr_state->traversing_mode==TRAVERSE_SORT) || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) )
			gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
		return;
	}
	/*not bound*/
	if (!fog->isBound || !fog->visibilityRange) return;

	/*fog visibility is expressed in current bound VP so get its matrix*/
	vp = (M_Viewpoint*)gf_list_get(tr_state->viewpoints, 0);
	vp_st = NULL;
	if (vp && vp->isBound) vp_st = (ViewStack *) gf_node_get_private((GF_Node *)vp);

	start.x = start.y = start.z = 0;
	end.x = end.y = 0;
	end.z = fog->visibilityRange;
	if (vp_st) {
		gf_mx_apply_vec(&vp_st->world_view_mx, &start);
		gf_mx_apply_vec(&vp_st->world_view_mx, &end);
	}
	gf_mx_apply_vec(&st->world_view_mx, &start);
	gf_mx_apply_vec(&st->world_view_mx, &end);
	gf_vec_diff(end, end, start);
	vrange = gf_vec_len(end);

	density = gf_invfix(vrange);
	visual_3d_set_fog(tr_state->visual, fog->fogType.buffer, fog->color, density, vrange);
}
Exemplo n.º 2
0
Arquivo: bindable.c Projeto: zsuo/gpac
void Bindable_OnSetBind(GF_Node *bindable, GF_List *stack_list, GF_List *for_stack)
{
	u32 i;
	Bool on_top, is_bound, set_bind;
	GF_Node *node;
	GF_List *stack;

	set_bind = Bindable_GetSetBind(bindable);
	is_bound = Bindable_GetIsBound(bindable);

	if (!set_bind && !is_bound) return;
	if (set_bind && is_bound) return;

	i=0;
	while ((stack = (GF_List*)gf_list_enum(stack_list, &i))) {
		if (for_stack && (for_stack!=stack)) continue;

		on_top = (gf_list_get(stack, 0)==bindable) ? GF_TRUE : GF_FALSE;

		if (!set_bind) {
			if (is_bound) Bindable_SetIsBound(bindable, GF_FALSE);
			if (on_top && (gf_list_count(stack)>1)) {
				gf_list_rem(stack, 0);
				gf_list_add(stack, bindable);
				node = (GF_Node*)gf_list_get(stack, 0);
				Bindable_SetIsBound(node, GF_TRUE);
			}
		} else {
			if (!is_bound) Bindable_SetIsBound(bindable, GF_TRUE);
			if (!on_top) {
				/*push old top one down and unbind*/
				node = (GF_Node*)gf_list_get(stack, 0);
				Bindable_SetIsBound(node, GF_FALSE);
				/*insert new top*/
				gf_list_del_item(stack, bindable);
				gf_list_insert(stack, bindable, 0);
			}
		}
	}
	/*force invalidate of the bindable stack's owner*/
	gf_node_dirty_set(bindable, 0, GF_TRUE);
	/*and redraw scene*/
	gf_sc_invalidate(gf_sc_get_compositor(bindable), NULL);
}
Exemplo n.º 3
0
Arquivo: bindable.c Projeto: zsuo/gpac
void PreDestroyBindable(GF_Node *bindable, GF_List *stack_list)
{
#if REBIND_AT_DESTROY
	Bool is_bound = Bindable_GetIsBound(bindable);
#endif
	Bindable_SetIsBound(bindable, GF_FALSE);

	while (gf_list_count(stack_list)) {
#if REBIND_AT_DESTROY
		GF_Node *stack_top;
#endif
		GF_List *stack = (GF_List*)gf_list_get(stack_list, 0);
		gf_list_rem(stack_list, 0);
		gf_list_del_item(stack, bindable);
#if REBIND_AT_DESTROY
		if (is_bound) {
			stack_top = (GF_Node*)gf_list_get(stack, 0);
			if (stack_top) Bindable_SetSetBind(stack_top, GF_TRUE);
		}
#endif
		
	}
}
Exemplo n.º 4
0
static void TraverseNavigationInfo(GF_Node *node, void *rs, Bool is_destroy)
{
	u32 i;
#ifndef GPAC_DISABLE_3D
	u32 nb_select_mode;
	SFVec3f start, end;
	Fixed scale;
	ViewStack *st = (ViewStack *) gf_node_get_private(node);
#endif
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	M_NavigationInfo *ni = (M_NavigationInfo *) node;

	if (is_destroy) {
		DestroyViewStack(node);
		return;
	}
#ifdef GPAC_DISABLE_3D

	/*FIXME, we only deal with one node, no bind stack for the current time*/
	for (i=0; i<ni->type.count; i++) {
		if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "NONE")) {
			tr_state->visual->compositor->navigation_disabled = 1;
		}
	}
#else

	if (!tr_state->navigations) return;

	/*first traverse, bound if needed*/
	if (gf_list_find(tr_state->navigations, node) < 0) {
		gf_list_add(tr_state->navigations, node);
		if (gf_list_get(tr_state->navigations, 0) == ni) {
			if (!ni->isBound) Bindable_SetIsBound(node, 1);
		}
		assert(gf_list_find(st->reg_stacks, tr_state->navigations)==-1);
		gf_list_add(st->reg_stacks, tr_state->navigations);
		gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
		/*in any case don't draw the first time*/
		gf_sc_invalidate(tr_state->visual->compositor, NULL);
		return;
	}
	/*not bound*/
	if (!ni->isBound) return;
	/*not evaluating, return*/
	if (tr_state->traversing_mode != TRAVERSE_BINDABLE) {
		if ((tr_state->traversing_mode==TRAVERSE_SORT) || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) ) {
			if (!gf_mx_equal(&st->world_view_mx, &tr_state->model_matrix)) {
				gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
				gf_node_dirty_set(node, 0, 0);
			}
		}
		return;
	}

	if (!gf_node_dirty_get(node)) return;
	gf_node_dirty_clear(node, 0);

	nb_select_mode = 0;
	tr_state->camera->navigation_flags = 0;
	tr_state->camera->navigate_mode = 0;
	for (i=0; i<ni->type.count; i++) {
		if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "ANY")) tr_state->camera->navigation_flags |= NAV_ANY;
		else {
			nb_select_mode++;
		}

		if (!tr_state->camera->navigate_mode) {
			if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "NONE")) tr_state->camera->navigate_mode = GF_NAVIGATE_NONE;
			else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "WALK")) tr_state->camera->navigate_mode = GF_NAVIGATE_WALK;
			else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "EXAMINE")) tr_state->camera->navigate_mode = GF_NAVIGATE_EXAMINE;
			else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "FLY")) tr_state->camera->navigate_mode = GF_NAVIGATE_FLY;
			else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "VR")) tr_state->camera->navigate_mode = GF_NAVIGATE_VR;
		}
	}
	if (nb_select_mode>1) tr_state->camera->navigation_flags |= NAV_SELECTABLE;

	if (ni->headlight) tr_state->camera->navigation_flags |= NAV_HEADLIGHT;

	start.x = start.y = start.z = 0;
	end.x = end.y = 0;
	end.z = FIX_ONE;
	gf_mx_apply_vec(&st->world_view_mx, &start);
	gf_mx_apply_vec(&st->world_view_mx, &end);
	gf_vec_diff(end, end, start);
	scale = gf_vec_len(end);

	tr_state->camera->speed = gf_mulfix(scale, ni->speed);
	tr_state->camera->visibility = gf_mulfix(scale, ni->visibilityLimit);
	if (ni->avatarSize.count) tr_state->camera->avatar_size.x = gf_mulfix(scale, ni->avatarSize.vals[0]);
	if (ni->avatarSize.count>1) tr_state->camera->avatar_size.y = gf_mulfix(scale, ni->avatarSize.vals[1]);
	if (ni->avatarSize.count>2) tr_state->camera->avatar_size.z = gf_mulfix(scale, ni->avatarSize.vals[2]);

	if (0 && tr_state->pixel_metrics) {
		u32 s = MAX(tr_state->visual->width, tr_state->visual->height);
		s /= 2;
//		tr_state->camera->speed = ni->speed;
		tr_state->camera->visibility *= s;
		tr_state->camera->avatar_size.x *= s;
		tr_state->camera->avatar_size.y *= s;
		tr_state->camera->avatar_size.z *= s;
	}
#endif

}
Exemplo n.º 5
0
static void TraverseViewpoint(GF_Node *node, void *rs, Bool is_destroy)
{
	SFVec3f pos, v1, v2;
	SFRotation ori;
	GF_Matrix mx;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	M_Viewpoint *vp = (M_Viewpoint*) node;
	ViewStack *st = (ViewStack *) gf_node_get_private(node);

	if (is_destroy) {
		DestroyViewStack(node);
		return;
	}
	/*may happen in get_bounds*/
	if (!tr_state->viewpoints) return;
//	if (!tr_state->camera->is_3D) return;

	/*first traverse, bound if needed*/
	if (gf_list_find(tr_state->viewpoints, node) < 0) {
		gf_list_add(tr_state->viewpoints, node);
		assert(gf_list_find(st->reg_stacks, tr_state->viewpoints)==-1);
		gf_list_add(st->reg_stacks, tr_state->viewpoints);

		if (gf_list_get(tr_state->viewpoints, 0) == vp) {
			if (!vp->isBound) Bindable_SetIsBound(node, 1);
		} else {
			if (gf_inline_is_default_viewpoint(node)) Bindable_SetSetBind(node, 1);
		}
		VPCHANGED(tr_state->visual->compositor);
		/*in any case don't draw the first time (since the viewport could have been declared last)*/
		if (tr_state->layer3d) gf_node_dirty_set(tr_state->layer3d, GF_SG_VRML_BINDABLE_DIRTY, 0);
		gf_sc_invalidate(tr_state->visual->compositor, NULL);
	}
	/*not evaluating vp, return*/
	if (tr_state->traversing_mode != TRAVERSE_BINDABLE) {
		/*store model matrix if changed - NOTE: we always have a 1-frame delay between VP used and real world...
		we could remove this by pre-traversing the scene before applying vp, but that would mean 2 scene
		traversals*/
		if ((tr_state->traversing_mode==TRAVERSE_SORT) || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) ) {
			if (!gf_mx_equal(&st->world_view_mx, &tr_state->model_matrix)) {
				gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
				gf_node_dirty_set(node, 0, 0);
			}
		}
		return;
	}

	/*not bound or in 2D visual*/
	if (!vp->isBound || !tr_state->navigations) return;

	if (!gf_node_dirty_get(node)) return;
	gf_node_dirty_clear(node, 0);

	/*move to local system*/
	gf_mx_copy(mx, st->world_view_mx);
	gf_mx_add_translation(&mx, vp->position.x, vp->position.y, vp->position.z);
	gf_mx_add_rotation(&mx, vp->orientation.q, vp->orientation.x, vp->orientation.y, vp->orientation.z);
	gf_mx_decompose(&mx, &pos, &v1, &ori, &v2);
	/*get center*/
	v1.x = v1.y = v1.z = 0;
#ifndef GPAC_DISABLE_X3D
	/*X3D specifies examine center*/
	if (gf_node_get_tag(node)==TAG_X3D_Viewpoint) v1 = ((X_Viewpoint *)node)->centerOfRotation;
#endif
	gf_mx_apply_vec(&st->world_view_mx, &v1);
	/*set frustrum param - animate only if not bound last frame and jump false*/
	visual_3d_viewpoint_change(tr_state, node, (!st->prev_was_bound && !vp->jump) ? 1 : 0, vp->fieldOfView, pos, ori, v1);
	st->prev_was_bound = 1;
}
Exemplo n.º 6
0
static void TraverseViewport(GF_Node *node, void *rs, Bool is_destroy)
{
	Fixed sx, sy, w, h, tx, ty;
#ifndef GPAC_DISABLE_3D
	GF_Matrix mx;
#endif
	GF_Matrix2D mat;
	GF_Rect rc, rc_bckup;
	ViewStack *st = (ViewStack *) gf_node_get_private(node);
	M_Viewport *vp = (M_Viewport *) node;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;

	if (is_destroy) {
		DestroyViewStack(node);
		return;
	}

#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d>1) return;
#endif

	/*first traverse, bound if needed*/
	if (gf_list_find(tr_state->viewpoints, node) < 0) {
		gf_list_add(tr_state->viewpoints, node);
		assert(gf_list_find(st->reg_stacks, tr_state->viewpoints)==-1);
		gf_list_add(st->reg_stacks, tr_state->viewpoints);

		if (gf_list_get(tr_state->viewpoints, 0) == vp) {
			if (!vp->isBound) Bindable_SetIsBound(node, 1);
		} else {
			if (gf_inline_is_default_viewpoint(node)) Bindable_SetSetBindEx(node, 1, tr_state->viewpoints);
		}
		VPCHANGED(tr_state->visual->compositor);
		/*in any case don't draw the first time (since the viewport could have been declared last)*/
		gf_sc_invalidate(tr_state->visual->compositor, NULL);
		return;
	}

	if (tr_state->traversing_mode != TRAVERSE_BINDABLE) return;
	if (!vp->isBound) return;

	if (gf_list_get(tr_state->viewpoints, 0) != vp)
		return;

#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		w = tr_state->bbox.max_edge.x - tr_state->bbox.min_edge.x;
		h = tr_state->bbox.max_edge.y - tr_state->bbox.min_edge.y;
	} else
#endif
	{
		w = tr_state->bounds.width;
		h = tr_state->bounds.height;
	}
	if (!w || !h) return;


	/*if no parent this is the main viewport, don't update if not changed*/
//	if (!tr_state->is_layer && !gf_node_dirty_get(node)) return;

	gf_node_dirty_clear(node, 0);

	gf_mx2d_init(mat);
	gf_mx2d_add_translation(&mat, vp->position.x, vp->position.y);
	gf_mx2d_add_rotation(&mat, 0, 0, vp->orientation);

	//compute scaling ratio
	sx = (vp->size.x>=0) ? vp->size.x : w;
	sy = (vp->size.y>=0) ? vp->size.y : h;
	rc = gf_rect_center(sx, sy);
	rc_bckup = rc;

	switch (vp->fit) {
	/*covers all area and respect aspect ratio*/
	case 2:
		if (gf_divfix(rc.width, w) > gf_divfix(rc.height, h)) {
			rc.width = gf_muldiv(rc.width, h, rc.height);
			rc.height = h;
		} else {
			rc.height = gf_muldiv(rc.height , w, rc.width);
			rc.width = w;
		}
		break;
	/*fits inside the area and respect AR*/
	case 1:
		if (gf_divfix(rc.width, w)> gf_divfix(rc.height, h)) {
			rc.height = gf_muldiv(rc.height, w, rc.width);
			rc.width = w;
		} else {
			rc.width = gf_muldiv(rc.width, h, rc.height);
			rc.height = h;
		}
		break;
	/*fit entirely: nothing to change*/
	case 0:
		rc.width = w;
		rc.height = h;
		break;
	default:
		return;
	}
	sx = gf_divfix(rc.width, rc_bckup.width);
	sy = gf_divfix(rc.height, rc_bckup.height);

	/*viewport on root visual, remove compositor scale*/
	if (!tr_state->is_layer && (tr_state->visual->compositor->visual==tr_state->visual) ) {
		sx = gf_divfix(sx, tr_state->visual->compositor->scale_x);
		sy = gf_divfix(sy, tr_state->visual->compositor->scale_y);
	}

	rc.x = - rc.width/2;
	rc.y = rc.height/2;

	tx = ty = 0;
	if (vp->fit && vp->alignment.count) {
		/*left alignment*/
		if (vp->alignment.vals[0] == -1) tx = rc.width/2 - w/2;
		else if (vp->alignment.vals[0] == 1) tx = w/2 - rc.width/2;

		if (vp->alignment.count>1) {
			/*top-alignment*/
			if (vp->alignment.vals[1]==-1) ty = rc.height/2 - h/2;
			else if (vp->alignment.vals[1]==1) ty = h/2 - rc.height/2;
		}
	}

	gf_mx2d_init(mat);
	if (tr_state->pixel_metrics) {
		gf_mx2d_add_scale(&mat, sx, sy);
	} else {
		/*if we are not in pixelMetrics, undo the meterMetrics->pixelMetrics transformation*/
		gf_mx2d_add_scale(&mat, gf_divfix(sx, tr_state->min_hsize), gf_divfix(sy, tr_state->min_hsize) );
	}
	gf_mx2d_add_translation(&mat, tx, ty);

	gf_mx2d_add_translation(&mat, -gf_mulfix(vp->position.x,sx), -gf_mulfix(vp->position.y,sy) );
	gf_mx2d_add_rotation(&mat, 0, 0, vp->orientation);

	tr_state->bounds = rc;
	tr_state->bounds.x += tx;
	tr_state->bounds.y += ty;

#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		/*in layers directly modify the model matrix*/
		if (tr_state->is_layer) {
			gf_mx_from_mx2d(&mx, &mat);
			gf_mx_add_matrix(&tr_state->model_matrix, &mx);
		}
		/*otherwise add to camera viewport matrix*/
		else {
			gf_mx_from_mx2d(&tr_state->camera->viewport, &mat);
			tr_state->camera->flags = (CAM_HAS_VIEWPORT | CAM_IS_DIRTY);
		}
	} else
#endif
		gf_mx2d_pre_multiply(&tr_state->transform, &mat);
}
Exemplo n.º 7
0
static void TraverseBackground2D(GF_Node *node, void *rs, Bool is_destroy)
{
	u32 col;
	BackgroundStatus *status;
	M_Background2D *bck;
	Background2DStack *stack = (Background2DStack *) gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;

	if (is_destroy) {
		DestroyBackground2D(node);
		return;
	}

	bck = (M_Background2D *)node;

	/*special case for background in Layer2D: the background is seen as a regular drawable, so 
	RENDER_BINDABLE is not used*/
	switch (tr_state->traversing_mode) {
	case TRAVERSE_DRAW_2D:
		DrawBackground2D_2D(tr_state->ctx, tr_state);
		return;
	case  TRAVERSE_PICK:
	case TRAVERSE_GET_BOUNDS:
		return;
	}

	/*first traverse, bound if needed*/
	if (gf_list_find(tr_state->backgrounds, node) < 0) {
		M_Background2D *top_bck = (M_Background2D *)node;
		gf_list_add(tr_state->backgrounds, node);
		assert(gf_list_find(stack->reg_stacks, tr_state->backgrounds)==-1);
		gf_list_add(stack->reg_stacks, tr_state->backgrounds);
		b2D_new_status(stack, bck);

		/*only bound if we're on top*/
		top_bck = gf_list_get(tr_state->backgrounds, 0);
		if (!bck->isBound) {
			if (top_bck== bck) {
				Bindable_SetIsBound(node, 1);
			} else if (!top_bck->isBound) {
				bck->set_bind = 1;
				bck->on_set_bind(node, NULL);
			}
		}
		/*open the stream if any*/
		if (back_use_texture(bck) && !stack->txh.is_open) gf_sc_texture_play(&stack->txh, &bck->url);
		/*in any case don't draw the first time (since the background could have been declared last)*/
		gf_sc_invalidate(stack->txh.compositor, NULL);
		return;
	}
	if (!bck->isBound) return;

	status = b2d_get_status(stack, tr_state->backgrounds);
	if (!status) return;

	if (gf_node_dirty_get(node)) {
		stack->flags |= CTX_APP_DIRTY;
		gf_node_dirty_clear(node, 0);


		col = GF_COL_ARGB_FIXED(FIX_ONE, bck->backColor.red, bck->backColor.green, bck->backColor.blue);
		if (col != status->ctx.aspect.fill_color) {
			status->ctx.aspect.fill_color = col;
			stack->flags |= CTX_APP_DIRTY;
		}
	} 

	if (back_use_texture(bck) ) {
		if (stack->txh.tx_io && !(status->ctx.flags & CTX_APP_DIRTY) && stack->txh.needs_refresh) 
			stack->flags |= CTX_TEXTURE_DIRTY;
	}
	status->ctx.flags = stack->flags;


	if (tr_state->traversing_mode != TRAVERSE_BINDABLE) return;

	/*3D mode*/
#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		DrawBackground2D_3D(bck, stack, tr_state);
	} else
#endif
		DrawBackground2D_2D(&status->ctx, tr_state);
}
Exemplo n.º 8
0
static void TraverseBackground(GF_Node *node, void *rs, Bool is_destroy)
{
	M_Background *bck;
	BackgroundStack *st;
	SFColor bcol;
	SFVec4f res;
	Fixed scale;
	Bool has_sky, has_ground, front_tx, back_tx, top_tx, bottom_tx, right_tx, left_tx;
	GF_Matrix mx;
	GF_Compositor *compositor;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;

	if (is_destroy) {
		DestroyBackground(node);
		return;
	}

	gf_node_dirty_clear(node, 0);
	bck = (M_Background *)node;
	st = (BackgroundStack *) gf_node_get_private(node);
	compositor = (GF_Compositor*)st->compositor;


	/*may happen in get_bounds*/
	if (!tr_state->backgrounds) return;

	/*first traverse, bound if needed*/
	if (gf_list_find(tr_state->backgrounds, node) < 0) {
		gf_list_add(tr_state->backgrounds, node);
		assert(gf_list_find(st->reg_stacks, tr_state->backgrounds)==-1);
		gf_list_add(st->reg_stacks, tr_state->backgrounds);
		/*only bound if we're on top*/
		if (gf_list_get(tr_state->backgrounds, 0) == bck) {
			if (!bck->isBound) Bindable_SetIsBound(node, 1);
		}

		/*check streams*/
		if (back_use_texture(&bck->frontUrl) && !st->txh_front.is_open) gf_sc_texture_play(&st->txh_front, &bck->frontUrl);
		if (back_use_texture(&bck->bottomUrl) && !st->txh_bottom.is_open) gf_sc_texture_play(&st->txh_bottom, &bck->bottomUrl);
		if (back_use_texture(&bck->backUrl) && !st->txh_back.is_open) gf_sc_texture_play(&st->txh_back, &bck->backUrl);
		if (back_use_texture(&bck->topUrl) && !st->txh_top.is_open) gf_sc_texture_play(&st->txh_top, &bck->topUrl);
		if (back_use_texture(&bck->rightUrl) && !st->txh_right.is_open) gf_sc_texture_play(&st->txh_right, &bck->rightUrl);
		if (back_use_texture(&bck->leftUrl) && !st->txh_left.is_open) gf_sc_texture_play(&st->txh_left, &bck->leftUrl);

		/*in any case don't draw the first time (since the background could have been declared last)*/
		gf_sc_invalidate(st->compositor, NULL);
		return;
	}
	if (!bck->isBound) return;

	if (tr_state->traversing_mode != TRAVERSE_BINDABLE) {
		if (tr_state->traversing_mode == TRAVERSE_SORT) {
			gf_mx_copy(st->current_mx, tr_state->model_matrix);
		}
		return;
	}

	front_tx = back_gf_sc_texture_enabled(&bck->frontUrl, &st->txh_front);
	back_tx = back_gf_sc_texture_enabled(&bck->backUrl, &st->txh_back);
	top_tx = back_gf_sc_texture_enabled(&bck->topUrl, &st->txh_top);
	bottom_tx = back_gf_sc_texture_enabled(&bck->bottomUrl, &st->txh_bottom);
	right_tx = back_gf_sc_texture_enabled(&bck->rightUrl, &st->txh_right);
	left_tx = back_gf_sc_texture_enabled(&bck->leftUrl, &st->txh_left);

	has_sky = ((bck->skyColor.count>1) && bck->skyAngle.count) ? 1 : 0;
	has_ground = ((bck->groundColor.count>1) && bck->groundAngle.count) ? 1 : 0;
	bcol.red = bcol.green = bcol.blue = 0;
	if (bck->skyColor.count) bcol = bck->skyColor.vals[0];

	/*if we clear the main visual clear it entirely - ONLY IF NOT IN LAYER*/
	if ((tr_state->visual == compositor->visual) && (tr_state->visual->back_stack == tr_state->backgrounds)) {
		visual_3d_clear(tr_state->visual, bcol, FIX_ONE);
		if (!has_sky && !has_ground && !front_tx && !back_tx && !top_tx && !bottom_tx && !left_tx && !right_tx) {
			return;
		}
	}

	/*undo translation*/
	res.x = res.y = res.z = 0;
	res.q = FIX_ONE;
	gf_mx_apply_vec_4x4(&tr_state->camera->unprojection, &res);
	assert(res.q);
	res.x = gf_divfix(res.x, res.q);
	res.y = gf_divfix(res.y, res.q);
	res.z = gf_divfix(res.z, res.q);
	/*NB: we don't support local rotation of the background ...*/

	/*enable background state (turn off all quality options)*/
	visual_3d_set_background_state(tr_state->visual, 1);

	if (has_sky) {
		GF_Matrix bck_mx;
		gf_mx_copy(bck_mx, tr_state->model_matrix);
		gf_mx_copy(tr_state->model_matrix, st->current_mx);

		if (!st->sky_mesh) {
			st->sky_mesh = new_mesh();
			back_build_dome(st->sky_mesh, &bck->skyAngle, &bck->skyColor, 0);
		}

		gf_mx_init(mx);
		gf_mx_add_translation(&mx, res.x, res.y, res.z);

		/*CHECKME - not sure why, we need to scale less in fixed point otherwise z-far clipping occur - probably some
		rounding issues...*/
#ifdef GPAC_FIXED_POINT
		scale = (tr_state->camera->z_far/10)*8;
#else
		scale = 9*tr_state->camera->z_far/10;
#endif
		gf_mx_add_scale(&mx, scale, scale, scale);

		gf_mx_add_matrix(&tr_state->model_matrix, &mx);

		visual_3d_mesh_paint(tr_state, st->sky_mesh);

		gf_mx_copy(tr_state->model_matrix, bck_mx);
	}

	if (has_ground) {
		GF_Matrix bck_mx;
		gf_mx_copy(bck_mx, tr_state->model_matrix);
		gf_mx_copy(tr_state->model_matrix, st->current_mx);

		if (!st->ground_mesh) {
			st->ground_mesh = new_mesh();
			back_build_dome(st->ground_mesh, &bck->groundAngle, &bck->groundColor, 1);
		}

		gf_mx_init(mx);
		gf_mx_add_translation(&mx, res.x, res.y, res.z);
		/*cf above*/
#ifdef GPAC_FIXED_POINT
		scale = (tr_state->camera->z_far/100)*70;
#else
		scale = 85*tr_state->camera->z_far/100;
#endif
		gf_mx_add_scale(&mx, scale, -scale, scale);

		gf_mx_add_matrix(&tr_state->model_matrix, &mx);
		visual_3d_mesh_paint(tr_state, st->ground_mesh);
		gf_mx_copy(tr_state->model_matrix, bck_mx);
	}

	if (front_tx || back_tx || left_tx || right_tx || top_tx || bottom_tx) {
		GF_Matrix bck_mx;
		gf_mx_copy(bck_mx, tr_state->model_matrix);
		gf_mx_copy(tr_state->model_matrix, st->current_mx);

		gf_mx_init(mx);
		gf_mx_add_translation(&mx, res.x, res.y, res.z);
#ifdef GPAC_FIXED_POINT
		scale = (tr_state->camera->z_far/100)*99;
		gf_mx_add_scale(&mx, scale, scale, scale);
#else
		gf_mx_add_scale(&mx, tr_state->camera->z_far, tr_state->camera->z_far, tr_state->camera->z_far);
#endif
		visual_3d_enable_antialias(tr_state->visual, 1);

		gf_mx_add_matrix(&tr_state->model_matrix, &mx);

		if (front_tx) back_draw_texture(tr_state, &st->txh_front, st->front_mesh);
		if (back_tx) back_draw_texture(tr_state, &st->txh_back, st->back_mesh);
		if (top_tx) back_draw_texture(tr_state, &st->txh_top, st->top_mesh);
		if (bottom_tx) back_draw_texture(tr_state, &st->txh_bottom, st->bottom_mesh);
		if (left_tx) back_draw_texture(tr_state, &st->txh_left, st->left_mesh);
		if (right_tx) back_draw_texture(tr_state, &st->txh_right, st->right_mesh);

		gf_mx_copy(tr_state->model_matrix, bck_mx);
	}

	/*enable background state (turn off all quality options)*/
	visual_3d_set_background_state(tr_state->visual, 0);
}