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"
59 MatrixTransform m_transform;
60 EntityKeyValues m_entity;
61 KeyObserverMap m_keyObservers;
63 OriginKey m_originKey;
67 RotationKey m_rotationKey;
69 SingletonModel m_model;
71 ClassnameFilter m_filter;
74 RenderablePivot m_renderOrigin;
75 RenderableNamedEntity m_renderName;
78 Callback<void()> m_transformChanged;
79 Callback<void()> m_evaluateTransform;
83 default_rotation(m_rotation);
85 m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
86 m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
87 if (g_gameType == eGameTypeDoom3) {
88 m_keyObservers.insert("angle", RotationKey::AngleChangedCaller(m_rotationKey));
89 m_keyObservers.insert("rotation", RotationKey::RotationChangedCaller(m_rotationKey));
91 m_keyObservers.insert("angle", AngleKey::AngleChangedCaller(m_angleKey));
93 m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
96 // vc 2k5 compiler fix
101 void updateTransform()
103 m_transform.localToParent() = g_matrix4_identity;
104 matrix4_translate_by_vec3(m_transform.localToParent(), m_origin);
106 if (g_gameType == eGameTypeDoom3) {
107 matrix4_multiply_by_matrix4(m_transform.localToParent(), rotation_toMatrix(m_rotation));
109 matrix4_multiply_by_matrix4(m_transform.localToParent(), matrix4_rotation_for_z_degrees(m_angle));
112 m_transformChanged();
115 typedef MemberCaller<EclassModel, void(), &EclassModel::updateTransform> UpdateTransformCaller;
119 m_origin = m_originKey.m_origin;
123 typedef MemberCaller<EclassModel, void(), &EclassModel::originChanged> OriginChangedCaller;
127 m_angle = m_angleKey.m_angle;
131 typedef MemberCaller<EclassModel, void(), &EclassModel::angleChanged> AngleChangedCaller;
133 void rotationChanged()
135 rotation_assign(m_rotation, m_rotationKey.m_rotation);
139 typedef MemberCaller<EclassModel, void(), &EclassModel::rotationChanged> RotationChangedCaller;
143 scene::Node *node = m_model.getNode();
145 Node_modelSkinChanged(*node);
149 typedef MemberCaller<EclassModel, void(), &EclassModel::skinChanged> SkinChangedCaller;
153 EclassModel(EntityClass *eclass, scene::Node &node, const Callback<void()> &transformChanged,
154 const Callback<void()> &evaluateTransform) :
156 m_originKey(OriginChangedCaller(*this)),
157 m_origin(ORIGINKEY_IDENTITY),
158 m_angleKey(AngleChangedCaller(*this)),
159 m_angle(ANGLEKEY_IDENTITY),
160 m_rotationKey(RotationChangedCaller(*this)),
161 m_filter(m_entity, node),
163 m_nameKeys(m_entity),
164 m_renderName(m_named, g_vector3_identity),
165 m_skin(SkinChangedCaller(*this)),
166 m_transformChanged(transformChanged),
167 m_evaluateTransform(evaluateTransform)
172 EclassModel(const EclassModel &other, scene::Node &node, const Callback<void()> &transformChanged,
173 const Callback<void()> &evaluateTransform) :
174 m_entity(other.m_entity),
175 m_originKey(OriginChangedCaller(*this)),
176 m_origin(ORIGINKEY_IDENTITY),
177 m_angleKey(AngleChangedCaller(*this)),
178 m_angle(ANGLEKEY_IDENTITY),
179 m_rotationKey(RotationChangedCaller(*this)),
180 m_filter(m_entity, node),
182 m_nameKeys(m_entity),
183 m_renderName(m_named, g_vector3_identity),
184 m_skin(SkinChangedCaller(*this)),
185 m_transformChanged(transformChanged),
186 m_evaluateTransform(evaluateTransform)
191 InstanceCounter m_instanceCounter;
193 void instanceAttach(const scene::Path &path)
195 if (++m_instanceCounter.m_count == 1) {
196 m_filter.instanceAttach();
197 m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
198 m_entity.attach(m_keyObservers);
199 m_model.modelChanged(m_entity.getEntityClass().modelpath());
200 m_skin.skinChanged(m_entity.getEntityClass().skin());
204 void instanceDetach(const scene::Path &path)
206 if (--m_instanceCounter.m_count == 0) {
207 m_skin.skinChanged("");
208 m_model.modelChanged("");
209 m_entity.detach(m_keyObservers);
210 m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
211 m_filter.instanceDetach();
215 EntityKeyValues &getEntity()
220 const EntityKeyValues &getEntity() const
225 scene::Traversable &getTraversable()
227 return m_model.getTraversable();
230 Namespaced &getNamespaced()
235 Nameable &getNameable()
240 TransformNode &getTransformNode()
245 ModelSkin &getModelSkin()
250 void attach(scene::Traversable::Observer *observer)
252 m_model.attach(observer);
255 void detach(scene::Traversable::Observer *observer)
257 m_model.detach(observer);
260 void renderSolid(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld, bool selected) const
263 m_renderOrigin.render(renderer, volume, localToWorld);
266 renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
269 void renderWireframe(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld, bool selected) const
271 renderSolid(renderer, volume, localToWorld, selected);
273 renderer.addRenderable(m_renderName, localToWorld);
277 void translate(const Vector3 &translation)
279 m_origin = origin_translated(m_origin, translation);
282 void rotate(const Quaternion &rotation)
284 if (g_gameType == eGameTypeDoom3) {
285 rotation_rotate(m_rotation, rotation);
287 m_angle = angle_rotated(m_angle, rotation);
291 void snapto(float snap)
293 m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
294 m_originKey.write(&m_entity);
297 void revertTransform()
299 m_origin = m_originKey.m_origin;
300 if (g_gameType == eGameTypeDoom3) {
301 rotation_assign(m_rotation, m_rotationKey.m_rotation);
303 m_angle = m_angleKey.m_angle;
307 void freezeTransform()
309 m_originKey.m_origin = m_origin;
310 m_originKey.write(&m_entity);
311 if (g_gameType == eGameTypeDoom3) {
312 rotation_assign(m_rotationKey.m_rotation, m_rotation);
313 m_rotationKey.write(&m_entity);
315 m_angleKey.m_angle = m_angle;
316 m_angleKey.write(&m_entity);
320 void transformChanged()
323 m_evaluateTransform();
327 typedef MemberCaller<EclassModel, void(), &EclassModel::transformChanged> TransformChangedCaller;
330 class EclassModelInstance : public TargetableInstance, public TransformModifier, public Renderable {
332 InstanceTypeCastTable m_casts;
336 m_casts = TargetableInstance::StaticTypeCasts::instance().get();
337 InstanceStaticCast<EclassModelInstance, Renderable>::install(m_casts);
338 InstanceStaticCast<EclassModelInstance, Transformable>::install(m_casts);
339 InstanceIdentityCast<EclassModelInstance>::install(m_casts);
342 InstanceTypeCastTable &get()
348 EclassModel &m_contained;
350 typedef LazyStatic<TypeCasts> StaticTypeCasts;
352 STRING_CONSTANT(Name, "EclassModelInstance");
354 EclassModelInstance(const scene::Path &path, scene::Instance *parent, EclassModel &contained) :
355 TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
356 TransformModifier(EclassModel::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
357 m_contained(contained)
359 m_contained.instanceAttach(Instance::path());
361 StaticRenderableConnectionLines::instance().attach(*this);
364 ~EclassModelInstance()
366 StaticRenderableConnectionLines::instance().detach(*this);
368 m_contained.instanceDetach(Instance::path());
371 void renderSolid(Renderer &renderer, const VolumeTest &volume) const
373 m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
376 void renderWireframe(Renderer &renderer, const VolumeTest &volume) const
378 m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
381 void evaluateTransform()
383 if (getType() == TRANSFORM_PRIMITIVE) {
384 m_contained.translate(getTranslation());
385 m_contained.rotate(getRotation());
389 void applyTransform()
391 m_contained.revertTransform();
393 m_contained.freezeTransform();
396 typedef MemberCaller<EclassModelInstance, void(), &EclassModelInstance::applyTransform> ApplyTransformCaller;
399 class EclassModelNode :
400 public scene::Node::Symbiot,
401 public scene::Instantiable,
402 public scene::Cloneable,
403 public scene::Traversable::Observer {
405 NodeTypeCastTable m_casts;
409 NodeStaticCast<EclassModelNode, scene::Instantiable>::install(m_casts);
410 NodeStaticCast<EclassModelNode, scene::Cloneable>::install(m_casts);
411 NodeContainedCast<EclassModelNode, scene::Traversable>::install(m_casts);
412 NodeContainedCast<EclassModelNode, Snappable>::install(m_casts);
413 NodeContainedCast<EclassModelNode, TransformNode>::install(m_casts);
414 NodeContainedCast<EclassModelNode, Entity>::install(m_casts);
415 NodeContainedCast<EclassModelNode, Nameable>::install(m_casts);
416 NodeContainedCast<EclassModelNode, Namespaced>::install(m_casts);
417 NodeContainedCast<EclassModelNode, ModelSkin>::install(m_casts);
420 NodeTypeCastTable &get()
428 InstanceSet m_instances;
429 EclassModel m_contained;
433 m_contained.attach(this);
438 m_contained.detach(this);
442 typedef LazyStatic<TypeCasts> StaticTypeCasts;
444 scene::Traversable &get(NullType<scene::Traversable>)
446 return m_contained.getTraversable();
449 Snappable &get(NullType<Snappable>)
454 TransformNode &get(NullType<TransformNode>)
456 return m_contained.getTransformNode();
459 Entity &get(NullType<Entity>)
461 return m_contained.getEntity();
464 Nameable &get(NullType<Nameable>)
466 return m_contained.getNameable();
469 Namespaced &get(NullType<Namespaced>)
471 return m_contained.getNamespaced();
474 ModelSkin &get(NullType<ModelSkin>)
476 return m_contained.getModelSkin();
479 EclassModelNode(EntityClass *eclass) :
480 m_node(this, this, StaticTypeCasts::instance().get()),
481 m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances),
482 InstanceSetEvaluateTransform<EclassModelInstance>::Caller(m_instances))
487 EclassModelNode(const EclassModelNode &other) :
488 scene::Node::Symbiot(other),
489 scene::Instantiable(other),
490 scene::Cloneable(other),
491 scene::Traversable::Observer(other),
492 m_node(this, this, StaticTypeCasts::instance().get()),
493 m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances),
494 InstanceSetEvaluateTransform<EclassModelInstance>::Caller(m_instances))
514 void insert(scene::Node &child)
516 m_instances.insert(child);
519 void erase(scene::Node &child)
521 m_instances.erase(child);
524 scene::Node &clone() const
526 return (new EclassModelNode(*this))->node();
529 scene::Instance *create(const scene::Path &path, scene::Instance *parent)
531 return new EclassModelInstance(path, parent, m_contained);
534 void forEachInstance(const scene::Instantiable::Visitor &visitor)
536 m_instances.forEachInstance(visitor);
539 void insert(scene::Instantiable::Observer *observer, const scene::Path &path, scene::Instance *instance)
541 m_instances.insert(observer, path, instance);
544 scene::Instance *erase(scene::Instantiable::Observer *observer, const scene::Path &path)
546 return m_instances.erase(observer, path);
550 scene::Node &New_EclassModel(EntityClass *eclass)
552 return (new EclassModelNode(eclass))->node();