mirror of https://github.com/mosra/magnum.git
9 changed files with 419 additions and 4 deletions
@ -0,0 +1,89 @@
|
||||
/*
|
||||
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. |
||||
*/ |
||||
|
||||
#include "ForceRenderer.h" |
||||
|
||||
#include "Buffer.h" |
||||
#include "Mesh.h" |
||||
#include "DebugTools/ResourceManager.h" |
||||
#include "SceneGraph/AbstractCamera.h" |
||||
#include "Shaders/FlatShader.h" |
||||
|
||||
#include "DebugTools/Implementation/ForceRendererTransformation.h" |
||||
|
||||
namespace Magnum { namespace DebugTools { |
||||
|
||||
namespace { |
||||
|
||||
template<UnsignedInt dimensions> ResourceKey shaderKey(); |
||||
template<> inline ResourceKey shaderKey<2>() { return ResourceKey("FlatShader2D"); } |
||||
template<> inline ResourceKey shaderKey<3>() { return ResourceKey("FlatShader3D"); } |
||||
|
||||
constexpr std::array<Vector2, 4> positions{{ |
||||
{0.0f, 0.0f}, |
||||
{1.0f, 0.0f}, |
||||
{0.9f, 0.1f}, |
||||
{0.9f, -0.1f} |
||||
}}; |
||||
|
||||
constexpr std::array<UnsignedByte, 6> indices{{ |
||||
0, 1, |
||||
1, 2, |
||||
1, 3 |
||||
}}; |
||||
|
||||
} |
||||
|
||||
template<UnsignedInt dimensions> ForceRenderer<dimensions>::ForceRenderer(SceneGraph::AbstractObject<dimensions>* object, const typename DimensionTraits<dimensions, Float>::VectorType& forcePosition, const typename DimensionTraits<dimensions, Float>::VectorType* force, ResourceKey options, SceneGraph::DrawableGroup<dimensions>* drawables): SceneGraph::Drawable<dimensions>(object, drawables), forcePosition(forcePosition), force(force), options(ResourceManager::instance()->get<ForceRendererOptions>(options)) { |
||||
/* Shader */ |
||||
shader = ResourceManager::instance()->get<AbstractShaderProgram, Shaders::FlatShader<dimensions>>(shaderKey<dimensions>()); |
||||
if(!shader) ResourceManager::instance()->set<AbstractShaderProgram>(shader.key(), new Shaders::FlatShader<dimensions>); |
||||
|
||||
/* Mesh and vertex buffer */ |
||||
mesh = ResourceManager::instance()->get<Mesh>("force"); |
||||
vertexBuffer = ResourceManager::instance()->get<Buffer>("force-vertices"); |
||||
indexBuffer = ResourceManager::instance()->get<Buffer>("force-indices"); |
||||
if(mesh) return; |
||||
|
||||
/* Create the mesh */ |
||||
Buffer* vertexBuffer = new Buffer(Buffer::Target::Array); |
||||
Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); |
||||
|
||||
vertexBuffer->setData(positions, Buffer::Usage::StaticDraw); |
||||
ResourceManager::instance()->set(this->vertexBuffer.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); |
||||
|
||||
indexBuffer->setData(indices, Buffer::Usage::StaticDraw); |
||||
ResourceManager::instance()->set(this->indexBuffer.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); |
||||
|
||||
Mesh* mesh = new Mesh; |
||||
mesh->setPrimitive(Mesh::Primitive::Lines) |
||||
->setIndexCount(indices.size()) |
||||
->addVertexBuffer(vertexBuffer, 0, |
||||
typename Shaders::FlatShader<dimensions>::Position(Shaders::FlatShader<dimensions>::Position::Components::Two)) |
||||
->setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 0, positions.size()); |
||||
ResourceManager::instance()->set<Mesh>(this->mesh.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void ForceRenderer<dimensions>::draw(const typename DimensionTraits<dimensions>::MatrixType& transformationMatrix, SceneGraph::AbstractCamera<dimensions>* camera) { |
||||
shader->setTransformationProjectionMatrix(camera->projectionMatrix()*Implementation::forceRendererTransformation<dimensions>(transformationMatrix.translation()+forcePosition, *force)*DimensionTraits<dimensions>::MatrixType::scaling(typename DimensionTraits<dimensions>::VectorType(options->scale()))) |
||||
->setColor(options->color()) |
||||
->use(); |
||||
mesh->draw(); |
||||
} |
||||
|
||||
template class ForceRenderer<2>; |
||||
template class ForceRenderer<3>; |
||||
|
||||
}} |
||||
@ -0,0 +1,136 @@
|
||||
#ifndef Magnum_DebugTools_ForceRenderer_h |
||||
#define Magnum_DebugTools_ForceRenderer_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::DebugTools::ForceRenderer, Magnum::DebugTools::ForceRendererOptions, typedef Magnum::DebugTools::ForceRenderer2D, Magnum::DebugTools::ForceRenderer3D |
||||
*/ |
||||
|
||||
#include "Color.h" |
||||
#include "Resource.h" |
||||
#include "SceneGraph/Drawable.h" |
||||
#include "Shaders/Shaders.h" |
||||
|
||||
#include "magnumDebugToolsVisibility.h" |
||||
|
||||
namespace Magnum { namespace DebugTools { |
||||
|
||||
/**
|
||||
@brief Force renderer options |
||||
|
||||
See ForceRenderer documentation for more information. |
||||
*/ |
||||
class ForceRendererOptions { |
||||
public: |
||||
inline constexpr ForceRendererOptions(): _size(1.0f) {} |
||||
|
||||
/** @brief Color of rendered arrow */ |
||||
inline constexpr Color3<> color() const { return _color; } |
||||
|
||||
/**
|
||||
* @brief Set color of rendered arrow |
||||
* @return Pointer to self (for method chaining) |
||||
* |
||||
* Default is black. |
||||
*/ |
||||
inline ForceRendererOptions* setColor(const Color3<>& color) { |
||||
_color = color; |
||||
return this; |
||||
} |
||||
|
||||
/** @brief Scale of rendered arrow */ |
||||
inline constexpr Float scale() const { return _size; } |
||||
|
||||
/**
|
||||
* @brief Set scale of rendered arrow |
||||
* @return Pointer to self (for method chaining) |
||||
* |
||||
* Default is `1.0f`. |
||||
*/ |
||||
inline ForceRendererOptions* setSize(Float size) { |
||||
_size = size; |
||||
return this; |
||||
} |
||||
|
||||
private: |
||||
Color3<> _color; |
||||
Float _size; |
||||
}; |
||||
|
||||
/**
|
||||
@brief Force renderer |
||||
|
||||
Visualizes force pushing on object by an arrow of the same direction and size. |
||||
See @ref debug-tools-renderers for more information. |
||||
|
||||
@section ForceRenderer-usage Basic usage |
||||
|
||||
Example code: |
||||
@code |
||||
// Create some options
|
||||
DebugTools::ResourceManager::instance()->set("my", (new DebugTools::ForceRendererOptions() |
||||
->setScale(5.0f) |
||||
->setColor(Color3<>::fromHSV(120.0_degf, 1.0f, 0.7f))); |
||||
|
||||
// Create debug renderer for given object, use "my" options for it
|
||||
Object3D* object; |
||||
Vector3 force; |
||||
new DebugTools::ForceRenderer2D(object, {0.3f, 1.5f, -0.7f}, &force, "my", debugDrawables); |
||||
@endcode |
||||
|
||||
@see ForceRenderer2D, ForceRenderer3D |
||||
*/ |
||||
template<UnsignedInt dimensions> class MAGNUM_DEBUGTOOLS_EXPORT ForceRenderer: public SceneGraph::Drawable<dimensions> { |
||||
public: |
||||
/**
|
||||
* @brief Constructor |
||||
* @param object Object for which to create debug renderer |
||||
* @param forcePosition Where to render the force, relative to object |
||||
* @param force Force vector |
||||
* @param options Options resource key. See |
||||
* @ref ForceRenderer-usage "class documentation" for more |
||||
* information. |
||||
* @param drawables Drawable group |
||||
* |
||||
* The renderer is automatically added to object's features, @p force is |
||||
* saved as reference to original vector and thus it must be available |
||||
* for the whole lifetime of the renderer. |
||||
*/ |
||||
explicit ForceRenderer(SceneGraph::AbstractObject<dimensions>* object, const typename DimensionTraits<dimensions, Float>::VectorType& forcePosition, const typename DimensionTraits<dimensions, Float>::VectorType* force, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup<dimensions>* drawables = nullptr); |
||||
|
||||
protected: |
||||
/** @todoc Remove Float when Doxygen properly treats this as override */ |
||||
void draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractCamera<dimensions, Float>* camera) override; |
||||
|
||||
private: |
||||
const typename DimensionTraits<dimensions, Float>::VectorType forcePosition; |
||||
const typename DimensionTraits<dimensions, Float>::VectorType* const force; |
||||
|
||||
Resource<ForceRendererOptions> options; |
||||
Resource<AbstractShaderProgram, Shaders::FlatShader<dimensions>> shader; |
||||
Resource<Mesh> mesh; |
||||
Resource<Buffer> vertexBuffer, indexBuffer; |
||||
}; |
||||
|
||||
/** @brief Two-dimensional force renderer */ |
||||
typedef ForceRenderer<2> ForceRenderer2D; |
||||
|
||||
/** @brief Three-dimensional force renderer */ |
||||
typedef ForceRenderer<3> ForceRenderer3D; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,61 @@
|
||||
#ifndef Magnum_DebugTools_Implementation_ForceRendererTransformation_h |
||||
#define Magnum_DebugTools_Implementation_ForceRendererTransformation_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. |
||||
*/ |
||||
|
||||
#include "Math/Matrix3.h" |
||||
#include "Math/Matrix4.h" |
||||
#include "Magnum.h" |
||||
#include "DimensionTraits.h" |
||||
|
||||
namespace Magnum { namespace DebugTools { namespace Implementation { |
||||
|
||||
template<UnsignedInt dimensions> typename DimensionTraits<dimensions>::MatrixType forceRendererTransformation(const typename DimensionTraits<dimensions>::VectorType& forcePosition, const typename DimensionTraits<dimensions>::VectorType& force); |
||||
|
||||
template<> inline Matrix3 forceRendererTransformation<2>(const Vector2& forcePosition, const Vector2& force) { |
||||
return Matrix3::from({force, Vector2(-force.y(), force.x())}, forcePosition); |
||||
} |
||||
|
||||
template<> inline Matrix4 forceRendererTransformation<3>(const Vector3& forcePosition, const Vector3& force) { |
||||
const Matrix4 translation = Matrix4::translation(forcePosition); |
||||
const Float forceLength = force.length(); |
||||
|
||||
/* Zero length, zero scaling */ |
||||
if(forceLength < Math::MathTypeTraits<Float>::epsilon()) |
||||
return translation*Matrix4::scaling(Vector3(0.0f)); |
||||
|
||||
const Float dot = Vector3::dot(force/forceLength, Vector3::xAxis()); |
||||
|
||||
/* Force is parallel to X axis, just scaling */ |
||||
if(dot > 1.0f - Math::MathTypeTraits<Float>::epsilon()) |
||||
return translation*Matrix4::scaling(Vector3(forceLength)); |
||||
|
||||
/* Force is antiparallel to X axis, scaling inverted on X */ |
||||
if(-dot > 1.0f - Math::MathTypeTraits<Float>::epsilon()) |
||||
return translation*Matrix4::scaling({-forceLength, forceLength, forceLength}); |
||||
|
||||
/* Normal of plane going through force vector and X axis vector */ |
||||
const Vector3 normal = Vector3::cross(Vector3::xAxis(), force).normalized(); |
||||
|
||||
/* Third base vector, orthogonal to force and normal */ |
||||
const Vector3 binormal = Vector3::cross(normal, force).normalized(); |
||||
|
||||
/* Transformation matrix from scaled base vectors and translation vector */ |
||||
return Matrix4::from({force, normal*forceLength, binormal*forceLength}, forcePosition); |
||||
} |
||||
|
||||
}}} |
||||
|
||||
#endif |
||||
@ -0,0 +1 @@
|
||||
corrade_add_test(MagnumDebugToolsForceRendererTest ForceRendererTest.cpp LIBRARIES MagnumMathTestLib) |
||||
@ -0,0 +1,114 @@
|
||||
/*
|
||||
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. |
||||
*/ |
||||
|
||||
#include <TestSuite/Tester.h> |
||||
|
||||
#include "DebugTools/Implementation/ForceRendererTransformation.h" |
||||
|
||||
namespace Magnum { namespace DebugTools { namespace Implementation { namespace Test { |
||||
|
||||
class ForceRendererTest: public Corrade::TestSuite::Tester { |
||||
public: |
||||
explicit ForceRendererTest(); |
||||
|
||||
void zero2D(); |
||||
void parallel2D(); |
||||
void antiParallel2D(); |
||||
void arbitrary2D(); |
||||
|
||||
void zero3D(); |
||||
void parallel3D(); |
||||
void antiParallel3D(); |
||||
void arbitrary3D(); |
||||
}; |
||||
|
||||
ForceRendererTest::ForceRendererTest() { |
||||
addTests({&ForceRendererTest::zero2D, |
||||
&ForceRendererTest::parallel2D, |
||||
&ForceRendererTest::antiParallel2D, |
||||
&ForceRendererTest::arbitrary2D, |
||||
|
||||
&ForceRendererTest::zero3D, |
||||
&ForceRendererTest::parallel3D, |
||||
&ForceRendererTest::antiParallel3D, |
||||
&ForceRendererTest::arbitrary3D}); |
||||
} |
||||
|
||||
void ForceRendererTest::zero2D() { |
||||
CORRADE_COMPARE(Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, Vector2()), |
||||
Matrix3::translation({0.5f, -3.0f})*Matrix3::scaling(Vector2(0.0f))); |
||||
} |
||||
|
||||
void ForceRendererTest::parallel2D() { |
||||
CORRADE_COMPARE(Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, Vector2::xAxis(2.5f)), |
||||
Matrix3::translation({0.5f, -3.0f})*Matrix3::scaling(Vector2(2.5f))); |
||||
} |
||||
|
||||
void ForceRendererTest::antiParallel2D() { |
||||
CORRADE_COMPARE(Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, Vector2::xAxis(-2.5f)), |
||||
Matrix3::translation({0.5f, -3.0f})*Matrix3::scaling(Vector2(-2.5f))); |
||||
} |
||||
|
||||
void ForceRendererTest::arbitrary2D() { |
||||
Vector2 force(2.7f, -11.5f); |
||||
Matrix3 m = Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, force); |
||||
|
||||
/* Translation, right-pointing base vector is the same as force */ |
||||
CORRADE_COMPARE(m.translation(), Vector2(0.5f, -3.0f)); |
||||
CORRADE_COMPARE(m.right(), force); |
||||
|
||||
/* All vectors have the same length */ |
||||
CORRADE_COMPARE(m.up().length(), force.length()); |
||||
|
||||
/* All vectors are parallel */ |
||||
CORRADE_COMPARE(Vector2::dot(m.right(), m.up()), 0.0f); |
||||
} |
||||
|
||||
void ForceRendererTest::zero3D() { |
||||
CORRADE_COMPARE(Implementation::forceRendererTransformation<3>({0.5f, -3.0f, 1.0f}, Vector3()), |
||||
Matrix4::translation({0.5f, -3.0f, 1.0f})*Matrix4::scaling(Vector3(0.0f))); |
||||
} |
||||
|
||||
void ForceRendererTest::parallel3D() { |
||||
CORRADE_COMPARE(Implementation::forceRendererTransformation<3>({0.5f, -3.0f, 1.0f}, Vector3::xAxis(2.5f)), |
||||
Matrix4::translation({0.5f, -3.0f, 1.0f})*Matrix4::scaling(Vector3(2.5f))); |
||||
} |
||||
|
||||
void ForceRendererTest::antiParallel3D() { |
||||
CORRADE_COMPARE(Implementation::forceRendererTransformation<3>({0.5f, -3.0f, 1.0f}, Vector3::xAxis(-2.5f)), |
||||
Matrix4::translation({0.5f, -3.0f, 1.0f})*Matrix4::scaling({-2.5f, 2.5f, 2.5f})); |
||||
} |
||||
|
||||
void ForceRendererTest::arbitrary3D() { |
||||
Vector3 force(3.7f, -5.7f, -11.5f); |
||||
Matrix4 m = Implementation::forceRendererTransformation<3>({0.5f, -3.0f, 1.0f}, force); |
||||
|
||||
/* Translation, right-pointing base vector is the same as force */ |
||||
CORRADE_COMPARE(m.translation(), Vector3(0.5f, -3.0f, 1.0f)); |
||||
CORRADE_COMPARE(m.right(), force); |
||||
|
||||
/* All vectors have the same length */ |
||||
CORRADE_COMPARE(m.up().length(), force.length()); |
||||
CORRADE_COMPARE(m.backward().length(), force.length()); |
||||
|
||||
/* All vectors are parallel */ |
||||
CORRADE_COMPARE(Vector3::dot(m.right(), m.up()), 0.0f); |
||||
CORRADE_COMPARE(Vector3::dot(m.right(), m.backward()), 0.0f); |
||||
CORRADE_COMPARE(Vector3::dot(m.up(), m.backward()), 0.0f); |
||||
} |
||||
|
||||
}}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::DebugTools::Implementation::Test::ForceRendererTest) |
||||
Loading…
Reference in new issue