NOW I do it right: #woxblox#
[divverent/netradiant.git] / libs / instancelib.h
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
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.
11
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.
16
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
20 */
21
22 #if !defined (INCLUDED_INSTANCELIB_H)
23 #define INCLUDED_INSTANCELIB_H
24
25 #include "debugging/debugging.h"
26
27 #include "iscenegraph.h"
28
29 #include "scenelib.h"
30 #include "generic/reference.h"
31 #include "generic/callback.h"
32 #include <map>
33
34 class InstanceSubgraphWalker : public scene::Traversable::Walker
35 {
36   scene::Instantiable::Observer* m_observer;
37   mutable scene::Path m_path;
38   mutable Stack<scene::Instance*> m_parent;
39 public:
40   InstanceSubgraphWalker(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* parent)
41     : m_observer(observer), m_path(path), m_parent(parent)
42   {
43   }
44   bool pre(scene::Node& node) const
45   {
46     m_path.push(makeReference(node));
47     scene::Instance* instance = Node_getInstantiable(node)->create(m_path, m_parent.top());
48     m_observer->insert(instance);
49     Node_getInstantiable(node)->insert(m_observer, m_path, instance);
50     m_parent.push(instance);
51     return true;
52   }
53   void post(scene::Node& node) const
54   {
55     m_path.pop();
56     m_parent.pop();
57   }
58 };
59
60 class UninstanceSubgraphWalker : public scene::Traversable::Walker
61 {
62   scene::Instantiable::Observer* m_observer;
63   mutable scene::Path m_path;
64 public:
65   UninstanceSubgraphWalker(scene::Instantiable::Observer* observer, const scene::Path& parent)
66     : m_observer(observer), m_path(parent)
67   {
68   }
69   bool pre(scene::Node& node) const
70   {
71     m_path.push(makeReference(node));
72     return true;
73   }
74   void post(scene::Node& node) const
75   {
76     scene::Instance* instance = Node_getInstantiable(node)->erase(m_observer, m_path);
77     m_observer->erase(instance);
78     delete instance;
79     m_path.pop();
80   }
81 };
82
83 class InstanceSet : public scene::Traversable::Observer
84 {
85   typedef std::pair<scene::Instantiable::Observer*, PathConstReference> CachePath;
86
87   typedef CachePath key_type;
88
89   typedef std::map<key_type, scene::Instance*> InstanceMap;
90   InstanceMap m_instances;
91 public:
92
93   typedef InstanceMap::iterator iterator;
94
95   iterator begin()
96   {
97     return m_instances.begin();
98   }
99   iterator end()
100   {
101     return m_instances.end();
102   }
103
104   // traverse observer
105   void insert(scene::Node& child)
106   {
107     for(iterator i = begin(); i != end(); ++i)
108     {
109       Node_traverseSubgraph(child, InstanceSubgraphWalker((*i).first.first, (*i).first.second, (*i).second));
110       (*i).second->boundsChanged();
111     }
112   }
113   void erase(scene::Node& child)
114   {
115     for(iterator i = begin(); i != end(); ++i)
116     {
117       Node_traverseSubgraph(child, UninstanceSubgraphWalker((*i).first.first, (*i).first.second));
118       (*i).second->boundsChanged();
119     }
120   }
121
122   // instance
123   void forEachInstance(const scene::Instantiable::Visitor& visitor)
124   {
125     for(iterator i = begin(); i != end(); ++i)
126     {
127       visitor.visit(*(*i).second);
128     }
129   }
130
131   void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
132   {
133     ASSERT_MESSAGE(m_instances.find(key_type(observer, PathConstReference(instance->path()))) == m_instances.end(), "InstanceSet::insert - element already exists");
134     m_instances.insert(InstanceMap::value_type(key_type(observer, PathConstReference(instance->path())), instance));
135   }
136   scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
137   {
138     ASSERT_MESSAGE(m_instances.find(key_type(observer, PathConstReference(path))) != m_instances.end(), "InstanceSet::erase - failed to find element");
139     InstanceMap::iterator i = m_instances.find(key_type(observer, PathConstReference(path)));
140     scene::Instance* instance = i->second;
141     m_instances.erase(i);
142     return instance;
143   }
144
145   void transformChanged()
146   {
147     for(InstanceMap::iterator i = m_instances.begin(); i != m_instances.end(); ++i)
148     {
149       (*i).second->transformChanged();
150     }
151   }
152   typedef MemberCaller<InstanceSet, &InstanceSet::transformChanged> TransformChangedCaller;
153   void boundsChanged()
154   {
155     for(InstanceMap::iterator i = m_instances.begin(); i != m_instances.end(); ++i)
156     {
157       (*i).second->boundsChanged();
158     }
159   }
160   typedef MemberCaller<InstanceSet, &InstanceSet::boundsChanged> BoundsChangedCaller;
161 };
162
163 template<typename Functor>
164 inline void InstanceSet_forEach(InstanceSet& instances, const Functor& functor)
165 {
166   for(InstanceSet::iterator i = instances.begin(), end = instances.end(); i != end; ++i)
167   {
168     functor(*(*i).second);
169   }
170 }
171
172 template<typename Type>
173 class InstanceEvaluateTransform
174 {
175 public:
176   inline void operator()(scene::Instance& instance) const
177   {
178     InstanceTypeCast<Type>::cast(instance)->evaluateTransform();
179   }
180 };
181
182 template<typename Type>
183 class InstanceSetEvaluateTransform
184 {
185 public:
186   static void apply(InstanceSet& instances)
187   {
188     InstanceSet_forEach(instances, InstanceEvaluateTransform<Type>());
189   }
190   typedef ReferenceCaller<InstanceSet, &InstanceSetEvaluateTransform<Type>::apply> Caller;
191 };
192
193 #endif