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