]> de.git.xonotic.org Git - voretournament/voretournament.git/blobdiff - misc/mediasource/netradiant-src/libs/scenelib.h
Move the netradiant and fteqcc sources
[voretournament/voretournament.git] / misc / mediasource / netradiant-src / libs / scenelib.h
diff --git a/misc/mediasource/netradiant-src/libs/scenelib.h b/misc/mediasource/netradiant-src/libs/scenelib.h
new file mode 100644 (file)
index 0000000..9a5c055
--- /dev/null
@@ -0,0 +1,1103 @@
+/*
+Copyright (C) 2001-2006, William Joseph.
+All Rights Reserved.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#if !defined (INCLUDED_SCENELIB_H)
+#define INCLUDED_SCENELIB_H
+
+#include "iscenegraph.h"
+#include "iselection.h"
+
+#include "warnings.h"
+#include <cstddef>
+#include <string.h>
+
+#include "math/aabb.h"
+#include "transformlib.h"
+#include "generic/callback.h"
+#include "generic/reference.h"
+#include "container/stack.h"
+#include "typesystem.h"
+
+class Selector;
+class SelectionTest;
+class VolumeTest;
+template<typename Element> class BasicVector3;
+typedef BasicVector3<float> Vector3;
+template<typename Element> class BasicVector4;
+typedef BasicVector4<float> Vector4;
+class Matrix4;
+typedef Vector4 Quaternion;
+class AABB;
+
+class ComponentSelectionTestable
+{
+public:
+  STRING_CONSTANT(Name, "ComponentSelectionTestable");
+
+  virtual bool isSelectedComponents() const = 0;
+  virtual void setSelectedComponents(bool select, SelectionSystem::EComponentMode mode) = 0;
+  virtual void testSelectComponents(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode) = 0;
+};
+
+class ComponentEditable
+{
+public:
+  STRING_CONSTANT(Name, "ComponentEditable");
+
+  virtual const AABB& getSelectedComponentsBounds() const = 0;
+};
+
+class ComponentSnappable
+{
+public:
+  STRING_CONSTANT(Name, "ComponentSnappable");
+
+  virtual void snapComponents(float snap) = 0;
+};
+
+class Bounded
+{
+public:
+  STRING_CONSTANT(Name, "Bounded");
+
+  virtual const AABB& localAABB() const = 0;
+};
+
+class BrushDoom3
+{
+public:
+  STRING_CONSTANT(Name, "BrushDoom3");
+
+  virtual void setDoom3GroupOrigin(const Vector3& origin) = 0;
+};
+
+
+
+
+typedef TypeCastTable<NODETYPEID_MAX> NodeTypeCastTable;
+
+template<typename Type>
+class NodeType : public StaticTypeSystemInitialiser
+{
+  TypeId m_typeId;
+public:
+  typedef typename Type::Name Name;
+  NodeType() : m_typeId(NODETYPEID_NONE)
+  {
+    StaticTypeSystemInitialiser::instance().addInitialiser(InitialiseCaller(*this));
+  }
+  void initialise()
+  {
+    m_typeId = GlobalSceneGraph().getNodeTypeId(Name());
+  }
+  typedef MemberCaller<NodeType<Type>, &NodeType<Type>::initialise> InitialiseCaller;
+  TypeId getTypeId()
+  {
+#if defined(_DEBUG)
+    ASSERT_MESSAGE(m_typeId != NODETYPEID_NONE, "node-type " << makeQuoted(Name()) << " used before being initialised");
+#endif
+    return m_typeId;
+  }
+};
+
+template<typename Type>
+class StaticNodeType
+{
+public:
+  enum unnamed0 { SIZE = NODETYPEID_MAX };
+  static TypeId getTypeId()
+  {
+    return Static< NodeType<Type> >::instance().getTypeId();
+  }
+};
+
+template<typename Type, typename Base>
+class NodeStaticCast :
+  public CastInstaller<
+    StaticNodeType<Base>,
+    StaticCast<Type, Base>
+  >
+{
+};
+
+template<typename Type, typename Contained>
+class NodeContainedCast :
+  public CastInstaller<
+    StaticNodeType<Contained>,
+    ContainedCast<Type, Contained>
+  >
+{
+};
+
+template<typename Type>
+class NodeIdentityCast :
+  public CastInstaller<
+    StaticNodeType<Type>,
+    IdentityCast<Type>
+  >
+{
+};
+
+namespace scene
+{
+  class Node
+  {
+  public:
+    enum unnamed0 { eVisible = 0 };
+    enum unnamed1 { eHidden = 1 << 0 };
+    enum unnamed2 { eFiltered = 1 << 1 };
+    enum unnamed3 { eExcluded = 1 << 2 };
+
+    class Symbiot
+    {
+    public:
+      virtual void release() = 0;
+    };
+
+  private:
+    unsigned int m_state;
+    std::size_t m_refcount;
+    Symbiot* m_symbiot;
+    void* m_node;
+    NodeTypeCastTable& m_casts;
+
+  public:
+    bool m_isRoot;
+
+    bool isRoot()
+    {
+      return m_isRoot;
+    }
+
+    Node(Symbiot* symbiot, void* node, NodeTypeCastTable& casts) :
+      m_state(eVisible),
+      m_refcount(0),
+      m_symbiot(symbiot),
+      m_node(node),
+      m_casts(casts),
+      m_isRoot(false)
+    {
+    }
+    ~Node()
+    {
+    }
+
+    void IncRef()
+    {
+      ASSERT_MESSAGE(m_refcount < (1 << 24), "Node::decref: uninitialised refcount");
+      ++m_refcount;
+    }
+    void DecRef()
+    {
+      ASSERT_MESSAGE(m_refcount < (1 << 24), "Node::decref: uninitialised refcount");
+      if(--m_refcount == 0)
+      {
+        m_symbiot->release();
+      }
+    }
+    std::size_t getReferenceCount() const
+    {
+      return m_refcount;
+    }
+
+    void* cast(TypeId typeId) const
+    {
+      return m_casts.cast(typeId, m_node);
+    }
+
+    void enable(unsigned int state)
+    {
+      m_state |= state;
+    }
+    void disable(unsigned int state)
+    {
+      m_state &= ~state;
+    }
+    bool visible()
+    {
+      return m_state == eVisible;
+    }
+    bool excluded()
+    {
+      return (m_state & eExcluded) != 0;
+    }
+  };
+
+  class NullNode : public Node::Symbiot
+  {
+    NodeTypeCastTable m_casts;
+    Node m_node;
+  public:
+    NullNode() : m_node(this, 0, m_casts)
+    {
+    }
+    void release()
+    {
+      delete this;
+    }
+    scene::Node& node()
+    {
+      return m_node;
+    }
+  };
+}
+
+template<typename Type>
+class NodeTypeCast
+{
+public:
+  static Type* cast(scene::Node& node)
+  {
+    return static_cast<Type*>(node.cast(StaticNodeType<Type>::getTypeId()));
+  }
+  static const Type* cast(const scene::Node& node)
+  {
+    return static_cast<const Type*>(node.cast(StaticNodeType<Type>::getTypeId()));
+  }
+};
+
+
+inline scene::Instantiable* Node_getInstantiable(scene::Node& node)
+{
+  return NodeTypeCast<scene::Instantiable>::cast(node);
+}
+
+inline scene::Traversable* Node_getTraversable(scene::Node& node)
+{
+  return NodeTypeCast<scene::Traversable>::cast(node);
+}
+
+inline void Node_traverseSubgraph(scene::Node& node, const scene::Traversable::Walker& walker)
+{
+  if(walker.pre(node))
+  {
+    scene::Traversable* traversable = Node_getTraversable(node);
+    if(traversable != 0)
+    {
+      traversable->traverse(walker);
+    }
+  }
+  walker.post(node);
+}
+
+inline TransformNode* Node_getTransformNode(scene::Node& node)
+{
+  return NodeTypeCast<TransformNode>::cast(node);
+}
+
+inline bool operator<(scene::Node& node, scene::Node& other)
+{
+  return &node < &other;
+}
+inline bool operator==(scene::Node& node, scene::Node& other)
+{
+  return &node == &other;
+}
+inline bool operator!=(scene::Node& node, scene::Node& other)
+{
+  return !::operator==(node, other);
+}
+
+
+inline scene::Node& NewNullNode()
+{
+  return (new scene::NullNode)->node();
+}
+
+inline void Path_deleteTop(const scene::Path& path)
+{
+  Node_getTraversable(path.parent())->erase(path.top());
+}
+
+
+
+
+
+class delete_all : public scene::Traversable::Walker
+{
+  scene::Node& m_parent;
+public:
+  delete_all(scene::Node& parent) : m_parent(parent)
+  {
+  }
+  bool pre(scene::Node& node) const
+  {
+    return false;
+  }
+  void post(scene::Node& node) const
+  {
+    Node_getTraversable(m_parent)->erase(node);
+  }
+};
+
+inline void DeleteSubgraph(scene::Node& subgraph)
+{
+  Node_getTraversable(subgraph)->traverse(delete_all(subgraph));
+}
+
+
+class EntityUndefined
+{
+public:
+  STRING_CONSTANT(Name, "Entity");
+};
+
+inline bool Node_isEntity(scene::Node& node)
+{
+  return NodeTypeCast<EntityUndefined>::cast(node) != 0;
+}
+
+template<typename Functor>
+class EntityWalker : public scene::Graph::Walker
+{
+  const Functor& functor;
+public:
+  EntityWalker(const Functor& functor) : functor(functor)
+  {
+  }
+  bool pre(const scene::Path& path, scene::Instance& instance) const
+  {
+    if(Node_isEntity(path.top()))
+    {
+      functor(instance);
+      return false;
+    }
+    return true;
+  }
+};
+
+template<typename Functor>
+inline const Functor& Scene_forEachEntity(const Functor& functor)
+{
+  GlobalSceneGraph().traverse(EntityWalker<Functor>(functor));
+  return functor;
+}
+
+class BrushUndefined
+{
+public:
+  STRING_CONSTANT(Name, "Brush");
+};
+
+inline bool Node_isBrush(scene::Node& node)
+{
+  return NodeTypeCast<BrushUndefined>::cast(node) != 0;
+}
+
+class PatchUndefined
+{
+public:
+  STRING_CONSTANT(Name, "Patch");
+};
+
+inline bool Node_isPatch(scene::Node& node)
+{
+  return NodeTypeCast<PatchUndefined>::cast(node) != 0;
+}
+
+inline bool Node_isPrimitive(scene::Node& node)
+{
+#if 1
+  return Node_isBrush(node) || Node_isPatch(node);
+#else
+  return !node.isRoot();
+#endif
+}
+
+class ParentBrushes : public scene::Traversable::Walker
+{
+  scene::Node& m_parent;
+public:
+  ParentBrushes(scene::Node& parent)
+    : m_parent(parent)
+  {
+  }
+  bool pre(scene::Node& node) const
+  {
+    return false;
+  }
+  void post(scene::Node& node) const
+  {
+    if(Node_isPrimitive(node))
+    {
+      Node_getTraversable(m_parent)->insert(node);
+    }
+  }
+};
+
+inline void parentBrushes(scene::Node& subgraph, scene::Node& parent)
+{
+  Node_getTraversable(subgraph)->traverse(ParentBrushes(parent));
+}
+
+class HasBrushes : public scene::Traversable::Walker
+{
+  bool& m_hasBrushes;
+public:
+  HasBrushes(bool& hasBrushes)
+    : m_hasBrushes(hasBrushes)
+  {
+    m_hasBrushes = true;
+  }
+  bool pre(scene::Node& node) const
+  {
+    if(!Node_isPrimitive(node))
+    {
+      m_hasBrushes = false;
+    }
+    return false;
+  }
+};
+
+inline bool node_is_group(scene::Node& node)
+{
+  scene::Traversable* traversable = Node_getTraversable(node);
+  if(traversable != 0)
+  {
+    bool hasBrushes = false;
+    traversable->traverse(HasBrushes(hasBrushes));
+    return hasBrushes;
+  }
+  return false;
+}
+
+typedef TypeCastTable<INSTANCETYPEID_MAX> InstanceTypeCastTable;
+
+template<typename Type>
+class InstanceType : public StaticTypeSystemInitialiser
+{
+  TypeId m_typeId;
+public:
+  typedef typename Type::Name Name;
+  InstanceType() : m_typeId(INSTANCETYPEID_NONE)
+  {
+    StaticTypeSystemInitialiser::instance().addInitialiser(InitialiseCaller(*this));
+  }
+  void initialise()
+  {
+    m_typeId = GlobalSceneGraph().getInstanceTypeId(Name());
+  }
+  typedef MemberCaller<InstanceType<Type>, &InstanceType<Type>::initialise> InitialiseCaller;
+  TypeId getTypeId()
+  {
+#if defined(_DEBUG)
+    ASSERT_MESSAGE(m_typeId != INSTANCETYPEID_NONE, "instance-type " << makeQuoted(Name()) << " used before being initialised");
+#endif
+    return m_typeId;
+  }
+};
+
+template<typename Type>
+class StaticInstanceType
+{
+public:
+  enum unnamed0 { SIZE = INSTANCETYPEID_MAX };
+  static TypeId getTypeId()
+  {
+    return Static< InstanceType<Type> >::instance().getTypeId();
+  }
+};
+
+template<typename Type, typename Base>
+class InstanceStaticCast :
+  public CastInstaller<
+    StaticInstanceType<Base>,
+    StaticCast<Type, Base>
+  >
+{
+};
+
+template<typename Type, typename Contained>
+class InstanceContainedCast :
+  public CastInstaller<
+    StaticInstanceType<Contained>,
+    ContainedCast<Type, Contained>
+  >
+{
+};
+
+template<typename Type>
+class InstanceIdentityCast :
+  public CastInstaller<
+    StaticInstanceType<Type>,
+    IdentityCast<Type>
+  >
+{
+};
+
+
+inline Selectable* Instance_getSelectable(scene::Instance& instance);
+inline const Selectable* Instance_getSelectable(const scene::Instance& instance);
+
+inline Bounded* Instance_getBounded(scene::Instance& instance);
+inline const Bounded* Instance_getBounded(const scene::Instance& instance);
+
+namespace scene
+{
+  class Instance
+  {
+    class AABBAccumulateWalker : public scene::Graph::Walker
+    {
+      AABB& m_aabb;
+      mutable std::size_t m_depth;
+    public:
+      AABBAccumulateWalker(AABB& aabb) : m_aabb(aabb), m_depth(0)
+      {
+      }
+      bool pre(const scene::Path& path, scene::Instance& instance) const
+      {
+        if(m_depth == 1)
+        {
+          aabb_extend_by_aabb_safe(m_aabb, instance.worldAABB());
+        }
+        return ++m_depth != 2;
+      }
+      void post(const scene::Path& path, scene::Instance& instance) const
+      {
+        --m_depth;
+      }
+    };
+
+
+    class TransformChangedWalker : public scene::Graph::Walker
+    {
+    public:
+      bool pre(const scene::Path& path, scene::Instance& instance) const
+      {
+        instance.transformChangedLocal();
+        return true;
+      }
+    };
+
+    class ParentSelectedChangedWalker : public scene::Graph::Walker
+    {
+    public:
+      bool pre(const scene::Path& path, scene::Instance& instance) const
+      {
+        instance.parentSelectedChanged();
+        return true;
+      }
+    };
+
+    class ChildSelectedWalker : public scene::Graph::Walker
+    {
+      bool& m_childSelected;
+      mutable std::size_t m_depth;
+    public:
+      ChildSelectedWalker(bool& childSelected) : m_childSelected(childSelected), m_depth(0)
+      {
+        m_childSelected = false;
+      }
+      bool pre(const scene::Path& path, scene::Instance& instance) const
+      {
+        if(m_depth == 1 && !m_childSelected)
+        {
+          m_childSelected = instance.isSelected() || instance.childSelected();
+        }
+        return ++m_depth != 2;
+      }
+      void post(const scene::Path& path, scene::Instance& instance) const
+      {
+        --m_depth;
+      }
+    };
+
+    Path m_path;
+    Instance* m_parent;
+    void* m_instance;
+    InstanceTypeCastTable& m_casts;
+
+    mutable Matrix4 m_local2world;
+    mutable AABB m_bounds;
+    mutable AABB m_childBounds;
+    mutable bool m_transformChanged;
+    mutable bool m_transformMutex;
+    mutable bool m_boundsChanged;
+    mutable bool m_boundsMutex;
+    mutable bool m_childBoundsChanged;
+    mutable bool m_childBoundsMutex;
+    mutable bool m_isSelected;
+    mutable bool m_isSelectedChanged;
+    mutable bool m_childSelected;
+    mutable bool m_childSelectedChanged;
+    mutable bool m_parentSelected;
+    mutable bool m_parentSelectedChanged;
+    Callback m_childSelectedChangedCallback;
+    Callback m_transformChangedCallback;
+
+
+    void evaluateTransform() const
+    {
+      if(m_transformChanged)
+      {
+        ASSERT_MESSAGE(!m_transformMutex, "re-entering transform evaluation");
+        m_transformMutex = true;
+
+        m_local2world = (m_parent != 0) ? m_parent->localToWorld() : g_matrix4_identity;
+        TransformNode* transformNode = Node_getTransformNode(m_path.top());
+        if(transformNode != 0)
+        {
+          matrix4_multiply_by_matrix4(m_local2world, transformNode->localToParent());
+        }
+
+        m_transformMutex = false;
+        m_transformChanged = false;
+      }
+    }
+    void evaluateChildBounds() const
+    {
+      if(m_childBoundsChanged)
+      {
+        ASSERT_MESSAGE(!m_childBoundsMutex, "re-entering bounds evaluation");
+        m_childBoundsMutex = true;
+
+        m_childBounds = AABB();
+
+        GlobalSceneGraph().traverse_subgraph(AABBAccumulateWalker(m_childBounds), m_path);
+
+        m_childBoundsMutex = false;
+        m_childBoundsChanged = false;
+      }
+    }
+    void evaluateBounds() const
+    {
+      if(m_boundsChanged)
+      {
+        ASSERT_MESSAGE(!m_boundsMutex, "re-entering bounds evaluation");
+        m_boundsMutex = true;
+
+        m_bounds = childBounds();
+
+        const Bounded* bounded = Instance_getBounded(*this);
+        if(bounded != 0)
+        {
+          aabb_extend_by_aabb_safe(
+            m_bounds,
+            aabb_for_oriented_aabb_safe(bounded->localAABB(), localToWorld())
+          );
+        }
+
+        m_boundsMutex = false;
+        m_boundsChanged = false;
+      }
+    }
+
+    Instance(const scene::Instance& other);
+    Instance& operator=(const scene::Instance& other);
+  public:
+
+    Instance(const scene::Path& path, Instance* parent, void* instance, InstanceTypeCastTable& casts) :
+      m_path(path),
+      m_parent(parent),
+      m_instance(instance),
+      m_casts(casts),
+      m_local2world(g_matrix4_identity),
+      m_transformChanged(true),
+      m_transformMutex(false),
+      m_boundsChanged(true),
+      m_boundsMutex(false),
+      m_childBoundsChanged(true),
+      m_childBoundsMutex(false),
+      m_isSelectedChanged(true),
+      m_childSelectedChanged(true),
+      m_parentSelectedChanged(true)
+    {
+      ASSERT_MESSAGE((parent == 0) == (path.size() == 1), "instance has invalid parent");
+    }
+    virtual ~Instance()
+    {
+    }
+
+    const scene::Path& path() const
+    {
+      return m_path;
+    }
+
+    void* cast(TypeId typeId) const
+    {
+      return m_casts.cast(typeId, m_instance);
+    }
+
+    const Matrix4& localToWorld() const
+    {
+      evaluateTransform();
+      return m_local2world;
+    }
+    void transformChangedLocal()
+    {
+      ASSERT_NOTNULL(m_parent);
+      m_transformChanged = true;
+      m_boundsChanged = true;
+      m_childBoundsChanged = true;
+      m_transformChangedCallback();
+    }
+    void transformChanged()
+    {
+      GlobalSceneGraph().traverse_subgraph(TransformChangedWalker(), m_path);
+      boundsChanged();
+    }
+    void setTransformChangedCallback(const Callback& callback)
+    {
+      m_transformChangedCallback = callback;
+    }
+
+
+    const AABB& worldAABB() const
+    {
+      evaluateBounds();
+      return m_bounds;
+    }
+    const AABB& childBounds() const
+    {
+      evaluateChildBounds();
+      return m_childBounds;
+    }
+    void boundsChanged()
+    {
+      m_boundsChanged = true;
+      m_childBoundsChanged = true;
+      if(m_parent != 0)
+      {
+        m_parent->boundsChanged();
+      }
+      GlobalSceneGraph().boundsChanged();
+    }
+
+    void childSelectedChanged()
+    {
+      m_childSelectedChanged = true;
+      m_childSelectedChangedCallback();
+      if(m_parent != 0)
+      {
+        m_parent->childSelectedChanged();
+      }
+    }
+    bool childSelected() const
+    {
+      if(m_childSelectedChanged)
+      {
+        m_childSelectedChanged = false;
+        GlobalSceneGraph().traverse_subgraph(ChildSelectedWalker(m_childSelected), m_path);
+      }
+      return m_childSelected;
+    }
+
+    void setChildSelectedChangedCallback(const Callback& callback)
+    {
+      m_childSelectedChangedCallback = callback;
+    }
+    void selectedChanged()
+    {
+      m_isSelectedChanged = true;
+      if(m_parent != 0)
+      {
+        m_parent->childSelectedChanged();
+      }
+      GlobalSceneGraph().traverse_subgraph(ParentSelectedChangedWalker(), m_path);
+    }
+    bool isSelected() const
+    {
+      if(m_isSelectedChanged)
+      {
+        m_isSelectedChanged = false;
+        const Selectable* selectable = Instance_getSelectable(*this);
+        m_isSelected = selectable != 0 && selectable->isSelected();
+      }
+      return m_isSelected;
+    }
+
+    void parentSelectedChanged()
+    {
+      m_parentSelectedChanged = true;
+    }
+    bool parentSelected() const
+    {
+      if(m_parentSelectedChanged)
+      {
+        m_parentSelectedChanged = false;
+        m_parentSelected = m_parent != 0 && (m_parent->isSelected() || m_parent->parentSelected());
+      }
+      return m_parentSelected;
+    }
+  };
+}
+
+template<typename Type>
+class InstanceTypeCast
+{
+public:
+  static Type* cast(scene::Instance& instance)
+  {
+    return static_cast<Type*>(instance.cast(StaticInstanceType<Type>::getTypeId()));
+  }
+  static const Type* cast(const scene::Instance& instance)
+  {
+    return static_cast<const Type*>(instance.cast(StaticInstanceType<Type>::getTypeId()));
+  }
+};
+
+template<typename Functor>
+class InstanceWalker : public scene::Graph::Walker
+{
+  const Functor& m_functor;
+public:
+  InstanceWalker(const Functor& functor) : m_functor(functor)
+  {
+  }
+  bool pre(const scene::Path& path, scene::Instance& instance) const
+  {
+    m_functor(instance);
+    return true;
+  }
+};
+
+template<typename Functor>
+class ChildInstanceWalker : public scene::Graph::Walker
+{
+  const Functor& m_functor;
+  mutable std::size_t m_depth;
+public:
+  ChildInstanceWalker(const Functor& functor) : m_functor(functor), m_depth(0)
+  {
+  }
+  bool pre(const scene::Path& path, scene::Instance& instance) const
+  {
+    if(m_depth == 1)
+    {
+      m_functor(instance);
+    }
+    return ++m_depth != 2;
+  }
+  void post(const scene::Path& path, scene::Instance& instance) const
+  {
+    --m_depth;
+  }
+};
+
+template<typename Type, typename Functor>
+class InstanceApply : public Functor
+{
+public:
+  InstanceApply(const Functor& functor) : Functor(functor)
+  {
+  }
+  void operator()(scene::Instance& instance) const
+  {
+    Type* result = InstanceTypeCast<Type>::cast(instance);
+    if(result != 0)
+    {
+      Functor::operator()(*result);
+    }
+  }
+};
+
+inline Selectable* Instance_getSelectable(scene::Instance& instance)
+{
+  return InstanceTypeCast<Selectable>::cast(instance);
+}
+inline const Selectable* Instance_getSelectable(const scene::Instance& instance)
+{
+  return InstanceTypeCast<Selectable>::cast(instance);
+}
+
+template<typename Functor>
+inline void Scene_forEachChildSelectable(const Functor& functor, const scene::Path& path)
+{
+  GlobalSceneGraph().traverse_subgraph(ChildInstanceWalker< InstanceApply<Selectable, Functor> >(functor), path);
+}
+
+class SelectableSetSelected
+{
+  bool m_selected;
+public:
+  SelectableSetSelected(bool selected) : m_selected(selected)
+  {
+  }
+  void operator()(Selectable& selectable) const
+  {
+    selectable.setSelected(m_selected);
+  }
+};
+
+inline Bounded* Instance_getBounded(scene::Instance& instance)
+{
+  return InstanceTypeCast<Bounded>::cast(instance);
+}
+inline const Bounded* Instance_getBounded(const scene::Instance& instance)
+{
+  return InstanceTypeCast<Bounded>::cast(instance);
+}
+
+inline Transformable* Instance_getTransformable(scene::Instance& instance)
+{
+  return InstanceTypeCast<Transformable>::cast(instance);
+}
+inline const Transformable* Instance_getTransformable(const scene::Instance& instance)
+{
+  return InstanceTypeCast<Transformable>::cast(instance);
+}
+
+
+inline ComponentSelectionTestable* Instance_getComponentSelectionTestable(scene::Instance& instance)
+{
+  return InstanceTypeCast<ComponentSelectionTestable>::cast(instance);
+}
+
+inline ComponentEditable* Instance_getComponentEditable(scene::Instance& instance)
+{
+  return InstanceTypeCast<ComponentEditable>::cast(instance);
+}
+
+inline ComponentSnappable* Instance_getComponentSnappable(scene::Instance& instance)
+{
+  return InstanceTypeCast<ComponentSnappable>::cast(instance);
+}
+
+
+inline void Instance_setSelected(scene::Instance& instance, bool selected)
+{
+  Selectable* selectable = Instance_getSelectable(instance);
+  if(selectable != 0)
+  {
+    selectable->setSelected(selected);
+  }
+}
+
+inline bool Instance_isSelected(scene::Instance& instance)
+{
+  Selectable* selectable = Instance_getSelectable(instance);
+  if(selectable != 0)
+  {
+    return selectable->isSelected();
+  }
+  return false;
+}
+
+inline scene::Instance& findInstance(const scene::Path& path)
+{
+  scene::Instance* instance = GlobalSceneGraph().find(path);
+  ASSERT_MESSAGE(instance != 0, "findInstance: path not found in scene-graph");
+  return *instance;
+}
+
+inline void selectPath(const scene::Path& path, bool selected)
+{
+  Instance_setSelected(findInstance(path), selected);
+}
+
+class SelectChildren : public scene::Traversable::Walker
+{
+  mutable scene::Path m_path;
+public:
+  SelectChildren(const scene::Path& root)
+    : m_path(root)
+  {
+  }
+  bool pre(scene::Node& node) const
+  {
+    m_path.push(makeReference(node));
+    selectPath(m_path, true);
+    return false;
+  }
+  void post(scene::Node& node) const
+  {
+    m_path.pop();
+  }
+};
+
+inline void Entity_setSelected(scene::Instance& entity, bool selected)
+{
+  scene::Node& node = entity.path().top();
+  if(node_is_group(node))
+  {
+    Node_getTraversable(node)->traverse(SelectChildren(entity.path()));
+  }
+  else
+  {
+    Instance_setSelected(entity, selected);
+  }
+}
+
+inline bool Entity_isSelected(scene::Instance& entity)
+{
+  if(node_is_group(entity.path().top()))
+  {
+    return entity.childSelected();
+  }
+  return Instance_isSelected(entity);
+}
+
+
+
+class InstanceCounter
+{
+public:
+  unsigned int m_count;
+  InstanceCounter() : m_count(0)
+  {
+  }
+};
+
+
+class Counter
+{
+public:
+  virtual void increment() = 0;
+  virtual void decrement() = 0;
+};
+
+#include "generic/callback.h"
+
+class SimpleCounter : public Counter
+{
+  Callback m_countChanged;
+  std::size_t m_count;
+public:
+  void setCountChangedCallback(const Callback& countChanged)
+  {
+    m_countChanged = countChanged;
+  }
+  void increment()
+  {
+    ++m_count;
+    m_countChanged();
+  }
+  void decrement()
+  {
+    --m_count;
+    m_countChanged();
+  }
+  std::size_t get() const
+  {
+    return m_count;
+  }
+};
+
+
+template<typename Contained>
+class ConstReference;
+typedef ConstReference<scene::Path> PathConstReference;
+
+#include "generic/referencecounted.h"
+typedef SmartReference<scene::Node, IncRefDecRefCounter<scene::Node> > NodeSmartReference;
+
+
+#endif