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);
98 m_origin = m_originKey.m_origin;
101 typedef MemberCaller<MiscModel, &MiscModel::originChanged> OriginChangedCaller;
104 m_angles = m_anglesKey.m_angles;
107 typedef MemberCaller<MiscModel, &MiscModel::anglesChanged> AnglesChangedCaller;
110 m_scale = m_scaleKey.m_scale;
113 typedef MemberCaller<MiscModel, &MiscModel::scaleChanged> ScaleChangedCaller;
116 MiscModel(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
118 m_originKey(OriginChangedCaller(*this)),
119 m_origin(ORIGINKEY_IDENTITY),
120 m_anglesKey(AnglesChangedCaller(*this)),
121 m_angles(ANGLESKEY_IDENTITY),
122 m_scaleKey(ScaleChangedCaller(*this)),
123 m_scale(SCALEKEY_IDENTITY),
124 m_filter(m_entity, node),
126 m_nameKeys(m_entity),
127 m_renderName(m_named, g_vector3_identity),
128 m_transformChanged(transformChanged),
129 m_evaluateTransform(evaluateTransform)
133 MiscModel(const MiscModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
134 m_entity(other.m_entity),
135 m_originKey(OriginChangedCaller(*this)),
136 m_origin(ORIGINKEY_IDENTITY),
137 m_anglesKey(AnglesChangedCaller(*this)),
138 m_angles(ANGLESKEY_IDENTITY),
139 m_scaleKey(ScaleChangedCaller(*this)),
140 m_scale(SCALEKEY_IDENTITY),
141 m_filter(m_entity, node),
143 m_nameKeys(m_entity),
144 m_renderName(m_named, g_vector3_identity),
145 m_transformChanged(transformChanged),
146 m_evaluateTransform(evaluateTransform)
151 InstanceCounter m_instanceCounter;
152 void instanceAttach(const scene::Path& path)
154 if(++m_instanceCounter.m_count == 1)
156 m_filter.instanceAttach();
157 m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
158 m_entity.attach(m_keyObservers);
161 void instanceDetach(const scene::Path& path)
163 if(--m_instanceCounter.m_count == 0)
165 m_entity.detach(m_keyObservers);
166 m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
167 m_filter.instanceDetach();
171 EntityKeyValues& getEntity()
175 const EntityKeyValues& getEntity() const
180 scene::Traversable& getTraversable()
182 return m_model.getTraversable();
184 Namespaced& getNamespaced()
188 Nameable& getNameable()
192 TransformNode& getTransformNode()
197 void attach(scene::Traversable::Observer* observer)
199 m_model.attach(observer);
201 void detach(scene::Traversable::Observer* observer)
203 m_model.detach(observer);
206 void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
210 m_renderOrigin.render(renderer, volume, localToWorld);
213 renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
215 void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
217 renderSolid(renderer, volume, localToWorld, selected);
220 renderer.addRenderable(m_renderName, localToWorld);
224 void translate(const Vector3& translation)
226 m_origin = origin_translated(m_origin, translation);
228 void rotate(const Quaternion& rotation)
230 m_angles = angles_rotated(m_angles, rotation);
232 void scale(const Vector3& scaling)
234 m_scale = scale_scaled(m_scale, scaling);
236 void snapto(float snap)
238 m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
239 m_originKey.write(&m_entity);
241 void revertTransform()
243 m_origin = m_originKey.m_origin;
244 m_angles = m_anglesKey.m_angles;
245 m_scale = m_scaleKey.m_scale;
247 void freezeTransform()
249 m_originKey.m_origin = m_origin;
250 m_originKey.write(&m_entity);
251 m_anglesKey.m_angles = m_angles;
252 m_anglesKey.write(&m_entity);
253 m_scaleKey.m_scale = m_scale;
254 m_scaleKey.write(&m_entity);
256 void transformChanged()
259 m_evaluateTransform();
262 typedef MemberCaller<MiscModel, &MiscModel::transformChanged> TransformChangedCaller;
265 class MiscModelInstance : public TargetableInstance, public TransformModifier, public Renderable
269 InstanceTypeCastTable m_casts;
273 m_casts = TargetableInstance::StaticTypeCasts::instance().get();
274 InstanceStaticCast<MiscModelInstance, Renderable>::install(m_casts);
275 InstanceStaticCast<MiscModelInstance, Transformable>::install(m_casts);
276 InstanceIdentityCast<MiscModelInstance>::install(m_casts);
278 InstanceTypeCastTable& get()
284 MiscModel& m_contained;
286 typedef LazyStatic<TypeCasts> StaticTypeCasts;
288 STRING_CONSTANT(Name, "MiscModelInstance");
290 MiscModelInstance(const scene::Path& path, scene::Instance* parent, MiscModel& miscmodel) :
291 TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), miscmodel.getEntity(), *this),
292 TransformModifier(MiscModel::TransformChangedCaller(miscmodel), ApplyTransformCaller(*this)),
293 m_contained(miscmodel)
295 m_contained.instanceAttach(Instance::path());
296 StaticRenderableConnectionLines::instance().attach(*this);
300 StaticRenderableConnectionLines::instance().detach(*this);
301 m_contained.instanceDetach(Instance::path());
303 void renderSolid(Renderer& renderer, const VolumeTest& volume) const
305 m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
307 void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
309 m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
311 void evaluateTransform()
313 if(getType() == TRANSFORM_PRIMITIVE)
315 m_contained.translate(getTranslation());
316 m_contained.rotate(getRotation());
317 m_contained.scale(getScale());
320 void applyTransform()
322 m_contained.revertTransform();
324 m_contained.freezeTransform();
326 typedef MemberCaller<MiscModelInstance, &MiscModelInstance::applyTransform> ApplyTransformCaller;
329 class MiscModelNode :
330 public scene::Node::Symbiot,
331 public scene::Instantiable,
332 public scene::Cloneable,
333 public scene::Traversable::Observer
337 NodeTypeCastTable m_casts;
341 NodeStaticCast<MiscModelNode, scene::Instantiable>::install(m_casts);
342 NodeStaticCast<MiscModelNode, scene::Cloneable>::install(m_casts);
343 NodeContainedCast<MiscModelNode, scene::Traversable>::install(m_casts);
344 NodeContainedCast<MiscModelNode, Snappable>::install(m_casts);
345 NodeContainedCast<MiscModelNode, TransformNode>::install(m_casts);
346 NodeContainedCast<MiscModelNode, Entity>::install(m_casts);
347 NodeContainedCast<MiscModelNode, Nameable>::install(m_casts);
348 NodeContainedCast<MiscModelNode, Namespaced>::install(m_casts);
350 NodeTypeCastTable& get()
358 InstanceSet m_instances;
359 MiscModel m_contained;
363 m_contained.attach(this);
367 m_contained.detach(this);
371 typedef LazyStatic<TypeCasts> StaticTypeCasts;
373 scene::Traversable& get(NullType<scene::Traversable>)
375 return m_contained.getTraversable();
377 Snappable& get(NullType<Snappable>)
381 TransformNode& get(NullType<TransformNode>)
383 return m_contained.getTransformNode();
385 Entity& get(NullType<Entity>)
387 return m_contained.getEntity();
389 Nameable& get(NullType<Nameable>)
391 return m_contained.getNameable();
393 Namespaced& get(NullType<Namespaced>)
395 return m_contained.getNamespaced();
398 MiscModelNode(EntityClass* eclass) :
399 m_node(this, this, StaticTypeCasts::instance().get()),
400 m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<MiscModelInstance>::Caller(m_instances))
404 MiscModelNode(const MiscModelNode& other) :
405 scene::Node::Symbiot(other),
406 scene::Instantiable(other),
407 scene::Cloneable(other),
408 scene::Traversable::Observer(other),
409 m_node(this, this, StaticTypeCasts::instance().get()),
410 m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<MiscModelInstance>::Caller(m_instances))
428 scene::Node& clone() const
430 return (new MiscModelNode(*this))->node();
433 void insert(scene::Node& child)
435 m_instances.insert(child);
437 void erase(scene::Node& child)
439 m_instances.erase(child);
442 scene::Instance* create(const scene::Path& path, scene::Instance* parent)
444 return new MiscModelInstance(path, parent, m_contained);
446 void forEachInstance(const scene::Instantiable::Visitor& visitor)
448 m_instances.forEachInstance(visitor);
450 void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
452 m_instances.insert(observer, path, instance);
454 scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
456 return m_instances.erase(observer, path);
460 scene::Node& New_MiscModel(EntityClass* eclass)
462 return (new MiscModelNode(eclass))->node();
465 void MiscModel_construct()
468 void MiscModel_destroy()