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