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 any entity which has a fixed size specified in its entity-definition and displays a model (e.g. ammo_bfg).
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.
29 #include "eclassmodel.h"
32 #include "renderable.h"
35 #include "selectionlib.h"
36 #include "instancelib.h"
37 #include "transformlib.h"
38 #include "traverselib.h"
39 #include "entitylib.h"
41 #include "eclasslib.h"
44 #include "targetable.h"
50 #include "namedentity.h"
51 #include "keyobservers.h"
53 #include "modelskinkey.h"
60 MatrixTransform m_transform;
61 EntityKeyValues m_entity;
62 KeyObserverMap m_keyObservers;
64 OriginKey m_originKey;
68 RotationKey m_rotationKey;
70 SingletonModel m_model;
72 ClassnameFilter m_filter;
75 RenderablePivot m_renderOrigin;
76 RenderableNamedEntity m_renderName;
79 Callback m_transformChanged;
80 Callback m_evaluateTransform;
84 default_rotation(m_rotation);
86 m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
87 m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
88 if(g_gameType == eGameTypeDoom3)
90 m_keyObservers.insert("angle", RotationKey::AngleChangedCaller(m_rotationKey));
91 m_keyObservers.insert("rotation", RotationKey::RotationChangedCaller(m_rotationKey));
95 m_keyObservers.insert("angle", AngleKey::AngleChangedCaller(m_angleKey));
97 m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
100 void updateTransform()
102 m_transform.localToParent() = g_matrix4_identity;
103 matrix4_translate_by_vec3(m_transform.localToParent(), m_origin);
105 if(g_gameType == eGameTypeDoom3)
107 matrix4_multiply_by_matrix4(m_transform.localToParent(), rotation_toMatrix(m_rotation));
111 matrix4_multiply_by_matrix4(m_transform.localToParent(), matrix4_rotation_for_z_degrees(m_angle));
114 m_transformChanged();
116 typedef MemberCaller<EclassModel, &EclassModel::updateTransform> UpdateTransformCaller;
120 m_origin = m_originKey.m_origin;
123 typedef MemberCaller<EclassModel, &EclassModel::originChanged> OriginChangedCaller;
126 m_angle = m_angleKey.m_angle;
129 typedef MemberCaller<EclassModel, &EclassModel::angleChanged> AngleChangedCaller;
130 void rotationChanged()
132 rotation_assign(m_rotation, m_rotationKey.m_rotation);
135 typedef MemberCaller<EclassModel, &EclassModel::rotationChanged> RotationChangedCaller;
139 scene::Node* node = m_model.getNode();
142 Node_modelSkinChanged(*node);
145 typedef MemberCaller<EclassModel, &EclassModel::skinChanged> SkinChangedCaller;
149 EclassModel(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
151 m_originKey(OriginChangedCaller(*this)),
152 m_origin(ORIGINKEY_IDENTITY),
153 m_angleKey(AngleChangedCaller(*this)),
154 m_angle(ANGLEKEY_IDENTITY),
155 m_rotationKey(RotationChangedCaller(*this)),
156 m_filter(m_entity, node),
158 m_nameKeys(m_entity),
159 m_renderName(m_named, g_vector3_identity),
160 m_skin(SkinChangedCaller(*this)),
161 m_transformChanged(transformChanged),
162 m_evaluateTransform(evaluateTransform)
166 EclassModel(const EclassModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
167 m_entity(other.m_entity),
168 m_originKey(OriginChangedCaller(*this)),
169 m_origin(ORIGINKEY_IDENTITY),
170 m_angleKey(AngleChangedCaller(*this)),
171 m_angle(ANGLEKEY_IDENTITY),
172 m_rotationKey(RotationChangedCaller(*this)),
173 m_filter(m_entity, node),
175 m_nameKeys(m_entity),
176 m_renderName(m_named, g_vector3_identity),
177 m_skin(SkinChangedCaller(*this)),
178 m_transformChanged(transformChanged),
179 m_evaluateTransform(evaluateTransform)
184 InstanceCounter m_instanceCounter;
185 void instanceAttach(const scene::Path& path)
187 if(++m_instanceCounter.m_count == 1)
189 m_filter.instanceAttach();
190 m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
191 m_entity.attach(m_keyObservers);
192 m_model.modelChanged(m_entity.getEntityClass().modelpath());
193 m_skin.skinChanged(m_entity.getEntityClass().skin());
196 void instanceDetach(const scene::Path& path)
198 if(--m_instanceCounter.m_count == 0)
200 m_skin.skinChanged("");
201 m_model.modelChanged("");
202 m_entity.detach(m_keyObservers);
203 m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
204 m_filter.instanceDetach();
208 EntityKeyValues& getEntity()
212 const EntityKeyValues& getEntity() const
217 scene::Traversable& getTraversable()
219 return m_model.getTraversable();
221 Namespaced& getNamespaced()
225 Nameable& getNameable()
229 TransformNode& getTransformNode()
233 ModelSkin& getModelSkin()
238 void attach(scene::Traversable::Observer* observer)
240 m_model.attach(observer);
242 void detach(scene::Traversable::Observer* observer)
244 m_model.detach(observer);
247 void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
251 m_renderOrigin.render(renderer, volume, localToWorld);
254 renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
256 void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
258 renderSolid(renderer, volume, localToWorld, selected);
261 renderer.addRenderable(m_renderName, localToWorld);
265 void translate(const Vector3& translation)
267 m_origin = origin_translated(m_origin, translation);
269 void rotate(const Quaternion& rotation)
271 if(g_gameType == eGameTypeDoom3)
273 rotation_rotate(m_rotation, rotation);
277 m_angle = angle_rotated(m_angle, rotation);
280 void snapto(float snap)
282 m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
283 m_originKey.write(&m_entity);
285 void revertTransform()
287 m_origin = m_originKey.m_origin;
288 if(g_gameType == eGameTypeDoom3)
290 rotation_assign(m_rotation, m_rotationKey.m_rotation);
294 m_angle = m_angleKey.m_angle;
297 void freezeTransform()
299 m_originKey.m_origin = m_origin;
300 m_originKey.write(&m_entity);
301 if(g_gameType == eGameTypeDoom3)
303 rotation_assign(m_rotationKey.m_rotation, m_rotation);
304 m_rotationKey.write(&m_entity);
308 m_angleKey.m_angle = m_angle;
309 m_angleKey.write(&m_entity);
312 void transformChanged()
315 m_evaluateTransform();
318 typedef MemberCaller<EclassModel, &EclassModel::transformChanged> TransformChangedCaller;
321 class EclassModelInstance : public TargetableInstance, public TransformModifier, public Renderable
325 InstanceTypeCastTable m_casts;
329 m_casts = TargetableInstance::StaticTypeCasts::instance().get();
330 InstanceStaticCast<EclassModelInstance, Renderable>::install(m_casts);
331 InstanceStaticCast<EclassModelInstance, Transformable>::install(m_casts);
332 InstanceIdentityCast<EclassModelInstance>::install(m_casts);
334 InstanceTypeCastTable& get()
340 EclassModel& m_contained;
342 typedef LazyStatic<TypeCasts> StaticTypeCasts;
344 STRING_CONSTANT(Name, "EclassModelInstance");
346 EclassModelInstance(const scene::Path& path, scene::Instance* parent, EclassModel& contained) :
347 TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
348 TransformModifier(EclassModel::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
349 m_contained(contained)
351 m_contained.instanceAttach(Instance::path());
353 StaticRenderableConnectionLines::instance().attach(*this);
355 ~EclassModelInstance()
357 StaticRenderableConnectionLines::instance().detach(*this);
359 m_contained.instanceDetach(Instance::path());
361 void renderSolid(Renderer& renderer, const VolumeTest& volume) const
363 m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
365 void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
367 m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
370 void evaluateTransform()
372 if(getType() == TRANSFORM_PRIMITIVE)
374 m_contained.translate(getTranslation());
375 m_contained.rotate(getRotation());
378 void applyTransform()
380 m_contained.revertTransform();
382 m_contained.freezeTransform();
384 typedef MemberCaller<EclassModelInstance, &EclassModelInstance::applyTransform> ApplyTransformCaller;
387 class EclassModelNode :
388 public scene::Node::Symbiot,
389 public scene::Instantiable,
390 public scene::Cloneable,
391 public scene::Traversable::Observer
395 NodeTypeCastTable m_casts;
399 NodeStaticCast<EclassModelNode, scene::Instantiable>::install(m_casts);
400 NodeStaticCast<EclassModelNode, scene::Cloneable>::install(m_casts);
401 NodeContainedCast<EclassModelNode, scene::Traversable>::install(m_casts);
402 NodeContainedCast<EclassModelNode, Snappable>::install(m_casts);
403 NodeContainedCast<EclassModelNode, TransformNode>::install(m_casts);
404 NodeContainedCast<EclassModelNode, Entity>::install(m_casts);
405 NodeContainedCast<EclassModelNode, Nameable>::install(m_casts);
406 NodeContainedCast<EclassModelNode, Namespaced>::install(m_casts);
407 NodeContainedCast<EclassModelNode, ModelSkin>::install(m_casts);
409 NodeTypeCastTable& get()
417 InstanceSet m_instances;
418 EclassModel m_contained;
422 m_contained.attach(this);
426 m_contained.detach(this);
430 typedef LazyStatic<TypeCasts> StaticTypeCasts;
432 scene::Traversable& get(NullType<scene::Traversable>)
434 return m_contained.getTraversable();
436 Snappable& get(NullType<Snappable>)
440 TransformNode& get(NullType<TransformNode>)
442 return m_contained.getTransformNode();
444 Entity& get(NullType<Entity>)
446 return m_contained.getEntity();
448 Nameable& get(NullType<Nameable>)
450 return m_contained.getNameable();
452 Namespaced& get(NullType<Namespaced>)
454 return m_contained.getNamespaced();
456 ModelSkin& get(NullType<ModelSkin>)
458 return m_contained.getModelSkin();
461 EclassModelNode(EntityClass* eclass) :
462 m_node(this, this, StaticTypeCasts::instance().get()),
463 m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<EclassModelInstance>::Caller(m_instances))
467 EclassModelNode(const EclassModelNode& other) :
468 scene::Node::Symbiot(other),
469 scene::Instantiable(other),
470 scene::Cloneable(other),
471 scene::Traversable::Observer(other),
472 m_node(this, this, StaticTypeCasts::instance().get()),
473 m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<EclassModelInstance>::Caller(m_instances))
490 void insert(scene::Node& child)
492 m_instances.insert(child);
494 void erase(scene::Node& child)
496 m_instances.erase(child);
499 scene::Node& clone() const
501 return (new EclassModelNode(*this))->node();
504 scene::Instance* create(const scene::Path& path, scene::Instance* parent)
506 return new EclassModelInstance(path, parent, m_contained);
508 void forEachInstance(const scene::Instantiable::Visitor& visitor)
510 m_instances.forEachInstance(visitor);
512 void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
514 m_instances.insert(observer, path, instance);
516 scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
518 return m_instances.erase(observer, path);
522 scene::Node& New_EclassModel(EntityClass* eclass)
524 return (new EclassModelNode(eclass))->node();