2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
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.
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.
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
23 ///\brief Represents the Quake3 misc_model entity.
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.
29 #include "renderable.h"
32 #include "selectionlib.h"
33 #include "instancelib.h"
34 #include "transformlib.h"
35 #include "traverselib.h"
36 #include "entitylib.h"
37 #include "eclasslib.h"
41 #include "targetable.h"
47 #include "namedentity.h"
48 #include "keyobservers.h"
55 EntityKeyValues m_entity;
56 KeyObserverMap m_keyObservers;
57 MatrixTransform m_transform;
59 OriginKey m_originKey;
61 AnglesKey m_anglesKey;
66 SingletonModel m_model;
68 ClassnameFilter m_filter;
71 RenderablePivot m_renderOrigin;
72 RenderableNamedEntity m_renderName;
74 Callback<void()> m_transformChanged;
75 Callback<void()> m_evaluateTransform;
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));
89 void updateTransform()
91 m_transform.localToParent() = g_matrix4_identity;
92 matrix4_transform_by_euler_xyz_degrees(m_transform.localToParent(), m_origin, m_angles, m_scale);
96 // vc 2k5 compiler fix
103 m_origin = m_originKey.m_origin;
107 typedef MemberCaller<MiscModel, void(), &MiscModel::originChanged> OriginChangedCaller;
111 m_angles = m_anglesKey.m_angles;
115 typedef MemberCaller<MiscModel, void(), &MiscModel::anglesChanged> AnglesChangedCaller;
119 m_scale = m_scaleKey.m_scale;
123 typedef MemberCaller<MiscModel, void(), &MiscModel::scaleChanged> ScaleChangedCaller;
126 MiscModel(EntityClass *eclass, scene::Node &node, const Callback<void()> &transformChanged,
127 const Callback<void()> &evaluateTransform) :
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),
137 m_nameKeys(m_entity),
138 m_renderName(m_named, g_vector3_identity),
139 m_transformChanged(transformChanged),
140 m_evaluateTransform(evaluateTransform)
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),
156 m_nameKeys(m_entity),
157 m_renderName(m_named, g_vector3_identity),
158 m_transformChanged(transformChanged),
159 m_evaluateTransform(evaluateTransform)
164 InstanceCounter m_instanceCounter;
166 void instanceAttach(const scene::Path &path)
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);
175 void instanceDetach(const scene::Path &path)
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();
184 EntityKeyValues &getEntity()
189 const EntityKeyValues &getEntity() const
194 scene::Traversable &getTraversable()
196 return m_model.getTraversable();
199 Namespaced &getNamespaced()
204 Nameable &getNameable()
209 TransformNode &getTransformNode()
214 void attach(scene::Traversable::Observer *observer)
216 m_model.attach(observer);
219 void detach(scene::Traversable::Observer *observer)
221 m_model.detach(observer);
224 void renderSolid(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld, bool selected) const
227 m_renderOrigin.render(renderer, volume, localToWorld);
230 renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
233 void renderWireframe(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld, bool selected) const
235 renderSolid(renderer, volume, localToWorld, selected);
237 renderer.addRenderable(m_renderName, localToWorld);
241 void translate(const Vector3 &translation)
243 m_origin = origin_translated(m_origin, translation);
246 void rotate(const Quaternion &rotation)
248 m_angles = angles_rotated(m_angles, rotation);
251 void scale(const Vector3 &scaling)
253 m_scale = scale_scaled(m_scale, scaling);
256 void snapto(float snap)
258 m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
259 m_originKey.write(&m_entity);
262 void revertTransform()
264 m_origin = m_originKey.m_origin;
265 m_angles = m_anglesKey.m_angles;
266 m_scale = m_scaleKey.m_scale;
269 void freezeTransform()
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);
279 void transformChanged()
282 m_evaluateTransform();
286 typedef MemberCaller<MiscModel, void(), &MiscModel::transformChanged> TransformChangedCaller;
289 class MiscModelInstance : public TargetableInstance, public TransformModifier, public Renderable {
291 InstanceTypeCastTable m_casts;
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);
301 InstanceTypeCastTable &get()
307 MiscModel &m_contained;
309 typedef LazyStatic<TypeCasts> StaticTypeCasts;
311 STRING_CONSTANT(Name, "MiscModelInstance");
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)
318 m_contained.instanceAttach(Instance::path());
319 StaticRenderableConnectionLines::instance().attach(*this);
324 StaticRenderableConnectionLines::instance().detach(*this);
325 m_contained.instanceDetach(Instance::path());
328 void renderSolid(Renderer &renderer, const VolumeTest &volume) const
330 m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
333 void renderWireframe(Renderer &renderer, const VolumeTest &volume) const
335 m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
338 void evaluateTransform()
340 if (getType() == TRANSFORM_PRIMITIVE) {
341 m_contained.translate(getTranslation());
342 m_contained.rotate(getRotation());
343 m_contained.scale(getScale());
347 void applyTransform()
349 m_contained.revertTransform();
351 m_contained.freezeTransform();
354 typedef MemberCaller<MiscModelInstance, void(), &MiscModelInstance::applyTransform> ApplyTransformCaller;
357 class MiscModelNode :
358 public scene::Node::Symbiot,
359 public scene::Instantiable,
360 public scene::Cloneable,
361 public scene::Traversable::Observer {
363 NodeTypeCastTable m_casts;
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);
377 NodeTypeCastTable &get()
385 InstanceSet m_instances;
386 MiscModel m_contained;
390 m_contained.attach(this);
395 m_contained.detach(this);
399 typedef LazyStatic<TypeCasts> StaticTypeCasts;
401 scene::Traversable &get(NullType<scene::Traversable>)
403 return m_contained.getTraversable();
406 Snappable &get(NullType<Snappable>)
411 TransformNode &get(NullType<TransformNode>)
413 return m_contained.getTransformNode();
416 Entity &get(NullType<Entity>)
418 return m_contained.getEntity();
421 Nameable &get(NullType<Nameable>)
423 return m_contained.getNameable();
426 Namespaced &get(NullType<Namespaced>)
428 return m_contained.getNamespaced();
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))
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))
466 scene::Node &clone() const
468 return (new MiscModelNode(*this))->node();
471 void insert(scene::Node &child)
473 m_instances.insert(child);
476 void erase(scene::Node &child)
478 m_instances.erase(child);
481 scene::Instance *create(const scene::Path &path, scene::Instance *parent)
483 return new MiscModelInstance(path, parent, m_contained);
486 void forEachInstance(const scene::Instantiable::Visitor &visitor)
488 m_instances.forEachInstance(visitor);
491 void insert(scene::Instantiable::Observer *observer, const scene::Path &path, scene::Instance *instance)
493 m_instances.insert(observer, path, instance);
496 scene::Instance *erase(scene::Instantiable::Observer *observer, const scene::Path &path)
498 return m_instances.erase(observer, path);
502 scene::Node &New_MiscModel(EntityClass *eclass)
504 return (new MiscModelNode(eclass))->node();
507 void MiscModel_construct()
511 void MiscModel_destroy()