|
|
|
|
@ -28,7 +28,9 @@
|
|
|
|
|
#include <Corrade/TestSuite/Tester.h> |
|
|
|
|
#include <Corrade/Utility/DebugStl.h> |
|
|
|
|
|
|
|
|
|
#include "Magnum/SceneGraph/MatrixTransformation3D.h" |
|
|
|
|
#include "Magnum/SceneGraph/AbstractFeature.hpp" |
|
|
|
|
#include "Magnum/SceneGraph/MatrixTransformation3D.hpp" |
|
|
|
|
#include "Magnum/SceneGraph/Object.hpp" |
|
|
|
|
#include "Magnum/SceneGraph/Scene.h" |
|
|
|
|
|
|
|
|
|
namespace Magnum { namespace SceneGraph { namespace Test { namespace { |
|
|
|
|
@ -36,86 +38,108 @@ namespace Magnum { namespace SceneGraph { namespace Test { namespace {
|
|
|
|
|
struct ObjectTest: TestSuite::Tester { |
|
|
|
|
explicit ObjectTest(); |
|
|
|
|
|
|
|
|
|
void addFeature(); |
|
|
|
|
|
|
|
|
|
void parenting(); |
|
|
|
|
void addChild(); |
|
|
|
|
void move(); |
|
|
|
|
void scene(); |
|
|
|
|
void setParentKeepTransformation(); |
|
|
|
|
void setParentKeepTransformationInvalid(); |
|
|
|
|
void absoluteTransformation(); |
|
|
|
|
void transformations(); |
|
|
|
|
void transformationsRelative(); |
|
|
|
|
void transformationsOrphan(); |
|
|
|
|
void transformationsDuplicate(); |
|
|
|
|
void setClean(); |
|
|
|
|
void setCleanListHierarchy(); |
|
|
|
|
void setCleanListBulk(); |
|
|
|
|
|
|
|
|
|
void rangeBasedForChildren(); |
|
|
|
|
void rangeBasedForFeatures(); |
|
|
|
|
template<class T> void addFeature(); |
|
|
|
|
|
|
|
|
|
template<class T> void parenting(); |
|
|
|
|
template<class T> void addChild(); |
|
|
|
|
template<class T> void move(); |
|
|
|
|
template<class T> void scene(); |
|
|
|
|
template<class T> void setParentKeepTransformation(); |
|
|
|
|
template<class T> void setParentKeepTransformationInvalid(); |
|
|
|
|
template<class T> void absoluteTransformation(); |
|
|
|
|
template<class T> void transformations(); |
|
|
|
|
template<class T> void transformationsRelative(); |
|
|
|
|
template<class T> void transformationsOrphan(); |
|
|
|
|
template<class T> void transformationsDuplicate(); |
|
|
|
|
template<class T> void setClean(); |
|
|
|
|
template<class T> void setCleanListHierarchy(); |
|
|
|
|
template<class T> void setCleanListBulk(); |
|
|
|
|
|
|
|
|
|
template<class T> void rangeBasedForChildren(); |
|
|
|
|
template<class T> void rangeBasedForFeatures(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D> Object3D; |
|
|
|
|
typedef SceneGraph::Scene<SceneGraph::MatrixTransformation3D> Scene3D; |
|
|
|
|
ObjectTest::ObjectTest() { |
|
|
|
|
addTests<ObjectTest>({ |
|
|
|
|
&ObjectTest::addFeature<Float>, |
|
|
|
|
&ObjectTest::addFeature<Double>, |
|
|
|
|
|
|
|
|
|
&ObjectTest::parenting<Float>, |
|
|
|
|
&ObjectTest::parenting<Double>, |
|
|
|
|
&ObjectTest::addChild<Float>, |
|
|
|
|
&ObjectTest::addChild<Double>, |
|
|
|
|
&ObjectTest::move<Float>, |
|
|
|
|
&ObjectTest::move<Double>, |
|
|
|
|
&ObjectTest::scene<Float>, |
|
|
|
|
&ObjectTest::scene<Double>, |
|
|
|
|
&ObjectTest::setParentKeepTransformation<Float>, |
|
|
|
|
&ObjectTest::setParentKeepTransformation<Double>, |
|
|
|
|
&ObjectTest::setParentKeepTransformationInvalid<Float>, |
|
|
|
|
&ObjectTest::setParentKeepTransformationInvalid<Double>, |
|
|
|
|
&ObjectTest::absoluteTransformation<Float>, |
|
|
|
|
&ObjectTest::absoluteTransformation<Double>, |
|
|
|
|
&ObjectTest::transformations<Float>, |
|
|
|
|
&ObjectTest::transformations<Double>, |
|
|
|
|
&ObjectTest::transformationsRelative<Float>, |
|
|
|
|
&ObjectTest::transformationsRelative<Double>, |
|
|
|
|
&ObjectTest::transformationsOrphan<Float>, |
|
|
|
|
&ObjectTest::transformationsOrphan<Double>, |
|
|
|
|
&ObjectTest::transformationsDuplicate<Float>, |
|
|
|
|
&ObjectTest::transformationsDuplicate<Double>, |
|
|
|
|
&ObjectTest::setClean<Float>, |
|
|
|
|
&ObjectTest::setClean<Double>, |
|
|
|
|
&ObjectTest::setCleanListHierarchy<Float>, |
|
|
|
|
&ObjectTest::setCleanListHierarchy<Double>, |
|
|
|
|
&ObjectTest::setCleanListBulk<Float>, |
|
|
|
|
&ObjectTest::setCleanListBulk<Double>, |
|
|
|
|
|
|
|
|
|
&ObjectTest::rangeBasedForChildren<Float>, |
|
|
|
|
&ObjectTest::rangeBasedForChildren<Double>, |
|
|
|
|
&ObjectTest::rangeBasedForFeatures<Float>, |
|
|
|
|
&ObjectTest::rangeBasedForFeatures<Double>}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template<class T> using Object3D = SceneGraph::Object<SceneGraph::BasicMatrixTransformation3D<T>>; |
|
|
|
|
template<class T> using Scene3D = SceneGraph::Scene<SceneGraph::BasicMatrixTransformation3D<T>>; |
|
|
|
|
|
|
|
|
|
class CachingObject: public Object3D, AbstractFeature3D { |
|
|
|
|
template<class T> class CachingObject: public Object3D<T>, AbstractBasicFeature3D<T> { |
|
|
|
|
public: |
|
|
|
|
CachingObject(Object3D* parent = nullptr): Object3D(parent), AbstractFeature3D(*this) { |
|
|
|
|
setCachedTransformations(CachedTransformation::Absolute); |
|
|
|
|
CachingObject(Object3D<T>* parent = nullptr): Object3D<T>(parent), AbstractBasicFeature3D<T>{*this} { |
|
|
|
|
this->setCachedTransformations(CachedTransformation::Absolute); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Matrix4 cleanedAbsoluteTransformation; |
|
|
|
|
Math::Matrix4<T> cleanedAbsoluteTransformation; |
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
void clean(const Matrix4& absoluteTransformation) override { |
|
|
|
|
void clean(const Math::Matrix4<T>& absoluteTransformation) override { |
|
|
|
|
cleanedAbsoluteTransformation = absoluteTransformation; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
ObjectTest::ObjectTest() { |
|
|
|
|
addTests({&ObjectTest::addFeature, |
|
|
|
|
|
|
|
|
|
&ObjectTest::parenting, |
|
|
|
|
&ObjectTest::addChild, |
|
|
|
|
&ObjectTest::move, |
|
|
|
|
&ObjectTest::scene, |
|
|
|
|
&ObjectTest::setParentKeepTransformation, |
|
|
|
|
&ObjectTest::setParentKeepTransformationInvalid, |
|
|
|
|
&ObjectTest::absoluteTransformation, |
|
|
|
|
&ObjectTest::transformations, |
|
|
|
|
&ObjectTest::transformationsRelative, |
|
|
|
|
&ObjectTest::transformationsOrphan, |
|
|
|
|
&ObjectTest::transformationsDuplicate, |
|
|
|
|
&ObjectTest::setClean, |
|
|
|
|
&ObjectTest::setCleanListHierarchy, |
|
|
|
|
&ObjectTest::setCleanListBulk, |
|
|
|
|
|
|
|
|
|
&ObjectTest::rangeBasedForChildren, |
|
|
|
|
&ObjectTest::rangeBasedForFeatures}); |
|
|
|
|
} |
|
|
|
|
template<class T> void ObjectTest::addFeature() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
void ObjectTest::addFeature() { |
|
|
|
|
class MyFeature: public AbstractFeature3D { |
|
|
|
|
class MyFeature: public AbstractBasicFeature3D<T> { |
|
|
|
|
public: |
|
|
|
|
explicit MyFeature(AbstractObject3D& object, Int&, Containers::Pointer<int>&&): AbstractFeature3D{object} {} |
|
|
|
|
explicit MyFeature(AbstractBasicObject3D<T>& object, Int&, Containers::Pointer<int>&&): AbstractBasicFeature3D<T>{object} {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Object3D o; |
|
|
|
|
Object3D<T> o; |
|
|
|
|
CORRADE_VERIFY(o.features().isEmpty()); |
|
|
|
|
/* Test perfect forwarding as well */ |
|
|
|
|
int a = 0; |
|
|
|
|
MyFeature& f = o.addFeature<MyFeature>(a, Containers::Pointer<int>{}); |
|
|
|
|
MyFeature& f = o.template addFeature<MyFeature>(a, Containers::Pointer<int>{}); |
|
|
|
|
CORRADE_VERIFY(!o.features().isEmpty()); |
|
|
|
|
CORRADE_COMPARE(&f.object(), &o); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::parenting() { |
|
|
|
|
Object3D root; |
|
|
|
|
template<class T> void ObjectTest::parenting() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
Object3D* childOne = new Object3D(&root); |
|
|
|
|
Object3D* childTwo = new Object3D(&root); |
|
|
|
|
Object3D<T> root; |
|
|
|
|
|
|
|
|
|
Object3D<T>* childOne = new Object3D<T>(&root); |
|
|
|
|
Object3D<T>* childTwo = new Object3D<T>(&root); |
|
|
|
|
|
|
|
|
|
CORRADE_VERIFY(childOne->parent() == &root); |
|
|
|
|
CORRADE_VERIFY(childTwo->parent() == &root); |
|
|
|
|
@ -141,26 +165,30 @@ void ObjectTest::parenting() {
|
|
|
|
|
CORRADE_VERIFY(childOne->children().isEmpty()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::addChild() { |
|
|
|
|
class MyObject: public Object3D { |
|
|
|
|
template<class T> void ObjectTest::addChild() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
class MyObject: public Object3D<T> { |
|
|
|
|
public: |
|
|
|
|
explicit MyObject(Int&, Containers::Pointer<int>&&, Object3D* parent = nullptr): Object3D{parent} {} |
|
|
|
|
explicit MyObject(Int&, Containers::Pointer<int>&&, Object3D<T>* parent = nullptr): Object3D<T>{parent} {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Object3D o; |
|
|
|
|
Object3D<T> o; |
|
|
|
|
CORRADE_VERIFY(o.children().isEmpty()); |
|
|
|
|
/* Test perfect forwarding as well */ |
|
|
|
|
int a = 0; |
|
|
|
|
MyObject& p = o.addChild<MyObject>(a, Containers::Pointer<int>{}); |
|
|
|
|
MyObject& p = o.template addChild<MyObject>(a, Containers::Pointer<int>{}); |
|
|
|
|
CORRADE_VERIFY(!o.children().isEmpty()); |
|
|
|
|
CORRADE_COMPARE(p.parent(), &o); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::move() { |
|
|
|
|
Scene3D scene; |
|
|
|
|
Object3D* a = new Object3D{&scene}; |
|
|
|
|
Object3D* b = new Object3D{&scene}; |
|
|
|
|
Object3D* c = new Object3D{&scene}; |
|
|
|
|
template<class T> void ObjectTest::move() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
Scene3D<T> scene; |
|
|
|
|
Object3D<T>* a = new Object3D<T>{&scene}; |
|
|
|
|
Object3D<T>* b = new Object3D<T>{&scene}; |
|
|
|
|
Object3D<T>* c = new Object3D<T>{&scene}; |
|
|
|
|
|
|
|
|
|
CORRADE_COMPARE(a->nextSibling(), b); |
|
|
|
|
CORRADE_COMPARE(b->nextSibling(), c); |
|
|
|
|
@ -177,29 +205,33 @@ void ObjectTest::move() {
|
|
|
|
|
CORRADE_COMPARE(a->nextSibling(), nullptr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::scene() { |
|
|
|
|
Scene3D scene; |
|
|
|
|
template<class T> void ObjectTest::scene() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
Scene3D<T> scene; |
|
|
|
|
CORRADE_VERIFY(scene.scene() == &scene); |
|
|
|
|
|
|
|
|
|
Object3D* childOne = new Object3D(&scene); |
|
|
|
|
Object3D* childTwo = new Object3D(childOne); |
|
|
|
|
Object3D<T>* childOne = new Object3D<T>(&scene); |
|
|
|
|
Object3D<T>* childTwo = new Object3D<T>(childOne); |
|
|
|
|
|
|
|
|
|
Object3D orphan; |
|
|
|
|
Object3D* childOfOrphan = new Object3D(&orphan); |
|
|
|
|
Object3D<T> orphan; |
|
|
|
|
Object3D<T>* childOfOrphan = new Object3D<T>(&orphan); |
|
|
|
|
|
|
|
|
|
CORRADE_VERIFY(childTwo->scene() == &scene); |
|
|
|
|
CORRADE_VERIFY(childOfOrphan->scene() == nullptr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::setParentKeepTransformation() { |
|
|
|
|
Object3D root; |
|
|
|
|
root.rotateZ(Deg(35.0f)); |
|
|
|
|
template<class T> void ObjectTest::setParentKeepTransformation() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
Object3D<T> root; |
|
|
|
|
root.rotateZ(Math::Deg<T>{T(35.0)}); |
|
|
|
|
|
|
|
|
|
Object3D* childOne = new Object3D(&root); |
|
|
|
|
Object3D* childTwo = new Object3D(&root); |
|
|
|
|
Object3D<T>* childOne = new Object3D<T>(&root); |
|
|
|
|
Object3D<T>* childTwo = new Object3D<T>(&root); |
|
|
|
|
|
|
|
|
|
childOne->translate(Vector3::xAxis(2.0f)); |
|
|
|
|
childTwo->rotateY(Deg(90.0f)); |
|
|
|
|
childOne->translate(Math::Vector3<T>::xAxis(T(2.0))); |
|
|
|
|
childTwo->rotateY(Math::Deg<T>{90.0}); |
|
|
|
|
|
|
|
|
|
/* Reparent to another and keep absolute transformation */ |
|
|
|
|
auto transformation = childOne->absoluteTransformation(); |
|
|
|
|
@ -208,116 +240,126 @@ void ObjectTest::setParentKeepTransformation() {
|
|
|
|
|
CORRADE_COMPARE(childOne->absoluteTransformation(), transformation); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::setParentKeepTransformationInvalid() { |
|
|
|
|
template<class T> void ObjectTest::setParentKeepTransformationInvalid() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
#ifdef CORRADE_NO_ASSERT |
|
|
|
|
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
Object3D root; |
|
|
|
|
root.rotateZ(Deg(35.0f)); |
|
|
|
|
Object3D<T> root; |
|
|
|
|
root.rotateZ(Math::Deg<T>{35.0}); |
|
|
|
|
|
|
|
|
|
Object3D* child = new Object3D(&root); |
|
|
|
|
Object3D<T>* child = new Object3D<T>(&root); |
|
|
|
|
|
|
|
|
|
/* Old parent and new parent must share the same scene */ |
|
|
|
|
std::ostringstream o; |
|
|
|
|
Error redirectError{&o}; |
|
|
|
|
Scene3D scene; |
|
|
|
|
Scene3D<T> scene; |
|
|
|
|
child->setParentKeepTransformation(&scene); |
|
|
|
|
CORRADE_COMPARE(o.str(), "SceneGraph::Object::setParentKeepTransformation(): both parents must be in the same scene\n"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::absoluteTransformation() { |
|
|
|
|
Scene3D s; |
|
|
|
|
template<class T> void ObjectTest::absoluteTransformation() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
Scene3D<T> s; |
|
|
|
|
|
|
|
|
|
/* Proper transformation composition */ |
|
|
|
|
Object3D o(&s); |
|
|
|
|
o.translate(Vector3::xAxis(2.0f)); |
|
|
|
|
CORRADE_COMPARE(o.transformation(), Matrix4::translation(Vector3::xAxis(2.0f))); |
|
|
|
|
Object3D<T> o(&s); |
|
|
|
|
o.translate(Math::Vector3<T>::xAxis(T(2.0))); |
|
|
|
|
CORRADE_COMPARE(o.transformation(), Math::Matrix4<T>::translation(Math::Vector3<T>::xAxis(T(2.0)))); |
|
|
|
|
CORRADE_COMPARE(o.transformation(), o.transformationMatrix()); |
|
|
|
|
Object3D o2(&o); |
|
|
|
|
o2.rotateY(Deg(90.0f)); |
|
|
|
|
Object3D<T> o2(&o); |
|
|
|
|
o2.rotateY(Math::Deg<T>{90.0}); |
|
|
|
|
CORRADE_COMPARE(o2.absoluteTransformation(), |
|
|
|
|
Matrix4::translation(Vector3::xAxis(2.0f))*Matrix4::rotationY(Deg(90.0f))); |
|
|
|
|
Math::Matrix4<T>::translation(Math::Vector3<T>::xAxis(T(2.0)))*Math::Matrix4<T>::rotationY(Math::Deg<T>{90.0})); |
|
|
|
|
CORRADE_COMPARE(o2.absoluteTransformation(), o2.absoluteTransformationMatrix()); |
|
|
|
|
|
|
|
|
|
/* Transformation of root object */ |
|
|
|
|
Object3D o3; |
|
|
|
|
o3.translate({1.0f, 2.0f, 3.0f}); |
|
|
|
|
CORRADE_COMPARE(o3.absoluteTransformation(), Matrix4::translation({1.0f, 2.0f, 3.0f})); |
|
|
|
|
Object3D<T> o3; |
|
|
|
|
o3.translate({T(1.0), T(2.0), T(3.0)}); |
|
|
|
|
CORRADE_COMPARE(o3.absoluteTransformation(), Math::Matrix4<T>::translation({T(1.0), T(2.0), T(3.0)})); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::transformations() { |
|
|
|
|
Scene3D s; |
|
|
|
|
template<class T> void ObjectTest::transformations() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
Scene3D<T> s; |
|
|
|
|
|
|
|
|
|
Matrix4 initial = Matrix4::rotationX(Deg(90.0f)).inverted(); |
|
|
|
|
Math::Matrix4<T> initial = Math::Matrix4<T>::rotationX(Math::Deg<T>{90.0}).inverted(); |
|
|
|
|
|
|
|
|
|
/* Empty list */ |
|
|
|
|
CORRADE_COMPARE(s.transformations({}, initial), std::vector<Matrix4>()); |
|
|
|
|
CORRADE_COMPARE(s.transformations({}, initial), std::vector<Math::Matrix4<T>>{}); |
|
|
|
|
|
|
|
|
|
/* Scene alone */ |
|
|
|
|
CORRADE_COMPARE(s.transformations({s}, initial), std::vector<Matrix4>{initial}); |
|
|
|
|
CORRADE_COMPARE(s.transformations({s}, initial), std::vector<Math::Matrix4<T>>{initial}); |
|
|
|
|
|
|
|
|
|
/* One object */ |
|
|
|
|
Object3D first(&s); |
|
|
|
|
first.rotateZ(Deg(30.0f)); |
|
|
|
|
Object3D second(&first); |
|
|
|
|
second.scale(Vector3(0.5f)); |
|
|
|
|
CORRADE_COMPARE(s.transformations({second}, initial), std::vector<Matrix4>{ |
|
|
|
|
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)) |
|
|
|
|
Object3D<T> first(&s); |
|
|
|
|
first.rotateZ(Math::Deg<T>{30.0}); |
|
|
|
|
Object3D<T> second(&first); |
|
|
|
|
second.scale(Math::Vector3<T>(T(0.5))); |
|
|
|
|
CORRADE_COMPARE(s.transformations({second}, initial), std::vector<Math::Matrix4<T>>{ |
|
|
|
|
initial*Math::Matrix4<T>::rotationZ(Math::Deg<T>{30.0})*Math::Matrix4<T>::scaling(Math::Vector3<T>(T(0.5))) |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
/* One object and scene */ |
|
|
|
|
CORRADE_COMPARE(s.transformations({second, s}, initial), (std::vector<Matrix4>{ |
|
|
|
|
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), |
|
|
|
|
CORRADE_COMPARE(s.transformations({second, s}, initial), (std::vector<Math::Matrix4<T>>{ |
|
|
|
|
initial*Math::Matrix4<T>::rotationZ(Math::Deg<T>{30.0})*Math::Matrix4<T>::scaling(Math::Vector3<T>(T(0.5))), |
|
|
|
|
initial |
|
|
|
|
})); |
|
|
|
|
|
|
|
|
|
/* Two objects with foreign joint */ |
|
|
|
|
Object3D third(&first); |
|
|
|
|
third.translate(Vector3::xAxis(5.0f)); |
|
|
|
|
CORRADE_COMPARE(s.transformations({second, third}, initial), (std::vector<Matrix4>{ |
|
|
|
|
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), |
|
|
|
|
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)), |
|
|
|
|
Object3D<T> third(&first); |
|
|
|
|
third.translate(Math::Vector3<T>::xAxis(T(5.0))); |
|
|
|
|
CORRADE_COMPARE(s.transformations({second, third}, initial), (std::vector<Math::Matrix4<T>>{ |
|
|
|
|
initial*Math::Matrix4<T>::rotationZ(Math::Deg<T>{30.0})*Math::Matrix4<T>::scaling(Math::Vector3<T>(T(0.5))), |
|
|
|
|
initial*Math::Matrix4<T>::rotationZ(Math::Deg<T>{30.0})*Math::Matrix4<T>::translation(Math::Vector3<T>::xAxis(T(5.0))), |
|
|
|
|
})); |
|
|
|
|
|
|
|
|
|
/* Three objects with joint as one of them */ |
|
|
|
|
CORRADE_COMPARE(s.transformations({second, third, first}, initial), (std::vector<Matrix4>{ |
|
|
|
|
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), |
|
|
|
|
initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)), |
|
|
|
|
initial*Matrix4::rotationZ(Deg(30.0f)), |
|
|
|
|
CORRADE_COMPARE(s.transformations({second, third, first}, initial), (std::vector<Math::Matrix4<T>>{ |
|
|
|
|
initial*Math::Matrix4<T>::rotationZ(Math::Deg<T>{30.0})*Math::Matrix4<T>::scaling(Math::Vector3<T>(T(0.5))), |
|
|
|
|
initial*Math::Matrix4<T>::rotationZ(Math::Deg<T>{30.0})*Math::Matrix4<T>::translation(Math::Vector3<T>::xAxis(T(5.0))), |
|
|
|
|
initial*Math::Matrix4<T>::rotationZ(Math::Deg<T>{30.0}), |
|
|
|
|
})); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::transformationsRelative() { |
|
|
|
|
template<class T> void ObjectTest::transformationsRelative() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
CORRADE_SKIP("Transformations not relative to scene are not implemented yet."); |
|
|
|
|
|
|
|
|
|
Scene3D s; |
|
|
|
|
Object3D first(&s); |
|
|
|
|
first.rotateZ(Deg(30.0f)); |
|
|
|
|
Object3D second(&first); |
|
|
|
|
second.scale(Vector3(0.5f)); |
|
|
|
|
Object3D third(&first); |
|
|
|
|
third.translate(Vector3::xAxis(5.0f)); |
|
|
|
|
Scene3D<T> s; |
|
|
|
|
Object3D<T> first(&s); |
|
|
|
|
first.rotateZ(Math::Deg<T>{30.0}); |
|
|
|
|
Object3D<T> second(&first); |
|
|
|
|
second.scale(Math::Vector3<T>(T(0.5))); |
|
|
|
|
Object3D<T> third(&first); |
|
|
|
|
third.translate(Math::Vector3<T>::xAxis(T(5.0))); |
|
|
|
|
|
|
|
|
|
/* Transformation relative to another object */ |
|
|
|
|
CORRADE_COMPARE(second.transformations({third}), std::vector<Matrix4>{ |
|
|
|
|
Matrix4::scaling(Vector3(0.5f)).inverted()*Matrix4::translation(Vector3::xAxis(5.0f)) |
|
|
|
|
CORRADE_COMPARE(second.transformations({third}), std::vector<Math::Matrix4<T>>{ |
|
|
|
|
Math::Matrix4<T>::scaling(Math::Vector3<T>(T(0.5))).inverted()*Math::Matrix4<T>::translation(Math::Vector3<T>::xAxis(T(5.0))) |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
/* Transformation relative to another object, not part of any scene (but should work) */ |
|
|
|
|
Object3D orphanParent1; |
|
|
|
|
orphanParent1.rotate(Deg(31.0f), Vector3(1.0f).normalized()); |
|
|
|
|
Object3D orphanParent(&orphanParent1); |
|
|
|
|
Object3D orphan1(&orphanParent); |
|
|
|
|
orphan1.scale(Vector3::xScale(3.0f)); |
|
|
|
|
Object3D orphan2(&orphanParent); |
|
|
|
|
orphan2.translate(Vector3::zAxis(5.0f)); |
|
|
|
|
CORRADE_COMPARE(orphan1.transformations({orphan2}), std::vector<Matrix4>{ |
|
|
|
|
Matrix4::scaling(Vector3::xScale(3.0f)).inverted()*Matrix4::translation(Vector3::zAxis(5.0f)) |
|
|
|
|
Object3D<T> orphanParent1; |
|
|
|
|
orphanParent1.rotate(Math::Deg<T>{31.0}, Math::Vector3<T>(T(1.0)).normalized()); |
|
|
|
|
Object3D<T> orphanParent(&orphanParent1); |
|
|
|
|
Object3D<T> orphan1(&orphanParent); |
|
|
|
|
orphan1.scale(Math::Vector3<T>::xScale(T(3.0))); |
|
|
|
|
Object3D<T> orphan2(&orphanParent); |
|
|
|
|
orphan2.translate(Math::Vector3<T>::zAxis(T(5.0))); |
|
|
|
|
CORRADE_COMPARE(orphan1.transformations({orphan2}), std::vector<Math::Matrix4<T>>{ |
|
|
|
|
Math::Matrix4<T>::scaling(Math::Vector3<T>::xScale(T(3.0))).inverted()*Math::Matrix4<T>::translation(Math::Vector3<T>::zAxis(T(5.0))) |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::transformationsOrphan() { |
|
|
|
|
template<class T> void ObjectTest::transformationsOrphan() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
#ifdef CORRADE_NO_ASSERT |
|
|
|
|
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); |
|
|
|
|
#endif |
|
|
|
|
@ -326,68 +368,72 @@ void ObjectTest::transformationsOrphan() {
|
|
|
|
|
Error redirectError{&o}; |
|
|
|
|
|
|
|
|
|
/* Transformation of objects not part of the same scene */ |
|
|
|
|
Scene3D s; |
|
|
|
|
Object3D orphan; |
|
|
|
|
CORRADE_COMPARE(s.transformations({orphan}), std::vector<Matrix4>()); |
|
|
|
|
Scene3D<T> s; |
|
|
|
|
Object3D<T> orphan; |
|
|
|
|
CORRADE_COMPARE(s.transformations({orphan}), std::vector<Math::Matrix4<T>>{}); |
|
|
|
|
CORRADE_COMPARE(o.str(), "SceneGraph::Object::transformations(): the objects are not part of the same tree\n"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::transformationsDuplicate() { |
|
|
|
|
Scene3D s; |
|
|
|
|
Object3D first(&s); |
|
|
|
|
first.rotateZ(Deg(30.0f)); |
|
|
|
|
Object3D second(&first); |
|
|
|
|
second.scale(Vector3(0.5f)); |
|
|
|
|
Object3D third(&first); |
|
|
|
|
third.translate(Vector3::xAxis(5.0f)); |
|
|
|
|
|
|
|
|
|
Matrix4 firstExpected = Matrix4::rotationZ(Deg(30.0f)); |
|
|
|
|
Matrix4 secondExpected = Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)); |
|
|
|
|
Matrix4 thirdExpected = Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)); |
|
|
|
|
CORRADE_COMPARE(s.transformations({second, third, second, first, third}), (std::vector<Matrix4>{ |
|
|
|
|
template<class T> void ObjectTest::transformationsDuplicate() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
Scene3D<T> s; |
|
|
|
|
Object3D<T> first(&s); |
|
|
|
|
first.rotateZ(Math::Deg<T>{T(30.0)}); |
|
|
|
|
Object3D<T> second(&first); |
|
|
|
|
second.scale(Math::Vector3<T>(T(0.5))); |
|
|
|
|
Object3D<T> third(&first); |
|
|
|
|
third.translate(Math::Vector3<T>::xAxis(T(5.0))); |
|
|
|
|
|
|
|
|
|
Math::Matrix4<T> firstExpected = Math::Matrix4<T>::rotationZ(Math::Deg<T>{30.0}); |
|
|
|
|
Math::Matrix4<T> secondExpected = Math::Matrix4<T>::rotationZ(Math::Deg<T>{30.0})*Math::Matrix4<T>::scaling(Math::Vector3<T>(T(0.5))); |
|
|
|
|
Math::Matrix4<T> thirdExpected = Math::Matrix4<T>::rotationZ(Math::Deg<T>{30.0})*Math::Matrix4<T>::translation(Math::Vector3<T>::xAxis(T(5.0))); |
|
|
|
|
CORRADE_COMPARE(s.transformations({second, third, second, first, third}), (std::vector<Math::Matrix4<T>>{ |
|
|
|
|
secondExpected, thirdExpected, secondExpected, firstExpected, thirdExpected |
|
|
|
|
})); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::setClean() { |
|
|
|
|
Scene3D scene; |
|
|
|
|
template<class T> void ObjectTest::setClean() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
class CachingFeature: public AbstractFeature3D { |
|
|
|
|
Scene3D<T> scene; |
|
|
|
|
|
|
|
|
|
class CachingFeature: public AbstractBasicFeature3D<T> { |
|
|
|
|
public: |
|
|
|
|
explicit CachingFeature(AbstractObject3D& object): AbstractFeature3D{object} { |
|
|
|
|
setCachedTransformations(CachedTransformation::Absolute); |
|
|
|
|
explicit CachingFeature(AbstractBasicObject3D<T>& object): AbstractBasicFeature3D<T>{object} { |
|
|
|
|
this->setCachedTransformations(CachedTransformation::Absolute); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Matrix4 cleanedAbsoluteTransformation; |
|
|
|
|
Math::Matrix4<T> cleanedAbsoluteTransformation; |
|
|
|
|
|
|
|
|
|
void clean(const Matrix4& absoluteTransformation) override { |
|
|
|
|
void clean(const Math::Matrix4<T>& absoluteTransformation) override { |
|
|
|
|
cleanedAbsoluteTransformation = absoluteTransformation; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class CachingInvertedFeature: public AbstractFeature3D { |
|
|
|
|
class CachingInvertedFeature: public AbstractBasicFeature3D<T> { |
|
|
|
|
public: |
|
|
|
|
explicit CachingInvertedFeature(AbstractObject3D& object): AbstractFeature3D{object} { |
|
|
|
|
setCachedTransformations(CachedTransformation::InvertedAbsolute); |
|
|
|
|
explicit CachingInvertedFeature(AbstractBasicObject3D<T>& object): AbstractBasicFeature3D<T>{object} { |
|
|
|
|
this->setCachedTransformations(CachedTransformation::InvertedAbsolute); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Matrix4 cleanedInvertedAbsoluteTransformation; |
|
|
|
|
Math::Matrix4<T> cleanedInvertedAbsoluteTransformation; |
|
|
|
|
|
|
|
|
|
void cleanInverted(const Matrix4& invertedAbsoluteTransformation) override { |
|
|
|
|
void cleanInverted(const Math::Matrix4<T>& invertedAbsoluteTransformation) override { |
|
|
|
|
cleanedInvertedAbsoluteTransformation = invertedAbsoluteTransformation; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
CachingObject* childOne = new CachingObject(&scene); |
|
|
|
|
childOne->scale(Vector3(2.0f)); |
|
|
|
|
CachingObject<T>* childOne = new CachingObject<T>{&scene}; |
|
|
|
|
childOne->scale(Math::Vector3<T>(T(2.0))); |
|
|
|
|
|
|
|
|
|
CachingObject* childTwo = new CachingObject(childOne); |
|
|
|
|
childTwo->translate(Vector3::xAxis(1.0f)); |
|
|
|
|
CachingObject<T>* childTwo = new CachingObject<T>{childOne}; |
|
|
|
|
childTwo->translate(Math::Vector3<T>::xAxis(T(1.0))); |
|
|
|
|
CachingFeature* childTwoFeature = new CachingFeature(*childTwo); |
|
|
|
|
CachingInvertedFeature* childTwoFeature2 = new CachingInvertedFeature(*childTwo); |
|
|
|
|
|
|
|
|
|
CachingObject* childThree = new CachingObject(childTwo); |
|
|
|
|
childThree->rotate(Deg(90.0f), Vector3::yAxis()); |
|
|
|
|
CachingObject<T>* childThree = new CachingObject<T>{childTwo}; |
|
|
|
|
childThree->rotate(Math::Deg<T>{90.0}, Math::Vector3<T>::yAxis()); |
|
|
|
|
|
|
|
|
|
/* Object is dirty at the beginning */ |
|
|
|
|
CORRADE_VERIFY(scene.isDirty()); |
|
|
|
|
@ -416,16 +462,16 @@ void ObjectTest::setClean() {
|
|
|
|
|
CORRADE_VERIFY(childThree->isDirty()); |
|
|
|
|
|
|
|
|
|
/* If the object itself is already clean, it shouldn't clean it again */ |
|
|
|
|
childOne->cleanedAbsoluteTransformation = Matrix4{Math::ZeroInit}; |
|
|
|
|
childOne->cleanedAbsoluteTransformation = Math::Matrix4<T>{Math::ZeroInit}; |
|
|
|
|
CORRADE_VERIFY(!childOne->isDirty()); |
|
|
|
|
childOne->setClean(); |
|
|
|
|
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4{Math::ZeroInit}); |
|
|
|
|
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Math::Matrix4<T>{Math::ZeroInit}); |
|
|
|
|
|
|
|
|
|
/* If any object in the hierarchy is already clean, it shouldn't clean it again */ |
|
|
|
|
CORRADE_VERIFY(!childOne->isDirty()); |
|
|
|
|
CORRADE_VERIFY(childTwo->isDirty()); |
|
|
|
|
childTwo->setClean(); |
|
|
|
|
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4{Math::ZeroInit}); |
|
|
|
|
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Math::Matrix4<T>{Math::ZeroInit}); |
|
|
|
|
|
|
|
|
|
/* Remove object from tree => make it and its children dirty */ |
|
|
|
|
childThree->setClean(); |
|
|
|
|
@ -441,40 +487,42 @@ void ObjectTest::setClean() {
|
|
|
|
|
|
|
|
|
|
/* Set object transformation => make it and its children dirty (but not parents) */ |
|
|
|
|
childThree->setClean(); |
|
|
|
|
childTwo->setTransformation(Matrix4::translation(Vector3::xAxis(1.0f))); |
|
|
|
|
childTwo->setTransformation(Math::Matrix4<T>::translation(Math::Vector3<T>::xAxis(T(1.0)))); |
|
|
|
|
CORRADE_VERIFY(!scene.isDirty()); |
|
|
|
|
CORRADE_VERIFY(childTwo->isDirty()); |
|
|
|
|
CORRADE_VERIFY(childThree->isDirty()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::setCleanListHierarchy() { |
|
|
|
|
Scene3D scene; |
|
|
|
|
template<class T> void ObjectTest::setCleanListHierarchy() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
Scene3D<T> scene; |
|
|
|
|
|
|
|
|
|
class CachingFeature: public AbstractFeature3D { |
|
|
|
|
class CachingFeature: public AbstractBasicFeature3D<T> { |
|
|
|
|
public: |
|
|
|
|
explicit CachingFeature(AbstractObject3D& object): AbstractFeature3D{object} { |
|
|
|
|
setCachedTransformations(CachedTransformation::Absolute); |
|
|
|
|
explicit CachingFeature(AbstractBasicObject3D<T>& object): AbstractBasicFeature3D<T>{object} { |
|
|
|
|
this->setCachedTransformations(CachedTransformation::Absolute); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Matrix4 cleanedAbsoluteTransformation; |
|
|
|
|
Math::Matrix4<T> cleanedAbsoluteTransformation; |
|
|
|
|
|
|
|
|
|
void clean(const Matrix4& absoluteTransformation) override { |
|
|
|
|
void clean(const Math::Matrix4<T>& absoluteTransformation) override { |
|
|
|
|
cleanedAbsoluteTransformation = absoluteTransformation; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
CachingObject* childOne = new CachingObject(&scene); |
|
|
|
|
childOne->scale(Vector3(2.0f)); |
|
|
|
|
CachingObject<T>* childOne = new CachingObject<T>{&scene}; |
|
|
|
|
childOne->scale(Math::Vector3<T>(T(2.0))); |
|
|
|
|
|
|
|
|
|
CachingObject* childTwo = new CachingObject(childOne); |
|
|
|
|
childTwo->translate(Vector3::xAxis(1.0f)); |
|
|
|
|
CachingObject<T>* childTwo = new CachingObject<T>{childOne}; |
|
|
|
|
childTwo->translate(Math::Vector3<T>::xAxis(T(1.0))); |
|
|
|
|
CachingFeature* childTwoFeature = new CachingFeature(*childTwo); |
|
|
|
|
|
|
|
|
|
CachingObject* childThree = new CachingObject(childTwo); |
|
|
|
|
childThree->rotate(Deg(90.0f), Vector3::yAxis()); |
|
|
|
|
CachingObject<T>* childThree = new CachingObject<T>{childTwo}; |
|
|
|
|
childThree->rotate(Math::Deg<T>{90.0}, Math::Vector3<T>::yAxis()); |
|
|
|
|
|
|
|
|
|
/* Clean the object and all its dirty parents (but not children) */ |
|
|
|
|
Scene3D::setClean({*childTwo}); |
|
|
|
|
Scene3D<T>::setClean({*childTwo}); |
|
|
|
|
CORRADE_VERIFY(!scene.isDirty()); |
|
|
|
|
CORRADE_VERIFY(!childOne->isDirty()); |
|
|
|
|
CORRADE_VERIFY(!childTwo->isDirty()); |
|
|
|
|
@ -486,31 +534,33 @@ void ObjectTest::setCleanListHierarchy() {
|
|
|
|
|
CORRADE_COMPARE(childTwoFeature->cleanedAbsoluteTransformation, childTwo->absoluteTransformationMatrix()); |
|
|
|
|
|
|
|
|
|
/* If the object itself is already clean, it shouldn't clean it again */ |
|
|
|
|
childOne->cleanedAbsoluteTransformation = Matrix4{Math::ZeroInit}; |
|
|
|
|
childOne->cleanedAbsoluteTransformation = Math::Matrix4<T>{Math::ZeroInit}; |
|
|
|
|
CORRADE_VERIFY(!childOne->isDirty()); |
|
|
|
|
Scene3D::setClean({*childOne}); |
|
|
|
|
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4{Math::ZeroInit}); |
|
|
|
|
Scene3D<T>::setClean({*childOne}); |
|
|
|
|
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Math::Matrix4<T>{Math::ZeroInit}); |
|
|
|
|
|
|
|
|
|
/* If any object in the hierarchy is already clean, it shouldn't clean it again */ |
|
|
|
|
CORRADE_VERIFY(!childOne->isDirty()); |
|
|
|
|
childTwo->setDirty(); |
|
|
|
|
Scene3D::setClean({*childTwo}); |
|
|
|
|
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4{Math::ZeroInit}); |
|
|
|
|
Scene3D<T>::setClean({*childTwo}); |
|
|
|
|
CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Math::Matrix4<T>{Math::ZeroInit}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::setCleanListBulk() { |
|
|
|
|
template<class T> void ObjectTest::setCleanListBulk() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
/* Verify it doesn't crash when passed empty list */ |
|
|
|
|
Object3D::setClean({}); |
|
|
|
|
Object3D<T>::setClean({}); |
|
|
|
|
|
|
|
|
|
Scene3D scene; |
|
|
|
|
Object3D a(&scene); |
|
|
|
|
Object3D b(&scene); |
|
|
|
|
Scene3D<T> scene; |
|
|
|
|
Object3D<T> a(&scene); |
|
|
|
|
Object3D<T> b(&scene); |
|
|
|
|
b.setClean(); |
|
|
|
|
Object3D c(&scene); |
|
|
|
|
c.translate(Vector3::zAxis(3.0f)); |
|
|
|
|
CachingObject d(&c); |
|
|
|
|
d.scale(Vector3(-2.0f)); |
|
|
|
|
Object3D e(&scene); |
|
|
|
|
Object3D<T> c(&scene); |
|
|
|
|
c.translate(Math::Vector3<T>::zAxis(T(3.0))); |
|
|
|
|
CachingObject<T> d(&c); |
|
|
|
|
d.scale(Math::Vector3<T>(T(-2.0))); |
|
|
|
|
Object3D<T> e(&scene); |
|
|
|
|
|
|
|
|
|
/* All objects should be cleaned */ |
|
|
|
|
CORRADE_VERIFY(a.isDirty()); |
|
|
|
|
@ -518,7 +568,7 @@ void ObjectTest::setCleanListBulk() {
|
|
|
|
|
CORRADE_VERIFY(c.isDirty()); |
|
|
|
|
CORRADE_VERIFY(d.isDirty()); |
|
|
|
|
CORRADE_VERIFY(e.isDirty()); |
|
|
|
|
Object3D::setClean({a, b, c, d, e}); |
|
|
|
|
Object3D<T>::setClean({a, b, c, d, e}); |
|
|
|
|
CORRADE_VERIFY(!a.isDirty()); |
|
|
|
|
CORRADE_VERIFY(!b.isDirty()); |
|
|
|
|
CORRADE_VERIFY(!c.isDirty()); |
|
|
|
|
@ -526,33 +576,37 @@ void ObjectTest::setCleanListBulk() {
|
|
|
|
|
CORRADE_VERIFY(!e.isDirty()); |
|
|
|
|
|
|
|
|
|
/* Verify that right transformation was passed */ |
|
|
|
|
CORRADE_COMPARE(d.cleanedAbsoluteTransformation, Matrix4::translation(Vector3::zAxis(3.0f))*Matrix4::scaling(Vector3(-2.0f))); |
|
|
|
|
CORRADE_COMPARE(d.cleanedAbsoluteTransformation, Math::Matrix4<T>::translation(Math::Vector3<T>::zAxis(T(3.0)))*Math::Matrix4<T>::scaling(Math::Vector3<T>(T(-2.0)))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::rangeBasedForChildren() { |
|
|
|
|
Scene3D scene; |
|
|
|
|
Object3D a(&scene); |
|
|
|
|
Object3D b(&scene); |
|
|
|
|
Object3D c(&scene); |
|
|
|
|
template<class T> void ObjectTest::rangeBasedForChildren() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
std::vector<Object3D*> objects; |
|
|
|
|
Scene3D<T> scene; |
|
|
|
|
Object3D<T> a{&scene}; |
|
|
|
|
Object3D<T> b{&scene}; |
|
|
|
|
Object3D<T> c{&scene}; |
|
|
|
|
|
|
|
|
|
std::vector<Object3D<T>*> objects; |
|
|
|
|
for(auto&& i: scene.children()) objects.push_back(&i); |
|
|
|
|
CORRADE_COMPARE(objects, (std::vector<Object3D*>{&a, &b, &c})); |
|
|
|
|
CORRADE_COMPARE(objects, (std::vector<Object3D<T>*>{&a, &b, &c})); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ObjectTest::rangeBasedForFeatures() { |
|
|
|
|
struct Feature: AbstractFeature3D { |
|
|
|
|
explicit Feature(AbstractObject3D& object): AbstractFeature3D{object} {} |
|
|
|
|
template<class T> void ObjectTest::rangeBasedForFeatures() { |
|
|
|
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
|
|
|
|
|
|
|
|
|
struct Feature: AbstractBasicFeature3D<T> { |
|
|
|
|
explicit Feature(AbstractBasicObject3D<T>& object): AbstractBasicFeature3D<T>{object} {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Object3D object; |
|
|
|
|
Feature a(object); |
|
|
|
|
Feature b(object); |
|
|
|
|
Feature c(object); |
|
|
|
|
Object3D<T> object; |
|
|
|
|
Feature a{object}; |
|
|
|
|
Feature b{object}; |
|
|
|
|
Feature c{object}; |
|
|
|
|
|
|
|
|
|
std::vector<AbstractFeature3D*> features; |
|
|
|
|
std::vector<AbstractBasicFeature3D<T>*> features; |
|
|
|
|
for(auto&& i: object.features()) features.push_back(&i); |
|
|
|
|
CORRADE_COMPARE(features, (std::vector<AbstractFeature3D*>{&a, &b, &c})); |
|
|
|
|
CORRADE_COMPARE(features, (std::vector<AbstractBasicFeature3D<T>*>{&a, &b, &c})); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}}}} |
|
|
|
|
|