Fix MSYS2 issues
[xonotic/netradiant.git] / libs / instancelib.h
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 #if !defined ( INCLUDED_INSTANCELIB_H )
23 #define INCLUDED_INSTANCELIB_H
24
25 #include "debugging/debugging.h"
26
27 #include "iscenegraph.h"
28
29 #include "scenelib.h"
30 #include "generic/reference.h"
31 #include "generic/callback.h"
32 #include <map>
33
34 class InstanceSubgraphWalker : public scene::Traversable::Walker
35 {
36 scene::Instantiable::Observer* m_observer;
37 mutable scene::Path m_path;
38 mutable Stack<scene::Instance*> m_parent;
39 public:
40 InstanceSubgraphWalker( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* parent )
41         : m_observer( observer ), m_path( path ), m_parent( parent ){
42 }
43 bool pre( scene::Node& node ) const {
44         m_path.push( makeReference( node ) );
45         scene::Instance* instance = Node_getInstantiable( node )->create( m_path, m_parent.top() );
46         m_observer->insert( instance );
47         Node_getInstantiable( node )->insert( m_observer, m_path, instance );
48         m_parent.push( instance );
49         return true;
50 }
51 void post( scene::Node& node ) const {
52         m_path.pop();
53         m_parent.pop();
54 }
55 };
56
57 class UninstanceSubgraphWalker : public scene::Traversable::Walker
58 {
59 scene::Instantiable::Observer* m_observer;
60 mutable scene::Path m_path;
61 public:
62 UninstanceSubgraphWalker( scene::Instantiable::Observer* observer, const scene::Path& parent )
63         : m_observer( observer ), m_path( parent ){
64 }
65 bool pre( scene::Node& node ) const {
66         m_path.push( makeReference( node ) );
67         return true;
68 }
69 void post( scene::Node& node ) const {
70         scene::Instance* instance = Node_getInstantiable( node )->erase( m_observer, m_path );
71         m_observer->erase( instance );
72         delete instance;
73         m_path.pop();
74 }
75 };
76
77 class InstanceSet : public scene::Traversable::Observer
78 {
79 typedef std::pair<scene::Instantiable::Observer*, PathConstReference> CachePath;
80
81 typedef CachePath key_type;
82
83 typedef std::map<key_type, scene::Instance*> InstanceMap;
84 InstanceMap m_instances;
85 public:
86
87 typedef InstanceMap::iterator iterator;
88
89 iterator begin(){
90         return m_instances.begin();
91 }
92 iterator end(){
93         return m_instances.end();
94 }
95
96 // traverse observer
97 void insert( scene::Node& child ){
98         for ( iterator i = begin(); i != end(); ++i )
99         {
100                 Node_traverseSubgraph( child, InstanceSubgraphWalker( ( *i ).first.first, ( *i ).first.second, ( *i ).second ) );
101                 ( *i ).second->boundsChanged();
102         }
103 }
104 void erase( scene::Node& child ){
105         for ( iterator i = begin(); i != end(); ++i )
106         {
107                 Node_traverseSubgraph( child, UninstanceSubgraphWalker( ( *i ).first.first, ( *i ).first.second ) );
108                 ( *i ).second->boundsChanged();
109         }
110 }
111
112 // instance
113 void forEachInstance( const scene::Instantiable::Visitor& visitor ){
114         for ( iterator i = begin(); i != end(); ++i )
115         {
116                 visitor.visit( *( *i ).second );
117         }
118 }
119
120 void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){
121         ASSERT_MESSAGE( m_instances.find( key_type( observer, PathConstReference( instance->path() ) ) ) == m_instances.end(), "InstanceSet::insert - element already exists" );
122         m_instances.insert( InstanceMap::value_type( key_type( observer, PathConstReference( instance->path() ) ), instance ) );
123 }
124 scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){
125         ASSERT_MESSAGE( m_instances.find( key_type( observer, PathConstReference( path ) ) ) != m_instances.end(), "InstanceSet::erase - failed to find element" );
126         InstanceMap::iterator i = m_instances.find( key_type( observer, PathConstReference( path ) ) );
127         scene::Instance* instance = i->second;
128         m_instances.erase( i );
129         return instance;
130 }
131
132 void transformChanged(){
133         for ( InstanceMap::iterator i = m_instances.begin(); i != m_instances.end(); ++i )
134         {
135                 ( *i ).second->transformChanged();
136         }
137 }
138 typedef MemberCaller<InstanceSet, &InstanceSet::transformChanged> TransformChangedCaller;
139 void boundsChanged(){
140         for ( InstanceMap::iterator i = m_instances.begin(); i != m_instances.end(); ++i )
141         {
142                 ( *i ).second->boundsChanged();
143         }
144 }
145 typedef MemberCaller<InstanceSet, &InstanceSet::boundsChanged> BoundsChangedCaller;
146 };
147
148 template<typename Functor>
149 inline void InstanceSet_forEach( InstanceSet& instances, const Functor& functor ){
150         for ( InstanceSet::iterator i = instances.begin(), end = instances.end(); i != end; ++i )
151         {
152                 functor( *( *i ).second );
153         }
154 }
155
156 template<typename Type>
157 class InstanceEvaluateTransform
158 {
159 public:
160 inline void operator()( scene::Instance& instance ) const {
161         InstanceTypeCast<Type>::cast( instance )->evaluateTransform();
162 }
163 };
164
165 template<typename Type>
166 class InstanceSetEvaluateTransform
167 {
168 public:
169 static void apply( InstanceSet& instances ){
170         InstanceSet_forEach( instances, InstanceEvaluateTransform<Type>() );
171 }
172 typedef ReferenceCaller<InstanceSet, &InstanceSetEvaluateTransform<Type>::apply> Caller;
173 };
174
175 #endif