Browse Source

DebugTools: added ForceRenderer.

Visualizes force using arrow.
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
5ff59b609e
  1. 6
      src/DebugTools/CMakeLists.txt
  2. 5
      src/DebugTools/DebugTools.h
  3. 89
      src/DebugTools/ForceRenderer.cpp
  4. 136
      src/DebugTools/ForceRenderer.h
  5. 61
      src/DebugTools/Implementation/ForceRendererTransformation.h
  6. 4
      src/DebugTools/ResourceManager.cpp
  7. 7
      src/DebugTools/ResourceManager.h
  8. 1
      src/DebugTools/Test/CMakeLists.txt
  9. 114
      src/DebugTools/Test/ForceRendererTest.cpp

6
src/DebugTools/CMakeLists.txt

@ -1,4 +1,5 @@
set(MagnumDebugTools_SRCS
ForceRenderer.cpp
ObjectRenderer.cpp
Profiler.cpp
ResourceManager.cpp
@ -11,6 +12,7 @@ set(MagnumDebugTools_SRCS
Implementation/PointRenderer.cpp)
set(MagnumDebugTools_HEADERS
ForceRenderer.h
DebugTools.h
ObjectRenderer.h
Profiler.h
@ -30,3 +32,7 @@ target_link_libraries(MagnumDebugTools
install(TARGETS MagnumDebugTools DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
install(FILES ${MagnumDebugTools_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/DebugTools)
if(BUILD_TESTS)
add_subdirectory(Test)
endif()

5
src/DebugTools/DebugTools.h

@ -25,6 +25,11 @@ namespace Magnum { namespace DebugTools {
/** @todoc Remove `ifndef` when Doxygen is sane again */
#ifndef DOXYGEN_GENERATING_OUTPUT
template<UnsignedInt> class ForceRenderer;
typedef ForceRenderer<2> ForceRenderer2D;
typedef ForceRenderer<3> ForceRenderer3D;
class ForceRendererOptions;
template<UnsignedInt> class ObjectRenderer;
typedef ObjectRenderer<2> ObjectRenderer2D;
typedef ObjectRenderer<3> ObjectRenderer3D;

89
src/DebugTools/ForceRenderer.cpp

@ -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>;
}}

136
src/DebugTools/ForceRenderer.h

@ -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

61
src/DebugTools/Implementation/ForceRendererTransformation.h

@ -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

4
src/DebugTools/ResourceManager.cpp

@ -19,16 +19,18 @@
#include "Buffer.h"
#include "Mesh.h"
#include "DebugTools/ForceRenderer.h"
#include "DebugTools/ObjectRenderer.h"
#include "DebugTools/ShapeRenderer.h"
namespace Magnum {
template class ResourceManager<AbstractShaderProgram, Buffer, Mesh, DebugTools::ObjectRendererOptions, DebugTools::ShapeRendererOptions>;
template class ResourceManager<AbstractShaderProgram, Buffer, Mesh, DebugTools::ForceRendererOptions, DebugTools::ObjectRendererOptions, DebugTools::ShapeRendererOptions>;
namespace DebugTools {
ResourceManager::ResourceManager() {
setFallback(new ForceRendererOptions);
setFallback(new ObjectRendererOptions);
setFallback(new ShapeRendererOptions);
}

7
src/DebugTools/ResourceManager.h

@ -34,16 +34,17 @@
namespace Magnum {
extern template ResourceManager<AbstractShaderProgram, Buffer, Mesh, DebugTools::ObjectRendererOptions, DebugTools::ShapeRendererOptions> MAGNUM_DEBUGTOOLS_EXPORT *& ResourceManager<AbstractShaderProgram, Buffer, Mesh, DebugTools::ObjectRendererOptions, DebugTools::ShapeRendererOptions>::internalInstance();
extern template ResourceManager<AbstractShaderProgram, Buffer, Mesh, DebugTools::ForceRendererOptions, DebugTools::ObjectRendererOptions, DebugTools::ShapeRendererOptions> MAGNUM_DEBUGTOOLS_EXPORT *& ResourceManager<AbstractShaderProgram, Buffer, Mesh, DebugTools::ForceRendererOptions, DebugTools::ObjectRendererOptions, DebugTools::ShapeRendererOptions>::internalInstance();
namespace DebugTools {
/**
@brief %Resource manager for debug tools
Stores various data used by debug renderers.
Stores various data used by debug renderers. See @ref debug-tools for more
information.
*/
class MAGNUM_DEBUGTOOLS_EXPORT ResourceManager: public Magnum::ResourceManager<AbstractShaderProgram, Buffer, Mesh, DebugTools::ObjectRendererOptions, DebugTools::ShapeRendererOptions> {
class MAGNUM_DEBUGTOOLS_EXPORT ResourceManager: public Magnum::ResourceManager<AbstractShaderProgram, Buffer, Mesh, DebugTools::ForceRendererOptions, DebugTools::ObjectRendererOptions, DebugTools::ShapeRendererOptions> {
public:
explicit ResourceManager();
~ResourceManager();

1
src/DebugTools/Test/CMakeLists.txt

@ -0,0 +1 @@
corrade_add_test(MagnumDebugToolsForceRendererTest ForceRendererTest.cpp LIBRARIES MagnumMathTestLib)

114
src/DebugTools/Test/ForceRendererTest.cpp

@ -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…
Cancel
Save