void gf_node_traverse(GF_Node *node, void *renderStack)
{
	if (!node || !node->sgprivate) return;

	if (node->sgprivate->flags & GF_NODE_IS_DEACTIVATED) return;

	if (node->sgprivate->UserCallback) {
#ifdef GF_CYCLIC_TRAVERSE_ON
		if (node->sgprivate->flags & GF_NODE_IN_TRAVERSE) return;
		node->sgprivate->flags |= GF_NODE_IN_TRAVERSE;
		assert(node->sgprivate->flags);
#endif
		GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[SceneGraph] Traversing node %s (ID %s)\n", gf_node_get_class_name(node) , gf_node_get_name(node) ));
		node->sgprivate->UserCallback(node, renderStack, 0);
#ifdef GF_CYCLIC_TRAVERSE_ON
		node->sgprivate->flags &= ~GF_NODE_IN_TRAVERSE;
#endif
		return;
	}

#ifndef GPAC_DISABLE_VRML
	if (node->sgprivate->tag != TAG_ProtoNode) return;

	/*if no rendering function is assigned this is a real proto (otherwise this is an hardcoded one)*/
	if (!node->sgprivate->UserCallback) {

		/*if a rendering node is assigned use it*/
		if (((GF_ProtoInstance *) node)->RenderingNode) {
			node = ((GF_ProtoInstance *) node)->RenderingNode;
			/*if rendering node is a proto and not a hardcoded proto, traverse it*/
			if (!node->sgprivate->UserCallback && (node->sgprivate->tag == TAG_ProtoNode)) {
				gf_node_traverse(node, renderStack);
				return;
			}
		}
		/*if no rendering node, check if the proto is fully instantiated (externProto)*/
		else {
			GF_ProtoInstance *proto_inst = (GF_ProtoInstance *) node;
			gf_node_dirty_clear(node, 0);
			/*proto has been deleted or dummy proto (without node code)*/
			if (!proto_inst->proto_interface || (proto_inst->flags & GF_SG_PROTO_LOADED) ) return;
			/*try to load the code*/
			gf_sg_proto_instantiate(proto_inst);

			/*if user callback is set, this is an hardcoded proto. If not, locate the first traversable node*/
			if (!node->sgprivate->UserCallback) {
				if (!proto_inst->RenderingNode) {
					gf_node_dirty_set(node, 0, 1);
					return;
				}
				/*signal we have been loaded*/
				node->sgprivate->scenegraph->NodeCallback(node->sgprivate->scenegraph->userpriv, GF_SG_CALLBACK_MODIFIED, node, NULL);
			}
		}
	}

	if (node->sgprivate->UserCallback) {
#ifdef GF_CYCLIC_TRAVERSE_ON
		if (node->sgprivate->flags & GF_NODE_IN_TRAVERSE) return;
		node->sgprivate->flags |= GF_NODE_IN_TRAVERSE;
#endif
		GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[SceneGraph] Traversing node %s\n", gf_node_get_class_name(node) ));
		node->sgprivate->UserCallback(node, renderStack, 0);
#ifdef GF_CYCLIC_TRAVERSE_ON
		node->sgprivate->flags &= ~GF_NODE_IN_TRAVERSE;
#endif
	}

#endif /*GPAC_DISABLE_VRML*/
}
void gf_node_traverse(GF_Node *node, void *renderStack)
{
	if (!node || !node->sgprivate) return;

	if (node->sgprivate->flags & GF_NODE_IS_DEACTIVATED) return;

	if (node->sgprivate->UserCallback) {
#ifdef GF_CYCLIC_TRAVERSE_ON
		if (node->sgprivate->flags & GF_NODE_IN_TRAVERSE) return;
		node->sgprivate->flags |= GF_NODE_IN_TRAVERSE;
		assert(node->sgprivate->flags);
#endif
		GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[SceneGraph] Traversing node %s (ID %s)\n", gf_node_get_class_name(node) , gf_node_get_name(node) ));
		node->sgprivate->UserCallback(node, renderStack, 0);
#ifdef GF_CYCLIC_TRAVERSE_ON
		node->sgprivate->flags &= ~GF_NODE_IN_TRAVERSE;
#endif
		return;
	}

#ifndef GPAC_DISABLE_VRML
	if (node->sgprivate->tag != TAG_ProtoNode) return;

	 
	if (!node->sgprivate->UserCallback) {

		 
		if (((GF_ProtoInstance *) node)->RenderingNode) {
			node = ((GF_ProtoInstance *) node)->RenderingNode;
			 
			if (!node->sgprivate->UserCallback && (node->sgprivate->tag == TAG_ProtoNode)) {
				gf_node_traverse(node, renderStack);
				return;
			}
		}
		 
		else {
			GF_ProtoInstance *proto_inst = (GF_ProtoInstance *) node;
			gf_node_dirty_clear(node, 0);
			 
			if (!proto_inst->proto_interface || (proto_inst->flags & GF_SG_PROTO_LOADED) ) return;
			 
			gf_sg_proto_instantiate(proto_inst);

			 
			if (!node->sgprivate->UserCallback) {
				if (!proto_inst->RenderingNode) {
					gf_node_dirty_set(node, 0, 1);
					return;
				}
				 
				node->sgprivate->scenegraph->NodeCallback(node->sgprivate->scenegraph->userpriv, GF_SG_CALLBACK_MODIFIED, node, NULL);
			}
		}
	}

	if (node->sgprivate->UserCallback) {
#ifdef GF_CYCLIC_TRAVERSE_ON
		if (node->sgprivate->flags & GF_NODE_IN_TRAVERSE) return;
		node->sgprivate->flags |= GF_NODE_IN_TRAVERSE;
#endif
		GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[SceneGraph] Traversing node %s\n", gf_node_get_class_name(node) ));
		node->sgprivate->UserCallback(node, renderStack, 0);
#ifdef GF_CYCLIC_TRAVERSE_ON
		node->sgprivate->flags &= ~GF_NODE_IN_TRAVERSE;
#endif
	}

#endif  
}