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