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