]> icculus.org git repositories - divverent/netradiant.git/blob - plugins/entity/generic.cpp
Merge branch 'icculus'
[divverent/netradiant.git] / plugins / entity / generic.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 has a fixed size specified in its entity-definition and does not display a model (e.g. info_player_start).
24 ///
25 /// This entity displays an axis-aligned bounding box of the size and colour specified in its entity-definition.
26 /// The "origin" key directly controls the entity's local-to-parent transform.
27 /// An arrow is drawn to visualise the "angle" key.
28
29 #include "cullable.h"
30 #include "renderable.h"
31 #include "editable.h"
32
33 #include "math/frustum.h"
34 #include "selectionlib.h"
35 #include "instancelib.h"
36 #include "transformlib.h"
37 #include "entitylib.h"
38 #include "render.h"
39 #include "eclasslib.h"
40 #include "math/line.h"
41
42 #include "targetable.h"
43 #include "origin.h"
44 #include "angles.h"
45 #include "filters.h"
46 #include "namedentity.h"
47 #include "keyobservers.h"
48 #include "namekeys.h"
49 #include "rotation.h"
50
51 #include "entity.h"
52
53
54 class RenderableArrow : public OpenGLRenderable
55 {
56   const Vector3& m_origin;
57   const Vector3& m_angles;
58
59 public:
60   RenderableArrow(const Vector3& origin, const Vector3& angles)
61     : m_origin(origin), m_angles(angles)
62   {
63   }
64
65   void render(RenderStateFlags state) const
66   {
67     Matrix4 mat = matrix4_rotation_for_euler_xyz_degrees(m_angles);
68     arrow_draw(m_origin, matrix4_transformed_direction(mat, Vector3(1, 0, 0)), matrix4_transformed_direction(mat, Vector3(0, 1, 0)), matrix4_transformed_direction(mat, Vector3(0, 0, 1)));
69   }
70 };
71
72 inline void read_aabb(AABB& aabb, const EntityClass& eclass)
73 {
74   aabb = aabb_for_minmax(eclass.mins, eclass.maxs);
75 }
76
77
78 class GenericEntity :
79   public Cullable,
80   public Bounded,
81   public Snappable
82 {
83   EntityKeyValues m_entity;
84   KeyObserverMap m_keyObservers;
85   MatrixTransform m_transform;
86
87   OriginKey m_originKey;
88   Vector3 m_origin;
89   AnglesKey m_anglesKey;
90   Vector3 m_angles;
91
92   ClassnameFilter m_filter;
93   NamedEntity m_named;
94   NameKeys m_nameKeys;
95
96   AABB m_aabb_local;
97
98   RenderableArrow m_arrow;
99   RenderableSolidAABB m_aabb_solid;
100   RenderableWireframeAABB m_aabb_wire;
101   RenderableNamedEntity m_renderName;
102
103   Callback m_transformChanged;
104   Callback m_evaluateTransform;
105
106   void construct()
107   {
108     read_aabb(m_aabb_local, m_entity.getEntityClass());
109
110     m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
111     m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
112     m_keyObservers.insert("angle", AnglesKey::AngleChangedCaller(m_anglesKey));
113     m_keyObservers.insert("angles", AnglesKey::AnglesChangedCaller(m_anglesKey));
114     m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
115   }
116
117 // vc 2k5 compiler fix  
118 #if _MSC_VER >= 1400
119         public:
120 #endif
121
122   void updateTransform()
123   {
124     m_transform.localToParent() = g_matrix4_identity;
125     matrix4_translate_by_vec3(m_transform.localToParent(), m_origin);
126     m_transformChanged();
127   }
128   typedef MemberCaller<GenericEntity, &GenericEntity::updateTransform> UpdateTransformCaller;
129   void originChanged()
130   {
131     m_origin = m_originKey.m_origin;
132     updateTransform();
133   }
134   typedef MemberCaller<GenericEntity, &GenericEntity::originChanged> OriginChangedCaller;
135   void anglesChanged()
136   {
137     m_angles = m_anglesKey.m_angles;
138     updateTransform();
139   }
140   typedef MemberCaller<GenericEntity, &GenericEntity::anglesChanged> AnglesChangedCaller;
141 public:
142
143   GenericEntity(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
144     m_entity(eclass),
145     m_originKey(OriginChangedCaller(*this)),
146     m_origin(ORIGINKEY_IDENTITY),
147     m_anglesKey(AnglesChangedCaller(*this)),
148     m_angles(ANGLESKEY_IDENTITY),
149     m_filter(m_entity, node),
150     m_named(m_entity),
151     m_nameKeys(m_entity),
152     m_arrow(m_aabb_local.origin, m_angles),
153     m_aabb_solid(m_aabb_local),
154     m_aabb_wire(m_aabb_local),
155     m_renderName(m_named, g_vector3_identity),
156     m_transformChanged(transformChanged),
157     m_evaluateTransform(evaluateTransform)
158   {
159     construct();
160   }
161   GenericEntity(const GenericEntity& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
162     m_entity(other.m_entity),
163     m_originKey(OriginChangedCaller(*this)),
164     m_origin(ORIGINKEY_IDENTITY),
165     m_anglesKey(AnglesChangedCaller(*this)),
166     m_angles(ANGLESKEY_IDENTITY),
167     m_filter(m_entity, node),
168     m_named(m_entity),
169     m_nameKeys(m_entity),
170     m_arrow(m_aabb_local.origin, m_angles),
171     m_aabb_solid(m_aabb_local),
172     m_aabb_wire(m_aabb_local),
173     m_renderName(m_named, g_vector3_identity),
174     m_transformChanged(transformChanged),
175     m_evaluateTransform(evaluateTransform)
176   {
177     construct();
178   }
179
180   InstanceCounter m_instanceCounter;
181   void instanceAttach(const scene::Path& path)
182   {
183     if(++m_instanceCounter.m_count == 1)
184     {
185       m_filter.instanceAttach();
186       m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
187       m_entity.attach(m_keyObservers);
188     }
189   }
190   void instanceDetach(const scene::Path& path)
191   {
192     if(--m_instanceCounter.m_count == 0)
193     {
194       m_entity.detach(m_keyObservers);
195       m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
196       m_filter.instanceDetach();
197     }
198   }
199
200   EntityKeyValues& getEntity()
201   {
202     return m_entity;
203   }
204   const EntityKeyValues& getEntity() const
205   {
206     return m_entity;
207   }
208
209   Namespaced& getNamespaced()
210   {
211     return m_nameKeys;
212   }
213   Nameable& getNameable()
214   {
215     return m_named;
216   }
217   TransformNode& getTransformNode()
218   {
219     return m_transform;
220   }
221
222   const AABB& localAABB() const
223   {
224     return m_aabb_local;
225   }
226
227   VolumeIntersectionValue intersectVolume(const VolumeTest& volume, const Matrix4& localToWorld) const
228   {
229     return volume.TestAABB(localAABB(), localToWorld);
230   }
231
232   void renderArrow(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
233   {
234     if(g_showAngles)
235     {
236       renderer.addRenderable(m_arrow, localToWorld);
237     }
238   }
239   void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
240   {
241     renderer.SetState(m_entity.getEntityClass().m_state_fill, Renderer::eFullMaterials);
242     renderer.addRenderable(m_aabb_solid, localToWorld);
243     renderArrow(renderer, volume, localToWorld);
244   }
245   void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
246   {
247     renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
248     renderer.addRenderable(m_aabb_wire, localToWorld);
249     renderArrow(renderer, volume, localToWorld);
250     if(g_showNames)
251     {
252       renderer.addRenderable(m_renderName, localToWorld);
253     }
254   }
255
256
257   void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
258   {
259     test.BeginMesh(localToWorld);
260
261     SelectionIntersection best;
262     aabb_testselect(m_aabb_local, test, best);
263     if(best.valid())
264     {
265       selector.addIntersection(best);
266     }
267   }
268
269   void translate(const Vector3& translation)
270   {
271     m_origin = origin_translated(m_origin, translation);
272   }
273   void rotate(const Quaternion& rotation)
274   {
275     m_angles = angles_rotated(m_angles, rotation);
276   }
277   void snapto(float snap)
278   {
279     m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
280     m_originKey.write(&m_entity);
281   }
282   void revertTransform()
283   {
284     m_origin = m_originKey.m_origin;
285     m_angles = m_anglesKey.m_angles;
286   }
287   void freezeTransform()
288   {
289     m_originKey.m_origin = m_origin;
290     m_originKey.write(&m_entity);
291     m_anglesKey.m_angles = m_angles;
292     m_anglesKey.write(&m_entity);
293   }
294   void transformChanged()
295   {
296     revertTransform();
297     m_evaluateTransform();
298     updateTransform();
299   }
300   typedef MemberCaller<GenericEntity, &GenericEntity::transformChanged> TransformChangedCaller;
301 };
302
303 class GenericEntityInstance :
304   public TargetableInstance,
305   public TransformModifier,
306   public Renderable,
307   public SelectionTestable
308 {
309   class TypeCasts
310   {
311     InstanceTypeCastTable m_casts;
312   public:
313     TypeCasts()
314     {
315       m_casts = TargetableInstance::StaticTypeCasts::instance().get();
316       InstanceContainedCast<GenericEntityInstance, Bounded>::install(m_casts);
317       InstanceContainedCast<GenericEntityInstance, Cullable>::install(m_casts);
318       InstanceStaticCast<GenericEntityInstance, Renderable>::install(m_casts);
319       InstanceStaticCast<GenericEntityInstance, SelectionTestable>::install(m_casts);
320       InstanceStaticCast<GenericEntityInstance, Transformable>::install(m_casts);
321       InstanceIdentityCast<GenericEntityInstance>::install(m_casts);
322     }
323     InstanceTypeCastTable& get()
324     {
325       return m_casts;
326     }
327   };
328
329   GenericEntity& m_contained;
330   mutable AABB m_bounds;
331 public:
332
333   typedef LazyStatic<TypeCasts> StaticTypeCasts;
334
335   Bounded& get(NullType<Bounded>)
336   {
337     return m_contained;
338   }
339   Cullable& get(NullType<Cullable>)
340   {
341     return m_contained;
342   }
343
344   STRING_CONSTANT(Name, "GenericEntityInstance");
345
346   GenericEntityInstance(const scene::Path& path, scene::Instance* parent, GenericEntity& contained) :
347     TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
348     TransformModifier(GenericEntity::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
349     m_contained(contained)
350   {
351     m_contained.instanceAttach(Instance::path());
352
353     StaticRenderableConnectionLines::instance().attach(*this);
354   }
355   ~GenericEntityInstance()
356   {
357     StaticRenderableConnectionLines::instance().detach(*this);
358
359     m_contained.instanceDetach(Instance::path());
360   }
361
362   void renderSolid(Renderer& renderer, const VolumeTest& volume) const
363   {
364     m_contained.renderSolid(renderer, volume, Instance::localToWorld());
365   }
366   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
367   {
368     m_contained.renderWireframe(renderer, volume, Instance::localToWorld());
369   }
370
371   void testSelect(Selector& selector, SelectionTest& test)
372   {
373     m_contained.testSelect(selector, test, Instance::localToWorld());
374   }
375
376   void evaluateTransform()
377   {
378     if(getType() == TRANSFORM_PRIMITIVE)
379     {
380       m_contained.translate(getTranslation());
381       m_contained.rotate(getRotation());
382     }
383   }
384   void applyTransform()
385   {
386     m_contained.revertTransform();
387     evaluateTransform();
388     m_contained.freezeTransform();
389   }
390   typedef MemberCaller<GenericEntityInstance, &GenericEntityInstance::applyTransform> ApplyTransformCaller;
391 };
392
393 class GenericEntityNode :
394   public scene::Node::Symbiot,
395   public scene::Instantiable,
396   public scene::Cloneable
397 {
398   class TypeCasts
399   {
400     NodeTypeCastTable m_casts;
401   public:
402     TypeCasts()
403     {
404       NodeStaticCast<GenericEntityNode, scene::Instantiable>::install(m_casts);
405       NodeStaticCast<GenericEntityNode, scene::Cloneable>::install(m_casts);
406       NodeContainedCast<GenericEntityNode, Snappable>::install(m_casts);
407       NodeContainedCast<GenericEntityNode, TransformNode>::install(m_casts);
408       NodeContainedCast<GenericEntityNode, Entity>::install(m_casts);
409       NodeContainedCast<GenericEntityNode, Nameable>::install(m_casts);
410       NodeContainedCast<GenericEntityNode, Namespaced>::install(m_casts);
411     }
412     NodeTypeCastTable& get()
413     {
414       return m_casts;
415     }
416   };
417
418
419   InstanceSet m_instances;
420
421   scene::Node m_node;
422   GenericEntity m_contained;
423
424 public:
425   typedef LazyStatic<TypeCasts> StaticTypeCasts;
426
427   Snappable& get(NullType<Snappable>)
428   {
429     return m_contained;
430   }
431   TransformNode& get(NullType<TransformNode>)
432   {
433     return m_contained.getTransformNode();
434   }
435   Entity& get(NullType<Entity>)
436   {
437     return m_contained.getEntity();
438   }
439   Nameable& get(NullType<Nameable>)
440   {
441     return m_contained.getNameable();
442   }
443   Namespaced& get(NullType<Namespaced>)
444   {
445     return m_contained.getNamespaced();
446   }
447
448   GenericEntityNode(EntityClass* eclass) :
449     m_node(this, this, StaticTypeCasts::instance().get()),
450     m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<GenericEntityInstance>::Caller(m_instances))
451   {
452   }
453   GenericEntityNode(const GenericEntityNode& other) :
454     scene::Node::Symbiot(other),
455     scene::Instantiable(other),
456     scene::Cloneable(other),
457     m_node(this, this, StaticTypeCasts::instance().get()),
458     m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<GenericEntityInstance>::Caller(m_instances))
459   {
460   }
461   void release()
462   {
463     delete this;
464   }
465   scene::Node& node()
466   {
467     return m_node;
468   }
469
470   scene::Node& clone() const
471   {
472     return (new GenericEntityNode(*this))->node();
473   }
474
475   scene::Instance* create(const scene::Path& path, scene::Instance* parent)
476   {
477     return new GenericEntityInstance(path, parent, m_contained);
478   }
479   void forEachInstance(const scene::Instantiable::Visitor& visitor)
480   {
481     m_instances.forEachInstance(visitor);
482   }
483   void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
484   {
485     m_instances.insert(observer, path, instance);
486   }
487   scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
488   {
489     return m_instances.erase(observer, path);
490   }
491 };
492
493 scene::Node& New_GenericEntity(EntityClass* eclass)
494 {
495   return (new GenericEntityNode(eclass))->node();
496 }