📄 commands.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / Scene Graph sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/internal/scenegraph_dev.h>/*MPEG4 tags (for internal nodes)*/#include <gpac/nodes_mpeg4.h>#include <gpac/nodes_svg_sa.h>#include <gpac/internal/laser_dev.h>GF_Command *gf_sg_command_new(GF_SceneGraph *graph, u32 tag){ GF_Command *ptr; GF_SAFEALLOC(ptr, GF_Command); if (!ptr) return NULL; ptr->tag = tag; ptr->in_scene = graph; ptr->command_fields = gf_list_new(); if (tag < GF_SG_LAST_BIFS_COMMAND) ptr->new_proto_list = gf_list_new(); return ptr;}static void SG_CheckNodeUnregister(GF_Command *com){ NodeIDedItem *reg_node; switch (com->tag) { case GF_SG_SCENE_REPLACE: case GF_SG_LSR_NEW_SCENE: case GF_SG_LSR_REFRESH_SCENE: gf_node_unregister(com->node, NULL); break; default: /*check if node is in registry - do NOT check the node's internals, because it may have been destroyed when cyclic references are found (only happens with conditional replacing self/other conditional buffer) note that we're sure the node has an ID since this is not a replace scene*/ reg_node = com->in_scene->id_node; while (reg_node) { if (reg_node->node == com->node) { gf_node_unregister(com->node, NULL); return; } reg_node = reg_node->next; } break; }}GF_EXPORTvoid gf_sg_command_del(GF_Command *com){ u32 i; GF_Proto *proto; if (!com) return; if (com->tag < GF_SG_LAST_BIFS_COMMAND) { while (gf_list_count(com->command_fields)) { GF_CommandField *inf = (GF_CommandField *)gf_list_get(com->command_fields, 0); gf_list_rem(com->command_fields, 0); switch (inf->fieldType) { case GF_SG_VRML_SFNODE: if (inf->new_node) gf_node_unregister(inf->new_node, com->node); break; case GF_SG_VRML_MFNODE: if (inf->field_ptr) { GF_ChildNodeItem *cur, *child; child = inf->node_list; while (child) { cur = child; gf_node_unregister(child->node, com->node); child = child->next; free(cur); } } break; default: if (inf->field_ptr) gf_sg_vrml_field_pointer_del(inf->field_ptr, inf->fieldType); break; } free(inf); } } else {#ifndef GPAC_DISABLE_SVG while (gf_list_count(com->command_fields)) { GF_CommandField *inf = (GF_CommandField *)gf_list_get(com->command_fields, 0); gf_list_rem(com->command_fields, 0); if (inf->new_node) gf_node_unregister(inf->new_node, com->node); else if (inf->node_list) { gf_node_unregister_children(com->node, inf->node_list); } else if (inf->field_ptr) { gf_svg_delete_attribute_value(inf->fieldType, inf->field_ptr, com->in_scene); } free(inf); }#endif } gf_list_del(com->command_fields); i=0; while ((proto = (GF_Proto*)gf_list_enum(com->new_proto_list, &i))) { gf_sg_proto_del(proto); } gf_list_del(com->new_proto_list); if (com->node) { if (!com->in_scene) gf_node_unregister(com->node, NULL); else SG_CheckNodeUnregister(com); } if (com->del_proto_list) free(com->del_proto_list); if (com->def_name) free(com->def_name); if (com->scripts_to_load) gf_list_del(com->scripts_to_load); free(com);}static void SG_CheckFieldChange(GF_Node *node, GF_FieldInfo *field){ /*and propagate eventIn if any*/ if (field->on_event_in) { field->on_event_in(node); } else if ((field->eventType==GF_SG_EVENT_IN) && (gf_node_get_tag(node) == TAG_MPEG4_Script)) { gf_sg_script_event_in(node, field); } else { /*Notify eventOut in all cases to handle protos*/ gf_node_event_out(node, field->fieldIndex); } /*signal node modif*/ gf_node_changed(node, field);}static void gf_node_unregister_children_deactivate(GF_Node *container, GF_ChildNodeItem *child){ GF_ChildNodeItem *cur; while (child) { gf_node_unregister(child->node, container); gf_node_deactivate(child->node); cur = child; child = child->next; free(cur); }}GF_EXPORTGF_Err gf_sg_command_apply(GF_SceneGraph *graph, GF_Command *com, Double time_offset){ GF_Err e; GF_CommandField *inf; GF_FieldInfo field; GF_Node *def, *node; void *slot_ptr; if (!com || !graph) return GF_BAD_PARAM; e = GF_OK; switch (com->tag) { case GF_SG_SCENE_REPLACE: /*unregister root*/ gf_node_unregister(graph->RootNode, NULL); /*remove all protos and routes*/ while (gf_list_count(graph->routes_to_activate)) gf_list_rem(graph->routes_to_activate, 0); /*destroy all routes*/ while (gf_list_count(graph->Routes)) { GF_Route *r = (GF_Route *)gf_list_get(graph->Routes, 0); /*this will unregister the route from the graph, so don't delete the chain entry*/ gf_sg_route_del(r); } /*destroy all proto*/ while (gf_list_count(graph->protos)) { GF_Proto *p = (GF_Proto*)gf_list_get(graph->protos, 0); /*this will unregister the proto from the graph, so don't delete the chain entry*/ gf_sg_proto_del(p); } /*DO NOT TOUCH node registry*/ /*DO NOT TOUCH UNREGISTERED PROTOS*/ /*move all protos in graph*/ while (gf_list_count(com->new_proto_list)) { GF_Proto *p = (GF_Proto*)gf_list_get(com->new_proto_list, 0); gf_list_rem(com->new_proto_list, 0); gf_list_del_item(graph->unregistered_protos, p); gf_list_add(graph->protos, p); } /*assign new root (no need to register/unregister)*/ graph->RootNode = com->node; com->node = NULL; break; case GF_SG_NODE_REPLACE: if (!gf_list_count(com->command_fields)) return GF_OK; inf = (GF_CommandField*)gf_list_get(com->command_fields, 0); e = gf_node_replace(com->node, inf->new_node, 0); if (inf->new_node) gf_node_register(inf->new_node, NULL); break; case GF_SG_MULTIPLE_REPLACE: case GF_SG_FIELD_REPLACE: { u32 j; GF_ChildNodeItem *list, *cur, *prev; j=0; while ((inf = (GF_CommandField*)gf_list_enum(com->command_fields, &j))) { e = gf_node_get_field(com->node, inf->fieldIndex, &field); if (e) return e; switch (field.fieldType) { case GF_SG_VRML_SFNODE: { node = *((GF_Node **) field.far_ptr); e = gf_node_unregister(node, com->node); *((GF_Node **) field.far_ptr) = inf->new_node; if (!e) gf_node_register(inf->new_node, com->node); break; } case GF_SG_VRML_MFNODE: gf_node_unregister_children(com->node, * ((GF_ChildNodeItem **) field.far_ptr)); * ((GF_ChildNodeItem **) field.far_ptr) = NULL; list = * ((GF_ChildNodeItem **) inf->field_ptr); prev=NULL; while (list) { cur = malloc(sizeof(GF_ChildNodeItem)); cur->next = NULL; cur->node = list->node; if (prev) { prev->next = cur; } else { * ((GF_ChildNodeItem **) field.far_ptr) = cur; } gf_node_register(list->node, com->node); prev = cur; list = list->next; } break; default: /*this is a regular field, reset it and clone - we cannot switch pointers since the original fields are NOT pointers*/ if (!gf_sg_vrml_is_sf_field(field.fieldType)) { e = gf_sg_vrml_mf_reset(field.far_ptr, field.fieldType); } if (e) return e; gf_sg_vrml_field_copy(field.far_ptr, inf->field_ptr, field.fieldType); if (field.fieldType==GF_SG_VRML_SFTIME) *(SFTime *)field.far_ptr = *(SFTime *)field.far_ptr + time_offset; break; } SG_CheckFieldChange(com->node, &field); } break; } case GF_SG_MULTIPLE_INDEXED_REPLACE: case GF_SG_INDEXED_REPLACE: { u32 sftype, i=0; while ((inf = (GF_CommandField*)gf_list_enum(com->command_fields, &i))) { e = gf_node_get_field(com->node, inf->fieldIndex, &field); if (e) return e; /*if MFNode remove the child and set new node*/ if (field.fieldType == GF_SG_VRML_MFNODE) { /*we must remove the node before in case the new node uses the same ID (not forbidden) and this command removes the last instance of the node with the same ID*/ gf_node_replace_child(com->node, (GF_ChildNodeItem**) field.far_ptr, inf->pos, inf->new_node); if (inf->new_node) gf_node_register(inf->new_node, NULL); } /*erase the field item*/ else { if ((inf->pos < 0) || ((u32) inf->pos >= ((GenMFField *) field.far_ptr)->count) ) { inf->pos = ((GenMFField *)field.far_ptr)->count - 1; /*may happen with text and default value*/ if (inf->pos < 0) { inf->pos = 0; gf_sg_vrml_mf_alloc(field.far_ptr, field.fieldType, 1); } } e = gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, & slot_ptr, inf->pos); if (e) return e; sftype = gf_sg_vrml_get_sf_type(field.fieldType); gf_sg_vrml_field_copy(slot_ptr, inf->field_ptr, sftype); /*note we don't add time offset, since there's no MFTime*/ } SG_CheckFieldChange(com->node, &field); } break; } case GF_SG_ROUTE_REPLACE: { GF_Route *r; char *name; r = gf_sg_route_find(graph, com->RouteID); def = gf_sg_find_node(graph, com->fromNodeID); node = gf_sg_find_node(graph, com->toNodeID); if (!node || !def) return GF_SG_UNKNOWN_NODE; name = NULL; if (r) { name = r->name; r->name = NULL; gf_sg_route_del(r); } r = gf_sg_route_new(graph, def, com->fromFieldIndex, node, com->toFieldIndex); gf_sg_route_set_id(r, com->RouteID); if (name) { gf_sg_route_set_name(r, name); free(name); } break; } case GF_SG_NODE_DELETE_EX: case GF_SG_NODE_DELETE: { if (com->node) gf_node_replace(com->node, NULL, (com->tag==GF_SG_NODE_DELETE_EX) ? 1 : 0); break; } case GF_SG_ROUTE_DELETE: { return gf_sg_route_del_by_id(graph, com->RouteID); } case GF_SG_INDEXED_DELETE: { if (!gf_list_count(com->command_fields)) return GF_OK; inf = (GF_CommandField*)gf_list_get(com->command_fields, 0); e = gf_node_get_field(com->node, inf->fieldIndex, &field); if (e) return e; if (gf_sg_vrml_is_sf_field(field.fieldType)) return GF_NON_COMPLIANT_BITSTREAM; /*then we need special handling in case of a node*/ if (gf_sg_vrml_get_sf_type(field.fieldType) == GF_SG_VRML_SFNODE) { e = gf_node_replace_child(com->node, (GF_ChildNodeItem **) field.far_ptr, inf->pos, NULL); } else { if ((inf->pos < 0) || ((u32) inf->pos >= ((GenMFField *) field.far_ptr)->count) ) { inf->pos = ((GenMFField *)field.far_ptr)->count - 1; } /*this is a regular MFField, just remove the item (realloc)*/ e = gf_sg_vrml_mf_remove(field.far_ptr, field.fieldType, inf->pos); } /*deletion -> node has changed*/ if (!e) SG_CheckFieldChange(com->node, &field); break; } case GF_SG_NODE_INSERT: { if (!gf_list_count(com->command_fields)) return GF_OK; inf = (GF_CommandField*)gf_list_get(com->command_fields, 0); e = gf_node_insert_child(com->node, inf->new_node, inf->pos); if (!e) gf_node_register(inf->new_node, com->node); if (!e) gf_node_event_out(com->node, inf->fieldIndex); if (!e) gf_node_changed(com->node, NULL); break; } case GF_SG_ROUTE_INSERT: { GF_Route *r; def = gf_sg_find_node(graph, com->fromNodeID); node = gf_sg_find_node(graph, com->toNodeID); if (!node || !def) return GF_SG_UNKNOWN_NODE; r = gf_sg_route_new(graph, def, com->fromFieldIndex, node, com->toFieldIndex); if (com->RouteID) gf_sg_route_set_id(r, com->RouteID); if (com->def_name) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -