/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant 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 General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined ( INCLUDED_ISCENEGRAPH_H ) #define INCLUDED_ISCENEGRAPH_H #include #include "generic/constant.h" #include "signal/signalfwd.h" template class Stack; template class Reference; namespace scene { class Instance; const Instance* const nullInstancePointer = 0; inline const Instance& nullInstance(){ return *nullInstancePointer; } class Node; const Node* const nullNodePointer = 0; inline const Node& nullNode(){ return *nullNodePointer; } } typedef Reference NodeReference; typedef std::size_t TypeId; const TypeId NODETYPEID_MAX = 64; const TypeId NODETYPEID_NONE = NODETYPEID_MAX; const TypeId INSTANCETYPEID_MAX = 64; const TypeId INSTANCETYPEID_NONE = INSTANCETYPEID_MAX; namespace scene { /// \brief A unique key to an instance of a node in the scene-graph. typedef Stack Path; /// \brief A scene-graph - a Directed Acyclic Graph (DAG). /// /// - Each node may refer to zero or more 'child' nodes (directed). /// - A node may never have itself as one of its ancestors (acyclic). /// - Each node may have more than one 'parent', thus having more than one 'instance' in the graph. /// - Each instance is uniquely identified by the list of its ancestors plus itself, known as a 'path'. class Graph { public: virtual ~Graph() = default; INTEGER_CONSTANT( Version, 1 ); STRING_CONSTANT( Name, "scenegraph" ); class Walker { public: /// \brief Called before traversing the first child-instance of 'instance'. If the return value is false, the children of the current instance are not traversed. virtual bool pre( const Path& path, Instance& instance ) const = 0; /// \brief Called after traversing the last child-instance of 'instance'. virtual void post( const Path& path, Instance& instance ) const { } }; /// \brief Returns the root-node of the graph. virtual Node& root() = 0; /// \brief Sets the root-node of the graph to be 'node'. virtual void insert_root( Node& root ) = 0; /// \brief Clears the root-node of the graph. virtual void erase_root() = 0; /// \brief Traverses all nodes in the graph depth-first, starting from the root node. virtual void traverse( const Walker& walker ) = 0; /// \brief Traverses all nodes in the graph depth-first, starting from 'start'. virtual void traverse_subgraph( const Walker& walker, const Path& start ) = 0; /// \brief Returns the instance at the location identified by 'path', or 0 if it does not exist. virtual scene::Instance* find( const Path& path ) = 0; /// \brief Invokes all scene-changed callbacks. Called when any part of the scene changes the way it will appear when the scene is rendered. /// \todo Move to a separate class. virtual void sceneChanged() = 0; /// \brief Add a \p callback to be invoked when the scene changes. /// \todo Move to a separate class. virtual void addSceneChangedCallback( const SignalHandler& handler ) = 0; /// \brief Invokes all bounds-changed callbacks. Called when the bounds of any instance in the scene change. /// \todo Move to a separate class. virtual void boundsChanged() = 0; /// \brief Add a \p callback to be invoked when the bounds of any instance in the scene change. virtual SignalHandlerId addBoundsChangedCallback( const SignalHandler& boundsChanged ) = 0; /// \brief Remove a \p callback to be invoked when the bounds of any instance in the scene change. virtual void removeBoundsChangedCallback( SignalHandlerId id ) = 0; virtual TypeId getNodeTypeId( const char* name ) = 0; virtual TypeId getInstanceTypeId( const char* name ) = 0; }; class Traversable { public: STRING_CONSTANT( Name, "scene::Traversable" ); class Observer { public: /// \brief Called when a node is added to the container. virtual void insert( Node& node ) = 0; /// \brief Called when a node is removed from the container. virtual void erase( Node& node ) = 0; }; class Walker { public: /// \brief Called before traversing the first child-node of 'node'. If the return value is false, the children of the current node are not traversed. virtual bool pre( Node& node ) const = 0; /// \brief Called after traversing the last child-node of 'node'. virtual void post( Node& node ) const { } }; /// \brief Adds a node to the container. virtual void insert( Node& node ) = 0; /// \brief Removes a node from the container. virtual void erase( Node& node ) = 0; /// \brief Traverses the subgraphs rooted at each node in the container, depth-first. virtual void traverse( const Walker& walker ) = 0; /// \brief Returns true if the container contains no nodes. virtual bool empty() const = 0; }; class Instantiable { public: STRING_CONSTANT( Name, "scene::Instantiable" ); class Observer { public: /// \brief Called when an instance is added to the container. virtual void insert( scene::Instance* instance ) = 0; /// \brief Called when an instance is removed from the container. virtual void erase( scene::Instance* instance ) = 0; }; class Visitor { public: virtual void visit( Instance& instance ) const = 0; }; /// \brief Returns a new instance uniquely identified by 'path'. virtual scene::Instance* create( const scene::Path& path, scene::Instance* parent ) = 0; /// \brief Calls Visitor::visit(instance) for each instance in the container. virtual void forEachInstance( const Visitor& visitor ) = 0; /// \brief Adds an instance to the container. virtual void insert( Observer* observer, const Path& path, scene::Instance* instance ) = 0; /// \brief Returns an instance removed from the container. virtual scene::Instance* erase( Observer* observer, const Path& path ) = 0; }; class Cloneable { public: STRING_CONSTANT( Name, "scene::Cloneable" ); /// \brief Returns a copy of itself. virtual scene::Node& clone() const = 0; }; } #include "modulesystem.h" template class GlobalModule; typedef GlobalModule GlobalSceneGraphModule; template class GlobalModuleRef; typedef GlobalModuleRef GlobalSceneGraphModuleRef; inline scene::Graph& GlobalSceneGraph(){ return GlobalSceneGraphModule::getTable(); } inline void AddSceneChangeCallback( const SignalHandler& handler ){ GlobalSceneGraph().addSceneChangedCallback( handler ); } inline void SceneChangeNotify(){ GlobalSceneGraph().sceneChanged(); } #endif