From 2553e5044420ca194a67f73374b10fb32b1db2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 16:03:24 +0200 Subject: [PATCH 01/27] Functions for normalizing and denormalizing numeric values. --- src/Math/Math.h | 39 +++++++++++++++++++++++++++++ src/Math/Test/MathTest.cpp | 50 ++++++++++++++++++++++++++++++++++++++ src/Math/Test/MathTest.h | 2 ++ 3 files changed, 91 insertions(+) diff --git a/src/Math/Math.h b/src/Math/Math.h index 7b56d7f5a..a0217f88c 100644 --- a/src/Math/Math.h +++ b/src/Math/Math.h @@ -16,6 +16,8 @@ */ #include +#include +#include #include "magnumVisibility.h" @@ -85,6 +87,43 @@ template inline constexpr T pow(T base) { */ size_t MAGNUM_EXPORT log(size_t base, size_t number); +/** +@brief Normalize floating-point value + +Converts integral value from full range of given (signed/unsigned) integral +type to value in range @f$ [0, 1] @f$. + +@attention To ensure the integral type is correctly detected when using +literals, this function should be called with both template parameters +explicit, e.g.: +@code +// Even if this is char literal, integral type is `int`, thus a = 0.1f +float a = normalize('\127'); + +// b = 1.0f +float b = normalize('\127'); +@endcode +*/ +template inline constexpr typename std::enable_if::value && std::is_integral::value, FloatingPoint>::type normalize(Integral value) { + return (FloatingPoint(value)-FloatingPoint(std::numeric_limits::min()))/ + (FloatingPoint(std::numeric_limits::max()) - FloatingPoint(std::numeric_limits::min())); +} + +/** +@brief Denormalize floating-point value + +Converts floating-point value in range @f$ [0, 1] @f$ to full range of given +integral type. + +@note For best precision, `FloatingPoint` type should be always larger that +resulting `Integral` type (e.g. `double` to `int`, `long double` to `long long`). +*/ +template inline constexpr typename std::enable_if::value && std::is_integral::value, Integral>::type denormalize(FloatingPoint value) { + return std::numeric_limits::min() + + Integral(value*std::numeric_limits::max()) - + Integral(value*std::numeric_limits::min()); +} + /** * @brief Angle in degrees * diff --git a/src/Math/Test/MathTest.cpp b/src/Math/Test/MathTest.cpp index 46babe120..dc02165f5 100644 --- a/src/Math/Test/MathTest.cpp +++ b/src/Math/Test/MathTest.cpp @@ -17,12 +17,16 @@ #include "Math.h" +using namespace std; + CORRADE_TEST_MAIN(Magnum::Math::Test::MathTest) namespace Magnum { namespace Math { namespace Test { MathTest::MathTest() { addTests(&MathTest::degrad, + &MathTest::normalize, + &MathTest::denormalize, &MathTest::pow, &MathTest::log); } @@ -33,6 +37,52 @@ void MathTest::degrad() { CORRADE_COMPARE(rad(Constants::pi()/2), Constants::pi()/2); } +void MathTest::normalize() { + /* Range for signed and unsigned */ + CORRADE_COMPARE((Math::normalize(-128)), 0.0f); + CORRADE_COMPARE((Math::normalize(127)), 1.0f); + CORRADE_COMPARE((Math::normalize(0)), 0.0f); + CORRADE_COMPARE((Math::normalize(255)), 1.0f); + + /* Between */ + CORRADE_COMPARE((Math::normalize(16384)), 0.750011f); + CORRADE_COMPARE((Math::normalize(-16384)), 0.250004f); + + /* Test overflow for large types */ + CORRADE_COMPARE((Math::normalize(numeric_limits::min())), 0.0f); + CORRADE_COMPARE((Math::normalize(numeric_limits::max())), 1.0f); + CORRADE_COMPARE((Math::normalize(0)), 0.0f); + CORRADE_COMPARE((Math::normalize(numeric_limits::max())), 1.0f); + + CORRADE_COMPARE((Math::normalize(numeric_limits::min())), 0.0); + CORRADE_COMPARE((Math::normalize(numeric_limits::max())), 1.0); + CORRADE_COMPARE((Math::normalize(0)), 0.0); + CORRADE_COMPARE((Math::normalize(numeric_limits::max())), 1.0); +} + +void MathTest::denormalize() { + /* Range for signed and unsigned */ + CORRADE_COMPARE(Math::denormalize(0.0f), -128); + CORRADE_COMPARE(Math::denormalize(1.0f), 127); + CORRADE_COMPARE(Math::denormalize(0.0f), 0); + CORRADE_COMPARE(Math::denormalize(1.0f), 255); + + /* Between */ + CORRADE_COMPARE(Math::denormalize(0.33f), -11142); + CORRADE_COMPARE(Math::denormalize(0.66f), 10484); + + /* Test overflow for large types */ + CORRADE_COMPARE(Math::denormalize(0.0f), numeric_limits::min()); + CORRADE_COMPARE(Math::denormalize(0.0f), 0); + CORRADE_COMPARE(Math::denormalize(0.0), numeric_limits::min()); + CORRADE_COMPARE(Math::denormalize(0.0), 0); + + CORRADE_COMPARE(Math::denormalize(1.0), numeric_limits::max()); + CORRADE_COMPARE(Math::denormalize(1.0), numeric_limits::max()); + CORRADE_COMPARE((Math::denormalize(1.0)), numeric_limits::max()); + CORRADE_COMPARE((Math::denormalize(1.0)), numeric_limits::max()); +} + void MathTest::pow() { CORRADE_COMPARE(Math::pow<10>(2ul), 1024ul); CORRADE_COMPARE(Math::pow<0>(3ul), 1ul); diff --git a/src/Math/Test/MathTest.h b/src/Math/Test/MathTest.h index 548b01e3c..b6dcba0c8 100644 --- a/src/Math/Test/MathTest.h +++ b/src/Math/Test/MathTest.h @@ -24,6 +24,8 @@ class MathTest: public Corrade::TestSuite::Tester { MathTest(); void degrad(); + void normalize(); + void denormalize(); void pow(); void log(); }; From dc7c5f5fae7facf04af3e6f709bc4be9adb37d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 16:04:06 +0200 Subject: [PATCH 02/27] Just-to-be-sure static_assert()s for Matrix and Vector size. --- src/Math/Matrix.h | 2 ++ src/Math/Vector.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 8dfd40d93..540f46d7b 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -36,6 +36,8 @@ namespace Implementation { * @todo first col, then row (cache adjacency) */ template class Matrix { + static_assert(size != 0, "Matrix cannot have zero elements"); + friend class Matrix; /* for ij() */ public: diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 7bd884fbc..6c4242529 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -42,6 +42,8 @@ namespace Implementation { /** @brief %Vector */ template class Vector { + static_assert(size != 0, "Vector cannot have zero elements"); + public: const static size_t Size = size; /**< @brief %Vector size */ typedef T Type; /**< @brief %Vector data type */ From 4aa07d3029ecba28be3ce9dfefd813ea30012ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 16:04:53 +0200 Subject: [PATCH 03/27] Use std:: variants for sin(), cos() and sqrt(). They should have overloads for given type, so we're not using doubles when only float is needed. --- src/Math/Matrix4.h | 4 ++-- src/Math/Vector.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index 9674d2159..fcecef081 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -75,8 +75,8 @@ template class Matrix4: public Matrix<4, T> { static Matrix4 rotation(T angle, const Vector3& vec) { Vector3 vn = vec.normalized(); - T sine = sin(angle); - T cosine = cos(angle); + T sine = std::sin(angle); + T cosine = std::cos(angle); T oneMinusCosine = T(1) - cosine; T xx = vn.x()*vn.x(); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 6c4242529..1d075e241 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -90,7 +90,7 @@ template class Vector { * @todo optimize - Assume the vectors are normalized? */ inline static T angle(const Vector& a, const Vector& b) { - return acos(dot(a, b)/(a.length()*b.length())); + return std::acos(dot(a, b)/(a.length()*b.length())); } /** @brief Default constructor */ @@ -248,7 +248,7 @@ template class Vector { * @see lengthSquared() */ inline T length() const { - return sqrt(dot(*this, *this)); + return std::sqrt(dot(*this, *this)); } /** From cfc955debe9e8b2ff41942923335cd7454b6554f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 16:06:23 +0200 Subject: [PATCH 04/27] Added Vector::sum(), so product() has a friend. --- src/Math/Test/VectorTest.cpp | 5 +++++ src/Math/Test/VectorTest.h | 1 + src/Math/Vector.h | 12 +++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index 965a4c871..2d409ceed 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -40,6 +40,7 @@ VectorTest::VectorTest() { &VectorTest::length, &VectorTest::lengthSquared, &VectorTest::normalized, + &VectorTest::sum, &VectorTest::product, &VectorTest::angle, &VectorTest::negative, @@ -121,6 +122,10 @@ void VectorTest::normalized() { CORRADE_COMPARE(Vector4(1.0f, 1.0f, 1.0f, 1.0f).normalized(), Vector4(0.5f, 0.5f, 0.5f, 0.5f)); } +void VectorTest::sum() { + CORRADE_COMPARE(Vector3(1.0f, 2.0f, 4.0f).sum(), 7.0f); +} + void VectorTest::product() { CORRADE_COMPARE(Vector3(1.0f, 2.0f, 3.0f).product(), 6.0f); } diff --git a/src/Math/Test/VectorTest.h b/src/Math/Test/VectorTest.h index c9b475e1c..a3795d551 100644 --- a/src/Math/Test/VectorTest.h +++ b/src/Math/Test/VectorTest.h @@ -32,6 +32,7 @@ class VectorTest: public Corrade::TestSuite::Tester { void length(); void lengthSquared(); void normalized(); + void sum(); void product(); void angle(); void negative(); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 1d075e241..fb3232947 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -268,9 +268,19 @@ template class Vector { return *this/length(); } + /** @brief Sum of values in the vector */ + T sum() const { + T out(0); + + for(size_t i = 0; i != size; ++i) + out += (*this)[i]; + + return out; + } + /** @brief Product of values in the vector */ T product() const { - T out = 1; + T out(1); for(size_t i = 0; i != size; ++i) out *= (*this)[i]; From 7f55f30ced7bbf863747e80e4e17fa7a01d74d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 16:28:23 +0200 Subject: [PATCH 05/27] CORRADE_ASSERT() now needs semicolon after. --- src/AbstractShaderProgram.cpp | 6 +++--- src/Camera.cpp | 2 +- src/IndexedMesh.cpp | 2 +- src/Mesh.cpp | 2 +- src/MeshTools/CombineIndexedArrays.h | 2 +- src/MeshTools/FlipNormals.cpp | 2 +- src/MeshTools/GenerateFlatNormals.cpp | 2 +- src/MeshTools/Interleave.h | 4 ++-- src/MeshTools/Subdivide.h | 2 +- src/Object.cpp | 4 ++-- src/Primitives/Capsule.cpp | 2 +- src/Primitives/UVSphere.cpp | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/AbstractShaderProgram.cpp b/src/AbstractShaderProgram.cpp index e8fd69658..4fd606973 100644 --- a/src/AbstractShaderProgram.cpp +++ b/src/AbstractShaderProgram.cpp @@ -39,14 +39,14 @@ bool AbstractShaderProgram::attachShader(Shader& shader) { } void AbstractShaderProgram::bindAttributeLocation(GLuint location, const string& name) { - CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: attribute cannot be bound after linking.", ) + CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: attribute cannot be bound after linking.", ); glBindAttribLocation(program, location, name.c_str()); } #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::bindFragmentDataLocation(GLuint location, const std::string& name) { - CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", ) + CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", ); glBindFragDataLocation(program, location, name.c_str()); } @@ -83,7 +83,7 @@ void AbstractShaderProgram::link() { GLint AbstractShaderProgram::uniformLocation(const std::string& name) { /** @todo What if linking just failed (not programmer error?) */ - CORRADE_ASSERT(state == Linked, "AbstractShaderProgram: uniform location cannot be retrieved before linking.", -1) + CORRADE_ASSERT(state == Linked, "AbstractShaderProgram: uniform location cannot be retrieved before linking.", -1); GLint location = glGetUniformLocation(program, name.c_str()); if(location == -1) diff --git a/src/Camera.cpp b/src/Camera.cpp index 32c44787e..f15454a27 100644 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -103,7 +103,7 @@ void Camera::fixAspectRatio() { void Camera::draw() { Scene* s = scene(); - CORRADE_ASSERT(s, "Camera: cannot draw without camera attached to scene", ) + CORRADE_ASSERT(s, "Camera: cannot draw without camera attached to scene", ); Framebuffer::clear(); diff --git a/src/IndexedMesh.cpp b/src/IndexedMesh.cpp index 76d1b5040..05a9b009a 100644 --- a/src/IndexedMesh.cpp +++ b/src/IndexedMesh.cpp @@ -41,7 +41,7 @@ void IndexedMesh::draw() { void IndexedMesh::finalize() { if(isFinalized()) return; - CORRADE_ASSERT(_indexCount, "IndexedMesh: the mesh has zero index count!", ) + CORRADE_ASSERT(_indexCount, "IndexedMesh: the mesh has zero index count!", ); /* Finalize attribute positions */ Mesh::finalize(); diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 6cd8633a5..5bfe0567c 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -78,7 +78,7 @@ void Mesh::finalize() { /* Already finalized */ if(finalized) return; - CORRADE_ASSERT(_vertexCount, "Mesh: the mesh has zero vertex count!", ) + CORRADE_ASSERT(_vertexCount, "Mesh: the mesh has zero vertex count!", ); /* Finalize attribute positions for every buffer */ for(auto& it: _buffers) { diff --git a/src/MeshTools/CombineIndexedArrays.h b/src/MeshTools/CombineIndexedArrays.h index 4ed096639..d3b272e8d 100644 --- a/src/MeshTools/CombineIndexedArrays.h +++ b/src/MeshTools/CombineIndexedArrays.h @@ -57,7 +57,7 @@ class CombineIndexedArrays { private: template inline static size_t indexCount(const std::vector& first, const std::vector&... next) { - CORRADE_ASSERT(sizeof...(next) == 0 || indexCount(next...) == first.size(), "MeshTools::combineIndexedArrays(): index arrays don't have the same length, nothing done.", 0) + CORRADE_ASSERT(sizeof...(next) == 0 || indexCount(next...) == first.size(), "MeshTools::combineIndexedArrays(): index arrays don't have the same length, nothing done.", 0); return first.size(); } diff --git a/src/MeshTools/FlipNormals.cpp b/src/MeshTools/FlipNormals.cpp index 8abc87cc2..1a38ede06 100644 --- a/src/MeshTools/FlipNormals.cpp +++ b/src/MeshTools/FlipNormals.cpp @@ -20,7 +20,7 @@ using namespace std; namespace Magnum { namespace MeshTools { void flipFaceWinding(vector& indices) { - CORRADE_ASSERT(!(indices.size()%3), "MeshTools::flipNormals(): index count is not divisible by 3!", ) + CORRADE_ASSERT(!(indices.size()%3), "MeshTools::flipNormals(): index count is not divisible by 3!", ); for(size_t i = 0; i != indices.size(); i += 3) swap(indices[i+1], indices[i+2]); diff --git a/src/MeshTools/GenerateFlatNormals.cpp b/src/MeshTools/GenerateFlatNormals.cpp index 69d9b7105..e52e4379e 100644 --- a/src/MeshTools/GenerateFlatNormals.cpp +++ b/src/MeshTools/GenerateFlatNormals.cpp @@ -22,7 +22,7 @@ using namespace std; namespace Magnum { namespace MeshTools { tuple, vector> generateFlatNormals(const std::vector< unsigned int >& indices, const vector< Vector4 >& vertices) { - CORRADE_ASSERT(!(indices.size()%3), "MeshTools::generateFlatNormals(): index count is not divisible by 3!", (tuple, vector>())) + CORRADE_ASSERT(!(indices.size()%3), "MeshTools::generateFlatNormals(): index count is not divisible by 3!", (tuple, vector>())); /* Create normal for every triangle (assuming counterclockwise winding) */ vector normalIndices; diff --git a/src/MeshTools/Interleave.h b/src/MeshTools/Interleave.h index 8376b1ae7..aa1de8558 100644 --- a/src/MeshTools/Interleave.h +++ b/src/MeshTools/Interleave.h @@ -53,7 +53,7 @@ class Interleave { } template void operator()(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const T&... attributes) { - CORRADE_ASSERT(mesh->isInterleaved(buffer), "MeshTools::interleave(): the buffer is not interleaved, nothing done", ) + CORRADE_ASSERT(mesh->isInterleaved(buffer), "MeshTools::interleave(): the buffer is not interleaved, nothing done", ); operator()(attributes...); @@ -64,7 +64,7 @@ class Interleave { } template inline static size_t attributeCount(const T& first, const U&... next) { - CORRADE_ASSERT(sizeof...(next) == 0 || attributeCount(next...) == first.size(), "MeshTools::interleave(): attribute arrays don't have the same length, nothing done.", 0) + CORRADE_ASSERT(sizeof...(next) == 0 || attributeCount(next...) == first.size(), "MeshTools::interleave(): attribute arrays don't have the same length, nothing done.", 0); return first.size(); } diff --git a/src/MeshTools/Subdivide.h b/src/MeshTools/Subdivide.h index 444c44611..7dad9a0b7 100644 --- a/src/MeshTools/Subdivide.h +++ b/src/MeshTools/Subdivide.h @@ -32,7 +32,7 @@ template class Subdivide { inline Subdivide(std::vector& indices, std::vector& vertices): indices(indices), vertices(vertices) {} void operator()(Interpolator interpolator) { - CORRADE_ASSERT(!(indices.size()%3), "MeshTools::subdivide(): index count is not divisible by 3!", ) + CORRADE_ASSERT(!(indices.size()%3), "MeshTools::subdivide(): index count is not divisible by 3!", ); size_t indexCount = indices.size(); indices.reserve(indices.size()*4); diff --git a/src/Object.cpp b/src/Object.cpp index 861b03346..66614f7ed 100644 --- a/src/Object.cpp +++ b/src/Object.cpp @@ -64,7 +64,7 @@ Matrix4 Object::absoluteTransformation(Camera* camera) { /* We got to the scene, multiply with camera matrix */ if(p->parent() == p) { if(camera) { - CORRADE_ASSERT(camera->scene() == scene(), "Object::absoluteTransformation(): the camera is not part of the same scene as object!", t) + CORRADE_ASSERT(camera->scene() == scene(), "Object::absoluteTransformation(): the camera is not part of the same scene as object!", t); t = camera->cameraMatrix()*t; } @@ -74,7 +74,7 @@ Matrix4 Object::absoluteTransformation(Camera* camera) { p = p->parent(); } - CORRADE_ASSERT(p != nullptr || camera == nullptr, "Object::absoluteTransformation(): the object is not part of camera scene!", t) + CORRADE_ASSERT(p != nullptr || camera == nullptr, "Object::absoluteTransformation(): the object is not part of camera scene!", t); return t; } diff --git a/src/Primitives/Capsule.cpp b/src/Primitives/Capsule.cpp index 00303e687..5df5b13f7 100644 --- a/src/Primitives/Capsule.cpp +++ b/src/Primitives/Capsule.cpp @@ -20,7 +20,7 @@ using namespace std; namespace Magnum { namespace Primitives { Capsule::Capsule(unsigned int rings, unsigned int segments, GLfloat length, TextureCoords textureCoords): MeshData("", Mesh::Primitive::Triangles, new vector, {new vector()}, {new vector()}, textureCoords == TextureCoords::Generate ? vector*>{new vector()} : vector*>()), segments(segments), textureCoords(textureCoords) { - CORRADE_ASSERT(rings >= 1 && segments >= 3, "Capsule must have at least one ring and three segments", ) + CORRADE_ASSERT(rings >= 1 && segments >= 3, "Capsule must have at least one ring and three segments", ); GLfloat height = 2.0f+length; GLfloat textureCoordsVIncrement = 1.0f/(rings*height); diff --git a/src/Primitives/UVSphere.cpp b/src/Primitives/UVSphere.cpp index ba798f68a..825a5ee26 100644 --- a/src/Primitives/UVSphere.cpp +++ b/src/Primitives/UVSphere.cpp @@ -20,7 +20,7 @@ using namespace std; namespace Magnum { namespace Primitives { UVSphere::UVSphere(unsigned int rings, unsigned int segments, TextureCoords textureCoords): Capsule(segments, textureCoords) { - CORRADE_ASSERT(rings >= 2 && segments >= 3, "UVSphere must have at least two rings and three segments", ) + CORRADE_ASSERT(rings >= 2 && segments >= 3, "UVSphere must have at least two rings and three segments", ); GLfloat textureCoordsVIncrement = 1.0f/rings; GLfloat ringAngleIncrement = Math::Constants::pi()/rings; From 0a0860a9f2ab1c1a847ad48b959681df986b519a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 17:20:15 +0200 Subject: [PATCH 06/27] Renamed Vector::lengthSquared() to parameterless Vector::dot(). It's now less confusing ("length squared" looks like it's even heavier than length), but on the other hand it's not so obvious that these two functions come together. --- src/Math/Geometry/Distance.h | 10 +++++----- src/Math/Test/VectorTest.cpp | 10 +++++----- src/Math/Test/VectorTest.h | 2 +- src/Math/Vector.h | 25 ++++++++++++++----------- src/Physics/Sphere.cpp | 4 ++-- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/Math/Geometry/Distance.h b/src/Math/Geometry/Distance.h index e3e710f03..143ab8784 100644 --- a/src/Math/Geometry/Distance.h +++ b/src/Math/Geometry/Distance.h @@ -52,7 +52,7 @@ class Distance { * values, because it doesn't compute the square root. */ template static T linePointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { - return Vector3::cross(point - a, point - b).lengthSquared()/(b - a).lengthSquared(); + return Vector3::cross(point - a, point - b).dot()/(b - a).dot(); } /** @@ -97,9 +97,9 @@ class Distance { template static T lineSegmentPointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { Vector3 pointMinusA = point - a; Vector3 pointMinusB = point - b; - T pointDistanceA = pointMinusA.lengthSquared(); - T pointDistanceB = pointMinusB.lengthSquared(); - T bDistanceA = (b - a).lengthSquared(); + T pointDistanceA = pointMinusA.dot(); + T pointDistanceB = pointMinusB.dot(); + T bDistanceA = (b - a).dot(); /* Point is before A */ if(pointDistanceB > bDistanceA + pointDistanceA) @@ -110,7 +110,7 @@ class Distance { return pointDistanceB; /* Between A and B */ - return Vector3::cross(pointMinusA, pointMinusB).lengthSquared()/bDistanceA; + return Vector3::cross(pointMinusA, pointMinusB).dot()/bDistanceA; } }; diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index 2d409ceed..459084f44 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -37,8 +37,8 @@ VectorTest::VectorTest() { &VectorTest::dot, &VectorTest::multiplyDivide, &VectorTest::addSubstract, + &VectorTest::dotSelf, &VectorTest::length, - &VectorTest::lengthSquared, &VectorTest::normalized, &VectorTest::sum, &VectorTest::product, @@ -110,12 +110,12 @@ void VectorTest::addSubstract() { CORRADE_COMPARE(expected - b, a); } -void VectorTest::length() { - CORRADE_COMPARE(Vector4(1.0f, 2.0f, 3.0f, 4.0f).length(), 5.4772256f); +void VectorTest::dotSelf() { + CORRADE_COMPARE(Vector4(1.0f, 2.0f, 3.0f, 4.0f).dot(), 30.0f); } -void VectorTest::lengthSquared() { - CORRADE_COMPARE(Vector4(1.0f, 2.0f, 3.0f, 4.0f).lengthSquared(), 30.0f); +void VectorTest::length() { + CORRADE_COMPARE(Vector4(1.0f, 2.0f, 3.0f, 4.0f).length(), 5.4772256f); } void VectorTest::normalized() { diff --git a/src/Math/Test/VectorTest.h b/src/Math/Test/VectorTest.h index a3795d551..e00481d59 100644 --- a/src/Math/Test/VectorTest.h +++ b/src/Math/Test/VectorTest.h @@ -29,8 +29,8 @@ class VectorTest: public Corrade::TestSuite::Tester { void dot(); void multiplyDivide(); void addSubstract(); + void dotSelf(); void length(); - void lengthSquared(); void normalized(); void sum(); void product(); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index fb3232947..5e089d81f 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -70,6 +70,7 @@ template class Vector { * @f[ * a \cdot b = \sum_{i=0}^{n-1} a_ib_i * @f] + * @see dot() const */ static T dot(const Vector& a, const Vector& b) { T out(0); @@ -243,24 +244,26 @@ template class Vector { } /** - * @brief %Vector length + * @brief Dot product of the vector * - * @see lengthSquared() + * Should be used instead of length() for comparing vector length with + * other values, because it doesn't compute the square root, just the + * dot product: @f$ a \cdot a < length \cdot length @f$ is faster + * than @f$ \sqrt{a \cdot a} < length @f$. + * + * @see dot(const Vector&, const Vector&) */ - inline T length() const { - return std::sqrt(dot(*this, *this)); + inline T dot() const { + return dot(*this, *this); } /** - * @brief %Vector length squared + * @brief %Vector length * - * More efficient than length() for comparing vector length with - * other values, because it doesn't compute the square root, just the - * dot product: @f$ a \cdot a < length \cdot length @f$ is faster - * than @f$ \sqrt{a \cdot a} < length @f$. + * @see dot() const */ - inline T lengthSquared() const { - return dot(*this, *this); + inline T length() const { + return std::sqrt(dot()); } /** @brief Normalized vector (of length 1) */ diff --git a/src/Physics/Sphere.cpp b/src/Physics/Sphere.cpp index ac9ed700d..334982b07 100644 --- a/src/Physics/Sphere.cpp +++ b/src/Physics/Sphere.cpp @@ -41,7 +41,7 @@ bool Sphere::collides(const AbstractShape* other) const { } bool Sphere::operator%(const Point& other) const { - return (other.transformedPosition()-transformedPosition()).lengthSquared() < + return (other.transformedPosition()-transformedPosition()).dot() < Math::pow<2>(transformedRadius()); } @@ -56,7 +56,7 @@ bool Sphere::operator%(const LineSegment& other) const { } bool Sphere::operator%(const Sphere& other) const { - return (other.transformedPosition()-transformedPosition()).lengthSquared() < + return (other.transformedPosition()-transformedPosition()).dot() < Math::pow<2>(transformedRadius()+other.transformedRadius()); } From 37a5d6347e68ec618e307118ecb52f0ca219ed69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 17:23:55 +0200 Subject: [PATCH 07/27] Vector::angle() now expects normalized vectors. --- src/Math/Test/CMakeLists.txt | 1 + src/Math/Test/VectorTest.cpp | 9 ++++++++- src/Math/Vector.h | 11 +++++++---- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Math/Test/CMakeLists.txt b/src/Math/Test/CMakeLists.txt index d19e1d975..f71db4d9a 100644 --- a/src/Math/Test/CMakeLists.txt +++ b/src/Math/Test/CMakeLists.txt @@ -1,6 +1,7 @@ corrade_add_test2(MathMathTypeTraitsTest MathTypeTraitsTest.cpp) corrade_add_test2(MathVectorTest VectorTest.cpp) +set_target_properties(MathVectorTest PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) corrade_add_test2(MathVector2Test Vector2Test.cpp) corrade_add_test2(MathVector3Test Vector3Test.cpp) corrade_add_test2(MathVector4Test Vector4Test.cpp) diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index 459084f44..109f50ca9 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -131,7 +131,14 @@ void VectorTest::product() { } void VectorTest::angle() { - CORRADE_COMPARE(Vector3::angle({2.0f, 3.0f, 4.0f}, {1.0f, -2.0f, 3.0f}), rad(1.162514f)); + ostringstream o; + Error::setOutput(&o); + /* Both vectors must be normalized, otherwise NaN is returned */ + CORRADE_COMPARE(Vector3::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), {1.0f, -2.0f, 3.0f}), numeric_limits::quiet_NaN()); + CORRADE_COMPARE(o.str(), "Math::Vector::angle(): vectors must be normalized!\n"); + CORRADE_COMPARE(Vector3::angle({2.0f, 3.0f, 4.0f}, Vector3(1.0f, -2.0f, 3.0f).normalized()), numeric_limits::quiet_NaN()); + + CORRADE_COMPARE(Vector3::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), Vector3(1.0f, -2.0f, 3.0f).normalized()), rad(1.162514f)); } void VectorTest::negative() { diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 5e089d81f..622ee3e00 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -20,6 +20,7 @@ */ #include +#include #include #include "MathTypeTraits.h" @@ -82,16 +83,18 @@ template class Vector { } /** - * @brief Angle between vectors + * @brief Angle between normalized vectors * * @f[ * \phi = \frac{a \cdot b}{|a| \cdot |b|} * @f] - * - * @todo optimize - Assume the vectors are normalized? + * @attention If any of the parameters is not normalized (and + * assertions are enabled), returns NaN. */ inline static T angle(const Vector& a, const Vector& b) { - return std::acos(dot(a, b)/(a.length()*b.length())); + CORRADE_ASSERT(MathTypeTraits::equals(a.dot(), T(1)) && MathTypeTraits::equals(b.dot(), T(1)), + "Math::Vector::angle(): vectors must be normalized!", std::numeric_limits::quiet_NaN()); + return std::acos(dot(a, b)); } /** @brief Default constructor */ From 06872c77274a54f99adfbf5e5773a7b038f6213e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 17:26:38 +0200 Subject: [PATCH 08/27] Added Vector::min() and Vector::max(). --- src/Math/Test/VectorTest.cpp | 10 ++++++++++ src/Math/Test/VectorTest.h | 2 ++ src/Math/Vector.h | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index 109f50ca9..327c2cb49 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -42,6 +42,8 @@ VectorTest::VectorTest() { &VectorTest::normalized, &VectorTest::sum, &VectorTest::product, + &VectorTest::min, + &VectorTest::max, &VectorTest::angle, &VectorTest::negative, &VectorTest::debug); @@ -130,6 +132,14 @@ void VectorTest::product() { CORRADE_COMPARE(Vector3(1.0f, 2.0f, 3.0f).product(), 6.0f); } +void VectorTest::min() { + CORRADE_COMPARE(Vector3(1.0f, -2.0f, 3.0f).min(), -2.0f); +} + +void VectorTest::max() { + CORRADE_COMPARE(Vector3(1.0f, -2.0f, 3.0f).max(), 3.0f); +} + void VectorTest::angle() { ostringstream o; Error::setOutput(&o); diff --git a/src/Math/Test/VectorTest.h b/src/Math/Test/VectorTest.h index e00481d59..662865119 100644 --- a/src/Math/Test/VectorTest.h +++ b/src/Math/Test/VectorTest.h @@ -34,6 +34,8 @@ class VectorTest: public Corrade::TestSuite::Tester { void normalized(); void sum(); void product(); + void min(); + void max(); void angle(); void negative(); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 622ee3e00..96b0fe502 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -294,6 +294,26 @@ template class Vector { return out; } + /** @brief Minimal value in the vector */ + T min() const { + T out((*this)[0]); + + for(size_t i = 1; i != size; ++i) + out = std::min(out, (*this)[i]); + + return out; + } + + /** @brief Maximal value in the vector */ + T max() const { + T out((*this)[0]); + + for(size_t i = 1; i != size; ++i) + out = std::max(out, (*this)[i]); + + return out; + } + private: T _data[size]; }; From 95ca0754f5edda73da017d3eda256a3e7fc4c2f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 17:56:29 +0200 Subject: [PATCH 09/27] Hide MathTypeTraits implementation in Implementation namespace. --- src/Math/MathTypeTraits.h | 42 ++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/Math/MathTypeTraits.h b/src/Math/MathTypeTraits.h index c1a989f8a..4330491e5 100644 --- a/src/Math/MathTypeTraits.h +++ b/src/Math/MathTypeTraits.h @@ -79,39 +79,45 @@ template struct MathTypeTraits { */ #ifndef DOXYGEN_GENERATING_OUTPUT -template struct _MathTypeTraitsIntegral { +namespace Implementation { + +template struct MathTypeTraitsIntegral { inline constexpr static T epsilon() { return 1; } inline constexpr static bool equals(T a, T b) { return a == b; } }; -template<> struct MathTypeTraits: public _MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public _MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public _MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public _MathTypeTraitsIntegral {}; +template struct MathTypeTraitsFloatingPoint { + inline static bool equals(T a, T b) { + return std::abs(a - b) < MathTypeTraits::epsilon(); + } +}; + +} -template<> struct MathTypeTraits: public _MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public _MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; + +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; + +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; /* long is 32 bits somewhere and 64 bits elsewhere, so it cannot be mapped to any of them */ -template<> struct MathTypeTraits: public _MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public _MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public _MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public _MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; -template struct _MathTypeTraitsFloatingPoint { - inline static bool equals(T a, T b) { - return std::abs(a - b) < MathTypeTraits::epsilon(); - } -}; -template<> struct MathTypeTraits: public _MathTypeTraitsFloatingPoint { +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsFloatingPoint { inline constexpr static float epsilon() { return FLOAT_EQUALITY_PRECISION; } }; -template<> struct MathTypeTraits: public _MathTypeTraitsFloatingPoint { +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsFloatingPoint { inline constexpr static double epsilon() { return DOUBLE_EQUALITY_PRECISION; } }; #endif From 3bcaed63220e9f8e0d9fbeccaaa44e702288de10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 21:37:18 +0200 Subject: [PATCH 10/27] Using round() in denormalization. Gives more precise results for smaller types, but creates overflow for large types. --- src/Math/Math.h | 5 +++-- src/Math/Test/MathTest.cpp | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Math/Math.h b/src/Math/Math.h index a0217f88c..cfd22d08a 100644 --- a/src/Math/Math.h +++ b/src/Math/Math.h @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -120,8 +121,8 @@ resulting `Integral` type (e.g. `double` to `int`, `long double` to `long long`) */ template inline constexpr typename std::enable_if::value && std::is_integral::value, Integral>::type denormalize(FloatingPoint value) { return std::numeric_limits::min() + - Integral(value*std::numeric_limits::max()) - - Integral(value*std::numeric_limits::min()); + round(FloatingPoint(value*std::numeric_limits::max()) - + FloatingPoint(value*std::numeric_limits::min())); } /** diff --git a/src/Math/Test/MathTest.cpp b/src/Math/Test/MathTest.cpp index dc02165f5..db4d29676 100644 --- a/src/Math/Test/MathTest.cpp +++ b/src/Math/Test/MathTest.cpp @@ -68,8 +68,8 @@ void MathTest::denormalize() { CORRADE_COMPARE(Math::denormalize(1.0f), 255); /* Between */ - CORRADE_COMPARE(Math::denormalize(0.33f), -11142); - CORRADE_COMPARE(Math::denormalize(0.66f), 10484); + CORRADE_COMPARE(Math::denormalize(0.33f), -11141); + CORRADE_COMPARE(Math::denormalize(0.66f), 10485); /* Test overflow for large types */ CORRADE_COMPARE(Math::denormalize(0.0f), numeric_limits::min()); @@ -79,8 +79,12 @@ void MathTest::denormalize() { CORRADE_COMPARE(Math::denormalize(1.0), numeric_limits::max()); CORRADE_COMPARE(Math::denormalize(1.0), numeric_limits::max()); - CORRADE_COMPARE((Math::denormalize(1.0)), numeric_limits::max()); - CORRADE_COMPARE((Math::denormalize(1.0)), numeric_limits::max()); + + { + CORRADE_EXPECT_FAIL("Denormalize doesn't work for large types well"); + CORRADE_COMPARE((Math::denormalize(1.0)), numeric_limits::max()); + CORRADE_COMPARE((Math::denormalize(1.0)), numeric_limits::max()); + } } void MathTest::pow() { From f2ac32341d802f87100d2bb233a09074760c0f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 21:38:37 +0200 Subject: [PATCH 11/27] Fixed massive bugs in Vector3 and Vector4. "These functions are so simple that no unit test is needed." --- src/Math/Vector3.h | 2 +- src/Math/Vector4.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Math/Vector3.h b/src/Math/Vector3.h index 30072d7f5..2d43ef63b 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -87,7 +87,7 @@ template class Vector3: public Vector<3, T> { inline constexpr Vector2 xy() const { return Vector2::from(Vector<3, T>::data()); } inline constexpr T r() const { return x(); } /**< @brief R component */ - inline constexpr T g() const { return x(); } /**< @brief G component */ + inline constexpr T g() const { return y(); } /**< @brief G component */ inline constexpr T b() const { return z(); } /**< @brief B component */ inline void setR(T value) { setX(value); } /**< @brief Set R component */ diff --git a/src/Math/Vector4.h b/src/Math/Vector4.h index c406ef19b..430b80de0 100644 --- a/src/Math/Vector4.h +++ b/src/Math/Vector4.h @@ -91,7 +91,7 @@ template class Vector4: public Vector<4, T> { inline void setR(T value) { setX(value); } /**< @brief Set R component */ inline void setG(T value) { setY(value); } /**< @brief Set G component */ inline void setB(T value) { setZ(value); } /**< @brief Set B component */ - inline void setA(T value) { setA(value); } /**< @brief Set A component */ + inline void setA(T value) { setW(value); } /**< @brief Set A component */ /** * @brief RGB part of the vector From 57d6ded23796a98d2b88001b75d56d09d26d6177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 22:45:17 +0200 Subject: [PATCH 12/27] Added NumericType and FloatingPointType to Math::MathTypeTraits. NumericType is corresponding numeric type with size at least the same as int. It is used in debug operators for Matrix and Vector to prevent printing chars as characters. If the type isn't already floating-point, FloatingPointType is corresponding larger type with sufficient size for normalization of given integral type. Also updated type traits for long types, they are now subclassed either from int or long long based on sizeof(long). --- src/Math/MathTypeTraits.h | 81 +++++++++++++++++++++++++++++++++------ src/Math/Matrix.h | 2 +- src/Math/Vector.h | 2 +- 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/src/Math/MathTypeTraits.h b/src/Math/MathTypeTraits.h index 4330491e5..5f4bb5cdb 100644 --- a/src/Math/MathTypeTraits.h +++ b/src/Math/MathTypeTraits.h @@ -51,6 +51,22 @@ support given feature, thus forcing the compilation stop with an error. */ template struct MathTypeTraits { #ifdef DOXYGEN_GENERATING_OUTPUT + /** + * @brief Corresponding numeric type large at least as `int` + * + * Usable e.g. to prevent conversion of `char` to characters when printing + * numeric types to output. + */ + typedef U NumericType; + + /** + * @brief Corresponding floating-point type for normalization + * + * If the type is not already floating-point, defines smallest larger + * floating-point type. + */ + typedef U FloatingPointType; + /** * @brief Epsilon value for fuzzy compare * @@ -95,29 +111,70 @@ template struct MathTypeTraitsFloatingPoint { } }; +template struct MathTypeTraitsLong {}; + +template<> struct MathTypeTraitsLong<8> { + typedef unsigned int UnsignedType; + typedef int Type; +}; + +template<> struct MathTypeTraitsLong<16> { + typedef unsigned long long UnsignedType; + typedef long long Type; +}; + } -template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral { + typedef unsigned int NumericType; + typedef float FloatingPointType; +}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral { + typedef int NumericType; + typedef float FloatingPointType; +}; -template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral { + typedef unsigned int NumericType; + typedef float FloatingPointType; +}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral { + typedef int NumericType; + typedef float FloatingPointType; +}; -template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral { + typedef unsigned int NumericType; + typedef double FloatingPointType; +}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral { + typedef int NumericType; + typedef double FloatingPointType; +}; -/* long is 32 bits somewhere and 64 bits elsewhere, so it cannot be mapped to - any of them */ -template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral { + typedef unsigned long long NumericType; + typedef long double FloatingPointType; +}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral { + typedef long long NumericType; + typedef long double FloatingPointType; +}; -template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; -template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral {}; +/* long is 32 bits somewhere and 64 bits elsewhere */ +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral::Type> {}; +template<> struct MathTypeTraits: public Implementation::MathTypeTraitsIntegral::Type> {}; template<> struct MathTypeTraits: public Implementation::MathTypeTraitsFloatingPoint { + typedef float NumericType; + typedef float FloatingPointType; + inline constexpr static float epsilon() { return FLOAT_EQUALITY_PRECISION; } }; template<> struct MathTypeTraits: public Implementation::MathTypeTraitsFloatingPoint { + typedef float NumericType; + typedef double FloatingPointType; + inline constexpr static double epsilon() { return DOUBLE_EQUALITY_PRECISION; } }; #endif diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 540f46d7b..a3e2609fe 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -260,7 +260,7 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili if(row != 0) debug << ",\n "; for(size_t col = 0; col != size; ++col) { if(col != 0) debug << ", "; - debug << value[col][row]; + debug << typename MathTypeTraits::NumericType(value[col][row]); } } debug << ')'; diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 96b0fe502..bfdb1681f 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -324,7 +324,7 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); for(size_t i = 0; i != size; ++i) { if(i != 0) debug << ", "; - debug << value[i]; + debug << typename MathTypeTraits::NumericType(value[i]); } debug << ')'; debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); From c8aa005e866b5f040d97e6a266c8fdc7f014fdfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 22:51:10 +0200 Subject: [PATCH 13/27] Added Color3 and Color4 classes with HSV conversion. They can be used for both floating-point (normalized) and integral (denormalized) representation and support conversion between them. HSV conversion is done always using floating-point types. Getters for RGB(A) were removed from Vector3 and Vector4, they are now part of Color3 and Color4. Because of this, Framebuffer now accepts Color instead of Vector. --- src/AbstractTexture.h | 3 +- src/CMakeLists.txt | 1 + src/Color.h | 409 ++++++++++++++++++++++++++++++++++++++++ src/Framebuffer.h | 3 +- src/Math/Vector3.h | 16 +- src/Math/Vector4.h | 30 +-- src/Test/CMakeLists.txt | 2 + src/Test/ColorTest.cpp | 121 ++++++++++++ src/Test/ColorTest.h | 44 +++++ 9 files changed, 591 insertions(+), 38 deletions(-) create mode 100644 src/Color.h create mode 100644 src/Test/ColorTest.cpp create mode 100644 src/Test/ColorTest.h diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index 97f6fbb3f..c7e2ef512 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -20,6 +20,7 @@ */ #include "Magnum.h" +#include "Color.h" namespace Magnum { @@ -611,7 +612,7 @@ class MAGNUM_EXPORT AbstractTexture { * to `ClampToBorder`. * @requires_gl */ - inline void setBorderColor(const Vector4& color) { + inline void setBorderColor(const Color4& color) { bind(); glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, color.data()); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f6fec80f..cd2fe4927 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,6 +40,7 @@ set(Magnum_HEADERS BufferedTexture.h Buffer.h Camera.h + Color.h CubeMapTextureArray.h CubeMapTexture.h Framebuffer.h diff --git a/src/Color.h b/src/Color.h new file mode 100644 index 000000000..7dd384a1f --- /dev/null +++ b/src/Color.h @@ -0,0 +1,409 @@ +#ifndef Magnum_Color_h +#define Magnum_Color_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + 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::Color3, Magnum::Color4 + */ + +#include + +#include "Math/MathTypeTraits.h" +#include "Math/Math.h" +#include "Math/Vector4.h" + +namespace Magnum { + +template class Color3; + +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + +/* Convert color from HSV */ +template inline typename std::enable_if::value, Color3>::type fromHSV(typename Color3::HSV hsv) { + T hue, saturation, value; + std::tie(hue, saturation, value) = hsv; + + /* Remove repeats */ + hue -= int(hue/T(360))*T(360); + if(hue < T(0)) hue += T(360); + + int h = int(hue/T(60)) % 6; + T f = hue/T(60) - h; + + T p = value * (T(1) - saturation); + T q = value * (T(1) - f*saturation); + T t = value * (T(1) - (T(1) - f)*saturation); + + switch(h) { + case 0: return {value, t, p}; + case 1: return {q, value, p}; + case 2: return {p, value, t}; + case 3: return {p, q, value}; + case 4: return {t, p, value}; + case 5: return {value, p, q}; + default: + CORRADE_ASSERT(false, "It shouldn't get here.", {}); + } +} +template inline typename std::enable_if::value, Color3>::type fromHSV(typename Color3::HSV hsv) { + return Color3::fromNormalized(fromHSV::FloatingPointType>(hsv)); +} + +/* Internal hue computing function */ +template T hue(const Color3& color, T max, T delta) { + T deltaInv60 = T(60)/delta; + + T hue(0); + if(delta != T(0)) { + if(max == color.r()) + hue = (color.g()-color.b())*deltaInv60 + (color.g() < color.b() ? T(360) : T(0)); + else if(max == color.g()) + hue = (color.b()-color.r())*deltaInv60 + T(120); + else /* max == color.b() */ + hue = (color.r()-color.g())*deltaInv60 + T(240); + } + + return hue; +} + +/* Hue, saturation, value for floating-point types */ +template inline T hue(typename std::enable_if::value, const Color3&>::type color) { + T max = color.max(); + T delta = max - color.min(); + return hue(color, max, delta); +} +template inline T saturation(typename std::enable_if::value, const Color3&>::type color) { + T max = color.max(); + T delta = max - color.min(); + return max != T(0) ? delta/max : T(0); +} +template inline T value(typename std::enable_if::value, const Color3&>::type color) { + return color.max(); +} + +/* Hue, saturation, value for integral types */ +template inline typename Color3::FloatingPointType hue(typename std::enable_if::value, const Color3&>::type color) { + return hue::FloatingPointType>(Color3::FloatingPointType>::fromDenormalized(color)); +} +template inline typename Color3::FloatingPointType saturation(typename std::enable_if::value, const Color3&>::type& color) { + return saturation::FloatingPointType>(Color3::FloatingPointType>::fromDenormalized(color)); +} +template inline typename Color3::FloatingPointType value(typename std::enable_if::value, const Color3&>::type color) { + return Math::normalize::FloatingPointType>(color.max()); +} + +/* Convert color to HSV */ +template inline typename Color3::HSV toHSV(typename std::enable_if::value, const Color3&>::type color) { + T max = color.max(); + T delta = max - color.min(); + + return typename Color3::HSV(hue::FloatingPointType>(color, max, delta), max != T(0) ? delta/max : T(0), max); +} +template inline typename Color3::HSV toHSV(typename std::enable_if::value, const Color3&>::type color) { + return toHSV::FloatingPointType>(Color3::FloatingPointType>::fromDenormalized(color)); +} + +/* Default alpha value */ +template inline constexpr typename std::enable_if::value, T>::type defaultAlpha() { + return T(1); +} +template inline constexpr typename std::enable_if::value, T>::type defaultAlpha() { + return std::numeric_limits::max(); +} + +} +#endif + +/** +@brief Three-component (RGB) color + +The class can store both floating-point (normalized) and integral +(denormalized) representation of color. You can convert between these two +representations using fromNormalized() and fromDenormalized(). + +Conversion from and to HSV is done always using floating-point types, so hue +is always in range in range @f$ [0.0, 360.0] @f$, saturation and value in +range @f$ [0.0, 1.0] @f$. + +@see Color4 +*/ +template class Color3: public Math::Vector3 { + public: + /** @brief Corresponding floating-point type for HSV computation */ + typedef typename Math::MathTypeTraits::FloatingPointType FloatingPointType; + + /** + * @brief Type for storing HSV values + * + * Hue in range @f$ [0.0, 360.0] @f$, saturation and value in + * range @f$ [0.0, 1.0] @f$. + */ + typedef std::tuple HSV; + + /** + * @brief Create integral color from floating-point color + * + * E.g. `{0.294118, 0.45098, 0.878431}` is converted to + * `{75, 115, 224}`, if resulting type is `unsigned char`. + * + * @note This function is enabled only if source type is floating-point + * and destination type is integral. + */ + template inline constexpr static typename std::enable_if::value && std::is_floating_point::value, Color3>::type fromNormalized(const Color3& color) { + return Color3(Math::denormalize(color.r()), + Math::denormalize(color.g()), + Math::denormalize(color.b())); + } + + /** + * @brief Create floating-point color from integral color + * + * E.g. `{75, 115, 224}` is converted to + * `{0.294118, 0.45098, 0.878431}`, if source type is `unsigned char`. + * + * @note This function is enabled only if source type is integral + * and destination type is floating-point. + */ + template inline constexpr static typename std::enable_if::value && std::is_integral::value, Color3>::type fromDenormalized(const Color3& color) { + return Color3(Math::normalize(color.r()), + Math::normalize(color.g()), + Math::normalize(color.b())); + } + + /** + * @brief Create RGB color from HSV representation + * @param hsv Hue, saturation and value + * + * Hue can overflow the range @f$ [0.0, 360.0] @f$. + */ + inline constexpr static Color3 fromHSV(HSV hsv) { + return Implementation::fromHSV(hsv); + } + /** @overload */ + inline constexpr static Color3 fromHSV(FloatingPointType hue, FloatingPointType saturation, FloatingPointType value) { + return fromHSV(std::make_tuple(hue, saturation, value)); + } + + /** + * @brief Default constructor + * + * All components are set to zero. + */ + inline constexpr Color3() {} + + /** + * @brief Gray constructor + * @param rgb RGB value + */ + inline constexpr explicit Color3(T rgb): Math::Vector3(rgb) {} + + /** @copydoc Math::Vector::Vector(const Vector&) */ + inline constexpr Color3(const Math::Vector<3, T>& other): Math::Vector3(other) {} + + /** + * @brief Constructor + * @param r R value + * @param g G value + * @param b B value + */ + inline constexpr Color3(T r, T g, T b): Math::Vector3(r, g, b) {} + + inline constexpr T r() const { return Math::Vector3::x(); } /**< @brief R component */ + inline constexpr T g() const { return Math::Vector3::y(); } /**< @brief G component */ + inline constexpr T b() const { return Math::Vector3::z(); } /**< @brief B component */ + + inline void setR(T value) { Math::Vector3::setX(value); } /**< @brief Set R component */ + inline void setG(T value) { Math::Vector3::setY(value); } /**< @brief Set G component */ + inline void setB(T value) { Math::Vector3::setZ(value); } /**< @brief Set B component */ + + /** + * @brief Convert to HSV + * + * Example usage: + * @code + * T hue, saturation, value; + * std::tie(hue, saturation, value) = color.toHSV(); + * @endcode + * + * @see hue(), saturation(), value(), fromHSV() + */ + inline constexpr HSV toHSV() const { + return Implementation::toHSV(*this); + } + + /** + * @brief Hue + * @return Hue in range @f$ [0.0, 360.0] @f$. + * + * @see saturation(), value(), toHSV(), fromHSV() + */ + inline constexpr FloatingPointType hue() const { + return Implementation::hue(*this); + } + + /** + * @brief Saturation + * @return Saturation in range @f$ [0.0, 1.0] @f$. + * + * @see hue(), value(), toHSV(), fromHSV() + */ + inline constexpr FloatingPointType saturation() const { + return Implementation::saturation(*this); + } + + /** + * @brief Value + * @return Value in range @f$ [0.0, 1.0] @f$. + * + * @see hue(), saturation(), toHSV(), fromHSV() + */ + inline constexpr FloatingPointType value() const { + return Implementation::value(*this); + } +}; + +/** +@brief Four-component (RGBA) color + +See Color3 for more information. +*/ +template class Color4: public Math::Vector4 { + public: + /** @copydoc Color3::FloatingPointType */ + typedef typename Color3::FloatingPointType FloatingPointType; + + /** @copydoc Color3::HSV */ + typedef typename Color3::HSV HSV; + + /** @copydoc Color3::fromNormalized() */ + template inline constexpr static typename std::enable_if::value && std::is_floating_point::value, Color4>::type fromNormalized(const Color4& color) { + return Color4(Math::denormalize(color.r()), + Math::denormalize(color.g()), + Math::denormalize(color.b()), + Math::denormalize(color.a())); + } + + /** @copydoc Color3::fromDenormalized() */ + template inline constexpr static typename std::enable_if::value && std::is_integral::value, Color4>::type fromDenormalized(const Color4& color) { + return Color4(Math::normalize(color.r()), + Math::normalize(color.g()), + Math::normalize(color.b()), + Math::normalize(color.a())); + } + + /** + * @copydoc Color3::fromHSV() + * @param a Alpha value, defaults to 1.0 for floating-point types + * and maximum positive value for integral types. + */ + inline constexpr static Color4 fromHSV(HSV hsv, T a = Implementation::defaultAlpha()) { + return Color4(Implementation::fromHSV(hsv), a); + } + /** @overload */ + inline constexpr static Color4 fromHSV(FloatingPointType hue, FloatingPointType saturation, FloatingPointType value, T alpha) { + return fromHSV(std::make_tuple(hue, saturation, value), alpha); + } + + /** + * @brief Default constructor + * + * RGB components are set to zero, A component is set to 1.0 for + * floating-point types and maximum positive value for integral types. + */ + inline constexpr Color4(): Math::Vector4(T(0), T(0), T(0), Implementation::defaultAlpha()) {} + + /** + * @copydoc Color3::Color3(T) + * @param alpha Alpha value, defaults to 1.0 for floating-point types + * and maximum positive value for integral types. + */ + inline constexpr explicit Color4(T rgb, T alpha = Implementation::defaultAlpha()): Math::Vector4(rgb, rgb, rgb, alpha) {} + + /** @copydoc Math::Vector::Vector(const Vector&) */ + inline constexpr Color4(const Math::Vector<4, T>& other): Math::Vector4(other) {} + + /** + * @brief Constructor + * @param r R value + * @param g G value + * @param b B value + * @param a A value, defaults to 1.0 for floating-point types and + * maximum positive value for integral types. + */ + inline constexpr Color4(T r, T g, T b, T a = Implementation::defaultAlpha()): Math::Vector4(r, g, b, a) {} + + /** + * @brief Constructor + * @param rgb Three-component color + * @param a A value + */ + /* Not marked as explicit, because conversion from Color3 to Color4 + is fairly common, nearly always with A set to 1 */ + inline constexpr Color4(const Math::Vector<3, T>& rgb, T a = Implementation::defaultAlpha()): Math::Vector4(rgb[0], rgb[1], rgb[2], a) {} + + inline constexpr T r() const { return Math::Vector4::x(); } /**< @brief R component */ + inline constexpr T g() const { return Math::Vector4::y(); } /**< @brief G component */ + inline constexpr T b() const { return Math::Vector4::z(); } /**< @brief B component */ + inline constexpr T a() const { return Math::Vector4::w(); } /**< @brief A component */ + + inline void setR(T value) { Math::Vector4::setX(value); } /**< @brief Set R component */ + inline void setG(T value) { Math::Vector4::setY(value); } /**< @brief Set G component */ + inline void setB(T value) { Math::Vector4::setZ(value); } /**< @brief Set B component */ + inline void setA(T value) { Math::Vector4::setW(value); } /**< @brief Set A component */ + + /** + * @brief RGB part of the vector + * @return First three components of the vector + * + * @see swizzle() + */ + inline constexpr Color3 rgb() const { return Math::Vector4::xyz(); } + + /** @copydoc Color3::toHSV() */ + inline constexpr HSV toHSV() const { + return Implementation::toHSV(rgb()); + } + + /** @copydoc Color3::hue() */ + inline constexpr FloatingPointType hue() const { + return Implementation::hue(rgb()); + } + + /** @copydoc Color3::saturation() */ + inline constexpr FloatingPointType saturation() const { + return Implementation::saturation(rgb()); + } + + /** @copydoc Color3::value() */ + inline constexpr FloatingPointType value() const { + return Implementation::value(rgb()); + } +}; + +/** @debugoperator{Color3} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color3& value) { + return debug << static_cast&>(value); +} + +/** @debugoperator{Color4} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color4& value) { + return debug << static_cast&>(value); +} + +} + +#endif diff --git a/src/Framebuffer.h b/src/Framebuffer.h index f88a47637..27ee0cb85 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -23,6 +23,7 @@ #include "BufferedImage.h" #include "CubeMapTexture.h" +#include "Color.h" #include "Image.h" #include "Renderbuffer.h" @@ -192,7 +193,7 @@ class MAGNUM_EXPORT Framebuffer { * * Initial value is `{0.0f, 0.0f, 0.0f, 1.0f}`. */ - inline static void setClearColor(const Vector4& color) { + inline static void setClearColor(const Color4& color) { glClearColor(color.r(), color.g(), color.b(), color.a()); } diff --git a/src/Math/Vector3.h b/src/Math/Vector3.h index 2d43ef63b..a4d24fc56 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -57,16 +57,16 @@ template class Vector3: public Vector<3, T> { /** * @brief Constructor - * @param x X / R value - * @param y Y / G value - * @param z Z / B value + * @param x X value + * @param y Y value + * @param z Z value */ inline constexpr Vector3(T x, T y, T z): Vector<3, T>(x, y, z) {} /** * @brief Constructor * @param other Two component vector - * @param z Z / B value + * @param z Z value */ inline constexpr Vector3(const Vector<2, T>& other, T z): Vector<3, T>(other[0], other[1], z) {} @@ -86,14 +86,6 @@ template class Vector3: public Vector<3, T> { */ inline constexpr Vector2 xy() const { return Vector2::from(Vector<3, T>::data()); } - inline constexpr T r() const { return x(); } /**< @brief R component */ - inline constexpr T g() const { return y(); } /**< @brief G component */ - inline constexpr T b() const { return z(); } /**< @brief B component */ - - inline void setR(T value) { setX(value); } /**< @brief Set R component */ - inline void setG(T value) { setY(value); } /**< @brief Set G component */ - inline void setB(T value) { setZ(value); } /**< @brief Set B component */ - MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3) }; diff --git a/src/Math/Vector4.h b/src/Math/Vector4.h index 430b80de0..490f2dcea 100644 --- a/src/Math/Vector4.h +++ b/src/Math/Vector4.h @@ -29,7 +29,7 @@ template class Vector4: public Vector<4, T> { /** * @copydoc Vector::Vector * - * W / A component is set to one. + * W component is set to one. */ inline constexpr Vector4(): Vector<4, T>(T(0), T(0), T(0), T(1)) {} @@ -41,17 +41,17 @@ template class Vector4: public Vector<4, T> { /** * @brief Constructor - * @param x X / R value - * @param y Y / G value - * @param z Z / B value - * @param w W / A value + * @param x X value + * @param y Y value + * @param z Z value + * @param w W value */ inline constexpr Vector4(T x, T y, T z, T w = T(1)): Vector<4, T>(x, y, z, w) {} /** * @brief Constructor * @param other Three component vector - * @param w W / A value + * @param w W value */ /* Not marked as explicit, because conversion from Vector3 to Vector4 is fairly common, nearly always with W set to 1 */ @@ -83,24 +83,6 @@ template class Vector4: public Vector<4, T> { */ inline constexpr Vector2 xy() const { return Vector2::from(Vector<4, T>::data()); } - inline constexpr T r() const { return x(); } /**< @brief R component */ - inline constexpr T g() const { return y(); } /**< @brief G component */ - inline constexpr T b() const { return z(); } /**< @brief B component */ - inline constexpr T a() const { return w(); } /**< @brief A component */ - - inline void setR(T value) { setX(value); } /**< @brief Set R component */ - inline void setG(T value) { setY(value); } /**< @brief Set G component */ - inline void setB(T value) { setZ(value); } /**< @brief Set B component */ - inline void setA(T value) { setW(value); } /**< @brief Set A component */ - - /** - * @brief RGB part of the vector - * @return First three components of the vector - * - * @see swizzle() - */ - inline constexpr Vector3 rgb() const { return xyz(); } - MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4) }; diff --git a/src/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 61f80a3a6..6c20f9a69 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -1,3 +1,5 @@ corrade_add_test2(ObjectTest ObjectTest.cpp LIBRARIES MagnumTestLib) corrade_add_test2(CameraTest CameraTest.cpp LIBRARIES Magnum) corrade_add_test2(SceneTest SceneTest.cpp LIBRARIES Magnum) + +corrade_add_test2(ColorTest ColorTest.cpp) diff --git a/src/Test/ColorTest.cpp b/src/Test/ColorTest.cpp new file mode 100644 index 000000000..a500ffee4 --- /dev/null +++ b/src/Test/ColorTest.cpp @@ -0,0 +1,121 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + 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 "ColorTest.h" + +#include "Color.h" + +using namespace std; + +CORRADE_TEST_MAIN(Magnum::Test::ColorTest) + +namespace Magnum { namespace Test { + +typedef Magnum::Color3 Color3; +typedef Magnum::Color4 Color4; +typedef Magnum::Color3 Color3f; + +ColorTest::ColorTest() { + addTests(&ColorTest::fromDenormalized, + &ColorTest::fromNormalized, + + &ColorTest::fromHue, + &ColorTest::fromSaturation, + &ColorTest::fromValue, + + &ColorTest::hue, + &ColorTest::saturation, + &ColorTest::value, + + &ColorTest::hsv, + &ColorTest::hsvOverflow, + &ColorTest::hsvAlpha); +} + +void ColorTest::fromDenormalized() { + CORRADE_COMPARE(Color3f::fromDenormalized(Color3(75, 115, 224)), Color3f(0.294118, 0.45098, 0.878431)); +} + +void ColorTest::fromNormalized() { + CORRADE_COMPARE(Color3::fromNormalized(Color3f(0.294118, 0.45098, 0.878431)), Color3(75, 115, 224)); +} + +void ColorTest::fromHue() { + CORRADE_COMPARE(Color3::fromHSV(27.0f, 1.0f, 1.0f), Color3(255, 115, 0)); + CORRADE_COMPARE(Color3::fromHSV(86.0f, 1.0f, 1.0f), Color3(145, 255, 0)); + CORRADE_COMPARE(Color3::fromHSV(134.0f, 1.0f, 1.0f), Color3(0, 255, 60)); + CORRADE_COMPARE(Color3::fromHSV(191.0f, 1.0f, 1.0f), Color3(0, 208, 255)); + CORRADE_COMPARE(Color3::fromHSV(269.0f, 1.0f, 1.0f), Color3(123, 0, 255)); + CORRADE_COMPARE(Color3::fromHSV(317.0f, 1.0f, 1.0f), Color3(255, 0, 183)); +} + +void ColorTest::hue() { + CORRADE_COMPARE(Color3(255, 115, 0).hue(), 27.058824f); + CORRADE_COMPARE(Color3(145, 255, 0).hue(), 85.882353f); + CORRADE_COMPARE(Color3(0, 255, 60).hue(), 134.11765f); + CORRADE_COMPARE(Color3(0, 208, 255).hue(), 191.05882f); + CORRADE_COMPARE(Color3(123, 0, 255).hue(), 268.94117f); + CORRADE_COMPARE(Color3(255, 0, 183).hue(), 316.94117f); +} + +void ColorTest::fromSaturation() { + CORRADE_COMPARE(Color3::fromHSV(0.0f, 0.702f, 1.0f), Color3(255, 76, 76)); +} + +void ColorTest::saturation() { + CORRADE_COMPARE(Color3(255, 76, 76).saturation(), 0.701961f); + CORRADE_COMPARE(Color3().saturation(), 0.0f); +} + +void ColorTest::fromValue() { + CORRADE_COMPARE(Color3::fromHSV(0.0f, 1.0f, 0.522f), Color3(133, 0, 0)); +} + +void ColorTest::value() { + CORRADE_COMPARE(Color3(133, 0, 0).value(), 0.521569f); +} + +void ColorTest::hsv() { + CORRADE_COMPARE(Color3::fromHSV(230.0f, 0.749f, 0.427f), Color3(27, 41, 109)); + + float hue, saturation, value; + tie(hue, saturation, value) = Color3(27, 41, 109).toHSV(); + CORRADE_COMPARE(hue, 229.756106f); + CORRADE_COMPARE(saturation, 0.752294f); + CORRADE_COMPARE(value, 0.427451f); +} + +void ColorTest::hsvOverflow() { + CORRADE_COMPARE(Color3::fromHSV(27.0f-360.0f, 1.0f, 1.0f), Color3(255, 115, 0)); + CORRADE_COMPARE(Color3::fromHSV(86.0f-360.0f, 1.0f, 1.0f), Color3(145, 255, 0)); + CORRADE_COMPARE(Color3::fromHSV(134.0f-360.0f, 1.0f, 1.0f), Color3(0, 255, 60)); + CORRADE_COMPARE(Color3::fromHSV(191.0f-360.0f, 1.0f, 1.0f), Color3(0, 208, 255)); + CORRADE_COMPARE(Color3::fromHSV(269.0f-360.0f, 1.0f, 1.0f), Color3(123, 0, 255)); + CORRADE_COMPARE(Color3::fromHSV(317.0f-360.0f, 1.0f, 1.0f), Color3(255, 0, 183)); + + CORRADE_COMPARE(Color3::fromHSV(360.0f+27.0f, 1.0f, 1.0f), Color3(255, 115, 0)); + CORRADE_COMPARE(Color3::fromHSV(360.0f+86.0f, 1.0f, 1.0f), Color3(145, 255, 0)); + CORRADE_COMPARE(Color3::fromHSV(360.0f+134.0f, 1.0f, 1.0f), Color3(0, 255, 60)); + CORRADE_COMPARE(Color3::fromHSV(360.0f+191.0f, 1.0f, 1.0f), Color3(0, 208, 255)); + CORRADE_COMPARE(Color3::fromHSV(360.0f+269.0f, 1.0f, 1.0f), Color3(123, 0, 255)); + CORRADE_COMPARE(Color3::fromHSV(360.0f+317.0f, 1.0f, 1.0f), Color3(255, 0, 183)); +} + +void ColorTest::hsvAlpha() { + CORRADE_COMPARE(Color4::fromHSV(make_tuple(230.0f, 0.749f, 0.427f), 23), Color4(27, 41, 109, 23)); + CORRADE_COMPARE(Color4::fromHSV(230.0f, 0.749f, 0.427f, 23), Color4(27, 41, 109, 23)); +} + +}} diff --git a/src/Test/ColorTest.h b/src/Test/ColorTest.h new file mode 100644 index 000000000..068e36da6 --- /dev/null +++ b/src/Test/ColorTest.h @@ -0,0 +1,44 @@ +#ifndef Magnum_Test_ColorTest_h +#define Magnum_Test_ColorTest_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + 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 + +namespace Magnum { namespace Test { + +class ColorTest: public Corrade::TestSuite::Tester { + public: + ColorTest(); + + void fromDenormalized(); + void fromNormalized(); + + void fromHue(); + void fromSaturation(); + void fromValue(); + + void hue(); + void saturation(); + void value(); + + void hsv(); + void hsvOverflow(); + void hsvAlpha(); +}; + +}} + +#endif From e5a72b25ce2ae8b025d72fab2b8d331e597a31b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 23:13:19 +0200 Subject: [PATCH 14/27] Have non-explicit parameterless constructor for Vector3. So it's possible to return Vector3 as {}. --- src/Math/Vector3.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Math/Vector3.h b/src/Math/Vector3.h index a4d24fc56..040fe1f58 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -49,8 +49,11 @@ template class Vector3: public Vector<3, T> { a[0]*b[1]-a[1]*b[0]); } + /** @copydoc Vector::Vector() */ + inline constexpr Vector3() {} + /** @copydoc Vector::Vector(T) */ - inline constexpr explicit Vector3(T value = T()): Vector<3, T>(value, value, value) {} + inline constexpr explicit Vector3(T value): Vector<3, T>(value, value, value) {} /** @copydoc Vector::Vector(const Vector&) */ inline constexpr Vector3(const Vector<3, T>& other): Vector<3, T>(other) {} From 88e6221ac30a403800a3f79c25e02cd3a5023c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2012 23:25:34 +0200 Subject: [PATCH 15/27] Better name for parameter in VectorN constructor from VectorN-1. --- src/Math/Vector3.h | 6 +++--- src/Math/Vector4.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Math/Vector3.h b/src/Math/Vector3.h index 040fe1f58..d70e6dc08 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -68,10 +68,10 @@ template class Vector3: public Vector<3, T> { /** * @brief Constructor - * @param other Two component vector - * @param z Z value + * @param xy Two component vector + * @param z Z value */ - inline constexpr Vector3(const Vector<2, T>& other, T z): Vector<3, T>(other[0], other[1], z) {} + inline constexpr Vector3(const Vector<2, T>& xy, T z): Vector<3, T>(xy[0], xy[1], z) {} inline constexpr T x() const { return (*this)[0]; } /**< @brief X component */ inline constexpr T y() const { return (*this)[1]; } /**< @brief Y component */ diff --git a/src/Math/Vector4.h b/src/Math/Vector4.h index 490f2dcea..32d4f3c51 100644 --- a/src/Math/Vector4.h +++ b/src/Math/Vector4.h @@ -50,12 +50,12 @@ template class Vector4: public Vector<4, T> { /** * @brief Constructor - * @param other Three component vector - * @param w W value + * @param xyz Three component vector + * @param w W value */ /* Not marked as explicit, because conversion from Vector3 to Vector4 is fairly common, nearly always with W set to 1 */ - inline constexpr Vector4(const Vector<3, T>& other, T w = T(1)): Vector<4, T>(other[0], other[1], other[2], w) {} + inline constexpr Vector4(const Vector<3, T>& xyz, T w = T(1)): Vector<4, T>(xyz[0], xyz[1], xyz[2], w) {} inline constexpr T x() const { return (*this)[0]; } /**< @brief X component */ inline constexpr T y() const { return (*this)[1]; } /**< @brief Y component */ From a22bbc9e1513e7c63904119c709762cfd0548d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 7 Aug 2012 01:12:39 +0200 Subject: [PATCH 16/27] Removed @todo (deprecated in GLES 3.0). --- src/AbstractTexture.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index c7e2ef512..79e912b9d 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -234,8 +234,6 @@ class MAGNUM_EXPORT AbstractTexture { * * For more information about default values for unused components and * normalization see enums Components and ComponentType. - * @todo ES2 - GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA? They are - * deprecated everywhere else. */ enum class Format: GLenum { #ifndef MAGNUM_TARGET_GLES From 2526f7f777a479a70b78d79f9be6271aa4daa208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 7 Aug 2012 02:07:50 +0200 Subject: [PATCH 17/27] GL_PRIMITIVES_GENERATED is since OpenGL 3.1. --- src/Query.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Query.h b/src/Query.h index a9780572b..27eb78ea3 100644 --- a/src/Query.h +++ b/src/Query.h @@ -109,6 +109,8 @@ class MAGNUM_EXPORT Query: public AbstractQuery { /** * Count of primitives generated from vertex shader or geometry * shader. + * + * @requires_gl31 (no extension providing this functionality) */ PrimitivesGenerated = GL_PRIMITIVES_GENERATED, From eac99d026e73e8cb95b53320461b25556671fdf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 7 Aug 2012 02:35:41 +0200 Subject: [PATCH 18/27] Conditional render is since OpenGL 3.0. --- src/Query.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Query.h b/src/Query.h index 27eb78ea3..aeff12ce8 100644 --- a/src/Query.h +++ b/src/Query.h @@ -182,6 +182,7 @@ q.beginConditionalRender(SampleQuery::ConditionalRenderMode::Wait); q.endConditionalRender(); @endcode @requires_gl +@requires_gl30 Extension @extension{NV,conditional_render} */ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { public: From 84566091197ea444ab4592ec447c48d280502de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 7 Aug 2012 14:25:01 +0200 Subject: [PATCH 19/27] Mention only OpenGL ES (without version). --- Doxyfile | 2 +- doc/mainpage.dox | 2 +- doc/required-extensions.dox | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doxyfile b/Doxyfile index 23f6dc968..40f5bcd66 100644 --- a/Doxyfile +++ b/Doxyfile @@ -198,7 +198,7 @@ ALIASES = \ "debugoperator{1}=@relates \1\n@brief Debug output operator" \ "collisionoperator{2}=@relates \1\n@brief Collision of %\1 and %\2\n@see \2::operator%(const \1&) const" \ "todoc=@xrefitem todoc \"Documentation todo\" \"Documentation-related todo list\"" \ - "requires_gl=@xrefitem requires-gl \"Requires desktop OpenGL\" \"Functionality requiring desktop OpenGL (not available on OpenGL ES 2)\" Not available on OpenGL ES 2." \ + "requires_gl=@xrefitem requires-gl \"Requires desktop OpenGL\" \"Functionality requiring desktop OpenGL (not available on OpenGL ES)\" Not available on OpenGL ES." \ "requires_gl30=@xrefitem requires-gl30 \"Requires OpenGL 3.0\" \"Functionality requiring OpenGL 3.0\"" \ "requires_gl31=@xrefitem requires-gl31 \"Requires OpenGL 3.1\" \"Functionality requiring OpenGL 3.1\"" \ "requires_gl32=@xrefitem requires-gl32 \"Requires OpenGL 3.2\" \"Functionality requiring OpenGL 3.2\"" \ diff --git a/doc/mainpage.dox b/doc/mainpage.dox index 460ce6399..3e369b994 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -26,7 +26,7 @@ Features: The engine is meant to be run on OpenGL 3 capable hardware, but most of the functionality is working on OpenGL 2.1 hardware too. The engine can be built -also for OpenGL ES 2 with limited functionality. See also @ref required-extensions. +also for OpenGL ES with limited functionality. See also @ref required-extensions. @section download-build Downloading and building Magnum diff --git a/doc/required-extensions.dox b/doc/required-extensions.dox index 1b2daf898..c35629ca5 100644 --- a/doc/required-extensions.dox +++ b/doc/required-extensions.dox @@ -3,8 +3,8 @@ The engine is meant to be run on OpenGL 3 capable hardware, but most of the functionality is working in OpenGL 2.1 hardware too (i.e. integrated Intel -GPUs), unless stated otherwise. OpenGL ES 2 is also supported, see -@ref building for guide how to build the engine for it. +GPUs), unless stated otherwise. OpenGL ES is also supported, see @ref building +for guide how to build the engine for it. Following are lists of functionality requiring specific OpenGL version. In most cases it is also specified which extension is required for given @@ -22,7 +22,7 @@ supported on Intel GPUs even if they are capable of OpenGL 2.1 only). - @subpage requires-gl42 - @subpage requires-extension -@page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES 2) +@page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES) @page requires-gl30 Functionality requiring OpenGL 3.0 @page requires-gl31 Functionality requiring OpenGL 3.1 @page requires-gl32 Functionality requiring OpenGL 3.2 From 1ec34457ee4f81c2f7ccdd47978f83ad1eccaf3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 7 Aug 2012 14:54:41 +0200 Subject: [PATCH 20/27] Clarified required GL versions for shader attribute binding. Also updated section names to follow coding style. --- src/AbstractShaderProgram.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/AbstractShaderProgram.h b/src/AbstractShaderProgram.h index 5027984ca..d15c2aeb9 100644 --- a/src/AbstractShaderProgram.h +++ b/src/AbstractShaderProgram.h @@ -28,7 +28,7 @@ namespace Magnum { /** @ingroup rendering @brief Base class for shaders -@section AbstractShaderProgramSubclassing Subclassing workflow +@section AbstractShaderProgram-subclassing Subclassing workflow This class is designed to be used via subclassing. Subclasses define these functions and properties: @@ -73,7 +73,7 @@ void setProjectionMatrixUniform(const Matrix4& matrix) { } @endcode -@subsection AbstractShaderProgramAttributeLocation Binding attribute location +@subsection AbstractShaderProgram-attribute-location Binding attribute location The preferred workflow is to specify attribute location for vertex shader input attributes and fragment shader output attributes explicitly in the shader code, e.g.: @@ -82,8 +82,12 @@ layout(location = 0) in vec4 vertex; layout(location = 1) in vec3 normal; layout(location = 2) in vec2 textureCoords; @endcode -@requires_gl (for explicit attribute location instead of using - bindAttributeLocation()) +@requires_gl (for explicit input attribute location instead of using + bindAttributeLocation()) +@requires_gl (for explicit output attribute location or using + bindFragmentDataLocation()) +@requires_gl30 Extension @extension{EXT,gpu_shader4} (for using + bindFragmentDataLocation()) @requires_gl33 Extension @extension{ARB,explicit_attrib_location} (for explicit attribute location instead of using bindAttributeLocation()) @@ -100,7 +104,7 @@ bindAttributeLocation(TextureCoords::Location, "textureCoords"); // Link... @endcode -@subsection AbstractShaderProgramTextureLayer Binding texture layer uniforms +@subsection AbstractShaderProgram-texture-layer Binding texture layer uniforms The preferred workflow is to specify texture layers directly in the shader code, e.g.: @code @@ -120,7 +124,7 @@ setUniform(uniformLocation("diffuseTexture"), DiffuseTextureLayer); setUniform(uniformLocation("specularTexture"), SpecularTextureLayer); @endcode -@section AbstractShaderProgramRenderingWorkflow Rendering workflow +@section AbstractShaderProgram-rendering-workflow Rendering workflow Basic workflow with %AbstractShaderProgram subclasses is: instancing the class (once at the beginning), then in Object::draw() reimplementation calling @@ -238,7 +242,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * before link(). * @deprecated Preferred usage is to specify attribute location * explicitly in the shader instead of using this function. See - * @ref AbstractShaderProgramAttributeLocation "class documentation" + * @ref AbstractShaderProgram-attribute-location "class documentation" * for more information. */ void bindAttributeLocation(GLuint location, const std::string& name); @@ -253,7 +257,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * before link(). * @deprecated Preferred usage is to specify attribute location * explicitly in the shader instead of using this function. See - * @ref AbstractShaderProgramAttributeLocation "class documentation" + * @ref AbstractShaderProgram-attribute-location "class documentation" * for more information. * @requires_gl * @requires_gl30 Extension @extension{EXT,gpu_shader4} From 6057693f9a8bb7388d8dd68a0229cf41cc6a0f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 7 Aug 2012 15:03:03 +0200 Subject: [PATCH 21/27] Clarified required GL version for some Query result types. --- src/Query.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Query.h b/src/Query.h index aeff12ce8..de768b09e 100644 --- a/src/Query.h +++ b/src/Query.h @@ -64,7 +64,7 @@ class MAGNUM_EXPORT AbstractQuery { * Note that this function is blocking until the result is available. * See resultAvailable(). * - * @requires_gl33 Extension @extension{ARB,timer_query} (64bit integers) + * @requires_gl33 Extension @extension{ARB,timer_query} (result type `GLuint64` and `GLint64`) */ template T result(); From e7bb19b70b69f0f2f4ed2bfd68351448975e8bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 7 Aug 2012 16:36:32 +0200 Subject: [PATCH 22/27] Documented unsized internal depth/stencil format. --- src/AbstractTexture.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index 79e912b9d..f30f78cb3 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -439,12 +439,21 @@ class MAGNUM_EXPORT AbstractTexture { CompressedBptcRGBUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, #endif - /** Depth component. */ + /** + * Depth component, at least 16bit. + * + * Prefer to use the exactly specified version of this format, in + * this case e.g. `Format::Depth16`. + */ Depth = GL_DEPTH_COMPONENT, #ifndef MAGNUM_TARGET_GLES /** - * Depth and stencil component. + * Depth and stencil component, at least 24bit depth and 8bit + * stencil. + * + * Prefer to use the exactly specified version of this format, in + * this case e.g. `Format::Depth24Stencil8`. * @requires_gl */ DepthStencil = GL_DEPTH_STENCIL, From ac5969ee489a647320176b2a97ca5331bcf8461e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 9 Aug 2012 00:21:59 +0200 Subject: [PATCH 23/27] Don't copy enum value twice only because preprocessor. --- src/Renderbuffer.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index 94b75a915..b4c47b23a 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -98,10 +98,10 @@ class Renderbuffer { DepthStencil = GL_DEPTH_STENCIL, #endif - #ifdef MAGNUM_TARGET_GLES Depth16 = GL_DEPTH_COMPONENT16 - #else - Depth16 = GL_DEPTH_COMPONENT16, + + #ifndef MAGNUM_TARGET_GLES + , Depth24 = GL_DEPTH_COMPONENT24, DepthFloat = GL_DEPTH_COMPONENT32F, From 9cb27a4dc38ff3f875fe6c85dcb2853763eed73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 9 Aug 2012 00:24:50 +0200 Subject: [PATCH 24/27] Depth/stencil can be stored only in renderbuffer in OpenGL ES 2.0. Moreover only sized version is permitted. --- src/AbstractImage.h | 19 ++++++++++++------- src/AbstractTexture.h | 18 +++++++++--------- src/Renderbuffer.h | 4 +--- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/AbstractImage.h b/src/AbstractImage.h index a8d9f0c5c..3dea087db 100644 --- a/src/AbstractImage.h +++ b/src/AbstractImage.h @@ -72,9 +72,11 @@ class MAGNUM_EXPORT AbstractImage { #endif RGB = GL_RGB, /**< Three-component RGB */ - RGBA = GL_RGBA, /**< Four-component RGBA */ + RGBA = GL_RGBA /**< Four-component RGBA */ #ifndef MAGNUM_TARGET_GLES + , + /** * Three-component BGR * @requires_gl @@ -86,16 +88,19 @@ class MAGNUM_EXPORT AbstractImage { * @requires_gl */ BGRA = GL_BGRA, - #endif - /** Depth component. For framebuffer reading only. */ + /** + * Depth component. For framebuffer reading only. + * @requires_gl + */ Depth = GL_DEPTH_COMPONENT, - /** Stencil index. For framebuffer reading only. */ - StencilIndex = GL_STENCIL_INDEX + /** + * Stencil index. For framebuffer reading only. + * @requires_gl + */ + StencilIndex = GL_STENCIL_INDEX, - #ifndef MAGNUM_TARGET_GLES - , /** * Depth and stencil component. For framebuffer reading only. * @requires_gl diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index f30f78cb3..ce766a7ab 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -344,10 +344,12 @@ class MAGNUM_EXPORT AbstractTexture { * Three-component RGB, unsigned normalized, red and blue 5bit, * green 6bit, 16bit total. */ - RGB565 = GL_RGB565, + RGB565 = GL_RGB565 #endif #ifndef MAGNUM_TARGET_GLES + , + /** * Three-component RGB, unsigned with exponent, each component * 9bit, exponent 5bit, 32bit total. @@ -407,7 +409,6 @@ class MAGNUM_EXPORT AbstractTexture { * @requires_gl30 Extension @extension{EXT,texture_compression_rgtc} */ CompressedRtgcSignedRedGreen = GL_COMPRESSED_SIGNED_RG_RGTC2, - #endif #if defined(GL_COMPRESSED_RGBA_BPTC_UNORM) || defined(DOXYGEN_GENERATING_OUTPUT) /** @@ -444,10 +445,10 @@ class MAGNUM_EXPORT AbstractTexture { * * Prefer to use the exactly specified version of this format, in * this case e.g. `Format::Depth16`. + * @requires_gl */ Depth = GL_DEPTH_COMPONENT, - #ifndef MAGNUM_TARGET_GLES /** * Depth and stencil component, at least 24bit depth and 8bit * stencil. @@ -457,13 +458,12 @@ class MAGNUM_EXPORT AbstractTexture { * @requires_gl */ DepthStencil = GL_DEPTH_STENCIL, - #endif - /** 16bit depth component. */ - Depth16 = GL_DEPTH_COMPONENT16 - - #ifndef MAGNUM_TARGET_GLES - , + /** + * 16bit depth component. + * @requires_gl + */ + Depth16 = GL_DEPTH_COMPONENT16, /** * 24bit depth component. diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index b4c47b23a..11e3c98c4 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -92,10 +92,8 @@ class Renderbuffer { RGB565 = GL_RGB565, #endif - Depth = GL_DEPTH_COMPONENT, - #ifndef MAGNUM_TARGET_GLES - DepthStencil = GL_DEPTH_STENCIL, + Depth = GL_DEPTH_COMPONENT, DepthStencil = GL_DEPTH_STENCIL, #endif Depth16 = GL_DEPTH_COMPONENT16 From f2dbb9e8d96030ede84d4fa00aada3ee2ec3e631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 9 Aug 2012 00:27:20 +0200 Subject: [PATCH 25/27] Don't copy unneeded from AbstractTexture documentation. --- src/BufferedTexture.h | 17 +++++++++++++---- src/Renderbuffer.h | 6 +++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/BufferedTexture.h b/src/BufferedTexture.h index 591ef3c11..fca8f74fc 100644 --- a/src/BufferedTexture.h +++ b/src/BufferedTexture.h @@ -49,18 +49,27 @@ class BufferedTexture { public: /** @{ @name Internal buffered texture formats */ - /** @copydoc Renderbuffer::Components */ + /** + * @copybrief AbstractTexture::Components + * + * Like AbstractTexture::Components, without three-component RGB. + */ enum class Components { Red, RedGreen, RGBA }; - /** @copydoc Renderbuffer::ComponentType */ + /** + * @copybrief AbstractTexture::ComponentType + * + * Like AbstractTexture::ComponentType, without normalized signed + * types. + */ enum class ComponentType { UnsignedByte, Byte, UnsignedShort, Short, UnsignedInt, Int, Half, Float, NormalizedUnsignedByte, NormalizedUnsignedShort }; - /** @copydoc AbstractTexture::Format */ + /** @copybrief AbstractTexture::Format */ enum class Format: GLenum { /** * Three-component RGB, float, each component 32bit, 96bit total. @@ -89,7 +98,7 @@ class BufferedTexture { /** @copydoc AbstractTexture::InternalFormat */ class MAGNUM_EXPORT InternalFormat { public: - /** @copydoc AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components, AbstractTexture::ComponentType) */ + /** @copybrief AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components, AbstractTexture::ComponentType) */ InternalFormat(Components components, ComponentType type); /** @copydoc AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Format) */ diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index 11e3c98c4..2c78954fc 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -41,7 +41,7 @@ class Renderbuffer { #ifndef MAGNUM_TARGET_GLES /** - * @copydoc AbstractTexture::Components + * @copybrief AbstractTexture::Components * * Like AbstractTexture::Components, without three-component RGB. * @requires_gl @@ -51,7 +51,7 @@ class Renderbuffer { }; /** - * @copydoc AbstractTexture::ComponentType + * @copybrief AbstractTexture::ComponentType * * Like AbstractTexture::ComponentType, without normalized signed * types. @@ -64,7 +64,7 @@ class Renderbuffer { #endif /** - * @copydoc AbstractTexture::Format + * @copybrief AbstractTexture::Format * * Like AbstractTexture::Format without * AbstractTexture::Format::RGB9Intensity5, three-component and From 26b6d40a8b5cfb59e02569eb859f97d1e00c8ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 9 Aug 2012 00:48:18 +0200 Subject: [PATCH 26/27] Added separate stencil formats to Renderbuffer. --- src/Renderbuffer.h | 57 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index 2c78954fc..3a9d14145 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -68,7 +68,7 @@ class Renderbuffer { * * Like AbstractTexture::Format without * AbstractTexture::Format::RGB9Intensity5, three-component and - * compressed formats. + * compressed formats, but with added separate stencil index. */ enum class Format: GLenum { #ifndef MAGNUM_TARGET_GLES @@ -93,21 +93,64 @@ class Renderbuffer { #endif #ifndef MAGNUM_TARGET_GLES - Depth = GL_DEPTH_COMPONENT, DepthStencil = GL_DEPTH_STENCIL, + /** + * Depth component, at least 16bit. + * + * Prefer to use the exactly specified version of this format, in + * this case e.g. `Format::%Depth16`. + * @requires_gl Use exactly specified format Format::%Depth16 instead. + */ + Depth = GL_DEPTH_COMPONENT, + + DepthStencil = GL_DEPTH_STENCIL, #endif - Depth16 = GL_DEPTH_COMPONENT16 + Depth16 = GL_DEPTH_COMPONENT16, #ifndef MAGNUM_TARGET_GLES - , - Depth24 = GL_DEPTH_COMPONENT24, DepthFloat = GL_DEPTH_COMPONENT32F, + + /** + * Stencil index (unspecified size). + * + * Prefer to use the exactly specified version of this format, in + * this case e.g. `Format::%Stencil8`. + * @requires_gl Use exactly specified format Format::%Stencil8 instead. + */ + Stencil = GL_STENCIL_INDEX, + + /** + * 1-bit stencil index. + * + * @requires_gl Use Format::%Stencil8 instead. + */ + Stencil1 = GL_STENCIL_INDEX1, + + /** + * 4-bit stencil index. + * + * @requires_gl Use Format::%Stencil8 instead. + */ + Stencil4 = GL_STENCIL_INDEX4, + #endif + + /** 8-bit stencil index. */ + Stencil8 = GL_STENCIL_INDEX8 + + #ifndef MAGNUM_TARGET_GLES + , + + /** + * 16-bit stencil index. + * + * @requires_gl Use Format::%Stencil8 instead. + */ + Stencil16 = GL_STENCIL_INDEX1, + Depth24Stencil8 = GL_DEPTH24_STENCIL8, DepthFloatStencil8 = GL_DEPTH32F_STENCIL8 #endif - - /** @todo GL_STENCIL_INDEX1 - GL_STENCIL_INDEX16 (renderbuffer only) */ }; /** @copydoc AbstractTexture::InternalFormat */ From 5c5da2b2f3259949a550836414712f88a16aceac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 9 Aug 2012 00:59:00 +0200 Subject: [PATCH 27/27] Clarified required OpenGL versions for queries. Query depends on 3.0/EXT_transform_feedback (also PRIMITIVES_GENERATED, even if it wasn't in the specs), only part of SampleQuery requires 3.0/NV_conditional_render, the rest is in 2.1 already. --- src/Query.h | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Query.h b/src/Query.h index de768b09e..38d4d1cf1 100644 --- a/src/Query.h +++ b/src/Query.h @@ -101,6 +101,7 @@ if(!q.resultAvailable()) { GLuint primitiveCount = q.result(); @endcode @requires_gl +@requires_gl30 Extension @extension{EXT,transform_feedback} */ class MAGNUM_EXPORT Query: public AbstractQuery { public: @@ -109,8 +110,6 @@ class MAGNUM_EXPORT Query: public AbstractQuery { /** * Count of primitives generated from vertex shader or geometry * shader. - * - * @requires_gl31 (no extension providing this functionality) */ PrimitivesGenerated = GL_PRIMITIVES_GENERATED, @@ -182,7 +181,6 @@ q.beginConditionalRender(SampleQuery::ConditionalRenderMode::Wait); q.endConditionalRender(); @endcode @requires_gl -@requires_gl30 Extension @extension{NV,conditional_render} */ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { public: @@ -199,7 +197,11 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { AnySamplesPassed = GL_ANY_SAMPLES_PASSED }; - /** @brief Conditional render mode */ + /** + * @brief Conditional render mode + * + * @requires_gl30 Extension @extension{NV,conditional_render} + */ enum class ConditionalRenderMode: GLenum { /** * If query result is not yet available, waits for it and @@ -236,12 +238,20 @@ class MAGNUM_EXPORT SampleQuery: public AbstractQuery { /** @copydoc Query::end() */ void end(); - /** @brief Begin conditional rendering based on result value */ + /** + * @brief Begin conditional rendering based on result value + * + * @requires_gl30 Extension @extension{NV,conditional_render} + */ inline void beginConditionalRender(ConditionalRenderMode mode) { glBeginConditionalRender(query, static_cast(mode)); } - /** @brief End conditional render */ + /** + * @brief End conditional render + * + * @requires_gl30 Extension @extension{NV,conditional_render} + */ inline void endConditionalRender() { glEndConditionalRender(); }