#ifndef Magnum_SceneGraph_Object_h #define Magnum_SceneGraph_Object_h /* This file is part of Magnum. Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** @file * @brief Class Magnum::SceneGraph::Object */ #include #include "AbstractFeature.h" #include "AbstractObject.h" #include "magnumSceneGraphVisibility.h" namespace Magnum { namespace SceneGraph { namespace Implementation { enum class ObjectFlag: UnsignedByte { Dirty = 1 << 0, Visited = 1 << 1, Joint = 1 << 2 }; typedef Containers::EnumSet ObjectFlags; CORRADE_ENUMSET_OPERATORS(ObjectFlags) } /** @brief %Object Base of scene graph. Contains specific transformation implementation, takes care of parent/children relationship and contains features. See @ref scenegraph for introduction. Common usage is to typedef Object with desired transformation type to save unnecessary typing later, along with Scene and possibly other types, e.g.: @code typedef SceneGraph::Scene Scene3D; typedef SceneGraph::Object Object3D; @endcode Uses Corrade::Containers::LinkedList for parent/children relationship. Traversing through the list is done like in the following code. It is also possible to go in reverse order using lastChild() and previousSibling(). @code for(Object* child = o->firstChild(); child; child = child->nextSibling()) { // ... } @endcode @section Object-explicit-specializations Explicit template specializations The following specialization are explicitly compiled into SceneGraph library. For other specializations (e.g. using Double type or special transformation class) you have to use Object.hpp implementation file to avoid linker errors. See @ref compilation-speedup-hpp for more information. - @ref DualComplexTransformation "Object>" - @ref DualQuaternionTransformation "Object>" - @ref MatrixTransformation2D "Object>" - @ref MatrixTransformation3D "Object>" - @ref RigidMatrixTransformation2D "Object>" - @ref RigidMatrixTransformation3D "Object>" @see Scene, AbstractFeature, AbstractTransformation, DebugTools::ObjectRenderer */ template class MAGNUM_SCENEGRAPH_EXPORT Object: public AbstractObject, public Transformation #ifndef DOXYGEN_GENERATING_OUTPUT , private Containers::LinkedList>, private Containers::LinkedListItem, Object> #endif { friend class Containers::LinkedList>; friend class Containers::LinkedListItem, Object>; #ifndef DOXYGEN_GENERATING_OUTPUT Object(const Object&) = delete; Object(Object&&) = delete; Object& operator=(const Object&) = delete; Object& operator=(Object&&) = delete; #endif public: /** @brief Matrix type */ typedef typename DimensionTraits::MatrixType MatrixType; /** * @brief Constructor * @param parent Parent object */ explicit Object(Object* parent = nullptr): counter(0xFFFFu), flags(Flag::Dirty) { setParent(parent); } /** * @brief Destructor * * Removes itself from parent's children list and destroys all own * children. */ ~Object(); /** * @{ @name Scene hierarchy * * See @ref scenegraph-hierarchy for more information. */ /** @copydoc AbstractObject::scene() */ Scene* scene(); const Scene* scene() const; /**< @overload */ /** @brief Parent object or `nullptr`, if this is root object */ Object* parent() { return Containers::LinkedListItem, Object>::list(); } /** @overload */ const Object* parent() const { return Containers::LinkedListItem, Object>::list(); } /** @brief Previous sibling object or `nullptr`, if this is first object */ Object* previousSibling() { return Containers::LinkedListItem, Object>::previous(); } /** @overload */ const Object* previousSibling() const { return Containers::LinkedListItem, Object>::previous(); } /** @brief Next sibling object or `nullptr`, if this is last object */ Object* nextSibling() { return Containers::LinkedListItem, Object>::next(); } /** @overload */ const Object* nextSibling() const { return Containers::LinkedListItem, Object>::next(); } /** @brief Whether this object has children */ bool hasChildren() const { return !Containers::LinkedList>::isEmpty(); } /** @brief First child object or `nullptr`, if this object has no children */ Object* firstChild() { return Containers::LinkedList>::first(); } /** @overload */ const Object* firstChild() const { return Containers::LinkedList>::first(); } /** @brief Last child object or `nullptr`, if this object has no children */ Object* lastChild() { return Containers::LinkedList>::last(); } /** @overload */ const Object* lastChild() const { return Containers::LinkedList>::last(); } /** * @brief Set parent object * @return Reference to self (for method chaining) * * @see setParentKeepTransformation() */ Object& setParent(Object* parent); /** * @brief Set parent object and keep absolute transformation * @return Reference to self (for method chaining) * * While setParent() preserves only relative transformation of the * object, this funcition preserves absolute transformation. */ Object& setParentKeepTransformation(Object* parent); /*@}*/ /** @{ @name Object transformation */ /** * @brief Transformation matrix * * @see transformation() */ MatrixType transformationMatrix() const { return Transformation::toMatrix(Transformation::transformation()); } /** * @brief Transformation matrix relative to root object * * @see absoluteTransformation() */ MatrixType absoluteTransformationMatrix() const { return Transformation::toMatrix(absoluteTransformation()); } /** * @brief Transformation relative to root object * * @see absoluteTransformationMatrix() */ typename Transformation::DataType absoluteTransformation() const; /** * @brief Transformation matrices of given set of objects relative to this object * * All transformations are premultiplied with @p initialTransformationMatrix, * if specified. * @see transformations() */ std::vector transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const; /** * @brief Transformations of given group of objects relative to this object * * All transformations can be premultiplied with @p initialTransformation, * if specified. * @see transformationMatrices() */ /* `objects` passed by copy intentionally (to allow move from transformationMatrices() and avoid copy in the function itself) */ std::vector transformations(std::vector*> objects, const typename Transformation::DataType& initialTransformation = typename Transformation::DataType()) const; /*@}*/ /** * @{ @name Transformation caching * * See @ref scenegraph-caching for more information. */ /** * @brief Clean absolute transformations of given set of objects * * Only dirty objects in the list are cleaned. * @see setClean() */ /* `objects` passed by copy intentionally (to avoid copy internally) */ static void setClean(std::vector*> objects); /** @copydoc AbstractObject::isDirty() */ bool isDirty() const { return !!(flags & Flag::Dirty); } /** @copydoc AbstractObject::setDirty() */ void setDirty(); /** @copydoc AbstractObject::setClean() */ void setClean(); /*@}*/ #ifndef DOXYGEN_GENERATING_OUTPUT public: virtual bool isScene() const { return false; } #endif private: Object* doScene() override final; const Object* doScene() const override final; MatrixType MAGNUM_SCENEGRAPH_LOCAL doTransformationMatrix() const override final { return transformationMatrix(); } MatrixType MAGNUM_SCENEGRAPH_LOCAL doAbsoluteTransformationMatrix() const override final { return absoluteTransformationMatrix(); } std::vector doTransformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix) const override final; typename Transformation::DataType MAGNUM_SCENEGRAPH_LOCAL computeJointTransformation(const std::vector*>& jointObjects, std::vector& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const; bool MAGNUM_SCENEGRAPH_LOCAL doIsDirty() const override final { return isDirty(); } void MAGNUM_SCENEGRAPH_LOCAL doSetDirty() override final { setDirty(); } void MAGNUM_SCENEGRAPH_LOCAL doSetClean() override final { setClean(); } void doSetClean(const std::vector*>& objects) override final; void MAGNUM_SCENEGRAPH_LOCAL setClean(const typename Transformation::DataType& absoluteTransformation); typedef Implementation::ObjectFlag Flag; typedef Implementation::ObjectFlags Flags; UnsignedShort counter; Flags flags; }; }} #endif