]> icculus.org git repositories - divverent/netradiant.git/blob - plugins/entity/group.cpp
support "target2" etc. name keys for Q3A maps too
[divverent/netradiant.git] / plugins / entity / group.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 ///\file
23 ///\brief Represents any entity which does not have a fixed size specified in its entity-definition (except misc_model).
24 ///
25 /// This entity behaves as a group, i.e. it contains brushes.
26
27 #include "cullable.h"
28 #include "renderable.h"
29 #include "editable.h"
30
31 #include "selectionlib.h"
32 #include "instancelib.h"
33 #include "transformlib.h"
34 #include "traverselib.h"
35 #include "entitylib.h"
36 #include "render.h"
37 #include "eclasslib.h"
38
39 #include "targetable.h"
40 #include "origin.h"
41 #include "angles.h"
42 #include "scale.h"
43 #include "filters.h"
44 #include "namedentity.h"
45 #include "keyobservers.h"
46 #include "namekeys.h"
47
48 #include "entity.h"
49
50 class Group
51 {
52   EntityKeyValues m_entity;
53   KeyObserverMap m_keyObservers;
54   MatrixTransform m_transform;
55   TraversableNodeSet m_traverse;
56
57   ClassnameFilter m_filter;
58   NamedEntity m_named;
59   NameKeys m_nameKeys;
60
61   RenderableNamedEntity m_renderName;
62   mutable Vector3 m_name_origin;
63
64   Callback m_transformChanged;
65
66   void construct()
67   {
68     m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
69     m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
70   }
71  
72 public:
73   Group(EntityClass* eclass, scene::Node& node, const Callback& transformChanged) :
74     m_entity(eclass),
75     m_filter(m_entity, node),
76     m_named(m_entity),
77     m_nameKeys(m_entity),
78     m_renderName(m_named, m_name_origin),
79         m_name_origin(g_vector3_identity),
80     m_transformChanged(transformChanged)
81   {
82     construct();
83   }
84   Group(const Group& other, scene::Node& node, const Callback& transformChanged) :
85     m_entity(other.m_entity),
86     m_filter(m_entity, node),
87     m_named(m_entity),
88     m_nameKeys(m_entity),
89     m_renderName(m_named, g_vector3_identity),
90     m_transformChanged(transformChanged)
91   {
92     construct();
93   }
94
95   InstanceCounter m_instanceCounter;
96   void instanceAttach(const scene::Path& path)
97   {
98     if(++m_instanceCounter.m_count == 1)
99     {
100       m_filter.instanceAttach();
101       m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
102       m_traverse.instanceAttach(path_find_mapfile(path.begin(), path.end()));
103       m_entity.attach(m_keyObservers);
104     }
105   }
106   void instanceDetach(const scene::Path& path)
107   {
108     if(--m_instanceCounter.m_count == 0)
109     {
110       m_entity.detach(m_keyObservers);
111       m_traverse.instanceDetach(path_find_mapfile(path.begin(), path.end()));
112       m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
113       m_filter.instanceDetach();
114     }
115   }
116
117   EntityKeyValues& getEntity()
118   {
119     return m_entity;
120   }
121   const EntityKeyValues& getEntity() const
122   {
123     return m_entity;
124   }
125
126   scene::Traversable& getTraversable()
127   {
128     return m_traverse;
129   }
130   Namespaced& getNamespaced()
131   {
132     return m_nameKeys;
133   }
134   Nameable& getNameable()
135   {
136     return m_named;
137   }
138   TransformNode& getTransformNode()
139   {
140     return m_transform;
141   }
142
143   void attach(scene::Traversable::Observer* observer)
144   {
145     m_traverse.attach(observer);
146   }
147   void detach(scene::Traversable::Observer* observer)
148   {
149     m_traverse.detach(observer);
150   }
151
152   void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
153   {
154     renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
155   }
156
157   void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, const AABB& childBounds) const
158   {
159     renderSolid(renderer, volume, localToWorld);
160
161         if(g_showNames)
162     {
163       // don't draw the name for worldspawn
164       if(!strcmp(m_entity.getEntityClass().name(), "worldspawn"))
165           return;
166
167           // place name in the middle of the "children cloud"
168           m_name_origin = childBounds.origin;
169
170       renderer.addRenderable(m_renderName, localToWorld);
171     }
172   }
173 };
174
175 #if 0
176 class TransformableSetTranslation
177 {
178   Translation m_value;
179 public:
180   TransformableSetTranslation(const Translation& value) : m_value(value)
181   {
182   }
183   void operator()(Transformable& transformable) const
184   {
185     transformable.setTranslation(m_value);
186   }
187 };
188
189 class TransformableSetRotation
190 {
191   Rotation m_value;
192 public:
193   TransformableSetRotation(const Rotation& value) : m_value(value)
194   {
195   }
196   void operator()(Transformable& transformable) const
197   {
198     transformable.setRotation(m_value);
199   }
200 };
201
202 class TransformableSetScale
203 {
204   Scale m_value;
205 public:
206   TransformableSetScale(const Scale& value) : m_value(value)
207   {
208   }
209   void operator()(Transformable& transformable) const
210   {
211     transformable.setScale(m_value);
212   }
213 };
214
215 class TransformableSetType
216 {
217   TransformModifierType m_value;
218 public:
219   TransformableSetType(const TransformModifierType& value) : m_value(value)
220   {
221   }
222   void operator()(Transformable& transformable) const
223   {
224     transformable.setType(m_value);
225   }
226 };
227
228 class TransformableFreezeTransform
229 {
230   TransformModifierType m_value;
231 public:
232   void operator()(Transformable& transformable) const
233   {
234     transformable.freezeTransform();
235   }
236 };
237
238 template<typename Functor>
239 inline void Scene_forEachChildTransformable(const Functor& functor, const scene::Path& path)
240 {
241   GlobalSceneGraph().traverse_subgraph(ChildInstanceWalker< InstanceApply<Transformable, Functor> >(functor), path);
242 }
243 #endif
244
245 class GroupInstance :
246   public TargetableInstance,
247 #if 0
248   public Transformable,
249 #endif
250   public Renderable
251 {
252   class TypeCasts
253   {
254     InstanceTypeCastTable m_casts;
255   public:
256     TypeCasts()
257     {
258       m_casts = TargetableInstance::StaticTypeCasts::instance().get();
259       InstanceStaticCast<GroupInstance, Renderable>::install(m_casts);
260 #if 0
261       InstanceStaticCast<GroupInstance, Transformable>::install(m_casts);
262 #endif
263     }
264     InstanceTypeCastTable& get()
265     {
266       return m_casts;
267     }
268   };
269
270   Group& m_contained;
271 public:
272   typedef LazyStatic<TypeCasts> StaticTypeCasts;
273
274   GroupInstance(const scene::Path& path, scene::Instance* parent, Group& group) :
275     TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), group.getEntity(), *this),
276     m_contained(group)
277   {
278     m_contained.instanceAttach(Instance::path());
279     StaticRenderableConnectionLines::instance().attach(*this);
280   }
281   ~GroupInstance()
282   {
283     StaticRenderableConnectionLines::instance().detach(*this);
284     m_contained.instanceDetach(Instance::path());
285   }
286   void renderSolid(Renderer& renderer, const VolumeTest& volume) const
287   {
288     m_contained.renderSolid(renderer, volume, Instance::localToWorld());
289   }
290   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
291   {
292           m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), Instance::childBounds());
293   }
294
295 #if 0
296   void setType(TransformModifierType type)
297   {
298     Scene_forEachChildTransformable(TransformableSetType(type), Instance::path());
299   }
300   void setTranslation(const Translation& value)
301   {
302     Scene_forEachChildTransformable(TransformableSetTranslation(value), Instance::path());
303   }
304   void setRotation(const Rotation& value)
305   {
306     Scene_forEachChildTransformable(TransformableSetRotation(value), Instance::path());
307   }
308   void setScale(const Scale& value)
309   {
310     Scene_forEachChildTransformable(TransformableSetScale(value), Instance::path());
311   }
312   void freezeTransform()
313   {
314     Scene_forEachChildTransformable(TransformableFreezeTransform(), Instance::path());
315   }
316
317   void evaluateTransform()
318   {
319   }
320 #endif
321 };
322
323 class GroupNode :
324   public scene::Node::Symbiot,
325   public scene::Instantiable,
326   public scene::Cloneable,
327   public scene::Traversable::Observer
328 {
329   class TypeCasts
330   {
331     NodeTypeCastTable m_casts;
332   public:
333     TypeCasts()
334     {
335       NodeStaticCast<GroupNode, scene::Instantiable>::install(m_casts);
336       NodeStaticCast<GroupNode, scene::Cloneable>::install(m_casts);
337       NodeContainedCast<GroupNode, scene::Traversable>::install(m_casts);
338       NodeContainedCast<GroupNode, TransformNode>::install(m_casts);
339       NodeContainedCast<GroupNode, Entity>::install(m_casts);
340       NodeContainedCast<GroupNode, Nameable>::install(m_casts);
341       NodeContainedCast<GroupNode, Namespaced>::install(m_casts);
342     }
343     NodeTypeCastTable& get()
344     {
345       return m_casts;
346     }
347   };
348
349
350   scene::Node m_node;
351   InstanceSet m_instances;
352   Group m_contained;
353
354   void construct()
355   {
356     m_contained.attach(this);
357   }
358   void destroy()
359   {
360     m_contained.detach(this);
361   }
362
363 public:
364
365   typedef LazyStatic<TypeCasts> StaticTypeCasts;
366
367   scene::Traversable& get(NullType<scene::Traversable>)
368   {
369     return m_contained.getTraversable();
370   }
371   TransformNode& get(NullType<TransformNode>)
372   {
373     return m_contained.getTransformNode();
374   }
375   Entity& get(NullType<Entity>)
376   {
377     return m_contained.getEntity();
378   }
379   Nameable& get(NullType<Nameable>)
380   {
381     return m_contained.getNameable();
382   }
383   Namespaced& get(NullType<Namespaced>)
384   {
385     return m_contained.getNamespaced();
386   }
387
388   GroupNode(EntityClass* eclass) :
389     m_node(this, this, StaticTypeCasts::instance().get()),
390     m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances))
391   {
392     construct();
393   }
394   GroupNode(const GroupNode& other) :
395     scene::Node::Symbiot(other),
396     scene::Instantiable(other),
397     scene::Cloneable(other),
398     scene::Traversable::Observer(other),
399     m_node(this, this, StaticTypeCasts::instance().get()),
400     m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances))
401   {
402     construct();
403   }
404   ~GroupNode()
405   {
406     destroy();
407   }
408
409   void release()
410   {
411     delete this;
412   }
413   scene::Node& node()
414   {
415     return m_node;
416   }
417
418   scene::Node& clone() const
419   {
420     return (new GroupNode(*this))->node();
421   }
422
423   void insert(scene::Node& child)
424   {
425     m_instances.insert(child);
426   }
427   void erase(scene::Node& child)
428   {
429     m_instances.erase(child);
430   }
431
432   scene::Instance* create(const scene::Path& path, scene::Instance* parent)
433   {
434     return new GroupInstance(path, parent, m_contained);
435   }
436   void forEachInstance(const scene::Instantiable::Visitor& visitor)
437   {
438     m_instances.forEachInstance(visitor);
439   }
440   void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
441   {
442     m_instances.insert(observer, path, instance);
443   }
444   scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
445   {
446     return m_instances.erase(observer, path);
447   }
448 };
449
450 scene::Node& New_Group(EntityClass* eclass)
451 {
452   return (new GroupNode(eclass))->node();
453 }