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