Bool visual_2d_draw_frame(GF_VisualManager *visual, GF_Node *root, GF_TraverseState *tr_state, Bool is_root_visual) { GF_SceneGraph *sg; GF_Matrix2D backup; u32 i; Bool res; GF_Err e; #ifndef GPAC_DISABLE_LOG u32 itime, time = gf_sys_clock(); #endif gf_mx2d_copy(backup, tr_state->transform); visual->bounds_tracker_modif_flag = DRAWABLE_HAS_CHANGED; e = visual_2d_init_draw(visual, tr_state); if (e) { gf_mx2d_copy(tr_state->transform, backup); GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Visual2D] Cannot init draw phase: %s\n", gf_error_to_string(e))); return 0; } #ifndef GPAC_DISABLE_LOG itime = gf_sys_clock(); visual->compositor->traverse_setup_time = itime - time; time = itime; #endif GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Traversing scene subtree (root node %s)\n", root ? gf_node_get_class_name(root) : "none")); if (is_root_visual) { gf_node_traverse(root, tr_state); i=0; while ((sg = (GF_SceneGraph*)gf_list_enum(visual->compositor->extra_scenes, &i))) { gf_sc_traverse_subscene(visual->compositor, root, sg, tr_state); } } else { gf_node_traverse(root, tr_state); } #ifndef GPAC_DISABLE_LOG itime = gf_sys_clock(); visual->compositor->traverse_and_direct_draw_time = itime - time; time = itime; #endif gf_mx2d_copy(tr_state->transform, backup); res = visual_2d_terminate_draw(visual, tr_state); #ifndef GPAC_DISABLE_LOG if (!tr_state->immediate_draw) { visual->compositor->indirect_draw_time = gf_sys_clock() - time; } #endif return res; }
void visual_2d_pick_node(GF_VisualManager *visual, GF_TraverseState *tr_state, GF_Event *ev, GF_ChildNodeItem *children) { GF_Matrix2D backup; visual->bounds_tracker_modif_flag = DRAWABLE_HAS_CHANGED_IN_LAST_TRAVERSE; gf_mx2d_copy(backup, tr_state->transform); visual_2d_setup_projection(visual, tr_state); visual->compositor->hit_node = NULL; tr_state->ray.orig.x = INT2FIX(ev->mouse.x); tr_state->ray.orig.y = INT2FIX(ev->mouse.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; visual->compositor->hit_world_point = tr_state->ray.orig; visual->compositor->hit_world_ray = tr_state->ray; visual->compositor->hit_square_dist = 0; gf_list_reset(visual->compositor->sensors); tr_state->traversing_mode = TRAVERSE_PICK; /*not the root scene, use children list*/ if (visual->compositor->visual != visual) { while (children) { gf_node_traverse(children->node, tr_state); children = children->next; } } else { u32 i = 0; GF_SceneGraph *sg = visual->compositor->scene; GF_Node *root = gf_sg_get_root_node(sg); gf_node_traverse(root, tr_state); while ((sg = (GF_SceneGraph*)gf_list_enum(visual->compositor->extra_scenes, &i))) { gf_sc_traverse_subscene(visual->compositor, root, sg, tr_state); } } gf_mx2d_copy(tr_state->transform, backup); }
static void svg_traverse_resource(GF_Node *node, void *rs, Bool is_destroy, Bool is_foreign_object) { GF_Matrix2D backup_matrix; GF_Matrix mx_3d; GF_Matrix2D translate; SVGPropertiesPointers backup_props; u32 backup_flags, dirty; Bool is_fragment; GF_Node *used_node; GF_TraverseState *tr_state = (GF_TraverseState *)rs; SVGAllAttributes all_atts; SVGlinkStack *stack = gf_node_get_private(node); SFVec2f prev_vp; SVG_Number *prev_opacity; if (is_destroy) { if (stack->resource) gf_mo_unload_xlink_resource(node, stack->resource); gf_free(stack); return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!all_atts.xlink_href) return; if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) return; dirty = gf_node_dirty_get(node); if (dirty & GF_SG_CHILD_DIRTY) drawable_reset_group_highlight(tr_state, node); if (dirty & GF_SG_SVG_XLINK_HREF_DIRTY) { stack->fragment_id = NULL; stack->inline_sg = NULL; if (all_atts.xlink_href->string && (all_atts.xlink_href->string[0]=='#')) { stack->fragment_id = all_atts.xlink_href->string; stack->inline_sg = gf_node_get_graph(node); } else { GF_MediaObject *new_res = gf_mo_load_xlink_resource(node, is_foreign_object, 0, -1); if (new_res != stack->resource) { if (stack->resource) gf_mo_unload_xlink_resource(node, stack->resource); stack->resource = new_res; } } } gf_node_dirty_clear(node, 0); /*locate the used node - this is done at each step to handle progressive loading*/ is_fragment = 0; used_node = NULL; if (!stack->inline_sg && !stack->fragment_id && all_atts.xlink_href) { if (all_atts.xlink_href->type == XMLRI_ELEMENTID) { used_node = all_atts.xlink_href->target; is_fragment = 1; } else if (stack->resource) { stack->inline_sg = gf_mo_get_scenegraph(stack->resource); if (!is_foreign_object) { stack->fragment_id = strchr(all_atts.xlink_href->string, '#'); } } } if (!used_node && stack->inline_sg) { if (stack->fragment_id) { used_node = gf_sg_find_node_by_name(stack->inline_sg, (char *) stack->fragment_id+1); is_fragment = 1; } else if (is_foreign_object) { used_node = gf_sg_get_root_node(stack->inline_sg); } } if (!used_node) goto end; /*stack use nodes for picking*/ gf_list_add(tr_state->use_stack, used_node); gf_list_add(tr_state->use_stack, node); gf_mx2d_init(translate); translate.m[2] = (all_atts.x ? all_atts.x->value : 0); translate.m[5] = (all_atts.y ? all_atts.y->value : 0); /*update VP size (SVG 1.1)*/ prev_vp = tr_state->vp_size; if (all_atts.width && all_atts.height) { tr_state->vp_size.x = gf_sc_svg_convert_length_to_display(tr_state->visual->compositor, all_atts.width); tr_state->vp_size.y = gf_sc_svg_convert_length_to_display(tr_state->visual->compositor, all_atts.height); } prev_opacity = tr_state->parent_use_opacity; tr_state->parent_use_opacity = all_atts.opacity; if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); if (!compositor_svg_is_display_off(tr_state->svg_props)) { gf_node_traverse(used_node, tr_state); gf_mx2d_apply_rect(&translate, &tr_state->bounds); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } /*SORT mode and visible, traverse*/ else if (!compositor_svg_is_display_off(tr_state->svg_props) && (*(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN)) { compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { gf_mx_add_matrix_2d(&tr_state->model_matrix, &translate); if (tr_state->traversing_mode==TRAVERSE_SORT) { GF_Matrix tmp; gf_mx_from_mx2d(&tmp, &translate); visual_3d_matrix_add(tr_state->visual, tmp.m); } } else #endif gf_mx2d_pre_multiply(&tr_state->transform, &translate); drawable_check_focus_highlight(node, tr_state, NULL); if (is_fragment) { gf_node_traverse(used_node, tr_state); } else { gf_sc_traverse_subscene(tr_state->visual->compositor, node, stack->inline_sg, tr_state); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } gf_list_rem_last(tr_state->use_stack); gf_list_rem_last(tr_state->use_stack); tr_state->vp_size = prev_vp; tr_state->parent_use_opacity = prev_opacity; end: memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; }
static void gf_inline_traverse(GF_Node *n, void *rs, Bool is_destroy) { MFURL *current_url; GF_Scene *scene = (GF_Scene *)gf_node_get_private(n); if (is_destroy) { GF_MediaObject *mo; if (!scene) return; mo = scene->root_od ? scene->root_od->mo : NULL; gf_scene_notify_event(scene, GF_EVENT_UNLOAD, n, NULL, GF_OK); if (!mo) return; gf_list_del_item(mo->nodes, n); /*disconnect current inline if we're the last one using it (same as regular OD session leave/join)*/ if (mo->num_open) { mo->num_open --; if (!mo->num_open) { gf_term_lock_media_queue(scene->root_od->term, 1); /*this is unspecified in the spec: whenever an inline not using the OD framework is destroyed, destroy the associated resource*/ if (mo->OD_ID == GF_MEDIA_EXTERNAL_ID) { /*get parent scene and remove MediaObject in case the ressource gets re-requested later on*/ GF_Scene *parent_scene = (GF_Scene *)gf_sg_get_private(gf_node_get_graph((GF_Node *) n) ); if (gf_list_del_item(parent_scene->scene_objects, mo)>=0) { gf_sg_vrml_mf_reset(&mo->URLs, GF_SG_VRML_MFURL); gf_list_del(mo->nodes); if (mo->odm) mo->odm->mo = NULL; gf_free(mo); } scene->root_od->action_type = GF_ODM_ACTION_DELETE; gf_list_add(scene->root_od->term->media_queue, scene->root_od); } else { scene->root_od->action_type = GF_ODM_ACTION_SCENE_DISCONNECT; gf_list_add(scene->root_od->term->media_queue, scene->root_od); } gf_term_lock_media_queue(scene->root_od->term, 0); } } return; } //if no private scene is associated get the node parent graph, retrieve the IS and find the OD if (!scene) { M_Inline *inl = (M_Inline *)n; gf_inline_set_scene(inl); scene = (GF_Scene *)gf_node_get_private(n); if (!scene) { /*just like protos, we must invalidate parent graph until attached*/ if (inl->url.count) { if (!inl->url.vals[0].OD_ID && (!inl->url.vals[0].url || !strlen(inl->url.vals[0].url) ) ) { gf_sg_vrml_mf_reset(&inl->url, GF_SG_VRML_MFURL); } else { gf_node_dirty_set(n, 0, 1); } } return; } } gf_inline_check_restart(scene); /*if we need to restart, shutdown graph and do it*/ if (scene->needs_restart) { /*special case: scene change*/ if (scene->needs_restart==2) { scene->needs_restart = 0; gf_inline_on_modified(n); return; } scene->needs_restart = 0; gf_term_lock_media_queue(scene->root_od->term, 1); scene->root_od->action_type = GF_ODM_ACTION_SCENE_INLINE_RESTART; gf_list_add(scene->root_od->term->media_queue, scene->root_od); gf_term_lock_media_queue(scene->root_od->term, 0); gf_node_dirty_set(n, 0, 1); return; } /*if not attached return (attaching the graph cannot be done in render since render is not called while unattached :) */ if (!scene->graph_attached) { /*just like protos, we must invalidate parent graph until attached*/ gf_node_dirty_set(n, 0, 1); return; } /*clear dirty flags for any sub-inlines, bitmaps or protos*/ gf_node_dirty_clear(n, 0); current_url = scene->current_url; scene->current_url = & ((M_Inline*)n)->url; gf_sc_traverse_subscene(scene->root_od->term->compositor, n, scene->graph, rs); scene->current_url = current_url; }
static void svg_traverse_animation(GF_Node *node, void *rs, Bool is_destroy) { SVGAllAttributes all_atts; GF_Matrix2D backup_matrix; GF_Matrix backup_matrix3d; SVGPropertiesPointers backup_props; u32 backup_flags; SFVec2f prev_vp; GF_Rect rc; GF_IRect clip, prev_clip; SVGAllAttributes *prev_vp_atts; GF_TraverseState *tr_state = (GF_TraverseState*)rs; GF_Matrix2D translate; SVGPropertiesPointers *old_props; SVGlinkStack *stack = gf_node_get_private(node); if (is_destroy) { if (stack->resource) gf_mo_unload_xlink_resource(node, stack->resource); gf_free(stack); return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!stack->inline_sg && !stack->resource) { if (!stack->init_vis_state) { if (all_atts.initialVisibility && (*all_atts.initialVisibility==SVG_INITIALVISIBILTY_ALWAYS)) { stack->init_vis_state = 2; svg_animation_smil_update(node, stack, 0); } else { stack->init_vis_state = 1; } } if (!stack->inline_sg && !stack->resource) return; } if (!all_atts.width || !all_atts.height) return; if (!all_atts.width->value || !all_atts.height->value) return; if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) return; if (compositor_svg_is_display_off(tr_state->svg_props) || *(tr_state->svg_props->visibility) == SVG_VISIBILITY_HIDDEN) { goto end; } compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &backup_matrix3d); /*add x/y translation*/ gf_mx2d_init(translate); translate.m[2] = (all_atts.x ? all_atts.x->value : 0); translate.m[5] = (all_atts.y ? all_atts.y->value : 0); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { gf_mx_add_matrix_2d(&tr_state->model_matrix, &translate); if (tr_state->traversing_mode==TRAVERSE_SORT) { GF_Matrix tmp; gf_mx_from_mx2d(&tmp, &translate); visual_3d_matrix_add(tr_state->visual, tmp.m); } } else #endif gf_mx2d_pre_multiply(&tr_state->transform, &translate); /*reset SVG props to reload a new inheritance context*/ old_props = tr_state->svg_props; tr_state->svg_props = NULL; /*store this node's attribute to compute PAR/ViewBox of the child <svg>*/ prev_vp_atts = tr_state->parent_anim_atts; tr_state->parent_anim_atts = &all_atts; /*update VP size*/ prev_vp = tr_state->vp_size; tr_state->vp_size.x = gf_sc_svg_convert_length_to_display(tr_state->visual->compositor, all_atts.width); tr_state->vp_size.y = gf_sc_svg_convert_length_to_display(tr_state->visual->compositor, all_atts.height); /*setup new clipper*/ rc.width = tr_state->vp_size.x; rc.height = tr_state->vp_size.y; rc.x = 0; rc.y = tr_state->vp_size.y; gf_mx2d_apply_rect(&tr_state->transform, &rc); prev_clip = tr_state->visual->top_clipper; clip = gf_rect_pixelize(&rc); // gf_irect_intersect(&tr_state->visual->top_clipper, &clip); if (!stack->inline_sg && stack->resource) { stack->inline_sg = gf_mo_get_scenegraph(stack->resource); } if (stack->inline_sg) { gf_sc_traverse_subscene(tr_state->visual->compositor, node, stack->inline_sg, tr_state); } if (stack->init_vis_state == 2) { stack->init_vis_state = 3; gf_mo_pause(stack->resource); } tr_state->svg_props = old_props; tr_state->visual->top_clipper = prev_clip; tr_state->parent_anim_atts = prev_vp_atts; tr_state->vp_size = prev_vp; compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &backup_matrix3d); end: memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; }