⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 base_scenegraph.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *			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>/*svg proto*/#include <gpac/scenegraph_svg.h>/*MPEG4 tags (for internal nodes)*/#include <gpac/nodes_mpeg4.h>/*X3D tags (for internal nodes)*/#include <gpac/nodes_x3d.h>static void ReplaceDEFNode(GF_Node *FromNode, GF_Node *node, GF_Node *newNode, Bool updateOrderedGroup);#ifndef GPAC_DISABLE_SVGstatic void ReplaceIRINode(GF_Node *FromNode, GF_Node *oldNode, GF_Node *newNode);#endifGF_SceneGraph *gf_sg_new(){	GF_SceneGraph *tmp;	GF_SAFEALLOC(tmp, GF_SceneGraph);	if (!tmp) return NULL;	tmp->protos = gf_list_new();	tmp->unregistered_protos = gf_list_new();	tmp->Routes = gf_list_new();	tmp->routes_to_activate = gf_list_new();	tmp->routes_to_destroy = gf_list_new();#ifndef GPAC_DISABLE_SVG	tmp->xlink_hrefs = gf_list_new();	tmp->smil_timed_elements = gf_list_new();#endif#ifdef GPAC_HAS_SPIDERMONKEY	tmp->scripts = gf_list_new();	tmp->objects = gf_list_new();	tmp->listeners_to_add = gf_list_new();#endif	return tmp;}GF_EXPORTGF_SceneGraph *gf_sg_new_subscene(GF_SceneGraph *scene){	GF_SceneGraph *tmp;	if (!scene) return NULL;	tmp = gf_sg_new();	if (!tmp) return NULL;	tmp->parent_scene = scene;	tmp->script_action = scene->script_action;	tmp->script_action_cbck = scene->script_action_cbck;	tmp->script_load = scene->script_load;	/*by default use the same callbacks*/	tmp->userpriv = scene->userpriv;	tmp->GetSceneTime = scene->GetSceneTime;	tmp->GetExternProtoLib = scene->GetExternProtoLib;	tmp->NodeCallback = scene->NodeCallback;	return tmp;}GF_EXPORTvoid gf_sg_set_node_callback(GF_SceneGraph *sg, void (*NodeCallback)(void *user_priv, u32 type, GF_Node *node, void *ctxdata) ){	sg->NodeCallback = NodeCallback;}GF_EXPORTvoid gf_sg_set_scene_time_callback(GF_SceneGraph *sg, Double (*GetSceneTime)(void *user_priv)){	sg->GetSceneTime = GetSceneTime;}GF_EXPORTDouble gf_node_get_scene_time(GF_Node *node){	if (!node || !node->sgprivate->scenegraph->GetSceneTime) return 0.0;	return node->sgprivate->scenegraph->GetSceneTime(node->sgprivate->scenegraph->userpriv);}GF_EXPORTvoid gf_sg_del(GF_SceneGraph *sg){		if (!sg) return;	gf_sg_reset(sg);#ifndef GPAC_DISABLE_SVG	gf_list_del(sg->xlink_hrefs);	gf_list_del(sg->smil_timed_elements);	gf_list_del(sg->listeners_to_add);#endif#ifdef GPAC_HAS_SPIDERMONKEY	gf_list_del(sg->scripts);	gf_list_del(sg->objects);#endif	gf_list_del(sg->Routes);	gf_list_del(sg->protos);	gf_list_del(sg->unregistered_protos);	gf_list_del(sg->routes_to_activate);	gf_list_del(sg->routes_to_destroy);	free(sg);}/*recursive traverse of the whole graph to check for scope mixes (nodes from an inline graphinserted in a parent graph through bind or routes). We must do this otherwise we're certain to get randomcrashes or mem leaks.*/void SG_GraphRemoved(GF_Node *node, GF_SceneGraph *sg){	u32 i, count;	GF_FieldInfo info;	u32 tag;	tag = node->sgprivate->tag;	count = gf_node_get_field_count(node);#ifndef GPAC_DISABLE_SVG	if (((tag>= GF_NODE_RANGE_FIRST_SVG) && (tag<= GF_NODE_RANGE_LAST_SVG)) #ifdef GPAC_ENABLE_SVG_SA		|| ((tag>= GF_NODE_RANGE_FIRST_SVG_SA) && (tag<= GF_NODE_RANGE_LAST_SVG_SA)) #endif#ifdef GPAC_ENABLE_SVG_SANI		|| ((tag>= GF_NODE_RANGE_FIRST_SVG_SANI) && (tag<= GF_NODE_RANGE_LAST_SVG_SANI))#endif		) {		/* TODO */		tag = 0;	} else #endif	{		for (i=0; i<count; i++) {			gf_node_get_field(node, i, &info);			if (info.fieldType==GF_SG_VRML_SFNODE) {				GF_Node *n = *(GF_Node **) info.far_ptr;				if (n) {					if (n->sgprivate->scenegraph==sg) {						/*if root of graph, skip*/						if (sg->RootNode!=n) {							gf_node_unregister(n, node);							/*don't forget to remove node...*/							*(GF_Node **) info.far_ptr = NULL;						}					} else {						SG_GraphRemoved(n, sg);					}				}			}			else if (info.fieldType==GF_SG_VRML_MFNODE) {				GF_ChildNodeItem *cur, *prev, *list = *(GF_ChildNodeItem **) info.far_ptr;				prev = NULL;				while (list) {					if (list->node->sgprivate->scenegraph==sg) {						gf_node_unregister(list->node, node);											if (prev) prev->next = list->next;						else *(GF_ChildNodeItem **) info.far_ptr = list->next;						cur = list;						free(cur);					} else {						SG_GraphRemoved(list->node, sg);					}					list = list->next;				}			}		}	}}GFINLINE GF_Node *SG_SearchForNode(GF_SceneGraph *sg, GF_Node *node){	NodeIDedItem *reg_node = sg->id_node;	while (reg_node) {		if (reg_node->node == node) return reg_node->node;		reg_node = reg_node->next;	}	return NULL;}static GFINLINE u32 get_num_id_nodes(GF_SceneGraph *sg){	u32 count = 0;	NodeIDedItem *reg_node = sg->id_node;	while (reg_node) {		count++;		reg_node = reg_node->next;	}	return count;}GF_EXPORTvoid gf_sg_reset(GF_SceneGraph *sg){	u32 type, count;	NodeIDedItem *reg_node;	if (!sg) return;	/*inlined graph, remove any of this graph nodes from the parent graph*/	if (!sg->pOwningProto && sg->parent_scene) {		GF_SceneGraph *par = sg->parent_scene;		while (par->parent_scene) par = par->parent_scene;		if (par->RootNode) SG_GraphRemoved(par->RootNode, sg);	}#ifdef GPAC_HAS_SPIDERMONKEY	/*scripts are the first source of cylic references in the graph. In order to clean properly	force a remove of all script nodes, this will release all references to nodes in JS*/	while (gf_list_count(sg->scripts)) {		GF_Node *n = gf_list_get(sg->scripts, 0);		gf_list_rem(sg->scripts, 0);		/*prevent destroy*/		gf_node_register(n, NULL);		/*remove from all parents*/		gf_node_replace(n, NULL, 0);		/*FORCE destroy in case the script refers to itself*/		n->sgprivate->num_instances=1;		gf_node_unregister(n, NULL);	}#endif#ifndef GPAC_DISABLE_SVG	/*flush any pending add_listener*/	gf_dom_listener_process_add(sg);#endif	if (sg->RootNode) gf_node_unregister(sg->RootNode, NULL);	sg->RootNode = NULL;	while (gf_list_count(sg->routes_to_activate)) {		gf_list_rem(sg->routes_to_activate, 0);	}	/*destroy all routes*/	while (gf_list_count(sg->Routes)) {		GF_Route *r = (GF_Route*)gf_list_get(sg->Routes, 0);		/*this will unregister the route from the graph, so don't delete the chain entry*/		gf_sg_route_del(r);	}	/*WATCHOUT: we may have cyclic dependencies due to	1- a node referencing itself (forbidden in VRML)	2- nodes refered to in commands of conditionals children of this node (MPEG-4 is mute about that)	we recursively preocess from last declared DEF node to first one	*/restart:	reg_node = sg->id_node;	while (reg_node) {		Bool ignore = 0;		GF_Node *node = reg_node->node;		if (!node) {			reg_node = reg_node->next;			continue;		}		/*first replace all instances in parents by NULL WITHOUT UNREGISTERING (to avoid destroying the node).		This will take care of nodes referencing themselves*/		{		GF_ParentList *nlist = node->sgprivate->parents;		type = node->sgprivate->tag;#ifndef GPAC_DISABLE_SVG		if (((type>= GF_NODE_RANGE_FIRST_SVG) && (type<= GF_NODE_RANGE_LAST_SVG)) #ifdef GPAC_ENABLE_SVG_SA			|| ((type>= GF_NODE_RANGE_FIRST_SVG_SA) && (type<= GF_NODE_RANGE_LAST_SVG_SA)) #endif#ifdef GPAC_ENABLE_SVG_SANI			|| ((type>= GF_NODE_RANGE_FIRST_SVG_SANI) && (type<= GF_NODE_RANGE_LAST_SVG_SANI))#endif		) 			type = 1;		else #endif			type = 0;		while (nlist) {			GF_ParentList *next = nlist->next;#if 0			/*parent is a DEF'ed node, try to clean-up properly?*/			if ((nlist->node!=node) && SG_SearchForNode(sg, nlist->node) != NULL) {				ignore = 1;				break;			}#endif#ifndef GPAC_DISABLE_SVG			if (type) {				ReplaceIRINode(nlist->node, node, NULL);			} else #endif				ReplaceDEFNode(nlist->node, reg_node->node, NULL, 0);						free(nlist);			nlist = next;		}		if (ignore) {			node->sgprivate->parents = nlist;			continue;		}		node->sgprivate->parents = NULL;		}		//sg->node_registry[i-1] = NULL;		count = get_num_id_nodes(sg);		node->sgprivate->num_instances = 1;		gf_node_unregister(node, NULL);		if (count != get_num_id_nodes(sg)) goto restart;		reg_node = reg_node->next;	}	assert(sg->id_node==NULL);	/*destroy all proto*/	while (gf_list_count(sg->protos)) {		GF_Proto *p = (GF_Proto *)gf_list_get(sg->protos, 0);		/*this will unregister the proto from the graph, so don't delete the chain entry*/		gf_sg_proto_del(p);	}	/*destroy all unregistered proto*/	while (gf_list_count(sg->unregistered_protos)) {		GF_Proto *p = (GF_Proto *)gf_list_get(sg->unregistered_protos, 0);		/*this will unregister the proto from the graph, so don't delete the chain entry*/		gf_sg_proto_del(p);	}#ifndef GPAC_DISABLE_SVG	assert(gf_list_count(sg->xlink_hrefs) == 0);#endif	/*last destroy all routes*/	gf_sg_destroy_routes(sg);	sg->simulation_tick = 0;#ifdef GF_SELF_REPLACE_ENABLE	sg->graph_has_been_reset = 1;#endif}GFINLINE GF_Node *SG_SearchForDuplicateNodeID(GF_SceneGraph *sg, u32 nodeID, GF_Node *toExclude){	NodeIDedItem *reg_node = sg->id_node;	while (reg_node) {		if ((reg_node->node != toExclude) && (reg_node->NodeID == nodeID)) return reg_node->node;		reg_node = reg_node->next;	}	return NULL;}void *gf_node_get_name_address(GF_Node*node){	NodeIDedItem *reg_node;	if (!(node->sgprivate->flags & GF_NODE_IS_DEF)) return NULL;	reg_node = node->sgprivate->scenegraph->id_node;	while (reg_node) {		if (reg_node->node == node) return &reg_node->NodeName;		reg_node = reg_node->next;	}	return NULL;}void gf_sg_set_private(GF_SceneGraph *sg, void *ptr){	if (sg) sg->userpriv = ptr;}void *gf_sg_get_private(GF_SceneGraph *sg){	return sg ? sg->userpriv : NULL;}GF_EXPORTvoid gf_sg_set_scene_size_info(GF_SceneGraph *sg, u32 width, u32 height, Bool usePixelMetrics){	if (!sg) return;	if (width && height) {		sg->width = width;		sg->height = height;	} else {		sg->width = sg->height = 0;	}	sg->usePixelMetrics = usePixelMetrics;}GF_EXPORTBool gf_sg_use_pixel_metrics(GF_SceneGraph *sg){	if (sg) {		while (sg->pOwningProto) sg = sg->parent_scene;		return sg->usePixelMetrics;	}	return 0;}GF_EXPORTBool gf_sg_get_scene_size_info(GF_SceneGraph *sg, u32 *width, u32 *height){	if (!sg) return 0;	*width = sg->width;	*height = sg->height;	return (sg->width && sg->height) ? 1 : 0;}GF_EXPORTGF_Node *gf_sg_get_root_node(GF_SceneGraph *sg){	return sg ? sg->RootNode : NULL;}GF_EXPORTvoid gf_sg_set_root_node(GF_SceneGraph *sg, GF_Node *node){	if (sg) sg->RootNode = node;}GFINLINE void remove_node_id(GF_SceneGraph *sg, GF_Node *node){	NodeIDedItem *reg_node = sg->id_node;	if (reg_node && (reg_node->node==node)) {		sg->id_node = reg_node->next;		if (sg->id_node_last==reg_node) 			sg->id_node_last = reg_node->next;		if (reg_node->NodeName) free(reg_node->NodeName);		free(reg_node);	} else {		NodeIDedItem *to_del;		while (reg_node->next) {			if (reg_node->next->node!=node) {				reg_node = reg_node->next;				continue;			}			to_del = reg_node->next;			reg_node->next = to_del->next;			if (sg->id_node_last==to_del) {				sg->id_node_last = reg_node->next ? reg_node->next : reg_node;			}			if (to_del->NodeName) free(to_del->NodeName);			free(to_del);			break;		}	}}GF_EXPORTGF_Err gf_node_unregister(GF_Node *pNode, GF_Node *parentNode){	u32 j;	GF_SceneGraph *pSG;	GF_Route *r;	if (!pNode) return GF_OK;	pSG = pNode->sgprivate->scenegraph;	/*if this is a proto its is registered in its parent graph, not the current*/	if (pSG && (pNode == (GF_Node*)pSG->pOwningProto)) pSG = pSG->parent_scene;	if (parentNode) {		GF_ParentList *nlist = pNode->sgprivate->parents;		if (nlist) {			GF_ParentList *prev = NULL;			while (nlist) {				if (nlist->node != parentNode) {					prev = nlist;					nlist = nlist->next;					continue;				}				if (prev) prev->next = nlist->next;				else pNode->sgprivate->parents = nlist->next;				free(nlist);				break;			}		}	}	/*unregister the instance*/	assert(pNode->sgprivate->num_instances);	pNode->sgprivate->num_instances -= 1;		/*this is just an instance removed*/	if (pNode->sgprivate->num_instances) {		return GF_OK;	}		assert(pNode->sgprivate->parents==NULL);	if (pSG) {		/*if def, remove from sg def table*/		if (pNode->sgprivate->flags & GF_NODE_IS_DEF) {			remove_node_id(pSG, pNode);		}		/*check all routes from or to this node and destroy them - cf spec*/		j=0;		while ((r = (GF_Route *)gf_list_enum(pSG->Routes, &j))) {			if ( (r->ToNode == pNode) || (r->FromNode == pNode)) {				gf_sg_route_del(r);				j--;			}		}	}	if (pNode->sgprivate->scenegraph && (pNode->sgprivate->scenegraph->RootNode==pNode))		pNode->sgprivate->scenegraph->RootNode = NULL;	/*delete the node*/	gf_node_del(pNode);	return GF_OK;}GF_EXPORTGF_Err gf_node_register(GF_Node *node, GF_Node *parentNode){	GF_SceneGraph *pSG; 	if (!node) return GF_OK;		pSG = node->sgprivate->scenegraph;	/*if this is a proto register to the parent graph, not the current*/	if (pSG && (node == (GF_Node*)pSG->pOwningProto)) pSG = pSG->parent_scene;	node->sgprivate->num_instances ++;	/*parent may be NULL (top node and proto)*/	if (parentNode) {		if (!node->sgprivate->parents) {			node->sgprivate->parents = (GF_ParentList*)malloc(sizeof(GF_ParentList));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -