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"
56 EntityKeyValues m_entity;
57 KeyObserverMap m_keyObservers;
58 MatrixTransform m_transform;
60 OriginKey m_originKey;
62 AnglesKey m_anglesKey;
67 SingletonModel m_model;
69 ClassnameFilter m_filter;
72 RenderablePivot m_renderOrigin;
73 RenderableNamedEntity m_renderName;
75 Callback m_transformChanged;
76 Callback m_evaluateTransform;
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));
90 void updateTransform()
92 m_transform.localToParent() = g_matrix4_identity;
93 matrix4_transform_by_euler_xyz_degrees(m_transform.localToParent(), m_origin, m_angles, m_scale);
97 // vc 2k5 compiler fix
104 m_origin = m_originKey.m_origin;
107 typedef MemberCaller<MiscModel, &MiscModel::originChanged> OriginChangedCaller;
110 m_angles = m_anglesKey.m_angles;
113 typedef MemberCaller<MiscModel, &MiscModel::anglesChanged> AnglesChangedCaller;
116 m_scale = m_scaleKey.m_scale;
119 typedef MemberCaller<MiscModel, &MiscModel::scaleChanged> ScaleChangedCaller;
122 MiscModel(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
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),
132 m_nameKeys(m_entity),
133 m_renderName(m_named, g_vector3_identity),
134 m_transformChanged(transformChanged),
135 m_evaluateTransform(evaluateTransform)
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),
149 m_nameKeys(m_entity),
150 m_renderName(m_named, g_vector3_identity),
151 m_transformChanged(transformChanged),
152 m_evaluateTransform(evaluateTransform)
157 InstanceCounter m_instanceCounter;
158 void instanceAttach(const scene::Path& path)
160 if(++m_instanceCounter.m_count == 1)
162 m_filter.instanceAttach();
163 m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
164 m_entity.attach(m_keyObservers);
167 void instanceDetach(const scene::Path& path)
169 if(--m_instanceCounter.m_count == 0)
171 m_entity.detach(m_keyObservers);
172 m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
173 m_filter.instanceDetach();
177 EntityKeyValues& getEntity()
181 const EntityKeyValues& getEntity() const
186 scene::Traversable& getTraversable()
188 return m_model.getTraversable();
190 Namespaced& getNamespaced()
194 Nameable& getNameable()
198 TransformNode& getTransformNode()
203 void attach(scene::Traversable::Observer* observer)
205 m_model.attach(observer);
207 void detach(scene::Traversable::Observer* observer)
209 m_model.detach(observer);
212 void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
216 m_renderOrigin.render(renderer, volume, localToWorld);
219 renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
221 void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
223 renderSolid(renderer, volume, localToWorld, selected);
226 renderer.addRenderable(m_renderName, localToWorld);
230 void translate(const Vector3& translation)
232 m_origin = origin_translated(m_origin, translation);
234 void rotate(const Quaternion& rotation)
236 m_angles = angles_rotated(m_angles, rotation);
238 void scale(const Vector3& scaling)
240 m_scale = scale_scaled(m_scale, scaling);
242 void snapto(float snap)
244 m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
245 m_originKey.write(&m_entity);
247 void revertTransform()
249 m_origin = m_originKey.m_origin;
250 m_angles = m_anglesKey.m_angles;
251 m_scale = m_scaleKey.m_scale;
253 void freezeTransform()
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);
262 void transformChanged()
265 m_evaluateTransform();
268 typedef MemberCaller<MiscModel, &MiscModel::transformChanged> TransformChangedCaller;
271 class MiscModelInstance : public TargetableInstance, public TransformModifier, public Renderable
275 InstanceTypeCastTable m_casts;
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);
284 InstanceTypeCastTable& get()
290 MiscModel& m_contained;
292 typedef LazyStatic<TypeCasts> StaticTypeCasts;
294 STRING_CONSTANT(Name, "MiscModelInstance");
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)
301 m_contained.instanceAttach(Instance::path());
302 StaticRenderableConnectionLines::instance().attach(*this);
306 StaticRenderableConnectionLines::instance().detach(*this);
307 m_contained.instanceDetach(Instance::path());
309 void renderSolid(Renderer& renderer, const VolumeTest& volume) const
311 m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
313 void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
315 m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
317 void evaluateTransform()
319 if(getType() == TRANSFORM_PRIMITIVE)
321 m_contained.translate(getTranslation());
322 m_contained.rotate(getRotation());
323 m_contained.scale(getScale());
326 void applyTransform()
328 m_contained.revertTransform();
330 m_contained.freezeTransform();
332 typedef MemberCaller<MiscModelInstance, &MiscModelInstance::applyTransform> ApplyTransformCaller;
335 class MiscModelNode :
336 public scene::Node::Symbiot,
337 public scene::Instantiable,
338 public scene::Cloneable,
339 public scene::Traversable::Observer
343 NodeTypeCastTable m_casts;
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);
356 NodeTypeCastTable& get()
364 InstanceSet m_instances;
365 MiscModel m_contained;
369 m_contained.attach(this);
373 m_contained.detach(this);
377 typedef LazyStatic<TypeCasts> StaticTypeCasts;
379 scene::Traversable& get(NullType<scene::Traversable>)
381 return m_contained.getTraversable();
383 Snappable& get(NullType<Snappable>)
387 TransformNode& get(NullType<TransformNode>)
389 return m_contained.getTransformNode();
391 Entity& get(NullType<Entity>)
393 return m_contained.getEntity();
395 Nameable& get(NullType<Nameable>)
397 return m_contained.getNameable();
399 Namespaced& get(NullType<Namespaced>)
401 return m_contained.getNamespaced();
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))
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))
434 scene::Node& clone() const
436 return (new MiscModelNode(*this))->node();
439 void insert(scene::Node& child)
441 m_instances.insert(child);
443 void erase(scene::Node& child)
445 m_instances.erase(child);
448 scene::Instance* create(const scene::Path& path, scene::Instance* parent)
450 return new MiscModelInstance(path, parent, m_contained);
452 void forEachInstance(const scene::Instantiable::Visitor& visitor)
454 m_instances.forEachInstance(visitor);
456 void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
458 m_instances.insert(observer, path, instance);
460 scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
462 return m_instances.erase(observer, path);
466 scene::Node& New_MiscModel(EntityClass* eclass)
468 return (new MiscModelNode(eclass))->node();
471 void MiscModel_construct()
474 void MiscModel_destroy()