]> icculus.org git repositories - divverent/netradiant.git/blob - plugins/entity/miscmodel.cpp
the historic move: getting rid of all visual studio project stuff, now that the mingw...
[divverent/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
97 // vc 2k5 compiler fix 
98 #if _MSC_VER >= 1400
99         public:
100 #endif 
101  
102   void originChanged()
103   {
104     m_origin = m_originKey.m_origin;
105     updateTransform();
106   }
107   typedef MemberCaller<MiscModel, &MiscModel::originChanged> OriginChangedCaller;
108   void anglesChanged()
109   {
110     m_angles = m_anglesKey.m_angles;
111     updateTransform();
112   }
113   typedef MemberCaller<MiscModel, &MiscModel::anglesChanged> AnglesChangedCaller;
114   void scaleChanged()
115   {
116     m_scale = m_scaleKey.m_scale;
117     updateTransform();
118   }
119   typedef MemberCaller<MiscModel, &MiscModel::scaleChanged> ScaleChangedCaller;
120 public:
121
122   MiscModel(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
123     m_entity(eclass),
124     m_originKey(OriginChangedCaller(*this)),
125     m_origin(ORIGINKEY_IDENTITY),
126     m_anglesKey(AnglesChangedCaller(*this)),
127     m_angles(ANGLESKEY_IDENTITY),
128     m_scaleKey(ScaleChangedCaller(*this)),
129     m_scale(SCALEKEY_IDENTITY),
130     m_filter(m_entity, node),
131     m_named(m_entity),
132     m_nameKeys(m_entity),
133     m_renderName(m_named, g_vector3_identity),
134     m_transformChanged(transformChanged),
135     m_evaluateTransform(evaluateTransform)
136   {
137     construct();
138   }
139   MiscModel(const MiscModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
140     m_entity(other.m_entity),
141     m_originKey(OriginChangedCaller(*this)),
142     m_origin(ORIGINKEY_IDENTITY),
143     m_anglesKey(AnglesChangedCaller(*this)),
144     m_angles(ANGLESKEY_IDENTITY),
145     m_scaleKey(ScaleChangedCaller(*this)),
146     m_scale(SCALEKEY_IDENTITY),
147     m_filter(m_entity, node),
148     m_named(m_entity),
149     m_nameKeys(m_entity),
150     m_renderName(m_named, g_vector3_identity),
151     m_transformChanged(transformChanged),
152     m_evaluateTransform(evaluateTransform)
153   {
154     construct();
155   }
156
157   InstanceCounter m_instanceCounter;
158   void instanceAttach(const scene::Path& path)
159   {
160     if(++m_instanceCounter.m_count == 1)
161     {
162       m_filter.instanceAttach();
163       m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
164       m_entity.attach(m_keyObservers);
165     }
166   }
167   void instanceDetach(const scene::Path& path)
168   {
169     if(--m_instanceCounter.m_count == 0)
170     {
171       m_entity.detach(m_keyObservers);
172       m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
173       m_filter.instanceDetach();
174     }
175   }
176
177   EntityKeyValues& getEntity()
178   {
179     return m_entity;
180   }
181   const EntityKeyValues& getEntity() const
182   {
183     return m_entity;
184   }
185
186   scene::Traversable& getTraversable()
187   {
188     return m_model.getTraversable();
189   }
190   Namespaced& getNamespaced()
191   {
192     return m_nameKeys;
193   }
194   Nameable& getNameable()
195   {
196     return m_named;
197   }
198   TransformNode& getTransformNode()
199   {
200     return m_transform;
201   }
202
203   void attach(scene::Traversable::Observer* observer)
204   {
205     m_model.attach(observer);
206   }
207   void detach(scene::Traversable::Observer* observer)
208   {
209     m_model.detach(observer);
210   }
211
212   void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
213   {
214     if(selected)
215     {
216       m_renderOrigin.render(renderer, volume, localToWorld);
217     }
218
219     renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
220   }
221   void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
222   {
223     renderSolid(renderer, volume, localToWorld, selected);
224     if(g_showNames)
225     {
226       renderer.addRenderable(m_renderName, localToWorld);
227     }
228   }
229
230   void translate(const Vector3& translation)
231   {
232     m_origin = origin_translated(m_origin, translation);
233   }
234   void rotate(const Quaternion& rotation)
235   {
236     m_angles = angles_rotated(m_angles, rotation);
237   }
238   void scale(const Vector3& scaling)
239   {
240     m_scale = scale_scaled(m_scale, scaling);
241   }
242   void snapto(float snap)
243   {
244     m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
245     m_originKey.write(&m_entity);
246   }
247   void revertTransform()
248   {
249     m_origin = m_originKey.m_origin;
250     m_angles = m_anglesKey.m_angles;
251     m_scale = m_scaleKey.m_scale;
252   }
253   void freezeTransform()
254   {
255     m_originKey.m_origin = m_origin;
256     m_originKey.write(&m_entity);
257     m_anglesKey.m_angles = m_angles;
258     m_anglesKey.write(&m_entity);
259     m_scaleKey.m_scale = m_scale;
260     m_scaleKey.write(&m_entity);
261   }
262   void transformChanged()
263   {
264     revertTransform();
265     m_evaluateTransform();
266     updateTransform();
267   }
268   typedef MemberCaller<MiscModel, &MiscModel::transformChanged> TransformChangedCaller;
269 };
270
271 class MiscModelInstance : public TargetableInstance, public TransformModifier, public Renderable
272 {
273   class TypeCasts
274   {
275     InstanceTypeCastTable m_casts;
276   public:
277     TypeCasts()
278     {
279       m_casts = TargetableInstance::StaticTypeCasts::instance().get();
280       InstanceStaticCast<MiscModelInstance, Renderable>::install(m_casts);
281       InstanceStaticCast<MiscModelInstance, Transformable>::install(m_casts);
282       InstanceIdentityCast<MiscModelInstance>::install(m_casts);
283     }
284     InstanceTypeCastTable& get()
285     {
286       return m_casts;
287     }
288   };
289
290   MiscModel& m_contained;
291 public:
292   typedef LazyStatic<TypeCasts> StaticTypeCasts;
293
294   STRING_CONSTANT(Name, "MiscModelInstance");
295
296   MiscModelInstance(const scene::Path& path, scene::Instance* parent, MiscModel& miscmodel) :
297     TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), miscmodel.getEntity(), *this),
298     TransformModifier(MiscModel::TransformChangedCaller(miscmodel), ApplyTransformCaller(*this)),
299     m_contained(miscmodel)
300   {
301     m_contained.instanceAttach(Instance::path());
302     StaticRenderableConnectionLines::instance().attach(*this);
303   }
304   ~MiscModelInstance()
305   {
306     StaticRenderableConnectionLines::instance().detach(*this);
307     m_contained.instanceDetach(Instance::path());
308   }
309   void renderSolid(Renderer& renderer, const VolumeTest& volume) const
310   {
311     m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
312   }
313   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
314   {
315     m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
316   }
317   void evaluateTransform()
318   {
319     if(getType() == TRANSFORM_PRIMITIVE)
320     {
321       m_contained.translate(getTranslation());
322       m_contained.rotate(getRotation());
323       m_contained.scale(getScale());
324     }
325   }
326   void applyTransform()
327   {
328     m_contained.revertTransform();
329     evaluateTransform();
330     m_contained.freezeTransform();
331   }
332   typedef MemberCaller<MiscModelInstance, &MiscModelInstance::applyTransform> ApplyTransformCaller;
333 };
334
335 class MiscModelNode :
336   public scene::Node::Symbiot,
337   public scene::Instantiable,
338   public scene::Cloneable,
339   public scene::Traversable::Observer
340 {
341   class TypeCasts
342   {
343     NodeTypeCastTable m_casts;
344   public:
345     TypeCasts()
346     {
347       NodeStaticCast<MiscModelNode, scene::Instantiable>::install(m_casts);
348       NodeStaticCast<MiscModelNode, scene::Cloneable>::install(m_casts);
349       NodeContainedCast<MiscModelNode, scene::Traversable>::install(m_casts);
350       NodeContainedCast<MiscModelNode, Snappable>::install(m_casts);
351       NodeContainedCast<MiscModelNode, TransformNode>::install(m_casts);
352       NodeContainedCast<MiscModelNode, Entity>::install(m_casts);
353       NodeContainedCast<MiscModelNode, Nameable>::install(m_casts);
354       NodeContainedCast<MiscModelNode, Namespaced>::install(m_casts);
355     }
356     NodeTypeCastTable& get()
357     {
358       return m_casts;
359     }
360   };
361
362
363   scene::Node m_node;
364   InstanceSet m_instances;
365   MiscModel m_contained;
366
367   void construct()
368   {
369     m_contained.attach(this);
370   }
371   void destroy()
372   {
373     m_contained.detach(this);
374   }
375
376 public:
377   typedef LazyStatic<TypeCasts> StaticTypeCasts;
378
379   scene::Traversable& get(NullType<scene::Traversable>)
380   {
381     return m_contained.getTraversable();
382   }
383   Snappable& get(NullType<Snappable>)
384   {
385     return m_contained;
386   }
387   TransformNode& get(NullType<TransformNode>)
388   {
389     return m_contained.getTransformNode();
390   }
391   Entity& get(NullType<Entity>)
392   {
393     return m_contained.getEntity();
394   }
395   Nameable& get(NullType<Nameable>)
396   {
397     return m_contained.getNameable();
398   }
399   Namespaced& get(NullType<Namespaced>)
400   {
401     return m_contained.getNamespaced();
402   }
403
404   MiscModelNode(EntityClass* eclass) :
405     m_node(this, this, StaticTypeCasts::instance().get()),
406     m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<MiscModelInstance>::Caller(m_instances))
407   {
408     construct();
409   }
410   MiscModelNode(const MiscModelNode& other) :
411     scene::Node::Symbiot(other),
412     scene::Instantiable(other),
413     scene::Cloneable(other),
414     scene::Traversable::Observer(other),
415     m_node(this, this, StaticTypeCasts::instance().get()),
416     m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<MiscModelInstance>::Caller(m_instances))
417   {
418     construct();
419   }
420   ~MiscModelNode()
421   {
422     destroy();
423   }
424
425   void release()
426   {
427     delete this;
428   }
429   scene::Node& node()
430   {
431     return m_node;
432   }
433
434   scene::Node& clone() const
435   {
436     return (new MiscModelNode(*this))->node();
437   }
438
439   void insert(scene::Node& child)
440   {
441     m_instances.insert(child);
442   }
443   void erase(scene::Node& child)
444   {
445     m_instances.erase(child);
446   }
447
448   scene::Instance* create(const scene::Path& path, scene::Instance* parent)
449   {
450     return new MiscModelInstance(path, parent, m_contained);
451   }
452   void forEachInstance(const scene::Instantiable::Visitor& visitor)
453   {
454     m_instances.forEachInstance(visitor);
455   }
456   void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
457   {
458     m_instances.insert(observer, path, instance);
459   }
460   scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
461   {
462     return m_instances.erase(observer, path);
463   }
464 };
465
466 scene::Node& New_MiscModel(EntityClass* eclass)
467 {
468   return (new MiscModelNode(eclass))->node();
469 }
470
471 void MiscModel_construct()
472 {
473 }
474 void MiscModel_destroy()
475 {
476 }