]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/scenegraph.cpp
- Fixed Etb saving custom tags to global tagfile (Shaderman/namespace)
[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 "signal/signal.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   Signal0 m_boundsChanged;
80   scene::Path m_rootpath;
81   Signal0 m_sceneChangedCallbacks;
82
83   TypeIdMap<NODETYPEID_MAX> m_nodeTypeIds;
84   TypeIdMap<INSTANCETYPEID_MAX> m_instanceTypeIds;
85
86 public:
87
88   CompiledGraph(scene::Instantiable::Observer* observer)
89     : m_observer(observer)
90   {
91   }
92
93   void addSceneChangedCallback(const SignalHandler& handler)
94   {
95     m_sceneChangedCallbacks.connectLast(handler);
96   }
97   void sceneChanged()
98   {
99     m_sceneChangedCallbacks();
100   }
101
102   scene::Node& root()
103   {
104     ASSERT_MESSAGE(!m_rootpath.empty(), "scenegraph root does not exist");
105     return m_rootpath.top();
106   }
107   void insert_root(scene::Node& root)
108   {
109     //globalOutputStream() << "insert_root\n";
110
111     ASSERT_MESSAGE(m_rootpath.empty(), "scenegraph root already exists");
112
113     root.IncRef();
114
115     Node_traverseSubgraph(root, InstanceSubgraphWalker(this, scene::Path(), 0));
116
117     m_rootpath.push(makeReference(root));
118   }
119   void erase_root()
120   {
121     //globalOutputStream() << "erase_root\n";
122
123     ASSERT_MESSAGE(!m_rootpath.empty(), "scenegraph root does not exist");
124
125     scene::Node& root = m_rootpath.top();
126
127     m_rootpath.pop();
128
129     Node_traverseSubgraph(root, UninstanceSubgraphWalker(this, scene::Path()));
130
131     root.DecRef();
132   }
133   void boundsChanged()
134   {
135     m_boundsChanged();
136   }
137
138   void traverse(const Walker& walker)
139   {
140     traverse_subgraph(walker, m_instances.begin());
141   }
142
143   void traverse_subgraph(const Walker& walker, const scene::Path& start)
144   {
145     if(!m_instances.empty())
146     {
147       traverse_subgraph(walker, m_instances.find(PathConstReference(start)));
148     }
149   }
150
151   scene::Instance* find(const scene::Path& path)
152   {
153     InstanceMap::iterator i = m_instances.find(PathConstReference(path));
154     if(i == m_instances.end())
155     {
156       return 0;
157     }
158     return (*i).second;
159   }
160
161   void insert(scene::Instance* instance)
162   {
163     m_instances.insert(InstanceMap::value_type(PathConstReference(instance->path()), instance));
164
165     m_observer->insert(instance);
166   }
167   void erase(scene::Instance* instance)
168   {
169     m_observer->erase(instance);
170
171     m_instances.erase(PathConstReference(instance->path()));
172   }
173
174   SignalHandlerId addBoundsChangedCallback(const SignalHandler& boundsChanged)
175   {
176     return m_boundsChanged.connectLast(boundsChanged);
177   }
178   void removeBoundsChangedCallback(SignalHandlerId id)
179   {
180     m_boundsChanged.disconnect(id);
181   }
182
183   TypeId getNodeTypeId(const char* name)
184   {
185     return m_nodeTypeIds.getTypeId(name);
186   }
187
188   TypeId getInstanceTypeId(const char* name)
189   {
190     return m_instanceTypeIds.getTypeId(name);
191   }
192
193 private:
194
195   bool pre(const Walker& walker, const InstanceMap::iterator& i)
196   {
197     return walker.pre(i->first, *i->second);
198   }
199
200   void post(const Walker& walker, const InstanceMap::iterator& i)
201   {
202     walker.post(i->first, *i->second);
203   }
204
205   void traverse_subgraph(const Walker& walker, InstanceMap::iterator i)
206   {
207     Stack<InstanceMap::iterator> stack;
208     if(i != m_instances.end())
209     {
210       const std::size_t startSize = (*i).first.get().size();
211       do
212       {
213         if(i != m_instances.end()
214           && stack.size() < ((*i).first.get().size() - startSize + 1))
215         {
216           stack.push(i);
217           ++i;
218           if(!pre(walker, stack.top()))
219           {
220             // skip subgraph
221             while(i != m_instances.end()
222               && stack.size() < ((*i).first.get().size() - startSize + 1))
223             {
224               ++i;
225             }
226           }
227         }
228         else
229         {
230           post(walker, stack.top());
231           stack.pop();
232         }
233       }
234       while(!stack.empty());
235     }
236   }
237 };
238
239 namespace
240 {
241   CompiledGraph* g_sceneGraph;
242   GraphTreeModel* g_tree_model;
243 }
244
245 GraphTreeModel* scene_graph_get_tree_model()
246 {
247   return g_tree_model;
248 }
249
250
251 class SceneGraphObserver : public scene::Instantiable::Observer
252 {
253 public:
254   void insert(scene::Instance* instance)
255   {
256     g_sceneGraph->sceneChanged();
257     graph_tree_model_insert(g_tree_model, *instance);
258   }
259   void erase(scene::Instance* instance)
260   {
261     g_sceneGraph->sceneChanged();
262     graph_tree_model_erase(g_tree_model, *instance);
263   }
264 };
265
266 SceneGraphObserver g_SceneGraphObserver;
267
268 void SceneGraph_Construct()
269 {
270   g_tree_model = graph_tree_model_new();
271
272   g_sceneGraph = new CompiledGraph(&g_SceneGraphObserver);
273 }
274
275 void SceneGraph_Destroy()
276 {
277   delete g_sceneGraph;
278
279   graph_tree_model_delete(g_tree_model);
280 }
281
282
283 #include "modulesystem/singletonmodule.h"
284 #include "modulesystem/moduleregistry.h"
285
286 class SceneGraphAPI
287 {
288   scene::Graph* m_scenegraph;
289 public:
290   typedef scene::Graph Type;
291   STRING_CONSTANT(Name, "*");
292
293   SceneGraphAPI()
294   {
295     SceneGraph_Construct();
296
297     m_scenegraph = g_sceneGraph;
298   }
299   ~SceneGraphAPI()
300   {
301     SceneGraph_Destroy();
302   }
303   scene::Graph* getTable()
304   {
305     return m_scenegraph;
306   }
307 };
308
309 typedef SingletonModule<SceneGraphAPI> SceneGraphModule;
310 typedef Static<SceneGraphModule> StaticSceneGraphModule;
311 StaticRegisterModule staticRegisterSceneGraph(StaticSceneGraphModule::instance());
312