Browse Source

Merge branch 'master' into compatibility

Vladimír Vondruš 14 years ago
parent
commit
1d053cfbc0
  1. 2
      Doxyfile
  2. 2
      doc/mainpage.dox
  3. 6
      doc/required-extensions.dox
  4. 19
      src/AbstractImage.h
  5. 6
      src/AbstractShaderProgram.cpp
  6. 20
      src/AbstractShaderProgram.h
  7. 36
      src/AbstractTexture.h
  8. 17
      src/BufferedTexture.h
  9. 1
      src/CMakeLists.txt
  10. 2
      src/Camera.cpp
  11. 409
      src/Color.h
  12. 3
      src/Framebuffer.h
  13. 2
      src/IndexedMesh.cpp
  14. 10
      src/Math/Geometry/Distance.h
  15. 40
      src/Math/Math.h
  16. 101
      src/Math/MathTypeTraits.h
  17. 4
      src/Math/Matrix.h
  18. 4
      src/Math/Matrix4.h
  19. 1
      src/Math/Test/CMakeLists.txt
  20. 54
      src/Math/Test/MathTest.cpp
  21. 2
      src/Math/Test/MathTest.h
  22. 34
      src/Math/Test/VectorTest.cpp
  23. 5
      src/Math/Test/VectorTest.h
  24. 72
      src/Math/Vector.h
  25. 25
      src/Math/Vector3.h
  26. 34
      src/Math/Vector4.h
  27. 2
      src/Mesh.cpp
  28. 2
      src/MeshTools/CombineIndexedArrays.h
  29. 2
      src/MeshTools/FlipNormals.cpp
  30. 2
      src/MeshTools/GenerateFlatNormals.cpp
  31. 4
      src/MeshTools/Interleave.h
  32. 2
      src/MeshTools/Subdivide.h
  33. 4
      src/Object.cpp
  34. 4
      src/Physics/Sphere.cpp
  35. 2
      src/Primitives/Capsule.cpp
  36. 2
      src/Primitives/UVSphere.cpp
  37. 21
      src/Query.h
  38. 61
      src/Renderbuffer.h
  39. 2
      src/Test/CMakeLists.txt
  40. 121
      src/Test/ColorTest.cpp
  41. 44
      src/Test/ColorTest.h

2
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\"" \

2
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

6
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

19
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

6
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)

20
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}

36
src/AbstractTexture.h

@ -20,6 +20,7 @@
*/
#include "Magnum.h"
#include "Color.h"
namespace Magnum {
@ -233,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
@ -345,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.
@ -408,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)
/**
@ -440,22 +440,30 @@ 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`.
* @requires_gl
*/
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,
#endif
/** 16bit depth component. */
Depth16 = GL_DEPTH_COMPONENT16
#ifndef MAGNUM_TARGET_GLES
,
/**
* 16bit depth component.
* @requires_gl
*/
Depth16 = GL_DEPTH_COMPONENT16,
/**
* 24bit depth component.
@ -611,7 +619,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());
}

17
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) */

1
src/CMakeLists.txt

@ -54,6 +54,7 @@ set(Magnum_HEADERS
BufferedTexture.h
Buffer.h
Camera.h
Color.h
CubeMapTextureArray.h
CubeMapTexture.h
Framebuffer.h

2
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();

409
src/Color.h

@ -0,0 +1,409 @@
#ifndef Magnum_Color_h
#define Magnum_Color_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
/** @file
* @brief Class Magnum::Color3, Magnum::Color4
*/
#include <tuple>
#include "Math/MathTypeTraits.h"
#include "Math/Math.h"
#include "Math/Vector4.h"
namespace Magnum {
template<class T> class Color3;
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
/* Convert color from HSV */
template<class T> inline typename std::enable_if<std::is_floating_point<T>::value, Color3<T>>::type fromHSV(typename Color3<T>::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<class T> inline typename std::enable_if<std::is_integral<T>::value, Color3<T>>::type fromHSV(typename Color3<T>::HSV hsv) {
return Color3<T>::fromNormalized(fromHSV<typename Color3<T>::FloatingPointType>(hsv));
}
/* Internal hue computing function */
template<class T> T hue(const Color3<T>& 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<class T> inline T hue(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
T max = color.max();
T delta = max - color.min();
return hue(color, max, delta);
}
template<class T> inline T saturation(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
T max = color.max();
T delta = max - color.min();
return max != T(0) ? delta/max : T(0);
}
template<class T> inline T value(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
return color.max();
}
/* Hue, saturation, value for integral types */
template<class T> inline typename Color3<T>::FloatingPointType hue(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type color) {
return hue<typename Color3<T>::FloatingPointType>(Color3<typename Color3<T>::FloatingPointType>::fromDenormalized(color));
}
template<class T> inline typename Color3<T>::FloatingPointType saturation(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type& color) {
return saturation<typename Color3<T>::FloatingPointType>(Color3<typename Color3<T>::FloatingPointType>::fromDenormalized(color));
}
template<class T> inline typename Color3<T>::FloatingPointType value(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type color) {
return Math::normalize<typename Color3<T>::FloatingPointType>(color.max());
}
/* Convert color to HSV */
template<class T> inline typename Color3<T>::HSV toHSV(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
T max = color.max();
T delta = max - color.min();
return typename Color3<T>::HSV(hue<typename Color3<T>::FloatingPointType>(color, max, delta), max != T(0) ? delta/max : T(0), max);
}
template<class T> inline typename Color3<T>::HSV toHSV(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type color) {
return toHSV<typename Color3<T>::FloatingPointType>(Color3<typename Color3<T>::FloatingPointType>::fromDenormalized(color));
}
/* Default alpha value */
template<class T> inline constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type defaultAlpha() {
return T(1);
}
template<class T> inline constexpr typename std::enable_if<std::is_integral<T>::value, T>::type defaultAlpha() {
return std::numeric_limits<T>::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 T> class Color3: public Math::Vector3<T> {
public:
/** @brief Corresponding floating-point type for HSV computation */
typedef typename Math::MathTypeTraits<T>::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<FloatingPointType, FloatingPointType, FloatingPointType> 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<class U> inline constexpr static typename std::enable_if<std::is_integral<T>::value && std::is_floating_point<U>::value, Color3<T>>::type fromNormalized(const Color3<U>& color) {
return Color3<T>(Math::denormalize<T>(color.r()),
Math::denormalize<T>(color.g()),
Math::denormalize<T>(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<class U> inline constexpr static typename std::enable_if<std::is_floating_point<T>::value && std::is_integral<U>::value, Color3<T>>::type fromDenormalized(const Color3<U>& color) {
return Color3<T>(Math::normalize<T>(color.r()),
Math::normalize<T>(color.g()),
Math::normalize<T>(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<T> fromHSV(HSV hsv) {
return Implementation::fromHSV<T>(hsv);
}
/** @overload */
inline constexpr static Color3<T> 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<T>(rgb) {}
/** @copydoc Math::Vector::Vector(const Vector&) */
inline constexpr Color3(const Math::Vector<3, T>& other): Math::Vector3<T>(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<T>(r, g, b) {}
inline constexpr T r() const { return Math::Vector3<T>::x(); } /**< @brief R component */
inline constexpr T g() const { return Math::Vector3<T>::y(); } /**< @brief G component */
inline constexpr T b() const { return Math::Vector3<T>::z(); } /**< @brief B component */
inline void setR(T value) { Math::Vector3<T>::setX(value); } /**< @brief Set R component */
inline void setG(T value) { Math::Vector3<T>::setY(value); } /**< @brief Set G component */
inline void setB(T value) { Math::Vector3<T>::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<T>(*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<T>(*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<T>(*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<T>(*this);
}
};
/**
@brief Four-component (RGBA) color
See Color3 for more information.
*/
template<class T> class Color4: public Math::Vector4<T> {
public:
/** @copydoc Color3::FloatingPointType */
typedef typename Color3<T>::FloatingPointType FloatingPointType;
/** @copydoc Color3::HSV */
typedef typename Color3<T>::HSV HSV;
/** @copydoc Color3::fromNormalized() */
template<class U> inline constexpr static typename std::enable_if<std::is_integral<T>::value && std::is_floating_point<U>::value, Color4<T>>::type fromNormalized(const Color4<U>& color) {
return Color4<T>(Math::denormalize<T>(color.r()),
Math::denormalize<T>(color.g()),
Math::denormalize<T>(color.b()),
Math::denormalize<T>(color.a()));
}
/** @copydoc Color3::fromDenormalized() */
template<class U> inline constexpr static typename std::enable_if<std::is_floating_point<T>::value && std::is_integral<U>::value, Color4<T>>::type fromDenormalized(const Color4<U>& color) {
return Color4<T>(Math::normalize<T>(color.r()),
Math::normalize<T>(color.g()),
Math::normalize<T>(color.b()),
Math::normalize<T>(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<T> fromHSV(HSV hsv, T a = Implementation::defaultAlpha<T>()) {
return Color4<T>(Implementation::fromHSV<T>(hsv), a);
}
/** @overload */
inline constexpr static Color4<T> 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>(T(0), T(0), T(0), Implementation::defaultAlpha<T>()) {}
/**
* @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<T>()): Math::Vector4<T>(rgb, rgb, rgb, alpha) {}
/** @copydoc Math::Vector::Vector(const Vector&) */
inline constexpr Color4(const Math::Vector<4, T>& other): Math::Vector4<T>(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<T>()): Math::Vector4<T>(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<T>()): Math::Vector4<T>(rgb[0], rgb[1], rgb[2], a) {}
inline constexpr T r() const { return Math::Vector4<T>::x(); } /**< @brief R component */
inline constexpr T g() const { return Math::Vector4<T>::y(); } /**< @brief G component */
inline constexpr T b() const { return Math::Vector4<T>::z(); } /**< @brief B component */
inline constexpr T a() const { return Math::Vector4<T>::w(); } /**< @brief A component */
inline void setR(T value) { Math::Vector4<T>::setX(value); } /**< @brief Set R component */
inline void setG(T value) { Math::Vector4<T>::setY(value); } /**< @brief Set G component */
inline void setB(T value) { Math::Vector4<T>::setZ(value); } /**< @brief Set B component */
inline void setA(T value) { Math::Vector4<T>::setW(value); } /**< @brief Set A component */
/**
* @brief RGB part of the vector
* @return First three components of the vector
*
* @see swizzle()
*/
inline constexpr Color3<T> rgb() const { return Math::Vector4<T>::xyz(); }
/** @copydoc Color3::toHSV() */
inline constexpr HSV toHSV() const {
return Implementation::toHSV<T>(rgb());
}
/** @copydoc Color3::hue() */
inline constexpr FloatingPointType hue() const {
return Implementation::hue<T>(rgb());
}
/** @copydoc Color3::saturation() */
inline constexpr FloatingPointType saturation() const {
return Implementation::saturation<T>(rgb());
}
/** @copydoc Color3::value() */
inline constexpr FloatingPointType value() const {
return Implementation::value<T>(rgb());
}
};
/** @debugoperator{Color3} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color3<T>& value) {
return debug << static_cast<const Magnum::Math::Vector3<T>&>(value);
}
/** @debugoperator{Color4} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color4<T>& value) {
return debug << static_cast<const Magnum::Math::Vector4<T>&>(value);
}
}
#endif

3
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<GLfloat>& color) {
glClearColor(color.r(), color.g(), color.b(), color.a());
}

2
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();

10
src/Math/Geometry/Distance.h

@ -52,7 +52,7 @@ class Distance {
* values, because it doesn't compute the square root.
*/
template<class T> static T linePointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return Vector3<T>::cross(point - a, point - b).lengthSquared()/(b - a).lengthSquared();
return Vector3<T>::cross(point - a, point - b).dot()/(b - a).dot();
}
/**
@ -97,9 +97,9 @@ class Distance {
template<class T> static T lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
Vector3<T> pointMinusA = point - a;
Vector3<T> 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<T>::cross(pointMinusA, pointMinusB).lengthSquared()/bDistanceA;
return Vector3<T>::cross(pointMinusA, pointMinusB).dot()/bDistanceA;
}
};

40
src/Math/Math.h

@ -16,6 +16,9 @@
*/
#include <cstddef>
#include <cmath>
#include <type_traits>
#include <limits>
#include "magnumCompatibility.h"
#include "magnumVisibility.h"
@ -86,6 +89,43 @@ template<size_t exponent, class T> 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<float>('\127');
// b = 1.0f
float b = normalize<float, char>('\127');
@endcode
*/
template<class FloatingPoint, class Integral> inline constexpr typename std::enable_if<std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value, FloatingPoint>::type normalize(Integral value) {
return (FloatingPoint(value)-FloatingPoint(std::numeric_limits<Integral>::min()))/
(FloatingPoint(std::numeric_limits<Integral>::max()) - FloatingPoint(std::numeric_limits<Integral>::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<class Integral, class FloatingPoint> inline constexpr typename std::enable_if<std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value, Integral>::type denormalize(FloatingPoint value) {
return std::numeric_limits<Integral>::min() +
round(FloatingPoint(value*std::numeric_limits<Integral>::max()) -
FloatingPoint(value*std::numeric_limits<Integral>::min()));
}
/**
* @brief Angle in degrees
*

101
src/Math/MathTypeTraits.h

@ -53,6 +53,22 @@ support given feature, thus forcing the compilation stop with an error.
*/
template<class T> 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
*
@ -81,39 +97,86 @@ template<class T> struct MathTypeTraits {
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class T> struct _MathTypeTraitsIntegral {
namespace Implementation {
template<class T> struct MathTypeTraitsIntegral {
inline constexpr static T epsilon() { return 1; }
inline constexpr static bool equals(T a, T b) {
return a == b;
}
};
template<> struct MathTypeTraits<unsigned char>: public _MathTypeTraitsIntegral<unsigned char> {};
template<> struct MathTypeTraits<char>: public _MathTypeTraitsIntegral<char> {};
template<> struct MathTypeTraits<unsigned short>: public _MathTypeTraitsIntegral<unsigned short> {};
template<> struct MathTypeTraits<short>: public _MathTypeTraitsIntegral<short> {};
template<class T> struct MathTypeTraitsFloatingPoint {
inline static bool equals(T a, T b) {
return std::abs(a - b) < MathTypeTraits<T>::epsilon();
}
};
template<> struct MathTypeTraits<unsigned int>: public _MathTypeTraitsIntegral<unsigned int> {};
template<> struct MathTypeTraits<int>: public _MathTypeTraitsIntegral<int> {};
template<size_t> struct MathTypeTraitsLong {};
/* long is 32 bits somewhere and 64 bits elsewhere, so it cannot be mapped to
any of them */
template<> struct MathTypeTraits<long unsigned int>: public _MathTypeTraitsIntegral<long unsigned int> {};
template<> struct MathTypeTraits<long int>: public _MathTypeTraitsIntegral<long int> {};
template<> struct MathTypeTraitsLong<8> {
typedef unsigned int UnsignedType;
typedef int Type;
};
template<> struct MathTypeTraits<unsigned long long>: public _MathTypeTraitsIntegral<unsigned long long> {};
template<> struct MathTypeTraits<long long>: public _MathTypeTraitsIntegral<long long> {};
template<> struct MathTypeTraitsLong<16> {
typedef unsigned long long UnsignedType;
typedef long long Type;
};
template<class T> struct _MathTypeTraitsFloatingPoint {
inline static bool equals(T a, T b) {
return std::abs(a - b) < MathTypeTraits<T>::epsilon();
}
}
template<> struct MathTypeTraits<unsigned char>: public Implementation::MathTypeTraitsIntegral<unsigned char> {
typedef unsigned int NumericType;
typedef float FloatingPointType;
};
template<> struct MathTypeTraits<char>: public Implementation::MathTypeTraitsIntegral<char> {
typedef int NumericType;
typedef float FloatingPointType;
};
template<> struct MathTypeTraits<unsigned short>: public Implementation::MathTypeTraitsIntegral<unsigned short> {
typedef unsigned int NumericType;
typedef float FloatingPointType;
};
template<> struct MathTypeTraits<short>: public Implementation::MathTypeTraitsIntegral<short> {
typedef int NumericType;
typedef float FloatingPointType;
};
template<> struct MathTypeTraits<unsigned int>: public Implementation::MathTypeTraitsIntegral<unsigned int> {
typedef unsigned int NumericType;
typedef double FloatingPointType;
};
template<> struct MathTypeTraits<float>: public _MathTypeTraitsFloatingPoint<float> {
template<> struct MathTypeTraits<int>: public Implementation::MathTypeTraitsIntegral<int> {
typedef int NumericType;
typedef double FloatingPointType;
};
template<> struct MathTypeTraits<unsigned long long>: public Implementation::MathTypeTraitsIntegral<unsigned long long> {
typedef unsigned long long NumericType;
typedef long double FloatingPointType;
};
template<> struct MathTypeTraits<long long>: public Implementation::MathTypeTraitsIntegral<long long> {
typedef long long NumericType;
typedef long double FloatingPointType;
};
/* long is 32 bits somewhere and 64 bits elsewhere */
template<> struct MathTypeTraits<long unsigned int>: public Implementation::MathTypeTraitsIntegral<typename Implementation::MathTypeTraitsLong<sizeof(long unsigned int)>::Type> {};
template<> struct MathTypeTraits<long int>: public Implementation::MathTypeTraitsIntegral<typename Implementation::MathTypeTraitsLong<sizeof(long int)>::Type> {};
template<> struct MathTypeTraits<float>: public Implementation::MathTypeTraitsFloatingPoint<float> {
typedef float NumericType;
typedef float FloatingPointType;
inline constexpr static float epsilon() { return FLOAT_EQUALITY_PRECISION; }
};
template<> struct MathTypeTraits<double>: public _MathTypeTraitsFloatingPoint<double> {
template<> struct MathTypeTraits<double>: public Implementation::MathTypeTraitsFloatingPoint<double> {
typedef float NumericType;
typedef double FloatingPointType;
inline constexpr static double epsilon() { return DOUBLE_EQUALITY_PRECISION; }
};
#endif

4
src/Math/Matrix.h

@ -36,6 +36,8 @@ namespace Implementation {
* @todo first col, then row (cache adjacency)
*/
template<size_t size, class T> class Matrix {
static_assert(size != 0, "Matrix cannot have zero elements");
friend class Matrix<size+1, T>; /* for ij() */
public:
@ -264,7 +266,7 @@ template<class T, size_t size> 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<T>::NumericType(value[col][row]);
}
}
debug << ')';

4
src/Math/Matrix4.h

@ -75,8 +75,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
static Matrix4<T> rotation(T angle, const Vector3<T>& vec) {
Vector3<T> 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();

1
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)

54
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,56 @@ void MathTest::degrad() {
CORRADE_COMPARE(rad(Constants<double>::pi()/2), Constants<double>::pi()/2);
}
void MathTest::normalize() {
/* Range for signed and unsigned */
CORRADE_COMPARE((Math::normalize<float, char>(-128)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, char>(127)), 1.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned char>(0)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned char>(255)), 1.0f);
/* Between */
CORRADE_COMPARE((Math::normalize<float, short>(16384)), 0.750011f);
CORRADE_COMPARE((Math::normalize<float, short>(-16384)), 0.250004f);
/* Test overflow for large types */
CORRADE_COMPARE((Math::normalize<float, int>(numeric_limits<int>::min())), 0.0f);
CORRADE_COMPARE((Math::normalize<float, int>(numeric_limits<int>::max())), 1.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned int>(0)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned int>(numeric_limits<unsigned int>::max())), 1.0f);
CORRADE_COMPARE((Math::normalize<double, long long>(numeric_limits<long long>::min())), 0.0);
CORRADE_COMPARE((Math::normalize<double, long long>(numeric_limits<long long>::max())), 1.0);
CORRADE_COMPARE((Math::normalize<double, unsigned long long>(0)), 0.0);
CORRADE_COMPARE((Math::normalize<double, unsigned long long>(numeric_limits<unsigned long long>::max())), 1.0);
}
void MathTest::denormalize() {
/* Range for signed and unsigned */
CORRADE_COMPARE(Math::denormalize<char>(0.0f), -128);
CORRADE_COMPARE(Math::denormalize<char>(1.0f), 127);
CORRADE_COMPARE(Math::denormalize<unsigned char>(0.0f), 0);
CORRADE_COMPARE(Math::denormalize<unsigned char>(1.0f), 255);
/* Between */
CORRADE_COMPARE(Math::denormalize<short>(0.33f), -11141);
CORRADE_COMPARE(Math::denormalize<short>(0.66f), 10485);
/* Test overflow for large types */
CORRADE_COMPARE(Math::denormalize<int>(0.0f), numeric_limits<int>::min());
CORRADE_COMPARE(Math::denormalize<unsigned int>(0.0f), 0);
CORRADE_COMPARE(Math::denormalize<long long>(0.0), numeric_limits<long long>::min());
CORRADE_COMPARE(Math::denormalize<unsigned long long>(0.0), 0);
CORRADE_COMPARE(Math::denormalize<int>(1.0), numeric_limits<int>::max());
CORRADE_COMPARE(Math::denormalize<unsigned int>(1.0), numeric_limits<unsigned int>::max());
{
CORRADE_EXPECT_FAIL("Denormalize doesn't work for large types well");
CORRADE_COMPARE((Math::denormalize<long long, long double>(1.0)), numeric_limits<long long>::max());
CORRADE_COMPARE((Math::denormalize<unsigned long long, long double>(1.0)), numeric_limits<unsigned long long>::max());
}
}
void MathTest::pow() {
CORRADE_COMPARE(Math::pow<10>(2ul), 1024ul);
CORRADE_COMPARE(Math::pow<0>(3ul), 1ul);

2
src/Math/Test/MathTest.h

@ -24,6 +24,8 @@ class MathTest: public Corrade::TestSuite::Tester<MathTest> {
MathTest();
void degrad();
void normalize();
void denormalize();
void pow();
void log();
};

34
src/Math/Test/VectorTest.cpp

@ -37,10 +37,13 @@ VectorTest::VectorTest() {
&VectorTest::dot,
&VectorTest::multiplyDivide,
&VectorTest::addSubstract,
&VectorTest::dotSelf,
&VectorTest::length,
&VectorTest::lengthSquared,
&VectorTest::normalized,
&VectorTest::sum,
&VectorTest::product,
&VectorTest::min,
&VectorTest::max,
&VectorTest::angle,
&VectorTest::negative,
&VectorTest::debug);
@ -109,24 +112,43 @@ 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() {
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);
}
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() {
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<Vector3::Type>::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<Vector3::Type>::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() {

5
src/Math/Test/VectorTest.h

@ -29,10 +29,13 @@ class VectorTest: public Corrade::TestSuite::Tester<VectorTest> {
void dot();
void multiplyDivide();
void addSubstract();
void dotSelf();
void length();
void lengthSquared();
void normalized();
void sum();
void product();
void min();
void max();
void angle();
void negative();

72
src/Math/Vector.h

@ -20,6 +20,7 @@
*/
#include <cmath>
#include <limits>
#include <Utility/Debug.h>
#include "MathTypeTraits.h"
@ -42,6 +43,8 @@ namespace Implementation {
/** @brief %Vector */
template<size_t size, class T> 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 */
@ -68,6 +71,7 @@ template<size_t size, class T> class Vector {
* @f[
* a \cdot b = \sum_{i=0}^{n-1} a_ib_i
* @f]
* @see dot() const
*/
static T dot(const Vector<size, T>& a, const Vector<size, T>& b) {
T out(0);
@ -79,16 +83,18 @@ template<size_t size, class T> 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<size, T>& a, const Vector<size, T>& b) {
return acos(dot(a, b)/(a.length()*b.length()));
CORRADE_ASSERT(MathTypeTraits<T>::equals(a.dot(), T(1)) && MathTypeTraits<T>::equals(b.dot(), T(1)),
"Math::Vector::angle(): vectors must be normalized!", std::numeric_limits<T>::quiet_NaN());
return std::acos(dot(a, b));
}
/** @brief Default constructor */
@ -241,24 +247,26 @@ template<size_t size, class T> class Vector {
}
/**
* @brief %Vector length
* @brief Dot product of the vector
*
* 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 lengthSquared()
* @see dot(const Vector<size, T>&, const Vector<size, T>&)
*/
inline T length() const {
return 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) */
@ -266,9 +274,19 @@ template<size_t size, class T> 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];
@ -276,6 +294,26 @@ template<size_t size, class T> 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];
};
@ -286,7 +324,7 @@ template<class T, size_t size> 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<T>::NumericType(value[i]);
}
debug << ')';
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true);

25
src/Math/Vector3.h

@ -49,26 +49,29 @@ template<class T> 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) {}
/**
* @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 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 */
@ -86,14 +89,6 @@ template<class T> class Vector3: public Vector<3, T> {
*/
inline constexpr Vector2<T> xy() const { return Vector2<T>::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 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)
};

34
src/Math/Vector4.h

@ -29,7 +29,7 @@ template<class T> 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,21 +41,21 @@ template<class T> 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 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 */
@ -83,24 +83,6 @@ template<class T> class Vector4: public Vector<4, T> {
*/
inline constexpr Vector2<T> xy() const { return Vector2<T>::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) { setA(value); } /**< @brief Set A component */
/**
* @brief RGB part of the vector
* @return First three components of the vector
*
* @see swizzle()
*/
inline constexpr Vector3<T> rgb() const { return xyz(); }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4)
};

2
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.begin(); it != _buffers.end(); ++it) {

2
src/MeshTools/CombineIndexedArrays.h

@ -57,7 +57,7 @@ class CombineIndexedArrays {
private:
template<class ...T> inline static size_t indexCount(const std::vector<unsigned int>& first, const std::vector<T>&... 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();
}

2
src/MeshTools/FlipNormals.cpp

@ -20,7 +20,7 @@ using namespace std;
namespace Magnum { namespace MeshTools {
void flipFaceWinding(vector<unsigned int>& 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]);

2
src/MeshTools/GenerateFlatNormals.cpp

@ -22,7 +22,7 @@ using namespace std;
namespace Magnum { namespace MeshTools {
tuple<vector<unsigned int>, vector<Vector3>> 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<unsigned int>, vector<Vector3>>()))
CORRADE_ASSERT(!(indices.size()%3), "MeshTools::generateFlatNormals(): index count is not divisible by 3!", (tuple<vector<unsigned int>, vector<Vector3>>()));
/* Create normal for every triangle (assuming counterclockwise winding) */
vector<unsigned int> normalIndices;

4
src/MeshTools/Interleave.h

@ -53,7 +53,7 @@ class Interleave {
}
template<class ...T> 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<class T, class ...U> 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();
}

2
src/MeshTools/Subdivide.h

@ -32,7 +32,7 @@ template<class Vertex, class Interpolator> class Subdivide {
inline Subdivide(std::vector<unsigned int>& indices, std::vector<Vertex>& 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);

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

4
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());
}

2
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<unsigned int>, {new vector<Vector4>()}, {new vector<Vector3>()}, textureCoords == TextureCoords::Generate ? vector<vector<Vector2>*>{new vector<Vector2>()} : vector<vector<Vector2>*>()), 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);

2
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<GLfloat>::pi()/rings;

21
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<class T> T result();
@ -101,6 +101,7 @@ if(!q.resultAvailable()) {
GLuint primitiveCount = q.result<GLuint>();
@endcode
@requires_gl
@requires_gl30 Extension @extension{EXT,transform_feedback}
*/
class MAGNUM_EXPORT Query: public AbstractQuery {
public:
@ -196,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
@ -233,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<GLenum>(mode));
}
/** @brief End conditional render */
/**
* @brief End conditional render
*
* @requires_gl30 Extension @extension{NV,conditional_render}
*/
inline void endConditionalRender() {
glEndConditionalRender();
}

61
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,11 +64,11 @@ class Renderbuffer {
#endif
/**
* @copydoc AbstractTexture::Format
* @copybrief AbstractTexture::Format
*
* 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
@ -92,24 +92,65 @@ class Renderbuffer {
RGB565 = GL_RGB565,
#endif
#ifndef MAGNUM_TARGET_GLES
/**
* 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 <tt>Format::%Depth16</tt> instead.
*/
Depth = GL_DEPTH_COMPONENT,
#ifndef MAGNUM_TARGET_GLES
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,
/**
* 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 <tt>Format::%Stencil8</tt> instead.
*/
Stencil = GL_STENCIL_INDEX,
/**
* 1-bit stencil index.
*
* @requires_gl Use <tt>Format::%Stencil8</tt> instead.
*/
Stencil1 = GL_STENCIL_INDEX1,
/**
* 4-bit stencil index.
*
* @requires_gl Use <tt>Format::%Stencil8</tt> 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 <tt>Format::%Stencil8</tt> 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 */

2
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)

121
src/Test/ColorTest.cpp

@ -0,0 +1,121 @@
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "ColorTest.h"
#include "Color.h"
using namespace std;
CORRADE_TEST_MAIN(Magnum::Test::ColorTest)
namespace Magnum { namespace Test {
typedef Magnum::Color3<unsigned char> Color3;
typedef Magnum::Color4<unsigned char> Color4;
typedef Magnum::Color3<float> 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));
}
}}

44
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š <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include <TestSuite/Tester.h>
namespace Magnum { namespace Test {
class ColorTest: public Corrade::TestSuite::Tester<ColorTest> {
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
Loading…
Cancel
Save