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