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