You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
7.7 KiB

#ifndef Magnum_Physics_ShapeGroup_h
#define Magnum_Physics_ShapeGroup_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
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<std::is_base_of<AbstractShape, T>::value, ShapeGroup>::type
#define enableIfAreBaseType typename std::enable_if<std::is_base_of<AbstractShape, T>::value && std::is_base_of<AbstractShape, U>::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<class T> friend constexpr enableIfIsBaseType operator~(const T& a);
template<class T> friend constexpr enableIfIsBaseType operator~(T&& a);
template<class T> friend constexpr enableIfIsBaseType operator~(T& a);
#define friendOp(char) \
template<class T, class U> friend constexpr enableIfAreBaseType operator char(const T& a, const U& b); \
template<class T, class U> friend constexpr enableIfAreBaseType operator char(const T& a, U&& b); \
template<class T, class U> friend constexpr enableIfAreBaseType operator char(T&& a, const U& b); \
template<class T, class U> friend constexpr enableIfAreBaseType operator char(T&& a, U&& b); \
template<class T, class U> friend constexpr enableIfAreBaseType operator char(const T& a, std::reference_wrapper<U> b); \
template<class T, class U> friend constexpr enableIfAreBaseType operator char(T&& a, std::reference_wrapper<U> b); \
template<class T, class U> friend constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, const U& b); \
template<class T, class U> friend constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, U&& b); \
template<class T, class U> friend constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, std::reference_wrapper<U> 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<class T> inline constexpr enableIfIsBaseType operator~(const T& a) {
return ShapeGroup(ShapeGroup::Complement, new T(a), nullptr);
}
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class T> inline constexpr enableIfIsBaseType operator~(T&& a) {
return ShapeGroup(ShapeGroup::Complement, new T(std::forward<T>(a)), nullptr);
}
template<class T> 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<class T, class U> 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<class T, class U> inline constexpr ShapeGroup operator&(T a, U b);
/** @brief Difference of two shapes */
template<class T, class U> inline constexpr ShapeGroup operator-(T a, U b);
/** @brief XOR of two shapes */
template<class T, class U> inline constexpr ShapeGroup operator^(T a, U b);
#else
#define op(type, char) \
template<class T, class U> inline constexpr enableIfAreBaseType operator char(const T& a, const U& b) { \
return ShapeGroup(ShapeGroup::type, new T(a), new U(b)); \
} \
template<class T, class U> inline constexpr enableIfAreBaseType operator char(const T& a, U&& b) { \
return ShapeGroup(ShapeGroup::type, new T(a), new U(std::forward<U>(b))); \
} \
template<class T, class U> inline constexpr enableIfAreBaseType operator char(T&& a, const U& b) { \
return ShapeGroup(ShapeGroup::type, new T(std::forward<T>(a)), new U(b)); \
} \
template<class T, class U> inline constexpr enableIfAreBaseType operator char(T&& a, U&& b) { \
return ShapeGroup(ShapeGroup::type, new T(std::forward<T>(a)), new U(std::forward<U>(b))); \
} \
template<class T, class U> inline constexpr enableIfAreBaseType operator char(const T& a, std::reference_wrapper<U> b) { \
return ShapeGroup(ShapeGroup::type|ShapeGroup::RefB, new T(a), &b.get()); \
} \
template<class T, class U> inline constexpr enableIfAreBaseType operator char(T&& a, std::reference_wrapper<U> b) { \
return ShapeGroup(ShapeGroup::type|ShapeGroup::RefB, new T(std::forward<T>(a)), &b.get()); \
} \
template<class T, class U> inline constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, const U& b) { \
return ShapeGroup(ShapeGroup::type|ShapeGroup::RefA, &a.get(), new U(b)); \
} \
template<class T, class U> inline constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, U&& b) { \
return ShapeGroup(ShapeGroup::type|ShapeGroup::RefA, &a.get(), new U(std::forward<U>(b))); \
} \
template<class T, class U> inline constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, std::reference_wrapper<U> 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