]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - plugins/entity/group.cpp
Merge commit '515673c08f8718a237e90c2130a1f5294f966d6a'
[xonotic/netradiant.git] / plugins / entity / group.cpp
index 23084d5076d746cf1a0493d485f046f1b0a94b00..f7a87059aec11c608fbd5bd21e4c61e59f48f353 100644 (file)
@@ -47,6 +47,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include "entity.h"
 
 
 #include "entity.h"
 
+/// The "origin" key directly controls the entity's local-to-parent transform.
+
 class Group
 {
   EntityKeyValues m_entity;
 class Group
 {
   EntityKeyValues m_entity;
@@ -58,34 +60,47 @@ class Group
   NamedEntity m_named;
   NameKeys m_nameKeys;
 
   NamedEntity m_named;
   NameKeys m_nameKeys;
 
+  OriginKey m_originKey;
+  Vector3 m_origin;
+
   RenderableNamedEntity m_renderName;
   RenderableNamedEntity m_renderName;
+  mutable Vector3 m_name_origin;
 
   Callback m_transformChanged;
 
   Callback m_transformChanged;
+  Callback m_evaluateTransform;
 
   void construct()
   {
     m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
     m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
 
   void construct()
   {
     m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
     m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
+       m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
   }
  
 public:
   }
  
 public:
-  Group(EntityClass* eclass, scene::Node& node, const Callback& transformChanged) :
+  Group(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
     m_entity(eclass),
     m_filter(m_entity, node),
     m_named(m_entity),
     m_nameKeys(m_entity),
     m_entity(eclass),
     m_filter(m_entity, node),
     m_named(m_entity),
     m_nameKeys(m_entity),
-    m_renderName(m_named, g_vector3_identity),
-    m_transformChanged(transformChanged)
+    m_originKey(OriginChangedCaller(*this)),
+    m_origin(ORIGINKEY_IDENTITY),
+    m_renderName(m_named, m_name_origin),
+       m_name_origin(g_vector3_identity),
+    m_transformChanged(transformChanged),
+    m_evaluateTransform(evaluateTransform)
   {
     construct();
   }
   {
     construct();
   }
-  Group(const Group& other, scene::Node& node, const Callback& transformChanged) :
+  Group(const Group& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
     m_entity(other.m_entity),
     m_filter(m_entity, node),
     m_named(m_entity),
     m_nameKeys(m_entity),
     m_entity(other.m_entity),
     m_filter(m_entity, node),
     m_named(m_entity),
     m_nameKeys(m_entity),
+    m_originKey(OriginChangedCaller(*this)),
+    m_origin(ORIGINKEY_IDENTITY),
     m_renderName(m_named, g_vector3_identity),
     m_renderName(m_named, g_vector3_identity),
-    m_transformChanged(transformChanged)
+    m_transformChanged(transformChanged),
+    m_evaluateTransform(evaluateTransform)
   {
     construct();
   }
   {
     construct();
   }
@@ -151,16 +166,59 @@ public:
   {
     renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
   }
   {
     renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
   }
-  void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
+
+  void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, const AABB& childBounds) const
   {
     renderSolid(renderer, volume, localToWorld);
   {
     renderSolid(renderer, volume, localToWorld);
-#if 0
-    if(g_showNames)
+
+       if(g_showNames)
     {
     {
-      renderer.addRenderable(m_renderName, g_matrix4_identity);
+      // don't draw the name for worldspawn
+      if(!strcmp(m_entity.getEntityClass().name(), "worldspawn"))
+          return;
+
+         // place name in the middle of the "children cloud"
+         m_name_origin = childBounds.origin;
+
+      renderer.addRenderable(m_renderName, localToWorld);
     }
     }
-#endif
   }
   }
+
+  void updateTransform()
+  {
+    m_transform.localToParent() = g_matrix4_identity;
+    matrix4_translate_by_vec3(m_transform.localToParent(), m_origin);
+    m_transformChanged();
+  }
+  typedef MemberCaller<Group, &Group::updateTransform> UpdateTransformCaller;
+  void originChanged()
+  {
+    m_origin = m_originKey.m_origin;
+    updateTransform();
+  }
+  typedef MemberCaller<Group, &Group::originChanged> OriginChangedCaller;
+
+  void translate(const Vector3& translation)
+  {
+    m_origin = origin_translated(m_origin, translation);
+  }
+
+  void revertTransform()
+  {
+    m_origin = m_originKey.m_origin;
+  }
+  void freezeTransform()
+  {
+    m_originKey.m_origin = m_origin;
+    m_originKey.write(&m_entity);
+  }
+  void transformChanged()
+  {
+    revertTransform();
+    m_evaluateTransform();
+    updateTransform();
+  }
+  typedef MemberCaller<Group, &Group::transformChanged> TransformChangedCaller;
 };
 
 #if 0
 };
 
 #if 0
@@ -235,6 +293,7 @@ inline void Scene_forEachChildTransformable(const Functor& functor, const scene:
 
 class GroupInstance :
   public TargetableInstance,
 
 class GroupInstance :
   public TargetableInstance,
+  public TransformModifier,
 #if 0
   public Transformable,
 #endif
 #if 0
   public Transformable,
 #endif
@@ -264,6 +323,7 @@ public:
 
   GroupInstance(const scene::Path& path, scene::Instance* parent, Group& group) :
     TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), group.getEntity(), *this),
 
   GroupInstance(const scene::Path& path, scene::Instance* parent, Group& group) :
     TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), group.getEntity(), *this),
+       TransformModifier(Group::TransformChangedCaller(group), ApplyTransformCaller(*this)),
     m_contained(group)
   {
     m_contained.instanceAttach(Instance::path());
     m_contained(group)
   {
     m_contained.instanceAttach(Instance::path());
@@ -280,9 +340,11 @@ public:
   }
   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
   {
   }
   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
   {
-    m_contained.renderWireframe(renderer, volume, Instance::localToWorld());
+         m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), Instance::childBounds());
   }
 
   }
 
+  STRING_CONSTANT(Name, "GroupInstance");
+
 #if 0
   void setType(TransformModifierType type)
   {
 #if 0
   void setType(TransformModifierType type)
   {
@@ -309,6 +371,21 @@ public:
   {
   }
 #endif
   {
   }
 #endif
+
+  void evaluateTransform()
+  {
+    if(getType() == TRANSFORM_PRIMITIVE)
+    {
+      m_contained.translate(getTranslation());
+    }
+  }
+  void applyTransform()
+  {
+    m_contained.revertTransform();
+    evaluateTransform();
+    m_contained.freezeTransform();
+  }
+  typedef MemberCaller<GroupInstance, &GroupInstance::applyTransform> ApplyTransformCaller;
 };
 
 class GroupNode :
 };
 
 class GroupNode :
@@ -378,7 +455,7 @@ public:
 
   GroupNode(EntityClass* eclass) :
     m_node(this, this, StaticTypeCasts::instance().get()),
 
   GroupNode(EntityClass* eclass) :
     m_node(this, this, StaticTypeCasts::instance().get()),
-    m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances))
+    m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<GroupInstance>::Caller(m_instances))
   {
     construct();
   }
   {
     construct();
   }
@@ -388,7 +465,7 @@ public:
     scene::Cloneable(other),
     scene::Traversable::Observer(other),
     m_node(this, this, StaticTypeCasts::instance().get()),
     scene::Cloneable(other),
     scene::Traversable::Observer(other),
     m_node(this, this, StaticTypeCasts::instance().get()),
-    m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances))
+    m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<GroupInstance>::Caller(m_instances))
   {
     construct();
   }
   {
     construct();
   }