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); } }
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 }
/*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; }
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; } }
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); } }
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; }
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); }
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); } }
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); } } }
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); } }