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