]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/entity/eclassmodel.cpp
When connecting entities, don't reuse the target field to name the entity
[xonotic/netradiant.git] / plugins / entity / eclassmodel.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 displays a model (e.g. ammo_bfg).
24 ///
25 /// This entity displays the model specified in its entity-definition.
26 /// The "origin" and "angle" keys directly control the entity's local-to-parent transform.
27 /// The "rotation" key directly controls the entity's local-to-parent transform for Doom3 only.
28
29 #include "eclassmodel.h"
30
31 #include "cullable.h"
32 #include "renderable.h"
33 #include "editable.h"
34
35 #include "selectionlib.h"
36 #include "instancelib.h"
37 #include "transformlib.h"
38 #include "traverselib.h"
39 #include "entitylib.h"
40 #include "render.h"
41 #include "eclasslib.h"
42 #include "pivot.h"
43
44 #include "targetable.h"
45 #include "origin.h"
46 #include "angle.h"
47 #include "rotation.h"
48 #include "model.h"
49 #include "filters.h"
50 #include "namedentity.h"
51 #include "keyobservers.h"
52 #include "namekeys.h"
53 #include "modelskinkey.h"
54
55 #include "entity.h"
56
57 class EclassModel :
58   public Snappable
59 {
60   MatrixTransform m_transform;
61   EntityKeyValues m_entity;
62   KeyObserverMap m_keyObservers;
63
64   OriginKey m_originKey;
65   Vector3 m_origin;
66   AngleKey m_angleKey;
67   float m_angle;
68   RotationKey m_rotationKey;
69   Float9 m_rotation;
70   SingletonModel m_model;
71
72   ClassnameFilter m_filter;
73   NamedEntity m_named;
74   NameKeys m_nameKeys;
75   RenderablePivot m_renderOrigin;
76   RenderableNamedEntity m_renderName;
77   ModelSkinKey m_skin;
78
79   Callback m_transformChanged;
80   Callback m_evaluateTransform;
81
82   void construct()
83   {
84     default_rotation(m_rotation);
85
86     m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
87     m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
88     if(g_gameType == eGameTypeDoom3)
89     {
90       m_keyObservers.insert("angle", RotationKey::AngleChangedCaller(m_rotationKey));
91       m_keyObservers.insert("rotation", RotationKey::RotationChangedCaller(m_rotationKey));
92     }
93     else
94     {
95       m_keyObservers.insert("angle", AngleKey::AngleChangedCaller(m_angleKey));
96     }
97     m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
98   }
99
100 // vc 2k5 compiler fix
101 #if _MSC_VER >= 1400
102         public:
103 #endif
104
105   void updateTransform()
106   {
107     m_transform.localToParent() = g_matrix4_identity;
108     matrix4_translate_by_vec3(m_transform.localToParent(), m_origin);
109
110     if(g_gameType == eGameTypeDoom3)
111     {
112       matrix4_multiply_by_matrix4(m_transform.localToParent(), rotation_toMatrix(m_rotation));
113     }
114     else
115     {
116       matrix4_multiply_by_matrix4(m_transform.localToParent(), matrix4_rotation_for_z_degrees(m_angle));
117     }
118
119     m_transformChanged();
120   }
121   typedef MemberCaller<EclassModel, &EclassModel::updateTransform> UpdateTransformCaller;
122
123   void originChanged()
124   {
125     m_origin = m_originKey.m_origin;
126     updateTransform();
127   }
128   typedef MemberCaller<EclassModel, &EclassModel::originChanged> OriginChangedCaller;
129   void angleChanged()
130   {
131     m_angle = m_angleKey.m_angle;
132     updateTransform();
133   }
134   typedef MemberCaller<EclassModel, &EclassModel::angleChanged> AngleChangedCaller;
135   void rotationChanged()
136   {
137     rotation_assign(m_rotation, m_rotationKey.m_rotation);
138     updateTransform();
139   }
140   typedef MemberCaller<EclassModel, &EclassModel::rotationChanged> RotationChangedCaller;
141
142   void skinChanged()
143   {
144     scene::Node* node = m_model.getNode();
145     if(node != 0)
146     {
147       Node_modelSkinChanged(*node);
148     }
149   }
150   typedef MemberCaller<EclassModel, &EclassModel::skinChanged> SkinChangedCaller;
151
152 public:
153
154   EclassModel(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
155     m_entity(eclass),
156     m_originKey(OriginChangedCaller(*this)),
157     m_origin(ORIGINKEY_IDENTITY),
158     m_angleKey(AngleChangedCaller(*this)),
159     m_angle(ANGLEKEY_IDENTITY),
160     m_rotationKey(RotationChangedCaller(*this)),
161     m_filter(m_entity, node),
162     m_named(m_entity),
163     m_nameKeys(m_entity),
164     m_renderName(m_named, g_vector3_identity),
165     m_skin(SkinChangedCaller(*this)),
166     m_transformChanged(transformChanged),
167     m_evaluateTransform(evaluateTransform)
168   {
169     construct();
170   }
171   EclassModel(const EclassModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
172     m_entity(other.m_entity),
173     m_originKey(OriginChangedCaller(*this)),
174     m_origin(ORIGINKEY_IDENTITY),
175     m_angleKey(AngleChangedCaller(*this)),
176     m_angle(ANGLEKEY_IDENTITY),
177     m_rotationKey(RotationChangedCaller(*this)),
178     m_filter(m_entity, node),
179     m_named(m_entity),
180     m_nameKeys(m_entity),
181     m_renderName(m_named, g_vector3_identity),
182     m_skin(SkinChangedCaller(*this)),
183     m_transformChanged(transformChanged),
184     m_evaluateTransform(evaluateTransform)
185   {
186     construct();
187   }
188
189   InstanceCounter m_instanceCounter;
190   void instanceAttach(const scene::Path& path)
191   {
192     if(++m_instanceCounter.m_count == 1)
193     {
194       m_filter.instanceAttach();
195       m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
196       m_entity.attach(m_keyObservers);
197       m_model.modelChanged(m_entity.getEntityClass().modelpath());
198       m_skin.skinChanged(m_entity.getEntityClass().skin());
199     }
200   }
201   void instanceDetach(const scene::Path& path)
202   {
203     if(--m_instanceCounter.m_count == 0)
204     {
205       m_skin.skinChanged("");
206       m_model.modelChanged("");
207       m_entity.detach(m_keyObservers);
208       m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
209       m_filter.instanceDetach();
210     }
211   }
212
213   EntityKeyValues& getEntity()
214   {
215     return m_entity;
216   }
217   const EntityKeyValues& getEntity() const
218   {
219     return m_entity;
220   }
221
222   scene::Traversable& getTraversable()
223   {
224     return m_model.getTraversable();
225   }
226   Namespaced& getNamespaced()
227   {
228     return m_nameKeys;
229   }
230   Nameable& getNameable()
231   {
232     return m_named;
233   }
234   TransformNode& getTransformNode()
235   {
236     return m_transform;
237   }
238   ModelSkin& getModelSkin()
239   {
240     return m_skin.get();
241   }
242
243   void attach(scene::Traversable::Observer* observer)
244   {
245     m_model.attach(observer);
246   }
247   void detach(scene::Traversable::Observer* observer)
248   {
249     m_model.detach(observer);
250   }
251
252   void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
253   {
254     if(selected)
255     {
256       m_renderOrigin.render(renderer, volume, localToWorld);
257     }
258
259     renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
260   }
261   void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
262   {
263     renderSolid(renderer, volume, localToWorld, selected);
264     if(g_showNames)
265     {
266       renderer.addRenderable(m_renderName, localToWorld);
267     }
268   }
269
270   void translate(const Vector3& translation)
271   {
272     m_origin = origin_translated(m_origin, translation);
273   }
274   void rotate(const Quaternion& rotation)
275   {
276     if(g_gameType == eGameTypeDoom3)
277     {
278       rotation_rotate(m_rotation, rotation);
279     }
280     else
281     {
282       m_angle = angle_rotated(m_angle, rotation);
283     }
284   }
285   void snapto(float snap)
286   {
287     m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
288     m_originKey.write(&m_entity);
289   }
290   void revertTransform()
291   {
292     m_origin = m_originKey.m_origin;
293     if(g_gameType == eGameTypeDoom3)
294     {
295       rotation_assign(m_rotation, m_rotationKey.m_rotation);
296     }
297     else
298     {
299       m_angle = m_angleKey.m_angle;
300     }
301   }
302   void freezeTransform()
303   {
304     m_originKey.m_origin = m_origin;
305     m_originKey.write(&m_entity);
306     if(g_gameType == eGameTypeDoom3)
307     {
308       rotation_assign(m_rotationKey.m_rotation, m_rotation);
309       m_rotationKey.write(&m_entity);
310     }
311     else
312     {
313       m_angleKey.m_angle = m_angle;
314       m_angleKey.write(&m_entity);
315     }
316   }
317   void transformChanged()
318   {
319     revertTransform();
320     m_evaluateTransform();
321     updateTransform();
322   }
323   typedef MemberCaller<EclassModel, &EclassModel::transformChanged> TransformChangedCaller;
324 };
325
326 class EclassModelInstance : public TargetableInstance, public TransformModifier, public Renderable
327 {
328   class TypeCasts
329   {
330     InstanceTypeCastTable m_casts;
331   public:
332     TypeCasts()
333     {
334       m_casts = TargetableInstance::StaticTypeCasts::instance().get();
335       InstanceStaticCast<EclassModelInstance, Renderable>::install(m_casts);
336       InstanceStaticCast<EclassModelInstance, Transformable>::install(m_casts);
337       InstanceIdentityCast<EclassModelInstance>::install(m_casts);
338     }
339     InstanceTypeCastTable& get()
340     {
341       return m_casts;
342     }
343   };
344
345   EclassModel& m_contained;
346 public:
347   typedef LazyStatic<TypeCasts> StaticTypeCasts;
348
349   STRING_CONSTANT(Name, "EclassModelInstance");
350
351   EclassModelInstance(const scene::Path& path, scene::Instance* parent, EclassModel& contained) :
352     TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
353     TransformModifier(EclassModel::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
354     m_contained(contained)
355   {
356     m_contained.instanceAttach(Instance::path());
357
358     StaticRenderableConnectionLines::instance().attach(*this);
359   }
360   ~EclassModelInstance()
361   {
362     StaticRenderableConnectionLines::instance().detach(*this);
363
364     m_contained.instanceDetach(Instance::path());
365   }
366   void renderSolid(Renderer& renderer, const VolumeTest& volume) const
367   {
368     m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
369   }
370   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
371   {
372     m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
373   }
374
375   void evaluateTransform()
376   {
377     if(getType() == TRANSFORM_PRIMITIVE)
378     {
379       m_contained.translate(getTranslation());
380       m_contained.rotate(getRotation());
381     }
382   }
383   void applyTransform()
384   {
385     m_contained.revertTransform();
386     evaluateTransform();
387     m_contained.freezeTransform();
388   }
389   typedef MemberCaller<EclassModelInstance, &EclassModelInstance::applyTransform> ApplyTransformCaller;
390 };
391
392 class EclassModelNode :
393   public scene::Node::Symbiot,
394   public scene::Instantiable,
395   public scene::Cloneable,
396   public scene::Traversable::Observer
397 {
398   class TypeCasts
399   {
400     NodeTypeCastTable m_casts;
401   public:
402     TypeCasts()
403     {
404       NodeStaticCast<EclassModelNode, scene::Instantiable>::install(m_casts);
405       NodeStaticCast<EclassModelNode, scene::Cloneable>::install(m_casts);
406       NodeContainedCast<EclassModelNode, scene::Traversable>::install(m_casts);
407       NodeContainedCast<EclassModelNode, Snappable>::install(m_casts);
408       NodeContainedCast<EclassModelNode, TransformNode>::install(m_casts);
409       NodeContainedCast<EclassModelNode, Entity>::install(m_casts);
410       NodeContainedCast<EclassModelNode, Nameable>::install(m_casts);
411       NodeContainedCast<EclassModelNode, Namespaced>::install(m_casts);
412       NodeContainedCast<EclassModelNode, ModelSkin>::install(m_casts);
413     }
414     NodeTypeCastTable& get()
415     {
416       return m_casts;
417     }
418   };
419
420
421   scene::Node m_node;
422   InstanceSet m_instances;
423   EclassModel m_contained;
424
425   void construct()
426   {
427     m_contained.attach(this);
428   }
429   void destroy()
430   {
431     m_contained.detach(this);
432   }
433
434 public:
435   typedef LazyStatic<TypeCasts> StaticTypeCasts;
436
437   scene::Traversable& get(NullType<scene::Traversable>)
438   {
439     return m_contained.getTraversable();
440   }
441   Snappable& get(NullType<Snappable>)
442   {
443     return m_contained;
444   }
445   TransformNode& get(NullType<TransformNode>)
446   {
447     return m_contained.getTransformNode();
448   }
449   Entity& get(NullType<Entity>)
450   {
451     return m_contained.getEntity();
452   }
453   Nameable& get(NullType<Nameable>)
454   {
455     return m_contained.getNameable();
456   }
457   Namespaced& get(NullType<Namespaced>)
458   {
459     return m_contained.getNamespaced();
460   }
461   ModelSkin& get(NullType<ModelSkin>)
462   {
463     return m_contained.getModelSkin();
464   }
465
466   EclassModelNode(EntityClass* eclass) :
467     m_node(this, this, StaticTypeCasts::instance().get()),
468     m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<EclassModelInstance>::Caller(m_instances))
469   {
470     construct();
471   }
472   EclassModelNode(const EclassModelNode& other) :
473     scene::Node::Symbiot(other),
474     scene::Instantiable(other),
475     scene::Cloneable(other),
476     scene::Traversable::Observer(other),
477     m_node(this, this, StaticTypeCasts::instance().get()),
478     m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<EclassModelInstance>::Caller(m_instances))
479   {
480     construct();
481   }
482   ~EclassModelNode()
483   {
484     destroy();
485   }
486   void release()
487   {
488     delete this;
489   }
490   scene::Node& node()
491   {
492     return m_node;
493   }
494
495   void insert(scene::Node& child)
496   {
497     m_instances.insert(child);
498   }
499   void erase(scene::Node& child)
500   {
501     m_instances.erase(child);
502   }
503
504   scene::Node& clone() const
505   {
506     return (new EclassModelNode(*this))->node();
507   }
508
509   scene::Instance* create(const scene::Path& path, scene::Instance* parent)
510   {
511     return new EclassModelInstance(path, parent, m_contained);
512   }
513   void forEachInstance(const scene::Instantiable::Visitor& visitor)
514   {
515     m_instances.forEachInstance(visitor);
516   }
517   void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
518   {
519     m_instances.insert(observer, path, instance);
520   }
521   scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
522   {
523     return m_instances.erase(observer, path);
524   }
525 };
526
527 scene::Node& New_EclassModel(EntityClass* eclass)
528 {
529   return (new EclassModelNode(eclass))->node();
530 }
531
532