]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/scenegraph.cpp
added missing files
[xonotic/netradiant.git] / radiant / scenegraph.cpp
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 #include "scenegraph.h"
23
24 #include "debugging/debugging.h"
25
26 #include <map>
27 #include <set>
28 #include <vector>
29
30 #include "string/string.h"
31 #include "generic/callback.h"
32 #include "scenelib.h"
33 #include "instancelib.h"
34 #include "treemodel.h"
35
36 class StringEqualPredicate
37 {
38   const char* m_string;
39 public:
40   StringEqualPredicate(const char* string) : m_string(string)
41   {
42   }
43   bool operator()(const char* other) const
44   {
45     return string_equal(m_string, other);
46   }
47 };
48
49 template<std::size_t SIZE>
50 class TypeIdMap
51 {
52   typedef const char* TypeName;
53   typedef TypeName TypeNames[SIZE];
54   TypeNames m_typeNames;
55   TypeName* m_typeNamesEnd;
56
57 public:
58   TypeIdMap() : m_typeNamesEnd(m_typeNames)
59   {
60   }
61   TypeId getTypeId(const char* name)
62   {
63     TypeName* i = std::find_if(m_typeNames, m_typeNamesEnd, StringEqualPredicate(name));
64     if(i == m_typeNamesEnd)
65     {
66       ASSERT_MESSAGE(m_typeNamesEnd != m_typeNames + SIZE, "reached maximum number of type names supported (" << Unsigned(SIZE) << ")");
67       *m_typeNamesEnd++ = name;
68     }
69     return i - m_typeNames;
70   }
71 };
72
73 class CompiledGraph : public scene::Graph, public scene::Instantiable::Observer
74 {
75   typedef std::map<PathConstReference, scene::Instance*> InstanceMap;
76
77   InstanceMap m_instances;
78   scene::Instantiable::Observer* m_observer;
79   typedef std::set<Callback> BoundsChangedCallbacks;
80   BoundsChangedCallbacks m_boundsChanged;
81   scene::Path m_rootpath;
82   std::vector<Callback> m_sceneChangedCallbacks;
83
84   TypeIdMap<NODETYPEID_MAX> m_nodeTypeIds;
85   TypeIdMap<INSTANCETYPEID_MAX> m_instanceTypeIds;
86
87 public:
88
89   CompiledGraph(scene::Instantiable::Observer* observer)
90     : m_observer(observer)
91   {
92   }
93
94   void addSceneChangedCallback(const Callback& callback)
95   {
96     m_sceneChangedCallbacks.push_back(callback);
97   }
98   void sceneChanged()
99   {
100     std::for_each(m_sceneChangedCallbacks.begin(), m_sceneChangedCallbacks.end(), CallbackInvoke());
101   }
102
103   scene::Node& root()
104   {
105     ASSERT_MESSAGE(!m_rootpath.empty(), "scenegraph root does not exist");
106     return *m_rootpath.top();
107   }
108   void insert_root(scene::Node& root)
109   {
110     //globalOutputStream() << "insert_root\n";
111
112     ASSERT_MESSAGE(m_rootpath.empty(), "scenegraph root already exists");
113
114     root.IncRef();
115
116     Node_traverseSubgraph(root, InstanceSubgraphWalker(this, scene::Path(), 0));
117
118     m_rootpath.push(makeReference(root));
119   }
120   void erase_root()
121   {
122     //globalOutputStream() << "erase_root\n";
123
124     ASSERT_MESSAGE(!m_rootpath.empty(), "scenegraph root does not exist");
125
126     scene::Node& root = *m_rootpath.top();
127
128     m_rootpath.pop();
129
130     Node_traverseSubgraph(root, UninstanceSubgraphWalker(this, scene::Path()));
131
132     root.DecRef();
133   }
134   void boundsChanged()
135   {
136     std::for_each(m_boundsChanged.begin(), m_boundsChanged.end(), CallbackInvoke());
137   }
138
139   void traverse(const Walker& walker)
140   {
141     traverse_subgraph(walker, m_instances.begin());
142   }
143
144   void traverse_subgraph(const Walker& walker, const scene::Path& start)
145   {
146     if(!m_instances.empty())
147     {
148       traverse_subgraph(walker, m_instances.find(PathConstReference(start)));
149     }
150   }
151
152   scene::Instance* find(const scene::Path& path)
153   {
154     InstanceMap::iterator i = m_instances.find(PathConstReference(path));
155     if(i == m_instances.end())
156     {
157       return 0;
158     }
159     return (*i).second;
160   }
161
162   void insert(scene::Instance* instance)
163   {
164     m_instances.insert(InstanceMap::value_type(PathConstReference(instance->path()), instance));
165
166     m_observer->insert(instance);
167   }
168   void erase(scene::Instance* instance)
169   {
170     m_observer->erase(instance);
171
172     m_instances.erase(PathConstReference(instance->path()));
173   }
174
175   void addBoundsChangedCallback(const Callback& boundsChanged)
176   {
177     ASSERT_MESSAGE(m_boundsChanged.find(boundsChanged) == m_boundsChanged.end(), "bounds-changed callback already registered");
178     m_boundsChanged.insert(boundsChanged);
179   }
180   void removeBoundsChangedCallback(const Callback& boundsChanged)
181   {
182     ASSERT_MESSAGE(m_boundsChanged.find(boundsChanged) != m_boundsChanged.end(), "bounds-changed callback not registered");
183     m_boundsChanged.erase(boundsChanged);
184   }
185
186   TypeId getNodeTypeId(const char* name)
187   {
188     return m_nodeTypeIds.getTypeId(name);
189   }
190
191   TypeId getInstanceTypeId(const char* name)
192   {
193     return m_instanceTypeIds.getTypeId(name);
194   }
195
196 private:
197
198   bool pre(const Walker& walker, const InstanceMap::iterator& i)
199   {
200     return walker.pre(i->first, *i->second);
201   }
202
203   void post(const Walker& walker, const InstanceMap::iterator& i)
204   {
205     walker.post(i->first, *i->second);
206   }
207
208   void traverse_subgraph(const Walker& walker, InstanceMap::iterator i)
209   {
210     Stack<InstanceMap::iterator> stack;
211     if(i != m_instances.end())
212     {
213       const std::size_t startSize = (*i).first.get().size();
214       do
215       {
216         if(i != m_instances.end()
217           && stack.size() < ((*i).first.get().size() - startSize + 1))
218         {
219           stack.push(i);
220           ++i;
221           if(!pre(walker, stack.top()))
222           {
223             // skip subgraph
224             while(i != m_instances.end()
225               && stack.size() < ((*i).first.get().size() - startSize + 1))
226             {
227               ++i;
228             }
229           }
230         }
231         else
232         {
233           post(walker, stack.top());
234           stack.pop();
235         }
236       }
237       while(!stack.empty());
238     }
239   }
240 };
241
242 namespace
243 {
244   CompiledGraph* g_sceneGraph;
245   GraphTreeModel* g_tree_model;
246 }
247
248 GraphTreeModel* scene_graph_get_tree_model()
249 {
250   return g_tree_model;
251 }
252
253
254 class SceneGraphObserver : public scene::Instantiable::Observer
255 {
256 public:
257   void insert(scene::Instance* instance)
258   {
259     g_sceneGraph->sceneChanged();
260     graph_tree_model_insert(g_tree_model, *instance);
261   }
262   void erase(scene::Instance* instance)
263   {
264     g_sceneGraph->sceneChanged();
265     graph_tree_model_erase(g_tree_model, *instance);
266   }
267 };
268
269 SceneGraphObserver g_SceneGraphObserver;
270
271 void SceneGraph_Construct()
272 {
273   g_tree_model = graph_tree_model_new();
274
275   g_sceneGraph = new CompiledGraph(&g_SceneGraphObserver);
276 }
277
278 void SceneGraph_Destroy()
279 {
280   delete g_sceneGraph;
281
282   graph_tree_model_delete(g_tree_model);
283 }
284
285
286 #include "modulesystem/singletonmodule.h"
287 #include "modulesystem/moduleregistry.h"
288
289 class SceneGraphAPI
290 {
291   scene::Graph* m_scenegraph;
292 public:
293   typedef scene::Graph Type;
294   STRING_CONSTANT(Name, "*");
295
296   SceneGraphAPI()
297   {
298     SceneGraph_Construct();
299
300     m_scenegraph = g_sceneGraph;
301   }
302   ~SceneGraphAPI()
303   {
304     SceneGraph_Destroy();
305   }
306   scene::Graph* getTable()
307   {
308     return m_scenegraph;
309   }
310 };
311
312 typedef SingletonModule<SceneGraphAPI> SceneGraphModule;
313 typedef Static<SceneGraphModule> StaticSceneGraphModule;
314 StaticRegisterModule staticRegisterSceneGraph(StaticSceneGraphModule::instance());
315