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 does not have a fixed size specified in its entity-definition (except misc_model).
25 /// This entity behaves as a group, i.e. it contains brushes.
28 #include "renderable.h"
31 #include "selectionlib.h"
32 #include "instancelib.h"
33 #include "transformlib.h"
34 #include "traverselib.h"
35 #include "entitylib.h"
37 #include "eclasslib.h"
39 #include "targetable.h"
44 #include "namedentity.h"
45 #include "keyobservers.h"
50 /// The "origin" key directly controls the entity's local-to-parent transform.
53 EntityKeyValues m_entity;
54 KeyObserverMap m_keyObservers;
55 MatrixTransform m_transform;
56 TraversableNodeSet m_traverse;
58 ClassnameFilter m_filter;
62 OriginKey m_originKey;
65 RenderableNamedEntity m_renderName;
66 mutable Vector3 m_name_origin;
68 Callback<void()> m_transformChanged;
69 Callback<void()> m_evaluateTransform;
73 m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
74 m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
75 m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
79 Group(EntityClass *eclass, scene::Node &node, const Callback<void()> &transformChanged,
80 const Callback<void()> &evaluateTransform) :
82 m_filter(m_entity, node),
85 m_originKey(OriginChangedCaller(*this)),
86 m_origin(ORIGINKEY_IDENTITY),
87 m_renderName(m_named, m_name_origin),
88 m_name_origin(g_vector3_identity),
89 m_transformChanged(transformChanged),
90 m_evaluateTransform(evaluateTransform)
95 Group(const Group &other, scene::Node &node, const Callback<void()> &transformChanged,
96 const Callback<void()> &evaluateTransform) :
97 m_entity(other.m_entity),
98 m_filter(m_entity, node),
100 m_nameKeys(m_entity),
101 m_originKey(OriginChangedCaller(*this)),
102 m_origin(ORIGINKEY_IDENTITY),
103 m_renderName(m_named, g_vector3_identity),
104 m_transformChanged(transformChanged),
105 m_evaluateTransform(evaluateTransform)
110 InstanceCounter m_instanceCounter;
112 void instanceAttach(const scene::Path &path)
114 if (++m_instanceCounter.m_count == 1) {
115 m_filter.instanceAttach();
116 m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
117 m_traverse.instanceAttach(path_find_mapfile(path.begin(), path.end()));
118 m_entity.attach(m_keyObservers);
122 void instanceDetach(const scene::Path &path)
124 if (--m_instanceCounter.m_count == 0) {
125 m_entity.detach(m_keyObservers);
126 m_traverse.instanceDetach(path_find_mapfile(path.begin(), path.end()));
127 m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
128 m_filter.instanceDetach();
132 EntityKeyValues &getEntity()
137 const EntityKeyValues &getEntity() const
142 scene::Traversable &getTraversable()
147 Namespaced &getNamespaced()
152 Nameable &getNameable()
157 TransformNode &getTransformNode()
162 void attach(scene::Traversable::Observer *observer)
164 m_traverse.attach(observer);
167 void detach(scene::Traversable::Observer *observer)
169 m_traverse.detach(observer);
172 void renderSolid(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
174 renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
177 void renderWireframe(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld,
178 const AABB &childBounds) const
180 renderSolid(renderer, volume, localToWorld);
183 // don't draw the name for worldspawn
184 if (!strcmp(m_entity.getEntityClass().name(), "worldspawn")) {
188 // place name in the middle of the "children cloud"
189 m_name_origin = childBounds.origin;
191 renderer.addRenderable(m_renderName, localToWorld);
195 void updateTransform()
197 m_transform.localToParent() = g_matrix4_identity;
198 matrix4_translate_by_vec3(m_transform.localToParent(), m_origin);
199 m_transformChanged();
202 typedef MemberCaller<Group, void(), &Group::updateTransform> UpdateTransformCaller;
206 m_origin = m_originKey.m_origin;
210 typedef MemberCaller<Group, void(), &Group::originChanged> OriginChangedCaller;
212 void translate(const Vector3 &translation)
214 m_origin = origin_translated(m_origin, translation);
217 void revertTransform()
219 m_origin = m_originKey.m_origin;
222 void freezeTransform()
224 m_originKey.m_origin = m_origin;
225 m_originKey.write(&m_entity);
228 void transformChanged()
231 m_evaluateTransform();
235 typedef MemberCaller<Group, void(), &Group::transformChanged> TransformChangedCaller;
239 class TransformableSetTranslation
243 TransformableSetTranslation( const Translation& value ) : m_value( value ){
245 void operator()( Transformable& transformable ) const {
246 transformable.setTranslation( m_value );
250 class TransformableSetRotation
254 TransformableSetRotation( const Rotation& value ) : m_value( value ){
256 void operator()( Transformable& transformable ) const {
257 transformable.setRotation( m_value );
261 class TransformableSetScale
265 TransformableSetScale( const Scale& value ) : m_value( value ){
267 void operator()( Transformable& transformable ) const {
268 transformable.setScale( m_value );
272 class TransformableSetType
274 TransformModifierType m_value;
276 TransformableSetType( const TransformModifierType& value ) : m_value( value ){
278 void operator()( Transformable& transformable ) const {
279 transformable.setType( m_value );
283 class TransformableFreezeTransform
285 TransformModifierType m_value;
287 void operator()( Transformable& transformable ) const {
288 transformable.freezeTransform();
292 template<typename Functor>
293 inline void Scene_forEachChildTransformable( const Functor& functor, const scene::Path& path ){
294 GlobalSceneGraph().traverse_subgraph( ChildInstanceWalker< InstanceApply<Transformable, Functor> >( functor ), path );
298 class GroupInstance :
299 public TargetableInstance,
300 public TransformModifier,
302 public Transformable,
306 InstanceTypeCastTable m_casts;
310 m_casts = TargetableInstance::StaticTypeCasts::instance().get();
311 InstanceStaticCast<GroupInstance, Renderable>::install(m_casts);
313 InstanceStaticCast<GroupInstance, Transformable>::install( m_casts );
317 InstanceTypeCastTable &get()
325 typedef LazyStatic<TypeCasts> StaticTypeCasts;
327 GroupInstance(const scene::Path &path, scene::Instance *parent, Group &group) :
328 TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), group.getEntity(), *this),
329 TransformModifier(Group::TransformChangedCaller(group), ApplyTransformCaller(*this)),
332 m_contained.instanceAttach(Instance::path());
333 StaticRenderableConnectionLines::instance().attach(*this);
338 StaticRenderableConnectionLines::instance().detach(*this);
339 m_contained.instanceDetach(Instance::path());
342 void renderSolid(Renderer &renderer, const VolumeTest &volume) const
344 m_contained.renderSolid(renderer, volume, Instance::localToWorld());
347 void renderWireframe(Renderer &renderer, const VolumeTest &volume) const
349 m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), Instance::childBounds());
352 STRING_CONSTANT(Name, "GroupInstance");
355 void setType( TransformModifierType type ){
356 Scene_forEachChildTransformable( TransformableSetType( type ), Instance::path() );
358 void setTranslation( const Translation& value ){
359 Scene_forEachChildTransformable( TransformableSetTranslation( value ), Instance::path() );
361 void setRotation( const Rotation& value ){
362 Scene_forEachChildTransformable( TransformableSetRotation( value ), Instance::path() );
364 void setScale( const Scale& value ){
365 Scene_forEachChildTransformable( TransformableSetScale( value ), Instance::path() );
367 void freezeTransform(){
368 Scene_forEachChildTransformable( TransformableFreezeTransform(), Instance::path() );
371 void evaluateTransform(){
375 void evaluateTransform()
377 if (getType() == TRANSFORM_PRIMITIVE) {
378 m_contained.translate(getTranslation());
382 void applyTransform()
384 m_contained.revertTransform();
386 m_contained.freezeTransform();
389 typedef MemberCaller<GroupInstance, void(), &GroupInstance::applyTransform> ApplyTransformCaller;
393 public scene::Node::Symbiot,
394 public scene::Instantiable,
395 public scene::Cloneable,
396 public scene::Traversable::Observer {
398 NodeTypeCastTable m_casts;
402 NodeStaticCast<GroupNode, scene::Instantiable>::install(m_casts);
403 NodeStaticCast<GroupNode, scene::Cloneable>::install(m_casts);
404 NodeContainedCast<GroupNode, scene::Traversable>::install(m_casts);
405 NodeContainedCast<GroupNode, TransformNode>::install(m_casts);
406 NodeContainedCast<GroupNode, Entity>::install(m_casts);
407 NodeContainedCast<GroupNode, Nameable>::install(m_casts);
408 NodeContainedCast<GroupNode, Namespaced>::install(m_casts);
411 NodeTypeCastTable &get()
419 InstanceSet m_instances;
424 m_contained.attach(this);
429 m_contained.detach(this);
434 typedef LazyStatic<TypeCasts> StaticTypeCasts;
436 scene::Traversable &get(NullType<scene::Traversable>)
438 return m_contained.getTraversable();
441 TransformNode &get(NullType<TransformNode>)
443 return m_contained.getTransformNode();
446 Entity &get(NullType<Entity>)
448 return m_contained.getEntity();
451 Nameable &get(NullType<Nameable>)
453 return m_contained.getNameable();
456 Namespaced &get(NullType<Namespaced>)
458 return m_contained.getNamespaced();
461 GroupNode(EntityClass *eclass) :
462 m_node(this, this, StaticTypeCasts::instance().get()),
463 m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances),
464 InstanceSetEvaluateTransform<GroupInstance>::Caller(m_instances))
469 GroupNode(const GroupNode &other) :
470 scene::Node::Symbiot(other),
471 scene::Instantiable(other),
472 scene::Cloneable(other),
473 scene::Traversable::Observer(other),
474 m_node(this, this, StaticTypeCasts::instance().get()),
475 m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances),
476 InstanceSetEvaluateTransform<GroupInstance>::Caller(m_instances))
496 scene::Node &clone() const
498 return (new GroupNode(*this))->node();
501 void insert(scene::Node &child)
503 m_instances.insert(child);
506 void erase(scene::Node &child)
508 m_instances.erase(child);
511 scene::Instance *create(const scene::Path &path, scene::Instance *parent)
513 return new GroupInstance(path, parent, m_contained);
516 void forEachInstance(const scene::Instantiable::Visitor &visitor)
518 m_instances.forEachInstance(visitor);
521 void insert(scene::Instantiable::Observer *observer, const scene::Path &path, scene::Instance *instance)
523 m_instances.insert(observer, path, instance);
526 scene::Instance *erase(scene::Instantiable::Observer *observer, const scene::Path &path)
528 return m_instances.erase(observer, path);
532 scene::Node &New_Group(EntityClass *eclass)
534 return (new GroupNode(eclass))->node();