#ifndef Magnum_Physics_ShapeGroup_h #define Magnum_Physics_ShapeGroup_h /* Copyright © 2010, 2011, 2012 Vladimír Vondruš This file is part of Magnum. Magnum is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 only, as published by the Free Software Foundation. Magnum 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 Lesser General Public License version 3 for more details. */ /** @file * @brief Class Magnum::Physics::ShapeGroup */ #include "AbstractShape.h" namespace Magnum { namespace Physics { #ifndef DOXYGEN_GENERATING_OUTPUT #define enableIfIsBaseType typename std::enable_if::value, ShapeGroup>::type #define enableIfAreBaseType typename std::enable_if::value && std::is_base_of::value, ShapeGroup>::type #endif /** @brief Collider group with defined set operation Result of union, intersection, substraction or XOR of two collider objects. See @ref CollisionDetection for brief introduction. */ class PHYSICS_EXPORT ShapeGroup: public AbstractShape { #ifndef DOXYGEN_GENERATING_OUTPUT template friend constexpr enableIfIsBaseType operator~(const T& a); template friend constexpr enableIfIsBaseType operator~(T&& a); template friend constexpr enableIfIsBaseType operator~(T& a); #define friendOp(char) \ template friend constexpr enableIfAreBaseType operator char(const T& a, const U& b); \ template friend constexpr enableIfAreBaseType operator char(const T& a, U&& b); \ template friend constexpr enableIfAreBaseType operator char(T&& a, const U& b); \ template friend constexpr enableIfAreBaseType operator char(T&& a, U&& b); \ template friend constexpr enableIfAreBaseType operator char(const T& a, std::reference_wrapper b); \ template friend constexpr enableIfAreBaseType operator char(T&& a, std::reference_wrapper b); \ template friend constexpr enableIfAreBaseType operator char(std::reference_wrapper a, const U& b); \ template friend constexpr enableIfAreBaseType operator char(std::reference_wrapper a, U&& b); \ template friend constexpr enableIfAreBaseType operator char(std::reference_wrapper a, std::reference_wrapper b); friendOp(|) friendOp(&) friendOp(-) friendOp(^) #undef friendOp #endif ShapeGroup(const ShapeGroup& other) = delete; ShapeGroup& operator=(const ShapeGroup& other) = delete; private: enum Operation { RefA = 0x01, RefB = 0x02, RefAB = 0x03, Complement = 1 << 2, Union = 2 << 2, Intersection = 3 << 2, Difference = 4 << 2, Xor = 5 << 2, FirstObjectOnly = 6 << 2, AlwaysFalse = 7 << 2 }; public: /** @brief Default constructor */ inline ShapeGroup(): operation(AlwaysFalse), a(nullptr), b(nullptr) {} /** @brief Move constructor */ ShapeGroup(ShapeGroup&& other); /** @brief Destructor */ ~ShapeGroup(); /** @brief Move assignment */ ShapeGroup& operator=(ShapeGroup&& other); void applyTransformation(const Matrix4& transformation); bool collides(const AbstractShape* other) const; protected: virtual Type type() const { return Type::ShapeGroup; } private: inline constexpr ShapeGroup(int operation, AbstractShape* a, AbstractShape* b): operation(operation), a(a), b(b) {} int operation; AbstractShape* a; AbstractShape* b; }; /** @brief Complement of shape */ template inline constexpr enableIfIsBaseType operator~(const T& a) { return ShapeGroup(ShapeGroup::Complement, new T(a), nullptr); } #ifndef DOXYGEN_GENERATING_OUTPUT template inline constexpr enableIfIsBaseType operator~(T&& a) { return ShapeGroup(ShapeGroup::Complement, new T(std::forward(a)), nullptr); } template inline constexpr enableIfIsBaseType operator~(T& a) { return ShapeGroup(ShapeGroup::Complement|ShapeGroup::RefA, &a.get(), nullptr); } #endif #ifdef DOXYGEN_GENERATING_OUTPUT /** @brief Union of two shapes */ template inline constexpr ShapeGroup operator&(T a, U b); /** @brief Intersection of two shapes Collision with @p a is computed first, so this operation can be also used for providing simplified version for shape @p b. See @ref CollisionDetectionShapeGroups for an example. */ template inline constexpr ShapeGroup operator&(T a, U b); /** @brief Difference of two shapes */ template inline constexpr ShapeGroup operator-(T a, U b); /** @brief XOR of two shapes */ template inline constexpr ShapeGroup operator^(T a, U b); #else #define op(type, char) \ template inline constexpr enableIfAreBaseType operator char(const T& a, const U& b) { \ return ShapeGroup(ShapeGroup::type, new T(a), new U(b)); \ } \ template inline constexpr enableIfAreBaseType operator char(const T& a, U&& b) { \ return ShapeGroup(ShapeGroup::type, new T(a), new U(std::forward(b))); \ } \ template inline constexpr enableIfAreBaseType operator char(T&& a, const U& b) { \ return ShapeGroup(ShapeGroup::type, new T(std::forward(a)), new U(b)); \ } \ template inline constexpr enableIfAreBaseType operator char(T&& a, U&& b) { \ return ShapeGroup(ShapeGroup::type, new T(std::forward(a)), new U(std::forward(b))); \ } \ template inline constexpr enableIfAreBaseType operator char(const T& a, std::reference_wrapper b) { \ return ShapeGroup(ShapeGroup::type|ShapeGroup::RefB, new T(a), &b.get()); \ } \ template inline constexpr enableIfAreBaseType operator char(T&& a, std::reference_wrapper b) { \ return ShapeGroup(ShapeGroup::type|ShapeGroup::RefB, new T(std::forward(a)), &b.get()); \ } \ template inline constexpr enableIfAreBaseType operator char(std::reference_wrapper a, const U& b) { \ return ShapeGroup(ShapeGroup::type|ShapeGroup::RefA, &a.get(), new U(b)); \ } \ template inline constexpr enableIfAreBaseType operator char(std::reference_wrapper a, U&& b) { \ return ShapeGroup(ShapeGroup::type|ShapeGroup::RefA, &a.get(), new U(std::forward(b))); \ } \ template inline constexpr enableIfAreBaseType operator char(std::reference_wrapper a, std::reference_wrapper b) { \ return ShapeGroup(ShapeGroup::type|ShapeGroup::RefAB, &a.get(), &b.get()); \ } op(Union, |) op(Intersection, &) op(Difference, -) op(Xor, ^) #undef op #endif #undef enableIfIsBaseType #undef enableIfAreBaseType }} #endif