2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #if !defined ( INCLUDED_INSTANCELIB_H )
23 #define INCLUDED_INSTANCELIB_H
25 #include "debugging/debugging.h"
27 #include "iscenegraph.h"
30 #include "generic/reference.h"
31 #include "generic/callback.h"
34 class InstanceSubgraphWalker : public scene::Traversable::Walker
36 scene::Instantiable::Observer* m_observer;
37 mutable scene::Path m_path;
38 mutable Stack<scene::Instance*> m_parent;
40 InstanceSubgraphWalker( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* parent )
41 : m_observer( observer ), m_path( path ), m_parent( parent ){
43 bool pre( scene::Node& node ) const {
44 m_path.push( makeReference( node ) );
45 scene::Instance* instance = Node_getInstantiable( node )->create( m_path, m_parent.top() );
46 m_observer->insert( instance );
47 Node_getInstantiable( node )->insert( m_observer, m_path, instance );
48 m_parent.push( instance );
51 void post( scene::Node& node ) const {
57 class UninstanceSubgraphWalker : public scene::Traversable::Walker
59 scene::Instantiable::Observer* m_observer;
60 mutable scene::Path m_path;
62 UninstanceSubgraphWalker( scene::Instantiable::Observer* observer, const scene::Path& parent )
63 : m_observer( observer ), m_path( parent ){
65 bool pre( scene::Node& node ) const {
66 m_path.push( makeReference( node ) );
69 void post( scene::Node& node ) const {
70 scene::Instance* instance = Node_getInstantiable( node )->erase( m_observer, m_path );
71 m_observer->erase( instance );
77 class InstanceSet : public scene::Traversable::Observer
79 typedef std::pair<scene::Instantiable::Observer*, PathConstReference> CachePath;
81 typedef CachePath key_type;
83 typedef std::map<key_type, scene::Instance*> InstanceMap;
84 InstanceMap m_instances;
87 typedef InstanceMap::iterator iterator;
90 return m_instances.begin();
93 return m_instances.end();
97 void insert( scene::Node& child ){
98 for ( iterator i = begin(); i != end(); ++i )
100 Node_traverseSubgraph( child, InstanceSubgraphWalker( ( *i ).first.first, ( *i ).first.second, ( *i ).second ) );
101 ( *i ).second->boundsChanged();
104 void erase( scene::Node& child ){
105 for ( iterator i = begin(); i != end(); ++i )
107 Node_traverseSubgraph( child, UninstanceSubgraphWalker( ( *i ).first.first, ( *i ).first.second ) );
108 ( *i ).second->boundsChanged();
113 void forEachInstance( const scene::Instantiable::Visitor& visitor ){
114 for ( iterator i = begin(); i != end(); ++i )
116 visitor.visit( *( *i ).second );
120 void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){
121 ASSERT_MESSAGE( m_instances.find( key_type( observer, PathConstReference( instance->path() ) ) ) == m_instances.end(), "InstanceSet::insert - element already exists" );
122 m_instances.insert( InstanceMap::value_type( key_type( observer, PathConstReference( instance->path() ) ), instance ) );
124 scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){
125 ASSERT_MESSAGE( m_instances.find( key_type( observer, PathConstReference( path ) ) ) != m_instances.end(), "InstanceSet::erase - failed to find element" );
126 InstanceMap::iterator i = m_instances.find( key_type( observer, PathConstReference( path ) ) );
127 scene::Instance* instance = i->second;
128 m_instances.erase( i );
132 void transformChanged(){
133 for ( InstanceMap::iterator i = m_instances.begin(); i != m_instances.end(); ++i )
135 ( *i ).second->transformChanged();
138 typedef MemberCaller<InstanceSet, &InstanceSet::transformChanged> TransformChangedCaller;
139 void boundsChanged(){
140 for ( InstanceMap::iterator i = m_instances.begin(); i != m_instances.end(); ++i )
142 ( *i ).second->boundsChanged();
145 typedef MemberCaller<InstanceSet, &InstanceSet::boundsChanged> BoundsChangedCaller;
148 template<typename Functor>
149 inline void InstanceSet_forEach( InstanceSet& instances, const Functor& functor ){
150 for ( InstanceSet::iterator i = instances.begin(), end = instances.end(); i != end; ++i )
152 functor( *( *i ).second );
156 template<typename Type>
157 class InstanceEvaluateTransform
160 inline void operator()( scene::Instance& instance ) const {
161 InstanceTypeCast<Type>::cast( instance )->evaluateTransform();
165 template<typename Type>
166 class InstanceSetEvaluateTransform
169 static void apply( InstanceSet& instances ){
170 InstanceSet_forEach( instances, InstanceEvaluateTransform<Type>() );
172 typedef ReferenceCaller<InstanceSet, &InstanceSetEvaluateTransform<Type>::apply> Caller;