Browse Source

Merge branch 'master' into compatibility

Conflicts:
	src/CMakeLists.txt
	src/Math/Matrix.h
	src/Mesh.cpp
Vladimír Vondruš 14 years ago
parent
commit
5ac10b2162
  1. 5
      CMakeLists.txt
  2. 12
      Doxyfile
  3. 2
      doc/building.dox
  4. 4
      doc/coding-style.dox
  5. 29
      doc/groups.dox
  6. 9
      doc/mainpage.dox
  7. 22
      doc/namespaces.dox
  8. 6
      doc/required-extensions.dox
  9. 21
      modules/FindMagnum.cmake
  10. 3
      src/AbstractImage.h
  11. 5
      src/AbstractShaderProgram.cpp
  12. 48
      src/AbstractShaderProgram.h
  13. 40
      src/AbstractTexture.h
  14. 7
      src/Buffer.h
  15. 8
      src/BufferedImage.h
  16. 2
      src/BufferedTexture.h
  17. 27
      src/CMakeLists.txt
  18. 125
      src/Camera.cpp
  19. 156
      src/Camera.h
  20. 14
      src/Color.h
  21. 64
      src/Contexts/AbstractGlInterface.h
  22. 142
      src/Contexts/AbstractXContext.cpp
  23. 142
      src/Contexts/AbstractXContext.h
  24. 78
      src/Contexts/CMakeLists.txt
  25. 186
      src/Contexts/EglContext.cpp
  26. 86
      src/Contexts/EglInterface.cpp
  27. 71
      src/Contexts/EglInterface.h
  28. 37
      src/Contexts/ExtensionWrangler.cpp
  29. 39
      src/Contexts/ExtensionWrangler.h
  30. 9
      src/Contexts/GlutContext.cpp
  31. 32
      src/Contexts/GlutContext.h
  32. 49
      src/Contexts/GlxContext.h
  33. 90
      src/Contexts/GlxInterface.cpp
  34. 66
      src/Contexts/GlxInterface.h
  35. 20
      src/Contexts/Sdl2Context.cpp
  36. 33
      src/Contexts/Sdl2Context.h
  37. 48
      src/Contexts/XEglContext.h
  38. 2
      src/CubeMapTexture.h
  39. 2
      src/CubeMapTextureArray.h
  40. 884
      src/Framebuffer.h
  41. 8
      src/Image.h
  42. 6
      src/ImageWrapper.h
  43. 2
      src/IndexedMesh.h
  44. 1
      src/Math/CMakeLists.txt
  45. 32
      src/Math/Math.h
  46. 2
      src/Math/MathTypeTraits.h
  47. 95
      src/Math/Matrix.h
  48. 14
      src/Math/Matrix3.h
  49. 14
      src/Math/Matrix4.h
  50. 2
      src/Math/Test/CMakeLists.txt
  51. 11
      src/Math/Test/MathTest.cpp
  52. 1
      src/Math/Test/MathTest.h
  53. 14
      src/Math/Test/Matrix3Test.cpp
  54. 2
      src/Math/Test/Matrix3Test.h
  55. 15
      src/Math/Test/Matrix4Test.cpp
  56. 1
      src/Math/Test/Matrix4Test.h
  57. 28
      src/Math/Test/MatrixTest.cpp
  58. 1
      src/Math/Test/MatrixTest.h
  59. 22
      src/Math/Test/Vector2Test.cpp
  60. 4
      src/Math/Test/Vector2Test.h
  61. 21
      src/Math/Test/Vector3Test.cpp
  62. 4
      src/Math/Test/Vector3Test.h
  63. 10
      src/Math/Test/Vector4Test.cpp
  64. 1
      src/Math/Test/Vector4Test.h
  65. 43
      src/Math/Test/VectorTest.cpp
  66. 5
      src/Math/Test/VectorTest.h
  67. 214
      src/Math/Vector.h
  68. 53
      src/Math/Vector2.h
  69. 67
      src/Math/Vector3.h
  70. 15
      src/Math/Vector4.h
  71. 32
      src/Mesh.cpp
  72. 14
      src/Mesh.h
  73. 2
      src/MeshTools/Clean.h
  74. 2
      src/MeshTools/CombineIndexedArrays.h
  75. 6
      src/MeshTools/CompressIndices.h
  76. 6
      src/MeshTools/FlipNormals.h
  77. 2
      src/MeshTools/GenerateFlatNormals.h
  78. 6
      src/MeshTools/Interleave.h
  79. 2
      src/MeshTools/Subdivide.h
  80. 2
      src/MeshTools/Tipsify.h
  81. 152
      src/Object.cpp
  82. 274
      src/Object.h
  83. 2
      src/Physics/ShapeGroup.h
  84. 2
      src/Primitives/Capsule.h
  85. 4
      src/Primitives/Cube.h
  86. 4
      src/Primitives/Icosphere.h
  87. 2
      src/Primitives/Plane.h
  88. 4
      src/Primitives/UVSphere.h
  89. 5
      src/Query.h
  90. 2
      src/Renderbuffer.h
  91. 47
      src/Scene.h
  92. 42
      src/SceneGraph/CMakeLists.txt
  93. 130
      src/SceneGraph/Camera.cpp
  94. 247
      src/SceneGraph/Camera.h
  95. 4
      src/SceneGraph/Light.cpp
  96. 16
      src/SceneGraph/Light.h
  97. 147
      src/SceneGraph/Object.cpp
  98. 366
      src/SceneGraph/Object.h
  99. 54
      src/SceneGraph/Scene.h
  100. 3
      src/SceneGraph/Test/CMakeLists.txt
  101. Some files were not shown because too many files have changed in this diff Show More

5
CMakeLists.txt

@ -13,9 +13,11 @@ option(WITH_EVERYTHING "Build everything (doesn't include contexts)" ON)
option(WITH_MESHTOOLS "Build MeshTools library" OFF)
option(WITH_PHYSICS "Build Physics library" OFF)
option(WITH_PRIMITIVES "Builf Primitives library" OFF)
option(WITH_SCENEGRAPH "Build SceneGraph library" OFF)
option(WITH_SHADERS "Build Shaders library" OFF)
cmake_dependent_option(WITH_EGLCONTEXT "Build EglContext library" OFF "TARGET_GLES" OFF)
option(WITH_GLXCONTEXT "Build GlxContext library" OFF)
cmake_dependent_option(WITH_XEGLCONTEXT "Build XEglContext library" OFF "TARGET_GLES" OFF)
cmake_dependent_option(WITH_GLUTCONTEXT "Build GlutContext library" OFF "NOT TARGET_GLES" OFF)
option(WITH_SDL2CONTEXT "Build Sdl2Context library" OFF)
@ -25,6 +27,7 @@ if(WITH_EVERYTHING)
set(WITH_MESHTOOLS ON)
set(WITH_PHYSICS ON)
set(WITH_PRIMITIVES ON)
set(WITH_SCENEGRAPH ON)
set(WITH_SHADERS ON)
endif()

12
Doxyfile

@ -195,7 +195,9 @@ TAB_SIZE = 8
# You can put \n's in the value part of an alias to insert newlines.
ALIASES = \
"debugoperator{1}=@relates \1\n@brief Debug output operator" \
"debugoperator{1}=@relates \1\n@brief Debug output operator @xrefitem debugoperators \"Debug output operator\" \"Debug output operators for custom types\" Allows printing \1 with Corrade::Utility::Debug and friends." \
"configurationvalueref{1}=@see @ref configurationvalues \"Corrade::Utility::ConfigurationValue<\1>\"" \
"configurationvalue{1}=@brief %Configuration value parser and writer @xrefitem configurationvalues \"Configuration value parser and writer\" \"Configuration value parsers and writers for custom types\" Allows parsing and writing \1 from and to Corrade::Utility::Configuration." \
"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)\" Not available on OpenGL ES." \
@ -206,8 +208,12 @@ ALIASES = \
"requires_gl40=@xrefitem requires-gl40 \"Requires OpenGL 4.0\" \"Functionality requiring OpenGL 4.0\"" \
"requires_gl41=@xrefitem requires-gl41 \"Requires OpenGL 4.1\" \"Functionality requiring OpenGL 4.1\"" \
"requires_gl42=@xrefitem requires-gl42 \"Requires OpenGL 4.2\" \"Functionality requiring OpenGL 4.2\"" \
"requires_extension=@xrefitem requires-extension \"Requires extension\" \"Functionality requiring specific OpenGL extension\"" \
"extension{2}=<a href=\"http://www.opengl.org/registry/specs/\1/\2.txt\"><tt>\1_\2</tt></a>"
"requires_gl43=@xrefitem requires-gl43 \"Requires OpenGL 4.3\" \"Functionality requiring OpenGL 4.3\"" \
"requires_extension=@xrefitem requires-extension \"Requires OpenGL extension\" \"Functionality requiring specific OpenGL extension\"" \
"extension{2}=<a href=\"http://www.opengl.org/registry/specs/\1/\2.txt\"><tt>\1_\2</tt></a>" \
"requires_gles30=@xrefitem requires-gles30 \"Requires OpenGL ES 3.0\" \"Functionality requiring OpenGL ES 3.0\"" \
"requires_es_extension=@xrefitem requires-es-extension \"Requires OpenGL ES extension\" \"Functionality requiring specific OpenGL ES extension\"" \
"es_extension{2}=<a href=\"http://www.khronos.org/registry/gles/extensions/\1/\2.txt\"><tt>\1_\2</tt></a>"
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding

2
doc/building.dox

@ -15,7 +15,7 @@ Minimal set of tools and libraries required for building is:
which are tested to support everything needed: **GCC** >= 4.6 and **Clang**
>= 3.1.
- **CMake** >= 2.8.8 (needed for `OBJECT` library target)
- **OpenGL** headers, on Linux most probably shipped with Mesa or
- **OpenGL** headers, on Linux most probably shipped with Mesa, or
**OpenGL ES 2** headers, if targeting OpenGL ES (see below).
- **GLEW** - OpenGL extension wrangler
- **Corrade** - Plugin management and utility library. You can get it at

4
doc/coding-style.dox

@ -33,8 +33,8 @@ removing redundant prefixes) is encouraged.
@subsection documentation-commands Special documentation commands
Additionally to @c \@todoc and @c \@debugoperator (same as in Corrade), these
are defined:
Additionally to @c \@todoc, @c \@debugoperator @c \@configurationvalue and
@c \@configurationvalueref (same as in Corrade), these are defined:
@subsubsection documentation-commands-collisionoperator Physics collision operators

29
doc/groups.dox

@ -1,29 +0,0 @@
namespace Magnum {
/** @page modules */
/**
@defgroup scene Scene graph
@brief %Scene hierarchy, cameras, lights and other objects
*/
/**
@defgroup mesh Meshes
@brief Creating, modifying and rendering meshes
*/
/**
@defgroup rendering Rendering
@brief %Shader, buffer and mesh management, render queries
*/
/** @ingroup rendering
@defgroup textures Textures
@brief Access to OpenGL textures, image data wrappers and framebuffer operations
*/
/**
@defgroup utility Utility
@brief Various supporting utility classes
*/
}

9
doc/mainpage.dox

@ -6,8 +6,8 @@ Features:
- Easy-to-use templated @ref Math "mathematical library" for matrix/vector
calculations and @ref Math::Geometry "geometry".
- Hierarchical @ref Object "scene graph" which supports transformation caching
for better performance, classes for convenient usage of
- Hierarchical @ref SceneGraph "scene graph" which supports transformation
caching for better performance, classes for convenient usage of
@ref AbstractShaderProgram "shaders", @ref Buffer "buffers" and
@ref AbstractTexture "textures". Access to @ref Framebuffer "framebuffer"
and @ref AbstractQuery "occlusion queries".
@ -50,11 +50,6 @@ in step-by-step tutorial. Then you can dig deeper and try @ref example-index
"other examples", read about fundamental principles in the documentation or
start experimenting on your own!
@subsection module-overview Module overview
Classes in %Magnum are grouped into a few modules for a better orientation.
Check the @ref modules "module index" for more information about all classes.
@subsection getting-started-hacking Hacking Magnum
If you want to hack on this engine, if you spotted a bug, need an feature or

22
doc/namespaces.dox

@ -7,8 +7,7 @@
/** @namespace Magnum
@brief Root namespace
Contains classes needed for building meshes, setting up and rendering the
scene.
Contains classes for interacting with OpenGL.
*/
/** @dir Contexts
@ -41,8 +40,7 @@ Functions for computing intersections, distances, areas and volumes.
/** @dir MeshTools
* @brief Namespace Magnum::MeshTools
*/
/** @ingroup mesh
@namespace Magnum::MeshTools
/** @namespace Magnum::MeshTools
@brief %Mesh tools
Tools for generating, optimizing and cleaning meshes.
@ -51,18 +49,26 @@ Tools for generating, optimizing and cleaning meshes.
/** @dir Primitives
* @brief Namespace Magnum::Primitives
*/
/** @ingroup mesh
@namespace Magnum::Primitives
/** @namespace Magnum::Primitives
@brief Primitive library
Basic primitives for testing purposes.
*/
/** @dir SceneGraph
* @brief Namespace Magnum::SceneGraph
*/
/**
@namespace Magnum::SceneGraph
@brief %Scene graph library
Setting up and rendering the scene.
*/
/** @dir Shaders
* @brief Namespace Magnum::Shaders
*/
/** @ingroup rendering
@namespace Magnum::Shaders
/** @namespace Magnum::Shaders
@brief Sample shaders
Collection of shaders for testing purposes.

6
doc/required-extensions.dox

@ -20,7 +20,10 @@ supported on Intel GPUs even if they are capable of OpenGL 2.1 only).
- @subpage requires-gl40
- @subpage requires-gl41
- @subpage requires-gl42
- @subpage requires-gl43
- @subpage requires-extension
- @subpage requires-gles30
- @subpage requires-es-extension
@page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES)
@page requires-gl30 Functionality requiring OpenGL 3.0
@ -30,6 +33,9 @@ supported on Intel GPUs even if they are capable of OpenGL 2.1 only).
@page requires-gl40 Functionality requiring OpenGL 4.0
@page requires-gl41 Functionality requiring OpenGL 4.1
@page requires-gl42 Functionality requiring OpenGL 4.2
@page requires-gl43 Functionality requiring OpenGL 4.3
@page requires-extension Functionality requiring specific OpenGL extension
@page requires-gles30 Functionality requiring OpenGL ES 3.0
@page requires-es-extension Functionality requiring specific OpenGL ES extension
*/

21
modules/FindMagnum.cmake

@ -18,8 +18,10 @@
# MeshTools - MeshTools library
# Physics - Physics library
# Primitives - Library with stock geometric primitives (static)
# SceneGraph - Scene graph library
# Shaders - Library with stock shaders
# EglContext - EGL context (depends on EGL and X11 libraries)
# GlxContext - GLX context (depends on X11 libraries)
# XEglContext - X/EGL context (depends on EGL and X11 libraries)
# GlutContext - GLUT context (depends on GLUT library)
# Sdl2Context - SDL2 context (depends on SDL2 library)
# Example usage with specifying additional components is:
@ -110,8 +112,18 @@ foreach(component ${Magnum_FIND_COMPONENTS})
endif()
endif()
# GLX context dependencies
if(${component} STREQUAL GlxContext)
find_package(X11)
if(X11_FOUND)
set(_MAGNUM_${_COMPONENT}_LIBRARIES ${X11_LIBRARIES})
else()
unset(MAGNUM_${_COMPONENT}_LIBRARY)
endif()
endif()
# X/EGL context dependencies
if(${component} STREQUAL EglContext)
if(${component} STREQUAL XEglContext)
find_package(EGL)
find_package(X11)
if(EGL_FOUND AND X11_FOUND)
@ -137,6 +149,11 @@ foreach(component ${Magnum_FIND_COMPONENTS})
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Cube.h)
endif()
# Scene graph library
if(${component} STREQUAL SceneGraph)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Scene.h)
endif()
# Shaders library
if(${component} STREQUAL Shaders)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES PhongShader.h)

3
src/AbstractImage.h

@ -23,7 +23,7 @@
namespace Magnum {
/** @ingroup textures
/**
@brief Non-templated base for one-, two- or three-dimensional images
See Image, BufferedImage, Trade::ImageData documentation for more information.
@ -44,6 +44,7 @@ class MAGNUM_EXPORT AbstractImage {
*/
/** @brief Color components */
/** @todo Support *_INTEGER types */
enum class Components: GLenum {
#ifndef MAGNUM_TARGET_GLES
/**

5
src/AbstractShaderProgram.cpp

@ -50,6 +50,11 @@ void AbstractShaderProgram::bindFragmentDataLocation(GLuint location, const std:
glBindFragDataLocation(program, location, name.c_str());
}
void AbstractShaderProgram::bindFragmentDataLocationIndexed(GLuint location, GLuint index, const std::string& name) {
CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", );
glBindFragDataLocationIndexed(program, location, index, name.c_str());
}
#endif
void AbstractShaderProgram::link() {

48
src/AbstractShaderProgram.h

@ -25,7 +25,7 @@
namespace Magnum {
/** @ingroup rendering
/**
@brief Base class for shaders
@section AbstractShaderProgram-subclassing Subclassing workflow
@ -39,6 +39,8 @@ typedef Attribute<0, Vector4> Vertex;
typedef Attribute<1, Vector3> Normal;
typedef Attribute<2, Vector2> TextureCoords;
@endcode
@todoc Output attribute location (for bindFragmentDataLocationIndexed(),
referenced also from Framebuffer::mapDefaultForDraw() / Framebuffer::mapForDraw())
- **Layers for texture uniforms** to which the textures will be bound before
rendering, for example:
@code
@ -78,22 +80,33 @@ 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.:
@code
#version 330
// or #extension GL_ARB_explicit_attrib_location: enable
layout(location = 0) in vec4 vertex;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 textureCoords;
@endcode
Similarly for ouput attributes, you can also specify blend equation color
index for them (see Framebuffer::BlendFunction for more information about
using color input index):
@code
layout(location = 0, index = 0) out vec4 color;
layout(location = 1, index = 1) out vec4 ambient;
@endcode
@requires_gl (for explicit input attribute location instead of using
bindAttributeLocation())
@requires_gl (for explicit output attribute location or using
bindFragmentDataLocation())
bindFragmentDataLocation() / bindFragmentDataLocationIndexed())
@requires_gl30 Extension @extension{EXT,gpu_shader4} (for using
bindFragmentDataLocation())
@requires_gl33 Extension @extension{ARB,blend_func_extended} (for using
bindFragmentDataLocationIndexed())
@requires_gl33 Extension @extension{ARB,explicit_attrib_location} (for
explicit attribute location instead of using bindAttributeLocation())
If you don't have the required extension, you can use functions bindAttributeLocation()
and bindFragmentDataLocation() between attaching of shaders and linking the
program:
and bindFragmentDataLocation() / bindFragmentDataLocationIndexed() between
attaching the shaders and linking the program:
@code
// Shaders attached...
@ -101,6 +114,9 @@ bindAttributeLocation(Vertex::Location, "vertex");
bindAttributeLocation(Normal::Location, "normal");
bindAttributeLocation(TextureCoords::Location, "textureCoords");
bindFragmentDataLocationIndexed(0, 0, "color");
bindFragmentDataLocationIndexed(1, 1, "ambient");
// Link...
@endcode
@ -108,6 +124,8 @@ bindAttributeLocation(TextureCoords::Location, "textureCoords");
The preferred workflow is to specify texture layers directly in the shader
code, e.g.:
@code
#version 420
// or #extension GL_ARB_shading_language_420pack: enable
layout(binding = 0) uniform sampler2D diffuseTexture;
layout(binding = 1) uniform sampler2D specularTexture;
@endcode
@ -236,8 +254,8 @@ class MAGNUM_EXPORT AbstractShaderProgram {
* @param location Location
* @param name Attribute name
*
* Binds attribute to location which is be used later for binding
* vertex buffers. Preferred usage is to
* Binds attribute to location which is used later for binding vertex
* buffers.
* @note This function should be called after attachShader() calls and
* before link().
* @deprecated Preferred usage is to specify attribute location
@ -249,16 +267,32 @@ class MAGNUM_EXPORT AbstractShaderProgram {
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Bind fragment data to given location
* @brief Bind fragment data to given location and color input index
* @param location Location
* @param name Fragment output variable name
* @param index Blend equation color input index (`0` or `1`)
*
* Binds fragment data to location which is used later for framebuffer
* operations. See also Framebuffer::BlendFunction for more
* information about using color input index.
* @requires_gl
* @requires_gl33 Extension @extension{ARB,blend_func_extended}
* @note This function should be called after attachShader() calls and
* before link().
* @deprecated Preferred usage is to specify attribute location
* explicitly in the shader instead of using this function. See
* @ref AbstractShaderProgram-attribute-location "class documentation"
* for more information.
*/
void bindFragmentDataLocationIndexed(GLuint location, GLuint index, const std::string& name);
/**
* @brief Bind fragment data to given location and first color input index
* @param location Location
* @param name Fragment output variable name
*
* The same as bindFragmentDataLocationIndexed(), but with `index` set
* to `0`.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,gpu_shader4}
*/

40
src/AbstractTexture.h

@ -24,7 +24,7 @@
namespace Magnum {
/** @ingroup textures
/**
@brief Base for textures
@attention Don't forget to call @ref Texture::setWrapping() "setWrapping()",
@ -122,12 +122,14 @@ class MAGNUM_EXPORT AbstractTexture {
/**
* Red component only. Green and blue are set to `0`, alpha is set
* to `1`.
* @requires_gl30 Extension @extension{ARB,texture_rg}
*/
Red,
/**
* Red and green component. Blue is set to `0`, alpha is set to
* `1`.
* @requires_gl30 Extension @extension{ARB,texture_rg}
*/
RedGreen,
@ -145,85 +147,75 @@ class MAGNUM_EXPORT AbstractTexture {
enum class ComponentType {
/**
* (Non-normalized) unsigned byte
*
* @requires_gl30 Extension @extension{EXT,texture_integer}
*/
UnsignedByte,
/**
* (Non-normalized) byte
*
* @requires_gl30 Extension @extension{EXT,texture_integer}
*/
Byte,
/**
* (Non-normalized) unsigned short
*
* @requires_gl30 Extension @extension{EXT,texture_integer}
*/
UnsignedShort,
/**
* (Non-normalized) short
*
* @requires_gl30 Extension @extension{EXT,texture_integer}
*/
Short,
/**
* (Non-normalized) unsigned integer
*
* @requires_gl30 Extension @extension{EXT,texture_integer}
*/
UnsignedInt,
/**
* (Non-normalized) integer
*
* @requires_gl30 Extension @extension{EXT,texture_integer}
*/
Int,
/**
* Half float (16 bit)
*
* @requires_gl30 Extension @extension{ARB,texture_float}
*/
Half,
/**
* Float (32 bit)
*
* @requires_gl30 Extension @extension{ARB,texture_float}
*/
Float,
/**
* Normalized unsigned byte, i.e. values from range
* @f$ [0; 255] @f$ are converted to range @f$ [0.0; 1.0] @f$.
* Normalized unsigned byte, i.e. values from range @f$ [0; 255] @f$
* are converted to range @f$ [0.0; 1.0] @f$.
*/
NormalizedUnsignedByte,
/**
* Normalized byte, i.e. values from range
* @f$ [-128; 127] @f$ are converted to range @f$ [0.0; 1.0] @f$.
*
* @requires_gl31 (no extension providing this functionality)
* Normalized signed byte, i.e. values from range @f$ [-128; 127] @f$
* are converted to range @f$ [-1.0; 1.0] @f$.
* @requires_gl31 Extension @extension{EXT,texture_snorm}
*/
NormalizedByte,
/**
* Normalized unsigned short, i.e. values from range
* @f$ [0; 65536] @f$ are converted to range @f$ [0.0; 1.0] @f$.
* Normalized unsigned short, i.e. values from range @f$ [0; 65536] @f$
* are converted to range @f$ [0.0; 1.0] @f$.
*/
NormalizedUnsignedShort,
/**
* Normalized short, i.e. values from range
* @f$ [-32768; 32767] @f$ are converted to range @f$ [0.0; 1.0] @f$.
*
* @requires_gl31 (no extension providing this functionality)
* Normalized signed short, i.e. values from range @f$ [-32768; 32767] @f$
* are converted to range @f$ [-1.0; 1.0] @f$.
* @requires_gl31 Extension @extension{EXT,texture_snorm}
*/
NormalizedShort
};
@ -241,7 +233,7 @@ class MAGNUM_EXPORT AbstractTexture {
* One-component (red channel), unsigned normalized, probably
* 8bit.
* @requires_gl
* @requires_gl30 (no extension providing this functionality)
* @requires_gl30 Extension @extension{ARB,texture_rg}
*/
Red = GL_RED,
@ -249,7 +241,7 @@ class MAGNUM_EXPORT AbstractTexture {
* Two-component (red and green channel), unsigned normalized,
* each component probably 8bit, 16bit total.
* @requires_gl
* @requires_gl30 (no extension providing this functionality)
* @requires_gl30 Extension @extension{ARB,texture_rg}
*/
RedGreen = GL_RG,
#endif
@ -365,12 +357,14 @@ class MAGNUM_EXPORT AbstractTexture {
/**
* Compressed red channel, unsigned normalized.
* @requires_gl
* @requires_gl30 Extension @extension{ARB,texture_rg}
*/
CompressedRed = GL_COMPRESSED_RED,
/**
* Compressed red and green channel, unsigned normalized.
* @requires_gl
* @requires_gl30 Extension @extension{ARB,texture_rg}
*/
CompressedRedGreen = GL_COMPRESSED_RG,

7
src/Buffer.h

@ -23,7 +23,7 @@
namespace Magnum {
/** @ingroup rendering
/**
@brief Class for managing buffers
@todo Support for buffer copying (OpenGL 3.1, @extension{ARB,copy_buffer})
@ -69,7 +69,10 @@ class Buffer {
*/
PixelUnpack = GL_PIXEL_UNPACK_BUFFER,
/** Target for pixel pack operations. */
/**
* Target for pixel pack operations.
* @requires_gl
*/
PixelPack = GL_PIXEL_PACK_BUFFER,
/**

8
src/BufferedImage.h

@ -16,7 +16,7 @@
*/
/** @file
* @brief Class Magnum::BufferedImage
* @brief Class Magnum::BufferedImage, typedef Magnum::BufferedImage1D, Magnum::BufferedImage2D, Magnum::BufferedImage3D
*/
#include "AbstractImage.h"
@ -26,10 +26,6 @@
namespace Magnum {
#ifndef MAGNUM_TARGET_GLES
/** @addtogroup textures
* @{
*/
/**
@brief %Buffered image
@ -116,8 +112,6 @@ typedef BufferedImage<2> BufferedImage2D;
/** @brief Three-dimensional buffered image */
typedef BufferedImage<3> BufferedImage3D;
/*@}*/
#endif
}

2
src/BufferedTexture.h

@ -25,7 +25,7 @@
namespace Magnum {
#ifndef MAGNUM_TARGET_GLES
/** @ingroup textures
/**
@brief Buffered texture
This texture is, unlike classic textures such as Texture or CubeMapTexture,

27
src/CMakeLists.txt

@ -33,10 +33,8 @@ set(Magnum_SRCS
AbstractTexture.cpp
AbstractShaderProgram.cpp
BufferedTexture.cpp
Camera.cpp
Framebuffer.cpp
IndexedMesh.cpp
Light.cpp
Mesh.cpp
Query.cpp
Renderbuffer.cpp
@ -53,7 +51,6 @@ set(Magnum_HEADERS
BufferedImage.h
BufferedTexture.h
Buffer.h
Camera.h
Color.h
CubeMapTextureArray.h
CubeMapTexture.h
@ -61,15 +58,13 @@ set(Magnum_HEADERS
Image.h
ImageWrapper.h
IndexedMesh.h
Light.h
Magnum.h
Mesh.h
Object.h
Query.h
Renderbuffer.h
Scene.h
Shader.h
SizeTraits.h
Swizzle.h
Texture.h
TypeTraits.h
@ -86,10 +81,6 @@ if(NOT CMAKE_NO_OBJECT_TARGET)
add_library(MagnumMathObjects OBJECT ${MagnumMath_SRCS})
endif()
# Files compiled with different flags for main library and unit test library
set(Magnum_GracefulAssert_SRCS
Object.cpp)
# Set shared library flags for the objects, as they will be part of shared lib
# TODO: fix when CMake sets target_EXPORTS for OBJECT targets as well
if(NOT CMAKE_NO_OBJECT_TARGET)
@ -100,13 +91,11 @@ endif()
if(NOT CMAKE_NO_OBJECT_TARGET)
add_library(Magnum SHARED
$<TARGET_OBJECTS:MagnumObjects>
$<TARGET_OBJECTS:MagnumMathObjects>
${Magnum_GracefulAssert_SRCS})
$<TARGET_OBJECTS:MagnumMathObjects>)
else()
add_library(Magnum SHARED
${Magnum_SRCS}
${MagnumMath_SRCS}
${Magnum_GracefulAssert_SRCS})
${MagnumMath_SRCS})
endif()
target_link_libraries(Magnum ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY})
if(NOT TARGET_GLES)
@ -137,6 +126,10 @@ if(WITH_PRIMITIVES)
add_subdirectory(Primitives)
endif()
if(WITH_SCENEGRAPH)
add_subdirectory(SceneGraph)
endif()
if(WITH_SHADERS)
add_subdirectory(Shaders)
endif()
@ -147,12 +140,10 @@ if(BUILD_TESTS)
# Library with graceful assert for testing
if(NOT CMAKE_NO_OBJECT_TARGET)
add_library(MagnumTestLib SHARED
$<TARGET_OBJECTS:MagnumObjects>
${Magnum_GracefulAssert_SRCS})
$<TARGET_OBJECTS:MagnumObjects>)
else()
add_library(MagnumTestLib SHARED
${Magnum_SRCS}
${Magnum_GracefulAssert_SRCS})
${Magnum_SRCS})
endif()
set_target_properties(MagnumTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
target_link_libraries(MagnumTestLib ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY})

125
src/Camera.cpp

@ -1,125 +0,0 @@
/*
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 "Camera.h"
#include "Framebuffer.h"
#include "Scene.h"
using namespace std;
namespace Magnum {
Camera::Camera(Object* parent): Object(parent), _aspectRatioPolicy(AspectRatioPolicy::Extend) {}
void Camera::setOrthographic(GLfloat size, GLfloat near, GLfloat far) {
_near = near;
_far = far;
/* Scale the volume down so it fits in (-1, 1) in all directions */
GLfloat xyScale = 2/size;
GLfloat zScale = 2/(far-near);
rawProjectionMatrix = Matrix4::scaling({xyScale, xyScale, -zScale});
/* Move the volume on z into (-1, 1) range */
rawProjectionMatrix = Matrix4::translation(Vector3::zAxis(-1-near*zScale))*rawProjectionMatrix;
fixAspectRatio();
}
void Camera::setPerspective(GLfloat fov, GLfloat near, GLfloat far) {
_near = near;
_far = far;
/* First move the volume on z in (-1, 1) range */
rawProjectionMatrix = Matrix4::translation(Vector3::zAxis(2*far*near/(far+near)));
/* Then apply magic perspective matrix (with reversed Z) */
static const Matrix4 a(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f, -1.0f,
0.0f, 0.0f, 0.0f, 0.0f);
rawProjectionMatrix = a*rawProjectionMatrix;
/* Then scale the volume down so it fits in (-1, 1) in all directions */
GLfloat xyScale = 1/tan(fov/2);
GLfloat zScale = 1+2*near/(far-near);
rawProjectionMatrix = Matrix4::scaling({xyScale, xyScale, zScale})*rawProjectionMatrix;
/* And... another magic */
rawProjectionMatrix[3][3] = 0;
fixAspectRatio();
}
void Camera::setViewport(const Math::Vector2<GLsizei>& size) {
Framebuffer::setViewport({0, 0}, size);
_viewport = size;
fixAspectRatio();
}
void Camera::clean(const Matrix4& absoluteTransformation) {
Object::clean(absoluteTransformation);
_cameraMatrix = absoluteTransformation.inverted();
}
void Camera::fixAspectRatio() {
/* Don't divide by zero */
if(_viewport.x() == 0 || _viewport.y() == 0) {
_projectionMatrix = rawProjectionMatrix;
return;
}
/* Extend on larger side = scale larger side down */
if(_aspectRatioPolicy == AspectRatioPolicy::Extend) {
_projectionMatrix = ((_viewport.x() > _viewport.y()) ?
Matrix4::scaling({GLfloat(_viewport.y())/_viewport.x(), 1, 1}) :
Matrix4::scaling({1, GLfloat(_viewport.x())/_viewport.y(), 1})
)*rawProjectionMatrix;
/* Clip on smaller side = scale smaller side up */
} else if(_aspectRatioPolicy == AspectRatioPolicy::Clip) {
_projectionMatrix = ((_viewport.x() > _viewport.y()) ?
Matrix4::scaling({1, GLfloat(_viewport.x())/_viewport.y(), 1}) :
Matrix4::scaling({GLfloat(_viewport.y())/_viewport.x(), 1, 1})
)*rawProjectionMatrix;
/* Don't preserve anything */
} else _projectionMatrix = rawProjectionMatrix;
}
void Camera::draw() {
Scene* s = scene();
CORRADE_ASSERT(s, "Camera: cannot draw without camera attached to scene", );
Framebuffer::clear();
/* Recursively draw child objects */
drawChildren(s, cameraMatrix());
}
void Camera::drawChildren(Object* object, const Matrix4& transformationMatrix) {
for(set<Object*>::const_iterator it = object->children().begin(); it != object->children().end(); ++it) {
/* Transformation matrix for the object */
Matrix4 matrix = transformationMatrix*(*it)->transformation();
/* Draw the object and its children */
(*it)->draw(matrix, this);
drawChildren(*it, matrix);
}
}
}

156
src/Camera.h

@ -1,156 +0,0 @@
#ifndef Magnum_Camera_h
#define Magnum_Camera_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::Camera
*/
#include "Object.h"
#ifdef WIN32 /* I so HATE windows.h */
#undef near
#undef far
#endif
namespace Magnum {
/** @ingroup scene
@brief %Camera object
*/
class MAGNUM_EXPORT Camera: public Object {
public:
/**
* @brief Aspect ratio policy
*
* @see aspectRatioPolicy(), setAspectRatioPolicy()
*/
enum class AspectRatioPolicy {
NotPreserved, /**< Don't preserve aspect ratio */
Extend, /**< Extend on larger side of view */
Clip /**< Clip on smaller side of view */
};
/**
* @brief Constructor
* @param parent Parent object
*
* Sets orthographic projection to the default OpenGL cube (range
* @f$ [-1; 1] @f$ in all directions) and clear color to black.
* @see setOrthographic(), setPerspective()
*/
Camera(Object* parent = nullptr);
/** @brief Aspect ratio policy */
inline AspectRatioPolicy aspectRatioPolicy() const { return _aspectRatioPolicy; }
/** @brief Set aspect ratio policy */
void setAspectRatioPolicy(AspectRatioPolicy policy) { _aspectRatioPolicy = policy; }
/**
* @brief Set orthographic projection
* @param size Size of (square) view
* @param near Near clipping plane
* @param far Far clipping plane
*
* The volume of given size will be scaled down to range
* @f$ [-1; 1] @f$ on all directions.
*/
void setOrthographic(GLfloat size, GLfloat near, GLfloat far);
/**
* @brief Set perspective projection
* @param fov Field of view angle
* @param near Near clipping plane
* @param far Far clipping plane
*/
void setPerspective(GLfloat fov, GLfloat near, GLfloat far);
/** @brief Near clipping plane */
inline GLfloat near() const { return _near; }
/** @brief Far clipping plane */
inline GLfloat far() const { return _far; }
/**
* @brief Camera matrix
*
* Camera matrix describes world position relative to the camera and is
* applied as first.
*/
inline Matrix4 cameraMatrix() {
setClean();
return _cameraMatrix;
}
/**
* @brief Projection matrix
*
* Projection matrix handles e.g. perspective distortion and is applied
* as last.
*/
inline Matrix4 projectionMatrix() const { return _projectionMatrix; }
/** @brief Viewport size */
inline Math::Vector2<GLsizei> viewport() const { return _viewport; }
/**
* @brief Set viewport size
*
* Call when window size changes.
*
* Calls Framebuffer::setViewport() and stores viewport size
* internally.
*/
virtual void setViewport(const Math::Vector2<GLsizei>& size);
/**
* @brief Draw the scene
*
* Calls Framebuffer::clear() and draws the scene using drawChildren().
*/
virtual void draw();
using Object::draw; /* Don't hide Object's draw() */
protected:
/**
* Recalculates camera matrix.
*/
void clean(const Matrix4& absoluteTransformation);
/**
* @brief Draw object children
*
* Recursively draws all children of the object.
*/
void drawChildren(Object* object, const Matrix4& transformationMatrix);
private:
Matrix4 rawProjectionMatrix;
Matrix4 _projectionMatrix;
Matrix4 _cameraMatrix;
GLfloat _near, _far;
Math::Vector2<GLsizei> _viewport;
AspectRatioPolicy _aspectRatioPolicy;
MAGNUM_LOCAL void fixAspectRatio();
};
}
#endif

14
src/Color.h

@ -140,6 +140,8 @@ 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
@todo Signed normalization to [-1.0, 1.0] like in OpenGL?
*/
template<class T> class Color3: public Math::Vector3<T> {
public:
@ -394,16 +396,24 @@ template<class T> class Color4: public Math::Vector4<T> {
}
};
/** @debugoperator{Color3} */
/** @debugoperator{Magnum::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} */
/** @debugoperator{Magnum::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);
}
}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Color3} */
template<class T> struct ConfigurationValue<Magnum::Color3<T>>: public ConfigurationValue<Magnum::Math::Vector<3, T>> {};
/** @configurationvalue{Magnum::Color4} */
template<class T> struct ConfigurationValue<Magnum::Color4<T>>: public ConfigurationValue<Magnum::Math::Vector<4, T>> {};
}}
#endif

64
src/Contexts/AbstractGlInterface.h

@ -0,0 +1,64 @@
#ifndef Magnum_Contexts_AbstractGlInterface_h
#define Magnum_Contexts_AbstractGlInterface_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::Contexts::AbstractGlInterface
*/
#include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts {
/** @brief Base for OpenGL interfaces */
template<class Display, class VisualId, class Window> class AbstractGlInterface {
public:
/**
* @brief Get visual ID
*
* Initializes the interface on given display and returns visual ID.
*/
virtual VisualId getVisualId(Display nativeDisplay) = 0;
/**
* @brief Destructor
*
* Finalizes and closes the interface.
*/
virtual ~AbstractGlInterface() {}
/** @brief Create context */
virtual void createContext(Window nativeWindow) = 0;
/**
* @brief Whether to enable experimental extension wrangler features
*
* Default is to disable.
*/
virtual inline ExtensionWrangler::ExperimentalFeatures experimentalExtensionWranglerFeatures() const {
return ExtensionWrangler::ExperimentalFeatures::Disable;
}
/** @brief Make the context current */
virtual void makeCurrent() = 0;
/** @brief Swap buffers */
virtual void swapBuffers() = 0;
};
}}
#endif

142
src/Contexts/AbstractXContext.cpp

@ -0,0 +1,142 @@
/*
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 "AbstractXContext.h"
#include "ExtensionWrangler.h"
#define None 0L // redef Xlib nonsense
/* Mask for X events */
#define INPUT_MASK KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask|StructureNotifyMask
using namespace std;
namespace Magnum { namespace Contexts {
AbstractXContext::AbstractXContext(AbstractGlInterface<Display*, VisualID, Window>* glInterface, int&, char**, const string& title, const Math::Vector2<GLsizei>& size): glInterface(glInterface), viewportSize(size), flags(Flag::Redraw) {
/* Get default X display */
display = XOpenDisplay(0);
/* Get visual ID */
VisualID visualId = glInterface->getVisualId(display);
/* Get visual info */
XVisualInfo *visInfo, visTemplate;
int visualCount;
visTemplate.visualid = visualId;
visInfo = XGetVisualInfo(display, VisualIDMask, &visTemplate, &visualCount);
if(!visInfo) {
Error() << "Cannot get X visual";
::exit(1);
}
/* Create X Window */
Window root = RootWindow(display, DefaultScreen(display));
XSetWindowAttributes attr;
attr.background_pixel = 0;
attr.border_pixel = 0;
attr.colormap = XCreateColormap(display, root, visInfo->visual, AllocNone);
attr.event_mask = 0;
unsigned long mask = CWBackPixel|CWBorderPixel|CWColormap|CWEventMask;
window = XCreateWindow(display, root, 20, 20, size.x(), size.y(), 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr);
XSetStandardProperties(display, window, title.c_str(), 0, None, 0, 0, 0);
XFree(visInfo);
/* Be notified about closing the window */
deleteWindow = XInternAtom(display, "WM_DELETE_WINDOW", True);
XSetWMProtocols(display, window, &deleteWindow, 1);
/* Create context */
glInterface->createContext(window);
/* Capture exposure, keyboard and mouse button events */
XSelectInput(display, window, INPUT_MASK);
/* Set OpenGL context as current */
glInterface->makeCurrent();
/* Initialize extension wrangler */
ExtensionWrangler::initialize(glInterface->experimentalExtensionWranglerFeatures());
}
AbstractXContext::~AbstractXContext() {
/* Shut down the interface */
delete glInterface;
/* Shut down X */
XDestroyWindow(display, window);
XCloseDisplay(display);
}
int AbstractXContext::exec() {
/* Show window */
XMapWindow(display, window);
/* Call viewportEvent for the first time */
viewportEvent(viewportSize);
while(!(flags & Flag::Exit)) {
XEvent event;
/* Closed window */
if(XCheckTypedWindowEvent(display, window, ClientMessage, &event) &&
Atom(event.xclient.data.l[0]) == deleteWindow) {
return 0;
}
while(XCheckWindowEvent(display, window, INPUT_MASK, &event)) {
switch(event.type) {
/* Window resizing */
case ConfigureNotify: {
Math::Vector2<GLsizei> size(event.xconfigure.width, event.xconfigure.height);
if(size != viewportSize) {
viewportSize = size;
viewportEvent(size);
flags |= Flag::Redraw;
}
} break;
/* Key/mouse events */
case KeyPress:
keyPressEvent(static_cast<Key>(XLookupKeysym(&event.xkey, 0)), static_cast<Modifier>(event.xkey.state), {event.xkey.x, event.xkey.y});
break;
case KeyRelease:
keyReleaseEvent(static_cast<Key>(XLookupKeysym(&event.xkey, 0)), static_cast<Modifier>(event.xkey.state), {event.xkey.x, event.xkey.y});
break;
case ButtonPress:
mousePressEvent(static_cast<MouseButton>(event.xbutton.button), static_cast<Modifier>(event.xkey.state), {event.xbutton.x, event.xbutton.y});
break;
case ButtonRelease:
mouseReleaseEvent(static_cast<MouseButton>(event.xbutton.button), static_cast<Modifier>(event.xkey.state), {event.xbutton.x, event.xbutton.y});
break;
/* Mouse move events */
case MotionNotify:
mouseMotionEvent(static_cast<Modifier>(event.xmotion.state), {event.xmotion.x, event.xmotion.y});
break;
}
}
if(flags & Flag::Redraw) {
flags &= ~Flag::Redraw;
drawEvent();
} else Corrade::Utility::sleep(5);
}
return 0;
}
}}

142
src/Contexts/EglContext.h → src/Contexts/AbstractXContext.h

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_EglContext_h
#define Magnum_Contexts_EglContext_h
#ifndef Magnum_Contexts_AbstractXContext_h
#define Magnum_Contexts_AbstractXContext_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,52 +16,57 @@
*/
/** @file
* @brief Class Magnum::Contexts::EglContext
* @brief Class Magnum::Contexts::AbstractXContext
*/
#include "Magnum.h"
#include <X11/Xlib.h>
#ifdef None // undef Xlib nonsense to avoid conflicts
#include <X11/Xutil.h>
/* undef Xlib nonsense to avoid conflicts */
#undef None
#endif
#undef Always
#ifndef SUPPORT_X11
#define SUPPORT_X11 // OpenGL ES on BeagleBoard needs this (?)
#endif
#include <EGL/egl.h>
#include <Containers/EnumSet.h>
#include "AbstractContext.h"
#include "AbstractGlInterface.h"
namespace Magnum { namespace Contexts {
/**
@brief X/EGL context
/** @nosubgrouping
@brief Base for X11-based contexts
Supports keyboard and mouse handling.
@note Not meant to be used directly, see subclasses.
*/
class EglContext: public AbstractContext {
class AbstractXContext: public AbstractContext {
public:
/**
* @brief Constructor
* @param argc Count of arguments of `main()` function
* @param argv Arguments of `main()` function
* @param title Window title
* @param size Window size
* @param glInterface Interface to OpenGL
* @param argc Count of arguments of `main()` function
* @param argv Arguments of `main()` function
* @param title Window title
* @param size Window size
*
* Creates window with double-buffered OpenGL ES 2 context.
*/
EglContext(int& argc, char** argv, const std::string& title = "Magnum X/EGL context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600));
AbstractXContext(AbstractGlInterface<Display*, VisualID, Window>* glInterface, int& argc, char** argv, const std::string& title = "Magnum X/EGL context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600));
/**
* @brief Destructor
*
* Deletes context and destroys the window.
*/
~EglContext();
virtual ~AbstractXContext() = 0;
int exec();
/** @brief Exit application main loop */
inline void exit() { flags |= Flag::Exit; }
/** @{ @name Drawing functions */
protected:
@ -72,18 +77,50 @@ class EglContext: public AbstractContext {
virtual void drawEvent() = 0;
/** @copydoc GlutContext::swapBuffers() */
inline void swapBuffers() { eglSwapBuffers(display, surface); }
inline void swapBuffers() { glInterface->swapBuffers(); }
/** @todo implement */
inline void redraw() {}
/** @copydoc GlutContext::redraw() */
inline void redraw() { flags |= Flag::Redraw; }
/*@}*/
/** @{ @name Keyboard handling */
public:
/** @brief Key */
/**
* @brief %Modifier
*
* @see Modifiers, keyPressEvent(), keyReleaseEvent(),
* mousePressEvent(), mouseReleaseEvent(), mouseMotionEvent()
*/
enum class Modifier: unsigned int {
Shift = ShiftMask, /**< Shift */
CapsLock = LockMask, /**< Caps lock */
Ctrl = ControlMask, /**< Ctrl */
Alt = Mod1Mask, /**< Alt */
NumLock = Mod2Mask, /**< Num lock */
AltGr = Mod5Mask, /**< AltGr */
LeftButton = Button1Mask, /**< Left mouse button */
MiddleButton = Button2Mask, /**< Middle mouse button */
RightButton = Button3Mask /**< Right mouse button */
};
/**
* @brief Set of modifiers
*
* @see keyPressEvent(), keyReleaseEvent()
*/
typedef Corrade::Containers::EnumSet<Modifier, unsigned int> Modifiers;
/**
* @brief Key
*
* @see keyPressEvent(), keyReleaseEvent()
*/
enum class Key: KeySym {
Esc = XK_Escape, /**< Escape */
Up = XK_Up, /**< Up arrow */
Down = XK_Down, /**< Down arrow */
Left = XK_Left, /**< Left arrow */
@ -157,27 +194,33 @@ class EglContext: public AbstractContext {
/**
* @brief Key press event
* @param key Key pressed
* @param modifiers Active modifiers
* @param position Cursor position
*
* Called when an key is pressed. Default implementation does nothing.
*/
virtual void keyPressEvent(Key key, const Math::Vector2<int>& position);
virtual void keyPressEvent(Key key, Modifiers modifiers, const Math::Vector2<int>& position);
/**
* @brief Key press event
* @param key Key released
* @param modifiers Active modifiers
* @param position Cursor position
*
* Called when an key is released. Default implementation does nothing.
*/
virtual void keyReleaseEvent(Key key, const Math::Vector2<int>& position);
virtual void keyReleaseEvent(Key key, Modifiers modifiers, const Math::Vector2<int>& position);
/*@}*/
/** @{ @name Mouse handling */
public:
/** @brief Mouse button */
/**
* @brief Mouse button
*
* @see mousePressEvent(), mouseReleaseEvent()
*/
enum class MouseButton: unsigned int {
Left = Button1, /**< Left button */
Middle = Button2, /**< Middle button */
@ -189,40 +232,67 @@ class EglContext: public AbstractContext {
protected:
/**
* @brief Mouse press event
* @param button Button pressed
* @param modifiers Active modifiers
* @param position Cursor position
*
* Called when mouse button is pressed. Default implementation does
* nothing.
*/
virtual void mousePressEvent(MouseButton button, const Math::Vector2<int>& position);
virtual void mousePressEvent(MouseButton button, Modifiers modifiers, const Math::Vector2<int>& position);
/**
* @brief Mouse release event
* @param button Button released
* @param modifiers Active modifiers
* @param position Cursor position
*
* Called when mouse button is released. Default implementation does
* nothing.
*/
virtual void mouseReleaseEvent(MouseButton button, const Math::Vector2<int>& position);
virtual void mouseReleaseEvent(MouseButton button, Modifiers modifiers, const Math::Vector2<int>& position);
/**
* @brief Mouse motion event
* @param modifiers Active modifiers
* @param position Cursor position
*
* Called when mouse is moved.
*/
virtual void mouseMotionEvent(Modifiers modifiers, const Math::Vector2<int>& position);
/*@}*/
private:
Display* xDisplay;
Window xWindow;
enum class Flag: unsigned int {
Redraw = 1 << 0,
Exit = 1 << 1
};
typedef Corrade::Containers::EnumSet<Flag, unsigned int> Flags;
CORRADE_ENUMSET_FRIEND_OPERATORS(Flags)
Display* display;
Window window;
Atom deleteWindow;
EGLDisplay display;
EGLSurface surface;
EGLContext context;
AbstractGlInterface<Display*, VisualID, Window>* glInterface;
/** @todo Get this from the created window */
Math::Vector2<GLsizei> viewportSize;
Flags flags;
};
inline void EglContext::keyPressEvent(EglContext::Key, const Math::Vector2<int>&) {}
inline void EglContext::keyReleaseEvent(EglContext::Key, const Math::Vector2<int>&) {}
inline void EglContext::mousePressEvent(EglContext::MouseButton, const Math::Vector2<int>&) {}
inline void EglContext::mouseReleaseEvent(EglContext::MouseButton, const Math::Vector2<int>&) {}
CORRADE_ENUMSET_OPERATORS(AbstractXContext::Modifiers)
CORRADE_ENUMSET_OPERATORS(AbstractXContext::Flags)
/* Implementations for inline functions with unused parameters */
inline void AbstractXContext::keyPressEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::keyReleaseEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::mousePressEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::mouseReleaseEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::mouseMotionEvent(Modifiers, const Math::Vector2<int>&) {}
}}

78
src/Contexts/CMakeLists.txt

@ -1,10 +1,19 @@
install(FILES AbstractContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
# Extension wrangler
add_library(MagnumContextsExtensionWrangler OBJECT ExtensionWrangler.cpp)
set(MagnumContexts_HEADERS
AbstractContext.h
AbstractGlInterface.h
ExtensionWrangler.h)
install(FILES ${MagnumContexts_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
# GLUT context
if(WITH_GLUTCONTEXT)
find_package(GLUT)
if(GLUT_FOUND)
add_library(MagnumGlutContext STATIC GlutContext.cpp)
add_library(MagnumGlutContext STATIC
GlutContext.cpp
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES GlutContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumGlutContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
else()
@ -17,7 +26,9 @@ if(WITH_SDL2CONTEXT)
find_package(SDL2)
if(SDL2_FOUND)
include_directories(${SDL2_INCLUDE_DIR})
add_library(MagnumSdl2Context STATIC Sdl2Context.cpp)
add_library(MagnumSdl2Context STATIC
Sdl2Context.cpp
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES Sdl2Context.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumSdl2Context DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
else()
@ -25,17 +36,58 @@ if(WITH_SDL2CONTEXT)
endif()
endif()
# GLX context
if(WITH_GLXCONTEXT)
set(NEED_ABSTRACTXCONTEXT 1)
set(NEED_GLXINTERFACE 1)
add_library(MagnumGlxContext STATIC
$<TARGET_OBJECTS:MagnumAbstractXContext>
$<TARGET_OBJECTS:MagnumGlxInterface>
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES GlxContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumGlxContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
endif()
# X/EGL context
if(WITH_EGLCONTEXT)
find_package(EGL)
if(WITH_XEGLCONTEXT)
set(NEED_ABSTRACTXCONTEXT 1)
set(NEED_EGLINTERFACE 1)
add_library(MagnumXEglContext STATIC
$<TARGET_OBJECTS:MagnumAbstractXContext>
$<TARGET_OBJECTS:MagnumEglInterface>
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES XEglContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumXEglContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
endif()
# Abstract X context
if(NEED_ABSTRACTXCONTEXT)
find_package(X11)
if(EGL_FOUND AND X11_FOUND)
add_library(MagnumEglContext STATIC EglContext.cpp)
# X11 macros are a mess, disable warnings for C-style casts
set_target_properties(MagnumEglContext PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES EglContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumEglContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
else()
message(FATAL_ERROR "EGL or X11 libraries, required by EglContext, were not found. Set WITH_EGLCONTEXT to OFF to skip building it.")
if(NOT X11_FOUND)
message(FATAL_ERROR "X11 library, required by some contexts, was not found. Set WITH_*X*CONTEXT to OFF to skip building them.")
endif()
add_library(MagnumAbstractXContext OBJECT AbstractXContext.cpp)
# X11 macros are a mess, disable warnings for C-style casts
set_target_properties(MagnumAbstractXContext PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES AbstractXContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
endif()
# GLX interface
if(NEED_GLXINTERFACE)
add_library(MagnumGlxInterface OBJECT GlxInterface.cpp)
# X11 macros are a mess, disable warnings for C-style casts
set_target_properties(MagnumGlxInterface PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES GlxInterface.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
endif()
# EGL interface
if(NEED_EGLINTERFACE)
find_package(EGL)
if(NOT EGL_FOUND)
message(FATAL_ERROR "EGL library, required by some contexts, was not found. Set WITH_*EGL*CONTEXT to OFF to skip building them.")
endif()
add_library(MagnumEglInterface OBJECT EglInterface.cpp)
# X11 macros are a mess, disable warnings for C-style casts
set_target_properties(MagnumEglInterface PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES EglInterface.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
endif()

186
src/Contexts/EglContext.cpp

@ -1,186 +0,0 @@
/*
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 "EglContext.h"
#define None 0L // redef Xlib nonsense
/* Mask for X events */
#define INPUT_MASK KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|StructureNotifyMask
using namespace std;
namespace Magnum { namespace Contexts {
EglContext::EglContext(int&, char**, const string& title, const Math::Vector2<GLsizei>& size): viewportSize(size) {
/* Get default X display and root window, init EGL */
xDisplay = XOpenDisplay(0);
display = eglGetDisplay(xDisplay);
eglInitialize(display, 0, 0);
#ifndef MAGNUM_TARGET_GLES
eglBindAPI(EGL_OPENGL_API);
#else
eglBindAPI(EGL_OPENGL_ES_API);
#endif
int screenNumber = DefaultScreen(xDisplay);
Window root = RootWindow(xDisplay, screenNumber);
/* Choose EGL config */
static const EGLint attribs[] = {
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_DEPTH_SIZE, 1,
#ifndef MAGNUM_TARGET_GLES
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
#else
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#endif
EGL_NONE
};
EGLConfig config;
EGLint configCount;
if(!eglChooseConfig(display, attribs, &config, 1, &configCount)) {
Error() << "Cannot get EGL visual config";
exit(1);
}
/* Get X visual */
EGLint visualId;
if(!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualId)) {
Error() << "Cannot get native visual ID";
exit(1);
}
XVisualInfo *visInfo, visTemplate;
int visualCount;
visTemplate.visualid = visualId;
visInfo = XGetVisualInfo(xDisplay, VisualIDMask, &visTemplate, &visualCount);
if(!visInfo) {
Error() << "Cannot get X visual";
exit(1);
}
/* Create X Window */
XSetWindowAttributes attr;
attr.background_pixel = 0;
attr.border_pixel = 0;
attr.colormap = XCreateColormap(xDisplay, root, visInfo->visual, AllocNone);
attr.event_mask = 0;
unsigned long mask = CWBackPixel|CWBorderPixel|CWColormap|CWEventMask;
xWindow = XCreateWindow(xDisplay, root, 20, 20, size.x(), size.y(), 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr);
XSetStandardProperties(xDisplay, xWindow, title.c_str(), 0, None, 0, 0, 0);
XFree(visInfo);
/* Be notified about closing the window */
deleteWindow = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
XSetWMProtocols(xDisplay, xWindow, &deleteWindow, 1);
/* Create context and window surface */
static const EGLint contextAttributes[] = {
#ifdef MAGNUM_TARGET_GLES
EGL_CONTEXT_CLIENT_VERSION, 2,
#endif
EGL_NONE
};
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);
if(!context) {
Error() << "Cannot create EGL context";
exit(1);
}
surface = eglCreateWindowSurface(display, config, xWindow, NULL);
if(!surface) {
Error() << "Cannot create window surface";
exit(1);
}
/* Capture exposure, keyboard and mouse button events */
XSelectInput(xDisplay, xWindow, INPUT_MASK);
/* Set OpenGL context as current */
eglMakeCurrent(display, surface, surface, context);
/** @bug Fixme: GLEW initialization fails (thinks that the context is not created) */
#ifndef MAGNUM_TARGET_GLES
/* Init GLEW */
GLenum err = glewInit();
if(err != GLEW_OK) {
Error() << "EglContext: cannot initialize GLEW:" << glewGetErrorString(err);
exit(1);
}
#endif
}
EglContext::~EglContext() {
/* Shut down EGL */
eglDestroyContext(display, context);
eglDestroySurface(display, surface);
eglTerminate(display);
/* Shut down X */
XDestroyWindow(xDisplay, xWindow);
XCloseDisplay(xDisplay);
}
int EglContext::exec() {
/* Show window */
XMapWindow(xDisplay, xWindow);
/* Call viewportEvent for the first time */
viewportEvent(viewportSize);
while(true) {
XEvent event;
/* Closed window */
if(XCheckTypedWindowEvent(xDisplay, xWindow, ClientMessage, &event) &&
Atom(event.xclient.data.l[0]) == deleteWindow) {
return 0;
}
while(XCheckWindowEvent(xDisplay, xWindow, INPUT_MASK, &event)) {
switch(event.type) {
/* Window resizing */
case ConfigureNotify: {
Math::Vector2<int> size(event.xconfigure.width, event.xconfigure.height);
if(size != viewportSize) {
viewportSize = size;
viewportEvent(size);
}
} break;
/* Key/mouse events */
case KeyPress:
keyPressEvent(static_cast<Key>(XLookupKeysym(&event.xkey, 0)), {event.xkey.x, event.xkey.y});
break;
case KeyRelease:
keyReleaseEvent(static_cast<Key>(XLookupKeysym(&event.xkey, 0)), {event.xkey.x, event.xkey.y});
break;
case ButtonPress:
mousePressEvent(static_cast<MouseButton>(event.xbutton.button), {event.xbutton.x, event.xbutton.y});
break;
case ButtonRelease:
mouseReleaseEvent(static_cast<MouseButton>(event.xbutton.button), {event.xbutton.x, event.xbutton.y});
break;
}
}
/** @todo Handle at least window closing and resizing */
drawEvent();
}
return 0;
}
}}

86
src/Contexts/EglInterface.cpp

@ -0,0 +1,86 @@
/*
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 "EglInterface.h"
namespace Magnum { namespace Contexts {
EglInterface::~EglInterface() {
eglDestroyContext(display, context);
eglDestroySurface(display, surface);
eglTerminate(display);
}
VisualId EglInterface::getVisualId(EGLNativeDisplayType nativeDisplay) {
/* Initialize */
display = eglGetDisplay(nativeDisplay);
eglInitialize(display, 0, 0);
#ifndef MAGNUM_TARGET_GLES
eglBindAPI(EGL_OPENGL_API);
#else
eglBindAPI(EGL_OPENGL_ES_API);
#endif
/* Choose EGL config */
static const EGLint attribs[] = {
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_DEPTH_SIZE, 1,
#ifndef MAGNUM_TARGET_GLES
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
#else
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#endif
EGL_NONE
};
EGLint configCount;
if(!eglChooseConfig(display, attribs, &config, 1, &configCount)) {
Error() << "Cannot get EGL visual config";
exit(1);
}
/* Get visual ID */
EGLint visualId;
if(!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualId)) {
Error() << "Cannot get native visual ID";
exit(1);
}
return visualId;
}
void EglInterface::createContext(EGLNativeWindowType window) {
static const EGLint contextAttributes[] = {
#ifdef MAGNUM_TARGET_GLES
EGL_CONTEXT_CLIENT_VERSION, 2,
#endif
EGL_NONE
};
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);
if(!context) {
Error() << "Cannot create EGL context";
exit(1);
}
surface = eglCreateWindowSurface(display, config, window, NULL);
if(!surface) {
Error() << "Cannot create window surface";
exit(1);
}
/** @bug Fixme: On desktop OpenGL and Mesa EGL implementation OpenGL version is 1.0, which is wrong */
}
}}

71
src/Contexts/EglInterface.h

@ -0,0 +1,71 @@
#ifndef Magnum_Contexts_EglInterface_h
#define Magnum_Contexts_EglInterface_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::Contexts::EglInterface
*/
#include "Magnum.h"
#ifndef SUPPORT_X11
#define SUPPORT_X11 // OpenGL ES on BeagleBoard needs this (?)
#endif
#include <EGL/egl.h>
#include "AbstractGlInterface.h"
namespace Magnum { namespace Contexts {
#ifndef DOXYGEN_GENERATING_OUTPUT
/* EGL returns visual ID as int, but Xorg expects long unsigned int */
#ifdef __unix__
typedef VisualID VisualId;
#else
typedef EGLInt VisualId;
#endif
#endif
/**
@brief EGL interface
Used in XEglContext.
*/
class EglInterface: public AbstractGlInterface<EGLNativeDisplayType, VisualId, EGLNativeWindowType> {
public:
~EglInterface();
VisualId getVisualId(EGLNativeDisplayType nativeDisplay);
void createContext(EGLNativeWindowType nativeWindow);
inline void makeCurrent() {
eglMakeCurrent(display, surface, surface, context);
}
inline void swapBuffers() {
eglSwapBuffers(display, surface);
}
private:
EGLDisplay display;
EGLConfig config;
EGLSurface surface;
EGLContext context;
};
}}
#endif

37
src/Contexts/ExtensionWrangler.cpp

@ -0,0 +1,37 @@
/*
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 "ExtensionWrangler.h"
#include "Magnum.h"
namespace Magnum { namespace Contexts {
void ExtensionWrangler::initialize(ExperimentalFeatures experimentalFeatures) {
#ifndef MAGNUM_TARGET_GLES
/* Enable experimental features */
if(experimentalFeatures == ExperimentalFeatures::Enable)
glewExperimental = true;
/* Init GLEW */
GLenum err = glewInit();
if(err != GLEW_OK) {
Error() << "ExtensionWrangler: cannot initialize GLEW:" << glewGetErrorString(err);
exit(1);
}
#endif
}
}}

39
src/Contexts/ExtensionWrangler.h

@ -0,0 +1,39 @@
#ifndef Magnum_Contexts_ExtensionWrangler_h
#define Magnum_Contexts_ExtensionWrangler_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::Contexts::ExtensionWrangler
*/
namespace Magnum { namespace Contexts {
/** @brief Extension wrangler interface */
class ExtensionWrangler {
public:
/** @brief Whether to enable or disable experimental features */
enum class ExperimentalFeatures {
Disable,
Enable
};
/** @brief Initialize extension wrangler */
static void initialize(ExperimentalFeatures experimentalFeatures = ExperimentalFeatures::Disable);
};
}}
#endif

9
src/Contexts/GlutContext.cpp

@ -15,6 +15,8 @@
#include "GlutContext.h"
#include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts {
GlutContext* GlutContext::instance = nullptr;
@ -35,12 +37,7 @@ GlutContext::GlutContext(int& argc, char** argv, const std::string& title, const
glutMotionFunc(staticMouseMotionEvent);
glutDisplayFunc(staticDrawEvent);
/* Init GLEW */
GLenum err = glewInit();
if(err != GLEW_OK) {
Error() << "GlutContext: cannot initialize GLEW:" << glewGetErrorString(err);
exit(1);
}
ExtensionWrangler::initialize();
}
}}

32
src/Contexts/GlutContext.h

@ -60,7 +60,8 @@ class GlutContext: public AbstractContext {
* @brief Viewport event
*
* Called when viewport size changes. You should pass the new size to
* Camera::viewport() function of your camera.
* Framebuffer::setViewport() or SceneGraph::Camera::setViewport(),
* if using scene graph.
*/
virtual void viewportEvent(const Math::Vector2<GLsizei>& size) = 0;
@ -68,8 +69,9 @@ class GlutContext: public AbstractContext {
* @brief Draw event
*
* Here implement your drawing functions, such as calling
* Camera::draw(). After drawing is finished, call swapBuffers(). If
* you want to draw immediately again, call also redraw().
* SceneGraph::Camera::draw(). After drawing is finished, call
* swapBuffers(). If you want to draw immediately again, call also
* redraw().
*/
virtual void drawEvent() = 0;
@ -97,7 +99,11 @@ class GlutContext: public AbstractContext {
/** @{ @name Keyboard handling */
public:
/** @brief Key */
/**
* @brief Key
*
* @see keyPressEvent()
*/
enum class Key: int {
Up = GLUT_KEY_UP, /**< Up arrow */
Down = GLUT_KEY_DOWN, /**< Down arrow */
@ -136,7 +142,11 @@ class GlutContext: public AbstractContext {
/** @{ @name Mouse handling */
public:
/** @brief Mouse button */
/**
* @brief Mouse button
*
* @see mousePressEvent(), mouseReleaseEvent()
*/
enum class MouseButton: int {
Left = GLUT_LEFT_BUTTON, /**< Left button */
Middle = GLUT_MIDDLE_BUTTON, /**< Middle button */
@ -145,7 +155,11 @@ class GlutContext: public AbstractContext {
WheelDown = 4 /**< Wheel down */
};
/** @brief Mouse cursor */
/**
* @brief Mouse cursor
*
* @see setMouseCursor()
*/
enum class MouseCursor: int {
Default = GLUT_CURSOR_INHERIT, /**< Default cursor provided by parent window */
None = GLUT_CURSOR_NONE /**< No cursor */
@ -231,9 +245,9 @@ class GlutContext: public AbstractContext {
};
/* Implementations for inline functions with unused parameters */
inline void GlutContext::keyPressEvent(GlutContext::Key, const Math::Vector2<int>&) {}
inline void GlutContext::mousePressEvent(GlutContext::MouseButton, const Math::Vector2<int>&) {}
inline void GlutContext::mouseReleaseEvent(GlutContext::MouseButton, const Math::Vector2<int>&) {}
inline void GlutContext::keyPressEvent(Key, const Math::Vector2<int>&) {}
inline void GlutContext::mousePressEvent(MouseButton, const Math::Vector2<int>&) {}
inline void GlutContext::mouseReleaseEvent(MouseButton, const Math::Vector2<int>&) {}
inline void GlutContext::mouseMotionEvent(const Math::Vector2<int>&) {}
}}

49
src/Contexts/GlxContext.h

@ -0,0 +1,49 @@
#ifndef Magnum_Contexts_GlxContext_h
#define Magnum_Contexts_GlxContext_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::Contexts::GlxContext
*/
#include "AbstractXContext.h"
#include "GlxInterface.h"
namespace Magnum { namespace Contexts {
/**
@brief GLX context
Uses GlxInterface.
*/
class GlxContext: public AbstractXContext {
public:
/**
* @brief Constructor
* @param argc Count of arguments of `main()` function
* @param argv Arguments of `main()` function
* @param title Window title
* @param size Window size
*
* Creates window with double-buffered OpenGL 3.3 core context or
* OpenGL ES 2.0 context, if targetting OpenGL ES.
*/
inline GlxContext(int& argc, char** argv, const std::string& title = "Magnum GLX context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600)): AbstractXContext(new GlxInterface, argc, argv, title, size) {}
};
}}
#endif

90
src/Contexts/GlxInterface.cpp

@ -0,0 +1,90 @@
/*
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 "GlxInterface.h"
#include <GL/glxext.h>
namespace Magnum { namespace Contexts {
VisualID GlxInterface::getVisualId(Display* nativeDisplay) {
display = nativeDisplay;
/* Check version */
int major, minor;
glXQueryVersion(nativeDisplay, &major, &minor);
if(major == 1 && minor < 4) {
Error() << "GlxInterface: GLX version 1.4 or greater is required.";
exit(1);
}
/* Choose config */
int configCount = 0;
static const int attributes[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_X_RENDERABLE, True,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_DOUBLEBUFFER, True,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
0
};
configs = glXChooseFBConfig(nativeDisplay, DefaultScreen(nativeDisplay), attributes, &configCount);
if(!configCount) {
Error() << "GlxInterface: no supported framebuffer configuration found.";
exit(1);
}
/* Get visual ID */
XVisualInfo* info = glXGetVisualFromFBConfig(display, configs[0]);
VisualID visualId = info->visualid;
XFree(info);
return visualId;
}
void GlxInterface::createContext(Window nativeWindow) {
window = nativeWindow;
GLint attributes[] = {
#ifndef MAGNUM_TARGET_GLES
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
#else
GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
#endif
0
};
/** @todo Use some extension wrangler for this, not GLEW, as it apparently needs context to create context, yo dawg wtf. */
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
context = glXCreateContextAttribsARB(display, configs[0], 0, True, attributes);
XFree(configs);
if(!context) {
Error() << "GlxInterface: cannot create context.";
exit(1);
}
}
GlxInterface::~GlxInterface() {
glXMakeCurrent(display, None, nullptr);
glXDestroyContext(display, context);
}
}}

66
src/Contexts/GlxInterface.h

@ -0,0 +1,66 @@
#ifndef Magnum_Contexts_EglInterface_h
#define Magnum_Contexts_EglInterface_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::Contexts::GlxInterface
*/
#include "Magnum.h"
#include <GL/glx.h>
#include "AbstractGlInterface.h"
namespace Magnum { namespace Contexts {
/**
@brief GLX interface
Creates OpenGL 3.3 core context or OpenGL ES 2.0 context, if targetting
OpenGL ES.
Used in GlxContext.
*/
class GlxInterface: public AbstractGlInterface<Display*, VisualID, Window> {
public:
~GlxInterface();
VisualID getVisualId(Display* nativeDisplay);
void createContext(Window nativeWindow);
/* This must be enabled, otherwise (on my NVidia) it crashes when creating VAO. WTF. */
inline ExtensionWrangler::ExperimentalFeatures experimentalExtensionWranglerFeatures() const {
return ExtensionWrangler::ExperimentalFeatures::Enable;
}
inline void makeCurrent() {
glXMakeCurrent(display, window, context);
}
inline void swapBuffers() {
glXSwapBuffers(display, window);
}
private:
Display* display;
Window window;
GLXFBConfig* configs;
GLXContext context;
};
}}
#endif

20
src/Contexts/Sdl2Context.cpp

@ -14,6 +14,7 @@
*/
#include "Sdl2Context.h"
#include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts {
@ -40,18 +41,9 @@ Sdl2Context::Sdl2Context(int, char**, const std::string& name, const Math::Vecto
context = SDL_GL_CreateContext(window);
#ifndef MAGNUM_TARGET_GLES
/* This must be enabled, otherwise (on my NVidia) it crashes when creating
VAO. WTF. */
glewExperimental = true;
/* Init GLEW */
GLenum err = glewInit();
if(err != GLEW_OK) {
Error() << "Sdl2Context: cannot initialize GLEW:" << glewGetErrorString(err);
exit(1);
}
#endif
ExtensionWrangler::initialize(ExtensionWrangler::ExperimentalFeatures::Enable);
/* Push resize event, so viewportEvent() is called at startup */
SDL_Event* sizeEvent = new SDL_Event;
@ -91,10 +83,10 @@ int Sdl2Context::exec() {
keyReleaseEvent(static_cast<Key>(event.key.keysym.sym));
break;
case SDL_MOUSEBUTTONDOWN:
mousePressEvent(static_cast<MouseButton>(event.button.button), {event.button.x, event.button.y});
break;
case SDL_MOUSEBUTTONUP:
mouseEvent(static_cast<MouseButton>(event.button.button),
static_cast<MouseState>(event.button.state),
{event.button.x, event.button.y});
mouseReleaseEvent(static_cast<MouseButton>(event.button.button), {event.button.x, event.button.y});
break;
case SDL_MOUSEWHEEL:
mouseWheelEvent({event.wheel.x, event.wheel.y});
@ -109,8 +101,8 @@ int Sdl2Context::exec() {
}
if(_redraw) {
drawEvent();
_redraw = false;
drawEvent();
} else Corrade::Utility::sleep(5);
}

33
src/Contexts/Sdl2Context.h

@ -79,6 +79,7 @@ class Sdl2Context: public AbstractContext {
public:
/**
* @brief Key
*
* @see keyPressEvent(), keyReleaseEvent()
*/
enum class Key: SDL_Keycode {
@ -111,6 +112,7 @@ class Sdl2Context: public AbstractContext {
public:
/**
* @brief Mouse button
*
* @see mouseEvent()
*/
enum class MouseButton: Uint8 {
@ -121,6 +123,7 @@ class Sdl2Context: public AbstractContext {
/**
* @brief Mouse state
*
* @see mouseEvent()
*/
enum class MouseState: Uint8 {
@ -130,15 +133,24 @@ class Sdl2Context: public AbstractContext {
protected:
/**
* @brief Mouse event
* @param button Mouse button
* @param state Mouse state
* @param position Mouse position relative to the window
* @brief Mouse press event
* @param button Button pressed
* @param position Cursor position
*
* Called when mouse button is pressed. Default implementation does
* nothing.
*/
virtual void mousePressEvent(MouseButton button, const Math::Vector2<int>& position);
/**
* @brief Mouse release event
* @param button Button released
* @param position Cursor position
*
* Called when mouse button is pressed or released. Default
* implementation does nothing.
* Called when mouse button is released. Default implementation does
* nothing.
*/
virtual void mouseEvent(MouseButton button, MouseState state, const Math::Vector2<int>& position);
virtual void mouseReleaseEvent(MouseButton button, const Math::Vector2<int>& position);
/**
* @brief Mouse wheel event
@ -169,9 +181,10 @@ class Sdl2Context: public AbstractContext {
};
/* Implementations for inline functions with unused parameters */
inline void Sdl2Context::keyPressEvent(Sdl2Context::Key, Uint8) {}
inline void Sdl2Context::keyReleaseEvent(Sdl2Context::Key) {}
inline void Sdl2Context::mouseEvent(Sdl2Context::MouseButton, Sdl2Context::MouseState, const Math::Vector2<int>&) {}
inline void Sdl2Context::keyPressEvent(Key, Uint8) {}
inline void Sdl2Context::keyReleaseEvent(Key) {}
inline void Sdl2Context::mousePressEvent(MouseButton, const Math::Vector2<int>&) {}
inline void Sdl2Context::mouseReleaseEvent(MouseButton, const Math::Vector2<int>&) {}
inline void Sdl2Context::mouseWheelEvent(const Math::Vector2<int>&) {}
inline void Sdl2Context::mouseMotionEvent(const Math::Vector2<int>&, const Math::Vector2<int>&) {}

48
src/Contexts/XEglContext.h

@ -0,0 +1,48 @@
#ifndef Magnum_Contexts_XEglContext_h
#define Magnum_Contexts_XEglContext_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::Contexts::XEglContext
*/
#include "AbstractXContext.h"
#include "EglInterface.h"
namespace Magnum { namespace Contexts {
/**
@brief X/EGL context
Uses EglInterface.
*/
class XEglContext: public AbstractXContext {
public:
/**
* @brief Constructor
* @param argc Count of arguments of `main()` function
* @param argv Arguments of `main()` function
* @param title Window title
* @param size Window size
*
* Creates window with double-buffered OpenGL ES 2 context.
*/
inline XEglContext(int& argc, char** argv, const std::string& title = "Magnum X/EGL context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600)): AbstractXContext(new EglInterface, argc, argv, title, size) {}
};
}}
#endif

2
src/CubeMapTexture.h

@ -23,7 +23,7 @@
namespace Magnum {
/** @ingroup textures
/**
@brief Cube map texture
%Texture used mainly for environemnt maps. See AbstractTexture documentation

2
src/CubeMapTextureArray.h

@ -23,7 +23,7 @@
namespace Magnum {
/** @ingroup textures
/**
@brief Cube map texture array
For information about usage, see CubeMapTexture documentation.

884
src/Framebuffer.h

File diff suppressed because it is too large Load Diff

8
src/Image.h

@ -16,7 +16,7 @@
*/
/** @file
* @brief Class Magnum::Image
* @brief Class Magnum::Image, typedef Magnum::Image1D, Magnum::Image2D, Magnum::Image3D
*/
#include "AbstractImage.h"
@ -24,10 +24,6 @@
namespace Magnum {
/** @addtogroup textures
* @{
*/
/**
@brief %Image
@ -128,8 +124,6 @@ typedef Image<2> Image2D;
/** @brief Three-dimensional image */
typedef Image<3> Image3D;
/*@}*/
}
#endif

6
src/ImageWrapper.h

@ -24,10 +24,6 @@
namespace Magnum {
/** @addtogroup textures
* @{
*/
/**
@brief %Image wrapper
@ -113,8 +109,6 @@ typedef ImageWrapper<2> ImageWrapper2D;
/** @brief Three-dimensional image wrapper */
typedef ImageWrapper<3> ImageWrapper3D;
/*@}*/
}
#endif

2
src/IndexedMesh.h

@ -24,7 +24,7 @@
namespace Magnum {
/** @ingroup rendering mesh
/**
* @brief Indexed mesh
*/
class MAGNUM_EXPORT IndexedMesh: public Mesh {

1
src/Math/CMakeLists.txt

@ -6,7 +6,6 @@ set(MagnumMath_HEADERS
Matrix.h
Matrix3.h
Matrix4.h
Swizzle.h
Vector.h
Vector2.h
Vector3.h

32
src/Math/Math.h

@ -51,14 +51,14 @@ template<class T> struct Constants {
#ifndef DOXYGEN_GENERATING_OUTPUT
template<> struct Constants<double> {
static inline constexpr double pi() { return 3.14159265359; }
static inline constexpr double sqrt2() { return 1.41421356237; }
static inline constexpr double sqrt3() { return 1.73205080757; }
static inline constexpr double pi() { return 3.141592653589793; }
static inline constexpr double sqrt2() { return 1.414213562373095; }
static inline constexpr double sqrt3() { return 1.732050807568877; }
};
template<> struct Constants<float> {
static inline constexpr float pi() { return 3.14159265359f; }
static inline constexpr float sqrt2() { return 1.41421356237f; }
static inline constexpr float sqrt3() { return 1.73205080757f; }
static inline constexpr float pi() { return 3.141592654f; }
static inline constexpr float sqrt2() { return 1.414213562f; }
static inline constexpr float sqrt3() { return 1.732050808f; }
};
namespace Implementation {
@ -105,6 +105,8 @@ float a = normalize<float>('\127');
// b = 1.0f
float b = normalize<float, char>('\127');
@endcode
@todo Signed normalization to [-1.0, 1.0] like in OpenGL?
*/
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()))/
@ -119,6 +121,8 @@ 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`).
@todo Signed normalization to [-1.0, 1.0] like in OpenGL?
*/
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() +
@ -127,17 +131,23 @@ template<class Integral, class FloatingPoint> inline constexpr typename std::ena
}
/**
* @brief Angle in degrees
*
* Function to make angle entering less error-prone. Converts the value to
* radians at compile time. For example `deg(180.0f)` is converted to `3.14f`.
@brief Angle in degrees
Function to make angle entering less error-prone. Converts the value to
radians at compile time. For example `deg(180.0f)` is converted to `3.14f`.
Usable for entering e.g. rotation:
@code
Matrix4::rotation(deg(30.0f), Vector3::yAxis());
@endcode
@see rad()
*/
template<class T> inline constexpr T deg(T value) { return value*Constants<T>::pi()/180; }
/**
* @brief Angle in radians
*
* See also deg().
* See deg() for more information.
*/
template<class T> inline constexpr T rad(T value) { return value; }

2
src/Math/MathTypeTraits.h

@ -35,7 +35,7 @@
namespace Magnum { namespace Math {
/** @ingroup utility
/**
@brief Traits class for numeric types
Traits classes are usable for detecting type features at compile time without

95
src/Math/Matrix.h

@ -30,10 +30,11 @@ namespace Implementation {
#endif
/**
* @brief %Matrix
*
* @todo @c PERFORMANCE - loop unrolling for Matrix<3, T> and Matrix<4, T>
* @todo first col, then row (cache adjacency)
@brief %Matrix
@configurationvalueref{Magnum::Math::Matrix}
@todo @c PERFORMANCE - loop unrolling for Matrix<3, T> and Matrix<4, T>
@todo first col, then row (cache adjacency)
*/
template<size_t size, class T> class Matrix {
static_assert(size != 0, "Matrix cannot have zero elements");
@ -41,6 +42,9 @@ template<size_t size, class T> class Matrix {
friend class Matrix<size+1, T>; /* for ij() */
public:
const static size_t Size = size; /**< @brief %Matrix size */
typedef T Type; /**< @brief %Matrix data type */
/**
* @brief %Matrix from array
* @return Reference to the data as if it was Matrix, thus doesn't
@ -122,7 +126,12 @@ template<size_t size, class T> class Matrix {
inline T* data() { return _data; }
inline constexpr const T* data() const { return _data; } /**< @overload */
/** @brief %Matrix column */
/**
* @brief %Matrix column
*
* For accessing individual elements prefer to use operator(), as it
* is guaranteed to not involve unnecessary conversions.
*/
inline Vector<size, T>& operator[](size_t col) {
return Vector<size, T>::from(_data+col*size);
}
@ -131,6 +140,20 @@ template<size_t size, class T> class Matrix {
return Vector<size, T>::from(_data+col*size);
}
/**
* @brief Element on given position
*
* Prefer this instead of using `[][]`.
* @see operator[]
*/
inline T& operator()(size_t col, size_t row) {
return _data[col*size+row];
}
/** @overload */
inline constexpr const T& operator()(size_t col, size_t row) const {
return _data[col*size+row];
}
/** @brief Equality operator */
inline bool operator==(const Matrix<size, T>& other) const {
for(size_t i = 0; i != size*size; ++i)
@ -240,26 +263,11 @@ template<size_t size, class T> class Matrix {
return Matrix<size, T>(first, next...);
}
#ifdef MAGNUM_GCC45_COMPATIBILITY
protected:
#endif
/* Used internally instead of [][], because GCC does some heavy
optimalization in release mode which breaks it */
inline T& operator()(size_t col, size_t row) {
return _data[col*size+row];
}
inline constexpr const T& operator()(size_t col, size_t row) const {
return _data[col*size+row];
}
#ifdef MAGNUM_GCC45_COMPATIBILITY
private:
#endif
T _data[size*size];
};
/** @debugoperator{Matrix} */
template<class T, size_t size> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix<size, T>& value) {
/** @debugoperator{Magnum::Math::Matrix} */
template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix<size, T>& value) {
debug << "Matrix(";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
for(size_t row = 0; row != size; ++row) {
@ -321,7 +329,7 @@ template<size_t size, class T> class MatrixDeterminant {
T out(0);
for(size_t col = 0; col != size; ++col)
out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant();
out += ((col & 1) ? -1 : 1)*m(col, 0)*m.ij(col, 0).determinant();
return out;
}
@ -331,7 +339,7 @@ template<class T> class MatrixDeterminant<2, T> {
public:
/** @brief Functor */
inline constexpr T operator()(const Matrix<2, T>& m) {
return m[0][0]*m[1][1] - m[1][0]*m[0][1];
return m(0, 0)*m(1, 1) - m(1, 0)*m(0, 1);
}
};
@ -339,7 +347,7 @@ template<class T> class MatrixDeterminant<1, T> {
public:
/** @brief Functor */
inline constexpr T operator()(const Matrix<1, T>& m) {
return m[0][0];
return m(0, 0);
}
};
@ -348,4 +356,41 @@ template<class T> class MatrixDeterminant<1, T> {
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Matrix} */
template<size_t size, class T> struct ConfigurationValue<Magnum::Math::Matrix<size, T>> {
/** @brief Writes elements separated with spaces */
static std::string toString(const Magnum::Math::Matrix<size, T>& value, int flags = 0) {
std::string output;
for(size_t row = 0; row != size; ++row) {
for(size_t col = 0; col != size; ++col) {
if(!output.empty()) output += ' ';
output += ConfigurationValue<T>::toString(value(col, row), flags);
}
}
return output;
}
/** @brief Reads elements separated with whitespace */
static Magnum::Math::Matrix<size, T> fromString(const std::string& stringValue, int flags = 0) {
Magnum::Math::Matrix<size, T> result(Magnum::Math::Matrix<size, T>::Zero);
std::istringstream in(stringValue);
for(size_t row = 0; row != size; ++row) {
for(size_t col = 0; col != size; ++col) {
std::string num;
in >> num;
result(col, row) = ConfigurationValue<T>::fromString(num, flags);
}
}
return result;
}
};
}}
#endif

14
src/Math/Matrix3.h

@ -29,6 +29,7 @@ namespace Magnum { namespace Math {
Provides functions for transformations in 2D. See also Matrix4 for 3D
transformations.
@configurationvalueref{Magnum::Math::Matrix3}
*/
template<class T> class Matrix3: public Matrix<3, T> {
public:
@ -36,7 +37,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @brief 2D translation matrix
* @param vec Translation vector
*
* @see Matrix4::translation()
* @see Matrix4::translation(), Vector2::xAxis(), Vector2::yAxis()
*/
inline constexpr static Matrix3<T> translation(const Vector2<T>& vec) {
return Matrix3<T>( /* Column-major! */
@ -50,7 +51,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @brief 2D scaling matrix
* @param vec Scaling vector
*
* @see Matrix4::scaling()
* @see Matrix4::scaling(), Vector2::xScale(), Vector2::yScale()
*/
inline constexpr static Matrix3<T> scaling(const Vector2<T>& vec) {
return Matrix3<T>( /* Column-major! */
@ -64,7 +65,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @brief 3D rotation matrix
* @param angle Rotation angle (counterclockwise, in radians)
*
* @see Matrix4::rotation()
* @see Matrix4::rotation(), deg(), rad()
*/
static Matrix3<T> rotation(T angle) {
return Matrix3<T>( /* Column-major! */
@ -97,11 +98,16 @@ template<class T> class Matrix3: public Matrix<3, T> {
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3)
};
/** @debugoperator{Matrix3} */
/** @debugoperator{Magnum::Math::Matrix3} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix3<T>& value) {
return debug << static_cast<const Magnum::Math::Matrix<3, T>&>(value);
}
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Matrix3} */
template<class T> struct ConfigurationValue<Magnum::Math::Matrix3<T>>: public ConfigurationValue<Magnum::Math::Matrix<3, T>> {};
}}
#endif

14
src/Math/Matrix4.h

@ -29,6 +29,7 @@ namespace Magnum { namespace Math {
Provides functions for transformations in 3D. See also Matrix3 for 2D
transformations.
@configurationvalueref{Magnum::Math::Matrix4}
@todo Shearing
@todo Reflection
*/
@ -38,7 +39,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @brief 3D translation matrix
* @param vec Translation vector
*
* @see Matrix3::translation()
* @see Matrix3::translation(), Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis()
*/
inline constexpr static Matrix4<T> translation(const Vector3<T>& vec) {
return Matrix4<T>( /* Column-major! */
@ -53,7 +54,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @brief 3D scaling matrix
* @param vec Scaling vector
*
* @see Matrix3::scaling()
* @see Matrix3::scaling(), Vector3::xScale(), Vector3::yScale(), Vector3::zScale()
*/
inline constexpr static Matrix4<T> scaling(const Vector3<T>& vec) {
return Matrix4<T>( /* Column-major! */
@ -69,7 +70,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @param angle Rotation angle (counterclockwise, in radians)
* @param vec Rotation vector
*
* @see Matrix3::rotation()
* @see Matrix3::rotation(), Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis(), deg(), rad()
* @todo optimize - Assume the vectors are normalized?
*/
static Matrix4<T> rotation(T angle, const Vector3<T>& vec) {
@ -159,11 +160,16 @@ template<class T> class Matrix4: public Matrix<4, T> {
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix4, Vector4, 4)
};
/** @debugoperator{Matrix4} */
/** @debugoperator{Magnum::Math::Matrix4} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix4<T>& value) {
return debug << static_cast<const Magnum::Math::Matrix<4, T>&>(value);
}
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Matrix4} */
template<class T> struct ConfigurationValue<Magnum::Math::Matrix4<T>>: public ConfigurationValue<Magnum::Math::Matrix<4, T>> {};
}}
#endif

2
src/Math/Test/CMakeLists.txt

@ -6,8 +6,6 @@ corrade_add_test2(MathVector2Test Vector2Test.cpp)
corrade_add_test2(MathVector3Test Vector3Test.cpp)
corrade_add_test2(MathVector4Test Vector4Test.cpp)
corrade_add_test2(MathSwizzleTest SwizzleTest.cpp)
corrade_add_test2(MathMatrixTest MatrixTest.cpp)
corrade_add_test2(MathMatrix3Test Matrix3Test.cpp)
corrade_add_test2(MathMatrix4Test Matrix4Test.cpp)

11
src/Math/Test/MathTest.cpp

@ -24,13 +24,22 @@ CORRADE_TEST_MAIN(Magnum::Math::Test::MathTest)
namespace Magnum { namespace Math { namespace Test {
MathTest::MathTest() {
addTests(&MathTest::degrad,
addTests(&MathTest::constants,
&MathTest::degrad,
&MathTest::normalize,
&MathTest::denormalize,
&MathTest::pow,
&MathTest::log);
}
void MathTest::constants() {
CORRADE_COMPARE(Math::pow<2>(Constants<float>::sqrt2()), 2.0f);
CORRADE_COMPARE(Math::pow<2>(Constants<float>::sqrt3()), 3.0f);
CORRADE_COMPARE(Math::pow<2>(Constants<double>::sqrt2()), 2.0);
CORRADE_COMPARE(Math::pow<2>(Constants<double>::sqrt3()), 3.0);
}
void MathTest::degrad() {
CORRADE_COMPARE(deg(90.0), Constants<double>::pi()/2);
CORRADE_COMPARE(deg(90.0f), Constants<float>::pi()/2);

1
src/Math/Test/MathTest.h

@ -23,6 +23,7 @@ class MathTest: public Corrade::TestSuite::Tester<MathTest> {
public:
MathTest();
void constants();
void degrad();
void normalize();
void denormalize();

14
src/Math/Test/Matrix3Test.cpp

@ -34,7 +34,8 @@ Matrix3Test::Matrix3Test() {
&Matrix3Test::translation,
&Matrix3Test::scaling,
&Matrix3Test::rotation,
&Matrix3Test::debug);
&Matrix3Test::debug,
&Matrix3Test::configuration);
}
void Matrix3Test::constructIdentity() {
@ -103,4 +104,15 @@ void Matrix3Test::debug() {
" 8, 7, 8)\n");
}
void Matrix3Test::configuration() {
Matrix3 m(
5.0f, 8.0f, 4.0f,
4.0f, 7.0f, 3.125f,
4.0f, 5.0f, 9.55f
);
string value("5 4 4 8 7 5 4 3.125 9.55");
CORRADE_COMPARE(ConfigurationValue<Matrix3>::toString(m), value);
CORRADE_COMPARE(ConfigurationValue<Matrix3>::fromString(value), m);
}
}}}

2
src/Math/Test/Matrix3Test.h

@ -28,7 +28,9 @@ class Matrix3Test: public Corrade::TestSuite::Tester<Matrix3Test> {
void translation();
void scaling();
void rotation();
void debug();
void configuration();
};
}}}

15
src/Math/Test/Matrix4Test.cpp

@ -37,7 +37,8 @@ Matrix4Test::Matrix4Test() {
&Matrix4Test::rotation,
&Matrix4Test::rotationScalingPart,
&Matrix4Test::rotationPart,
&Matrix4Test::debug);
&Matrix4Test::debug,
&Matrix4Test::configuration);
}
void Matrix4Test::constructIdentity() {
@ -144,4 +145,16 @@ void Matrix4Test::debug() {
" 4, 3, 0, 9)\n");
}
void Matrix4Test::configuration() {
Matrix4 m(
3.0f, 5.0f, 8.0f, 4.0f,
4.0f, 4.0f, 7.0f, 3.125f,
7.0f, -1.0f, 8.0f, 0.0f,
9.0f, 4.0f, 5.0f, 9.55f
);
string value("3 4 7 9 5 4 -1 4 8 7 8 5 4 3.125 0 9.55");
CORRADE_COMPARE(ConfigurationValue<Matrix4>::toString(m), value);
CORRADE_COMPARE(ConfigurationValue<Matrix4>::fromString(value), m);
}
}}}

1
src/Math/Test/Matrix4Test.h

@ -32,6 +32,7 @@ class Matrix4Test: public Corrade::TestSuite::Tester<Matrix4Test> {
void rotationPart();
void debug();
void configuration();
};
}}}

28
src/Math/Test/MatrixTest.cpp

@ -44,7 +44,8 @@ MatrixTest::MatrixTest() {
&MatrixTest::ij,
&MatrixTest::determinant,
&MatrixTest::inverted,
&MatrixTest::debug);
&MatrixTest::debug,
&MatrixTest::configuration);
}
void MatrixTest::construct() {
@ -124,9 +125,10 @@ void MatrixTest::data() {
m[3] = vector;
m[2][1] = 1.0f;
m[1][2] = 1.5f;
m(1, 2) = 1.5f;
CORRADE_COMPARE(m[2][1], 1.0f);
CORRADE_COMPARE(m(2, 1), 1.0f);
CORRADE_COMPARE(m[1][2], 1.5f);
CORRADE_COMPARE(m[3], vector);
Matrix4 expected(
@ -142,20 +144,20 @@ void MatrixTest::data() {
void MatrixTest::copy() {
Matrix4 m1(Matrix4::Zero);
m1[2][3] = 1.0f;
m1(2, 3) = 1.0f;
/* Copy */
Matrix4 m2(m1);
Matrix4 m3;
m3[0][0] = 1.0f; /* this line is here so it's not optimized to Matrix4 m3(m1) */
m3(0, 0) = 1.0f; /* this line is here so it's not optimized to Matrix4 m3(m1) */
m3 = m1;
/* Change original */
m1[3][2] = 1.0f;
m1(3, 2) = 1.0f;
/* Verify the copy is the same as original */
Matrix4 original(Matrix4::Zero);
original[2][3] = 1.0f;
original(2, 3) = 1.0f;
CORRADE_COMPARE(m2, original);
CORRADE_COMPARE(m3, original);
@ -307,4 +309,16 @@ void MatrixTest::debug() {
" 0, 0, 0, 1)\n");
}
void MatrixTest::configuration() {
Matrix4 m(
3.0f, 5.0f, 8.0f, 4.0f,
4.0f, 4.0f, 7.0f, 3.125f,
7.0f, -1.0f, 8.0f, 0.0f,
9.0f, 4.0f, 5.0f, 9.55f
);
string value("3 4 7 9 5 4 -1 4 8 7 8 5 4 3.125 0 9.55");
CORRADE_COMPARE(ConfigurationValue<Matrix4>::toString(m), value);
CORRADE_COMPARE(ConfigurationValue<Matrix4>::fromString(value), m);
}
}}}

1
src/Math/Test/MatrixTest.h

@ -38,6 +38,7 @@ class MatrixTest: public Corrade::TestSuite::Tester<MatrixTest> {
void inverted();
void debug();
void configuration();
};
}}}

22
src/Math/Test/Vector2Test.cpp

@ -30,17 +30,37 @@ typedef Math::Vector2<float> Vector2;
Vector2Test::Vector2Test() {
addTests(&Vector2Test::construct,
&Vector2Test::debug);
&Vector2Test::axes,
&Vector2Test::scales,
&Vector2Test::debug,
&Vector2Test::configuration);
}
void Vector2Test::construct() {
CORRADE_COMPARE(Vector2(1, 2), (Vector<2, float>(1.0f, 2.0f)));
}
void Vector2Test::axes() {
CORRADE_COMPARE(Vector2::xAxis(5.0f), Vector2(5.0f, 0.0f));
CORRADE_COMPARE(Vector2::yAxis(6.0f), Vector2(0.0f, 6.0f));
}
void Vector2Test::scales() {
CORRADE_COMPARE(Vector2::xScale(-5.0f), Vector2(-5.0f, 1.0f));
CORRADE_COMPARE(Vector2::yScale(-0.2f), Vector2(1.0f, -0.2f));
}
void Vector2Test::debug() {
ostringstream o;
Debug(&o) << Vector2(0.5f, 15.0f);
CORRADE_COMPARE(o.str(), "Vector(0.5, 15)\n");
}
void Vector2Test::configuration() {
Vector2 vec(3.125f, 9.0f);
string value("3.125 9");
CORRADE_COMPARE(ConfigurationValue<Vector2>::toString(vec), value);
CORRADE_COMPARE(ConfigurationValue<Vector2>::fromString(value), vec);
}
}}}

4
src/Math/Test/Vector2Test.h

@ -24,7 +24,11 @@ class Vector2Test: public Corrade::TestSuite::Tester<Vector2Test> {
Vector2Test();
void construct();
void axes();
void scales();
void debug();
void configuration();
};
}}}

21
src/Math/Test/Vector3Test.cpp

@ -32,9 +32,11 @@ typedef Math::Vector2<float> Vector2;
Vector3Test::Vector3Test() {
addTests(&Vector3Test::construct,
&Vector3Test::cross,
&Vector3Test::axis,
&Vector3Test::axes,
&Vector3Test::scales,
&Vector3Test::twoComponent,
&Vector3Test::debug);
&Vector3Test::debug,
&Vector3Test::configuration);
}
void Vector3Test::construct() {
@ -49,12 +51,18 @@ void Vector3Test::cross() {
CORRADE_COMPARE(Vector3::cross(a, b), Vector3(-10, -3, 7));
}
void Vector3Test::axis() {
void Vector3Test::axes() {
CORRADE_COMPARE(Vector3::xAxis(5.0f), Vector3(5.0f, 0.0f, 0.0f));
CORRADE_COMPARE(Vector3::yAxis(6.0f), Vector3(0.0f, 6.0f, 0.0f));
CORRADE_COMPARE(Vector3::zAxis(7.0f), Vector3(0.0f, 0.0f, 7.0f));
}
void Vector3Test::scales() {
CORRADE_COMPARE(Vector3::xScale(-5.0f), Vector3(-5.0f, 1.0f, 1.0f));
CORRADE_COMPARE(Vector3::yScale(-0.2f), Vector3(1.0f, -0.2f, 1.0f));
CORRADE_COMPARE(Vector3::zScale(71.0f), Vector3(1.0f, 1.0f, 71.0f));
}
void Vector3Test::twoComponent() {
CORRADE_COMPARE(Vector3(1.0f, 2.0f, 3.0f).xy(), Vector2(1.0f, 2.0f));
}
@ -65,4 +73,11 @@ void Vector3Test::debug() {
CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1)\n");
}
void Vector3Test::configuration() {
Vector3 vec(3.0f, 3.125f, 9.55f);
string value("3 3.125 9.55");
CORRADE_COMPARE(ConfigurationValue<Vector3>::toString(vec), value);
CORRADE_COMPARE(ConfigurationValue<Vector3>::fromString(value), vec);
}
}}}

4
src/Math/Test/Vector3Test.h

@ -25,10 +25,12 @@ class Vector3Test: public Corrade::TestSuite::Tester<Vector3Test> {
void construct();
void cross();
void axis();
void axes();
void scales();
void twoComponent();
void debug();
void configuration();
};
}}}

10
src/Math/Test/Vector4Test.cpp

@ -34,7 +34,8 @@ Vector4Test::Vector4Test() {
addTests(&Vector4Test::construct,
&Vector4Test::threeComponent,
&Vector4Test::twoComponent,
&Vector4Test::debug);
&Vector4Test::debug,
&Vector4Test::configuration);
}
void Vector4Test::construct() {
@ -57,4 +58,11 @@ void Vector4Test::debug() {
CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1, 1)\n");
}
void Vector4Test::configuration() {
Vector4 vec(3.0f, 3.125f, 9.0f, 9.55f);
string value("3 3.125 9 9.55");
CORRADE_COMPARE(ConfigurationValue<Vector4>::toString(vec), value);
CORRADE_COMPARE(ConfigurationValue<Vector4>::fromString(value), vec);
}
}}}

1
src/Math/Test/Vector4Test.h

@ -28,6 +28,7 @@ class Vector4Test: public Corrade::TestSuite::Tester<Vector4Test> {
void twoComponent();
void debug();
void configuration();
};
}}}

43
src/Math/Test/VectorTest.cpp

@ -28,15 +28,18 @@ using namespace Corrade::Utility;
namespace Magnum { namespace Math { namespace Test {
typedef Vector<4, float> Vector4;
typedef Vector<4, int> Vector4i;
typedef Vector<3, float> Vector3;
VectorTest::VectorTest() {
addTests(&VectorTest::construct,
&VectorTest::constructFrom,
&VectorTest::data,
&VectorTest::copy,
&VectorTest::dot,
&VectorTest::multiplyDivide,
&VectorTest::addSubstract,
&VectorTest::multiplyDivideComponentWise,
&VectorTest::addSubtract,
&VectorTest::dotSelf,
&VectorTest::length,
&VectorTest::normalized,
@ -46,7 +49,8 @@ VectorTest::VectorTest() {
&VectorTest::max,
&VectorTest::angle,
&VectorTest::negative,
&VectorTest::debug);
&VectorTest::debug,
&VectorTest::configuration);
}
void VectorTest::construct() {
@ -56,6 +60,15 @@ void VectorTest::construct() {
CORRADE_COMPARE(Vector4::from(data), Vector4(1.0f, 2.0f, 3.0f, 4.0f));
}
void VectorTest::constructFrom() {
Vector4 floatingPoint(1.3f, 2.7f, -15.0f, 7.0f);
Vector4 floatingPointRounded(1.0f, 2.0f, -15.0f, 7.0f);
Vector4i integral(1, 2, -15, 7);
CORRADE_COMPARE(Vector4i::from(floatingPoint), integral);
CORRADE_COMPARE(Vector4::from(integral), floatingPointRounded);
}
void VectorTest::data() {
Vector4 v;
v[2] = 1.5f;
@ -95,15 +108,32 @@ void VectorTest::multiplyDivide() {
Vector4 multiplied(-1.5f, -3.0f, -4.5f, -6.0f);
CORRADE_COMPARE(vec*-1.5f, multiplied);
CORRADE_COMPARE(-1.5f*vec, multiplied);
CORRADE_COMPARE(multiplied/-1.5f, vec);
Math::Vector<1, char> vecChar(32);
Math::Vector<1, char> multipliedChar(-48);
CORRADE_COMPARE(vecChar*-1.5f, multipliedChar);
CORRADE_COMPARE(multipliedChar/-1.5f, vecChar);
CORRADE_COMPARE(-1.5f*vecChar, multipliedChar);
/* Divide vector with number and inverse */
Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f);
Vector4 result(1.0f, 0.5f, -0.25f, 0.125f);
CORRADE_COMPARE(1.0f/divisor, result);
CORRADE_COMPARE(-1550.0f/multipliedChar, vecChar);
}
void VectorTest::multiplyDivideComponentWise() {
Vector4 vec(1.0f, 2.0f, 3.0f, 4.0f);
Vector4 multiplier(7.0f, -4.0f, -1.5f, 1.0f);
Vector4 multiplied(7.0f, -8.0f, -4.5f, 4.0f);
CORRADE_COMPARE(vec*multiplier, multiplied);
CORRADE_COMPARE(multiplied/multiplier, vec);
}
void VectorTest::addSubstract() {
void VectorTest::addSubtract() {
Vector4 a(0.5f, -7.5f, 9.0f, -11.0f);
Vector4 b(-0.5, 1.0f, 0.0f, 7.5f);
Vector4 expected(0.0f, -6.5f, 9.0f, -3.5f);
@ -165,4 +195,11 @@ void VectorTest::debug() {
CORRADE_COMPARE(o.str(), "a Vector(0, 0, 0, 0) b Vector(0, 0, 0, 0)\n");
}
void VectorTest::configuration() {
Vector4 vec(3.0f, 3.125f, 9.0f, 9.55f);
string value("3 3.125 9 9.55");
CORRADE_COMPARE(ConfigurationValue<Vector4>::toString(vec), value);
CORRADE_COMPARE(ConfigurationValue<Vector4>::fromString(value), vec);
}
}}}

5
src/Math/Test/VectorTest.h

@ -24,11 +24,13 @@ class VectorTest: public Corrade::TestSuite::Tester<VectorTest> {
VectorTest();
void construct();
void constructFrom();
void data();
void copy();
void dot();
void multiplyDivide();
void addSubstract();
void multiplyDivideComponentWise();
void addSubtract();
void dotSelf();
void length();
void normalized();
@ -40,6 +42,7 @@ class VectorTest: public Corrade::TestSuite::Tester<VectorTest> {
void negative();
void debug();
void configuration();
};
}}}

214
src/Math/Vector.h

@ -22,11 +22,14 @@
#include <cmath>
#include <limits>
#include <Utility/Debug.h>
#include <Utility/Configuration.h>
#include "MathTypeTraits.h"
namespace Magnum { namespace Math {
template<size_t size, class T> class Vector;
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<size_t ...> struct Sequence {};
@ -38,10 +41,20 @@ namespace Implementation {
template<size_t ...sequence> struct GenerateSequence<0, sequence...> {
typedef Sequence<sequence...> Type;
};
/* Implementation for Vector<size, T>::from(const Vector<size, U>&) */
template<class T, class U, size_t ...sequence> inline constexpr Math::Vector<sizeof...(sequence), T> vectorFrom(Sequence<sequence...>, const Math::Vector<sizeof...(sequence), U>& vector) {
return {T(vector[sequence])...};
}
}
#endif
/** @brief %Vector */
/**
@brief %Vector
@configurationvalueref{Magnum::Math::Vector}
@todo Constexprize all for loops
*/
template<size_t size, class T> class Vector {
static_assert(size != 0, "Vector cannot have zero elements");
@ -65,6 +78,21 @@ template<size_t size, class T> class Vector {
return *reinterpret_cast<const Vector<size, T>*>(data);
}
/**
* @brief %Vector from another of different type
*
* Performs only default casting on the values, no rounding or
* anything else. Example usage:
* @code
* Vector<4, float> floatingPoint(1.3f, 2.7f, -15.0f, 7.0f);
* Vector<4, int> integral(Vector<4, int>::from(floatingPoint));
* // integral == {1, 2, -15, 7}
* @endcode
*/
template<class U> inline constexpr static Vector<size, T> from(const Vector<size, U>& other) {
return Implementation::vectorFrom<T, U>(typename Implementation::GenerateSequence<size>::Type(), other);
}
/**
* @brief Dot product
*
@ -161,45 +189,107 @@ template<size_t size, class T> class Vector {
/**
* @brief Multiply vector
*
* Note that corresponding operator with swapped type order
* (multiplying number with vector) is not available, because it would
* cause ambiguity in some cases.
* @see operator*=(U), operator*(U, const Vector<size, T>&)
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator*(U number) const {
#else
template<class U> inline Vector<size, T> operator*(U number) const {
#endif
return Vector<size, T>(*this)*=number;
}
/**
* @brief Multiply and assign vector
* @brief Multiply vector and assign
*
* More efficient than operator*(), because it does the computation
* in-place.
* More efficient than operator*(U) const, because it does the
* computation in-place.
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>&>::type operator*=(U number) {
#else
template<class U> Vector<size, T>& operator*=(U number) {
#endif
for(size_t i = 0; i != size; ++i)
(*this)[i] *= number;
return *this;
}
/** @brief Divide vector */
/**
* @brief Multiply vector component-wise
*
* @see operator*=(const Vector<size, T>&)
*/
Vector<size, T> operator*(const Vector<size, T>& other) const {
return Vector<size, T>(*this)*=other;
}
/**
* @brief Multiply vector component-wise and assign
*
* More efficient than operator*(const Vector<size, T>&) const,
* because it does the computation in-place.
*/
Vector<size, T>& operator*=(const Vector<size, T>& other) {
for(size_t i = 0; i != size; ++i)
(*this)[i] *= other[i];
return *this;
}
/**
* @brief Divide vector
*
* @see operator/=(U), operator/(U, const Vector<size, T>&)
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator/(U number) const {
#else
template<class U> inline Vector<size, T> operator/(U number) const {
#endif
return Vector<size, T>(*this)/=number;
}
/**
* @brief Divide and assign vector
* @brief Divide vector and assign
*
* More efficient than operator/(), because it does the computation
* in-place.
* More efficient than operator/(U) const, because it does the
* computation in-place.
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>&>::type operator/=(U number) {
#else
template<class U> Vector<size, T>& operator/=(U number) {
#endif
for(size_t i = 0; i != size; ++i)
(*this)[i] /= number;
return *this;
}
/**
* @brief Divide vector component-wise
*
* @see operator/=(const Vector<size, T>&)
*/
Vector<size, T> operator/(const Vector<size, T>& other) const {
return Vector<size, T>(*this)/=other;
}
/**
* @brief Divide vector component-wise and assign
*
* More efficient than operator/(const Vector<size, T>&) const,
* because it does the computation in-place.
*/
Vector<size, T>& operator/=(const Vector<size, T>& other) {
for(size_t i = 0; i != size; ++i)
(*this)[i] /= other[i];
return *this;
}
/** @brief Add two vectors */
inline Vector<size, T> operator+(const Vector<size, T>& other) const {
return Vector<size, T>(*this)+=other;
@ -218,13 +308,13 @@ template<size_t size, class T> class Vector {
return *this;
}
/** @brief Substract two vectors */
/** @brief Subtract two vectors */
inline Vector<size, T> operator-(const Vector<size, T>& other) const {
return Vector<size, T>(*this)-=other;
}
/**
* @brief Substract and assign vector
* @brief Subtract and assign vector
*
* More efficient than operator-(), because it does the computation
* in-place.
@ -318,8 +408,44 @@ template<size_t size, class T> class Vector {
T _data[size];
};
/** @debugoperator{Vector} */
template<class T, size_t size> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Vector<size, T>& value) {
/** @relates Vector
@brief Multiply number with vector
@see Vector::operator*(U) const
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator*(U number, const Vector<size, T>& vector) {
#else
template<size_t size, class T, class U> inline Vector<size, T> operator*(U number, const Vector<size, T>& vector) {
#endif
return vector*number;
}
/** @relates Vector
@brief Divide vector with number and invert
Example:
@code
Vector<4, float> vec(1.0f, 2.0f, -4.0f, 8.0f);
Vector<4, float> another = 1.0f/vec; // {1.0f, 0.5f, -0.25f, 0.128f}
@endcode
@see Vector::operator/(U) const
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<size_t size, class T, class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator/(U number, const Vector<size, T>& vector) {
#else
template<size_t size, class T, class U> Vector<size, T> operator/(U number, const Vector<size, T>& vector) {
#endif
Vector<size, T> out;
for(size_t i = 0; i != size; ++i)
out[i] = number/vector[i];
return out;
}
/** @debugoperator{Magnum::Math::Vector} */
template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Vector<size, T>& value) {
debug << "Vector(";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
for(size_t i = 0; i != size; ++i) {
@ -338,6 +464,9 @@ template<class T, size_t size> Corrade::Utility::Debug operator<<(Corrade::Utili
} \
inline constexpr static const Type<T>& from(const T* data) { \
return *reinterpret_cast<const Type<T>*>(data); \
} \
template<class U> inline constexpr static Type<T> from(const Vector<size, U>& other) { \
return Vector<size, T>::from(other); \
} \
\
inline Type<T>& operator=(const Type<T>& other) { \
@ -352,12 +481,26 @@ template<class T, size_t size> Corrade::Utility::Debug operator<<(Corrade::Utili
Vector<size, T>::operator*=(number); \
return *this; \
} \
inline Type<T> operator*(const Vector<size, T>& other) const { \
return Vector<size, T>::operator*(other); \
} \
inline Type<T>& operator*=(const Vector<size, T>& other) { \
Vector<size, T>::operator*=(other); \
return *this; \
} \
template<class U> inline Type<T> operator/(U number) const { \
return Vector<size, T>::operator/(number); \
} \
template<class U> inline Type<T>& operator/=(U number) { \
Vector<size, T>::operator/=(number); \
return *this; \
} \
inline Type<T> operator/(const Vector<size, T>& other) const { \
return Vector<size, T>::operator/(other); \
} \
inline Type<T>& operator/=(const Vector<size, T>& other) { \
Vector<size, T>::operator/=(other); \
return *this; \
} \
\
inline Type<T> operator+(const Vector<size, T>& other) const { \
@ -377,8 +520,49 @@ template<class T, size_t size> Corrade::Utility::Debug operator<<(Corrade::Utili
\
inline Type<T> operator-() const { return Vector<size, T>::operator-(); } \
inline Type<T> normalized() const { return Vector<size, T>::normalized(); }
#define MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \
template<class T, class U> inline Type<T> operator*(U number, const Type<T>& vector) { \
return number*Vector<size, T>(vector); \
} \
template<class T, class U> inline Type<T> operator/(U number, const Type<T>& vector) { \
return number/Vector<size, T>(vector); \
}
#endif
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Vector} */
template<size_t size, class T> struct ConfigurationValue<Magnum::Math::Vector<size, T>> {
/** @brief Writes elements separated with spaces */
static std::string toString(const Magnum::Math::Vector<size, T>& value, int flags = 0) {
std::string output;
for(size_t pos = 0; pos != size; ++pos) {
if(!output.empty()) output += ' ';
output += ConfigurationValue<T>::toString(value[pos], flags);
}
return output;
}
/** @brief Reads elements separated with whitespace */
static Magnum::Math::Vector<size, T> fromString(const std::string& stringValue, int flags = 0) {
Magnum::Math::Vector<size, T> result;
std::istringstream in(stringValue);
std::string num;
for(size_t pos = 0; pos != size; ++pos) {
in >> num;
result[pos] = ConfigurationValue<T>::fromString(num, flags);
}
return result;
}
};
}}
#endif

53
src/Math/Vector2.h

@ -23,9 +23,51 @@
namespace Magnum { namespace Math {
/** @brief Two-component vector */
/**
@brief Two-component vector
@configurationvalueref{Magnum::Math::Vector2}
*/
template<class T> class Vector2: public Vector<2, T> {
public:
/**
* @brief %Vector in direction of X axis
*
* Usable for translation in given axis, for example:
* @code
* Matrix3::translation(Vector2::xAxis(5.0f)); // same as Matrix3::translation({5.0f, 0.0f});
* @endcode
* @see yAxis(), xScale()
*/
inline constexpr static Vector2<T> xAxis(T length = T(1)) { return Vector2<T>(length, T()); }
/**
* @brief %Vector in direction of Y axis
*
* See xAxis() for more information.
* @see yScale()
*/
inline constexpr static Vector2<T> yAxis(T length = T(1)) { return Vector2<T>(T(), length); }
/**
* @brief Scaling vector in direction of X axis
*
* Usable for scaling along given direction, for example:
* @code
* Matrix3::scaling(Vector2::xScale(-2.0f)); // same as Matrix3::scaling({-2.0f, 1.0f});
* @endcode
* @see yScale(), xAxis()
*/
inline constexpr static Vector2<T> xScale(T scale) { return Vector2<T>(scale, T(1)); }
/**
* @brief Scaling vector in direction of Y axis
*
* See xScale() for more information.
* @see yAxis()
*/
inline constexpr static Vector2<T> yScale(T scale) { return Vector2<T>(T(1), scale); }
/** @copydoc Vector::Vector(T) */
inline constexpr explicit Vector2(T value = T()): Vector<2, T>(value, value) {}
@ -48,11 +90,18 @@ template<class T> class Vector2: public Vector<2, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector2, 2)
};
/** @debugoperator{Vector2} */
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector2, 2)
/** @debugoperator{Magnum::Math::Vector2} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Vector2<T>& value) {
return debug << static_cast<const Magnum::Math::Vector<2, T>&>(value);
}
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Vector2} */
template<class T> struct ConfigurationValue<Magnum::Math::Vector2<T>>: public ConfigurationValue<Magnum::Math::Vector<2, T>> {};
}}
#endif

67
src/Math/Vector3.h

@ -23,18 +23,68 @@
namespace Magnum { namespace Math {
/** @brief Three-component vector */
/**
@brief Three-component vector
@configurationvalueref{Magnum::Math::Vector3}
*/
template<class T> class Vector3: public Vector<3, T> {
public:
/** @brief %Vector in direction of X axis */
/**
* @brief %Vector in direction of X axis
*
* Usable for translation or rotation along given axis, for example:
* @code
* Matrix4::translation(Vector3::xAxis(5.0f)); // same as Matrix4::translation({5.0f, 0.0f, 0.0f});
* Matrix4::rotation(deg(30.0f), Vector3::xAxis()); // same as Matrix::rotation(deg(30.0f), {1.0f, 0.0f, 0.0f});
* @endcode
* @see yAxis(), zAxis(), xScale()
*/
inline constexpr static Vector3<T> xAxis(T length = T(1)) { return Vector3<T>(length, T(), T()); }
/** @brief %Vector in direction of Y axis */
/**
* @brief %Vector in direction of Y axis
*
* See xAxis() for more information.
* @see yScale()
*/
inline constexpr static Vector3<T> yAxis(T length = T(1)) { return Vector3<T>(T(), length, T()); }
/** @brief %Vector in direction of Z axis */
/**
* @brief %Vector in direction of Z axis
*
* See xAxis() for more information.
* @see zScale()
*/
inline constexpr static Vector3<T> zAxis(T length = T(1)) { return Vector3<T>(T(), T(), length); }
/**
* @brief Scaling vector in direction of X axis
*
* Usable for scaling along given direction, for example:
* @code
* Matrix4::scaling(Vector3::xScale(-2.0f)); // same as Matrix4::scaling({-2.0f, 1.0f, 1.0f});
* @endcode
* @see yScale(), zScale(), xAxis()
*/
inline constexpr static Vector3<T> xScale(T scale) { return Vector3<T>(scale, T(1), T(1)); }
/**
* @brief Scaling vector in direction of Y axis
*
* See xScale() for more information.
* @see yAxis()
*/
inline constexpr static Vector3<T> yScale(T scale) { return Vector3<T>(T(1), scale, T(1)); }
/**
* @brief Scaling vector in direction of Z axis
*
* See xScale() for more information.
* @see zAxis()
*/
inline constexpr static Vector3<T> zScale(T scale) { return Vector3<T>(T(1), T(1), scale); }
/**
* @brief Cross product
*
@ -92,11 +142,18 @@ template<class T> class Vector3: public Vector<3, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3)
};
/** @debugoperator{Vector3} */
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector3, 3)
/** @debugoperator{Magnum::Math::Vector3} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Vector3<T>& value) {
return debug << static_cast<const Magnum::Math::Vector<3, T>&>(value);
}
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Vector3} */
template<class T> struct ConfigurationValue<Magnum::Math::Vector3<T>>: public ConfigurationValue<Magnum::Math::Vector<3, T>> {};
}}
#endif

15
src/Math/Vector4.h

@ -23,7 +23,11 @@
namespace Magnum { namespace Math {
/** @brief Four-component vector */
/**
@brief Four-component vector
@configurationvalueref{Magnum::Math::Vector4}
*/
template<class T> class Vector4: public Vector<4, T> {
public:
/**
@ -86,11 +90,18 @@ template<class T> class Vector4: public Vector<4, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4)
};
/** @debugoperator{Vector4} */
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector4, 4)
/** @debugoperator{Magnum::Math::Vector4} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Vector4<T>& value) {
return debug << static_cast<const Magnum::Math::Vector<4, T>&>(value);
}
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Vector4} */
template<class T> struct ConfigurationValue<Magnum::Math::Vector4<T>>: public ConfigurationValue<Magnum::Math::Vector<4, T>> {};
}}
#endif

32
src/Mesh.cpp

@ -20,7 +20,18 @@ using namespace std;
namespace Magnum {
Mesh::~Mesh() {
Mesh::Mesh(Mesh&& other):
#ifndef MAGNUM_TARGET_GLES
vao(other.vao),
#endif
_primitive(other._primitive), _vertexCount(other._vertexCount), finalized(other.finalized), _buffers(other._buffers), _attributes(other._attributes)
{
#ifndef MAGNUM_TARGET_GLES
other.vao = 0;
#endif
}
void Mesh::destroy() {
for(auto it = _buffers.begin(); it != _buffers.end(); ++it)
delete it->first;
@ -29,6 +40,25 @@ Mesh::~Mesh() {
#endif
}
Mesh& Mesh::operator=(Mesh&& other) {
destroy();
#ifndef MAGNUM_TARGET_GLES
vao = other.vao;
#endif
_primitive = other._primitive;
_vertexCount = other._vertexCount;
finalized = other.finalized;
_buffers = other._buffers;
_attributes = other._attributes;
#ifndef MAGNUM_TARGET_GLES
other.vao = 0;
#endif
return *this;
}
Buffer* Mesh::addBuffer(BufferType interleaved) {
Buffer* buffer = new Buffer(Buffer::Target::Array);
_buffers.insert(make_pair(buffer, make_pair(interleaved, vector<Attribute>())));

14
src/Mesh.h

@ -30,7 +30,7 @@ namespace Magnum {
class Buffer;
/** @ingroup rendering mesh
/**
@brief Base class for managing non-indexed meshes
VAOs are used for desktop OpenGL (not in OpenGL ES).
@ -48,9 +48,7 @@ VAOs are used for desktop OpenGL (not in OpenGL ES).
*/
class MAGNUM_EXPORT Mesh {
Mesh(const Mesh& other) = delete;
Mesh(Mesh&& other) = delete;
Mesh& operator=(const Mesh& other) = delete;
Mesh& operator=(Mesh&& other) = delete;
public:
#ifndef MAGNUM_TARGET_GLES
@ -208,12 +206,18 @@ class MAGNUM_EXPORT Mesh {
#endif
}
/** @brief Move constructor */
Mesh(Mesh&& other);
/**
* @brief Destructor
*
* Deletes all associated buffers.
*/
virtual ~Mesh();
inline virtual ~Mesh() { destroy(); }
/** @brief Move assignment */
Mesh& operator=(Mesh&& other);
/**
* @brief Whether the mesh is finalized
@ -340,6 +344,8 @@ class MAGNUM_EXPORT Mesh {
std::set<GLuint> _attributes;
MAGNUM_EXPORT void bindAttribute(Buffer* buffer, GLuint attribute, GLint size, Type type);
void destroy();
};
}

2
src/MeshTools/Clean.h

@ -121,7 +121,7 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean {
}
#endif
/** @ingroup mesh
/**
@brief %Clean the mesh
@tparam Vertex Vertex data type
@tparam vertexSize How many initial vertex fields are important (for

2
src/MeshTools/CombineIndexedArrays.h

@ -89,7 +89,7 @@ class CombineIndexedArrays {
}
#endif
/** @ingroup mesh
/**
@brief Combine indexed arrays
@param[in,out] indexedArrays Index and attribute arrays
@return Array with resulting indices

6
src/MeshTools/CompressIndices.h

@ -78,10 +78,6 @@ class CompressIndices {
}
#endif
/** @addtogroup mesh
* @{
*/
/**
@brief Compress vertex indices
@param indices Index array
@ -124,8 +120,6 @@ inline void compressIndices(IndexedMesh* mesh, Buffer::Usage usage, const std::v
return Implementation::CompressIndices{indices}(mesh, usage);
}
/*@}*/
}}
#endif

6
src/MeshTools/FlipNormals.h

@ -24,10 +24,6 @@
namespace Magnum { namespace MeshTools {
/** @addtogroup mesh
* @{
*/
/**
@brief Flip face winding
@ -61,8 +57,6 @@ inline void flipNormals(std::vector<unsigned int>& indices, std::vector<Vector3>
flipNormals(normals);
}
/*@}*/
}}
#endif

2
src/MeshTools/GenerateFlatNormals.h

@ -26,7 +26,7 @@
namespace Magnum { namespace MeshTools {
/** @ingroup mesh
/**
@brief Generate flat normals
@param indices Array of triangle face indexes
@param vertices Vertex array

6
src/MeshTools/Interleave.h

@ -96,10 +96,6 @@ class Interleave {
}
#endif
/** @addtogroup mesh
* @{
*/
/**
@brief %Interleave vertex attributes
@param attribute First attribute array
@ -157,8 +153,6 @@ template<class ...T> inline void interleave(Mesh* mesh, Buffer* buffer, Buffer::
return Implementation::Interleave()(mesh, buffer, usage, attributes...);
}
/*@}*/
}}
#endif

2
src/MeshTools/Subdivide.h

@ -84,7 +84,7 @@ template<class Vertex, class Interpolator> class Subdivide {
}
#endif
/** @ingroup mesh
/**
@brief %Subdivide the mesh
@tparam Vertex Vertex data type
@tparam Interpolator See `interpolator` function parameter

2
src/MeshTools/Tipsify.h

@ -51,7 +51,7 @@ class MESHTOOLS_EXPORT Tipsify {
}
#endif
/** @ingroup mesh
/**
@brief %Tipsify the mesh
@param[in,out] indices Indices array to operate on
@param[in] vertexCount Vertex count

152
src/Object.cpp

@ -1,152 +0,0 @@
/*
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 "Object.h"
#include <stack>
#include "Scene.h"
#include "Camera.h"
using namespace std;
namespace Magnum {
Object* Object::setParent(Object* parent) {
/* Skip if nothing to do or this is scene */
if(_parent == parent || _parent == this) return this;
/* Add the object to children list of new parent */
if(parent != nullptr) {
/* Only Fry can be his own grandfather */
Object* p = parent;
while(p != nullptr && p->parent() != p) {
if(p == this) return this;
p = p->parent();
}
parent->_children.insert(this);
}
/* Remove the object from old parent children list */
if(_parent != nullptr)
_parent->_children.erase(this);
/* Set new parent */
_parent = parent;
setDirty();
return this;
}
Matrix4 Object::absoluteTransformation(Camera* camera) {
/* Shortcut for absolute transformation of camera relative to itself */
if(camera == this) return Matrix4();
Matrix4 t = _transformation;
Object* p = parent();
while(p != nullptr) {
t = p->transformation()*t;
/* 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);
t = camera->cameraMatrix()*t;
}
break;
}
p = p->parent();
}
CORRADE_ASSERT(p != nullptr || camera == nullptr, "Object::absoluteTransformation(): the object is not part of camera scene!", t);
return t;
}
Object::~Object() {
/* Remove the object from parent's children */
setParent(nullptr);
/* Delete all children */
while(!_children.empty())
delete *_children.begin();
}
Scene* Object::scene() {
/* Goes up the family tree until it finds object which is parent of itself
(that's the scene) */
Object* p = parent();
while(p != nullptr) {
if(p->parent() == p) return static_cast<Scene*>(p);
p = p->parent();
}
return nullptr;
}
Object* Object::setTransformation(const Matrix4& transformation) {
if(_parent == this) return this;
_transformation = transformation;
setDirty();
return this;
}
void Object::setDirty() {
/* The object (and all its children) are already dirty, nothing to do */
if(dirty) return;
dirty = true;
/* Make all children dirty */
for(set<Object*>::iterator it = _children.begin(); it != _children.end(); ++it)
(*it)->setDirty();
}
void Object::setClean() {
/* The object (and all its parents) are already clean, nothing to do */
if(!dirty) return;
/* Collect all parents */
stack<Object*> objects;
Object* p = this;
for(;;) {
objects.push(p);
/* Stop on root object / scene / clean object */
if(p->parent() == nullptr || p->parent() == p || !p->parent()->isDirty())
break;
p = p->parent();
}
/* Call setClean(const Matrix4&) for every parent and also this object */
Object* o = objects.top();
objects.pop();
Matrix4 absoluteTransformation = o->absoluteTransformation();
o->clean(absoluteTransformation);
while(!objects.empty()) {
o = objects.top();
objects.pop();
absoluteTransformation = absoluteTransformation*o->transformation();
o->clean(absoluteTransformation);
}
}
}

274
src/Object.h

@ -1,274 +0,0 @@
#ifndef Magnum_Object_h
#define Magnum_Object_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::Object
*/
#include <set>
#include "Magnum.h"
namespace Magnum {
class Scene;
class Camera;
/**
@todo User-specified Object implementation:
- for front-to-back sorting, LoD changes etc.
- for different parent/children implementation (e.g. no std::set, direct
access to scene etc.)
- for using doubles/halves instead of floats
- for using quat + position instead of matrices (where (asymmetric) scaling is
not needed)
*/
/** @ingroup scene
* @brief Base for all positioned objects
*
* @todo Transform transformation when changing parent, so the object stays in
* place.
*/
class MAGNUM_EXPORT Object {
Object(const Object& other) = delete;
Object(Object&& other) = delete;
Object& operator=(const Object& other) = delete;
Object& operator=(Object&& other) = delete;
friend class Scene;
public:
/**
* @brief Constructor
* @param parent Parent object
*
* Sets all transformations to their default values.
*/
inline Object(Object* parent = nullptr): _parent(nullptr), dirty(true) {
setParent(parent);
}
/**
* @brief Destructor
*
* Removes itself from parent's children list and destroys all own
* children.
*/
virtual ~Object();
/** @{ @name Scene hierarchy */
/**
* @brief %Scene
* @return If the object is not assigned to any scene, returns nullptr.
*/
Scene* scene();
/** @brief Parent object */
inline Object* parent() { return _parent; }
/** @brief Child objects */
inline const std::set<Object*>& children() { return _children; }
/** @brief Set parent object */
Object* setParent(Object* parent);
/*@}*/
/** @{ @name Object transformation
*
* All transformations (except absoluteTransformation()) are relative
* to parent.
*/
/** @brief Transformation type */
enum class Transformation: char {
/** Global transformation, applied after all other transformations. */
Global = 0x00,
/** Local transformation, applied before all other transformations. */
Local = 0x01
};
/** @brief Transformation */
inline Matrix4 transformation() const {
return _transformation;
}
/**
* @brief Absolute transformation
*
* Returns absolute transformation matrix relative to the camera or
* root object, if no camera is specified. If the camera is specified,
* it should be part of the same scene as object.
*
* Note that the absolute transformation is computed from all parent
* objects every time it is asked, unless this function is
* reimplemented in a different way.
*/
virtual Matrix4 absoluteTransformation(Camera* camera = nullptr);
/** @brief Set transformation */
Object* setTransformation(const Matrix4& transformation);
/**
* @brief Multiply transformation
* @param transformation Transformation
* @param type Transformation type
*/
inline Object* multiplyTransformation(const Matrix4& transformation, Transformation type = Transformation::Global) {
setTransformation(type == Transformation::Global ?
transformation*_transformation : _transformation*transformation);
return this;
}
/**
* @brief Translate object
*
* Same as calling multiplyTransformation() with Matrix4::translation().
*/
inline Object* translate(Vector3 vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::translation(vec), type);
return this;
}
/**
* @brief Scale object
*
* Same as calling multiplyTransformation() with Matrix4::scaling().
*/
inline Object* scale(Vector3 vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::scaling(vec), type);
return this;
}
/**
* @brief Rotate object
*
* Same as calling multiplyTransformation() with Matrix4::rotation().
*/
inline Object* rotate(GLfloat angle, Vector3 vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::rotation(angle, vec), type);
return this;
}
/*@}*/
/**
* @brief Draw object
* @param transformationMatrix %Matrix specifying object
* transformation relative to the scene.
* @param camera Active camera (containing
* projection matrix)
*
* Default implementation does nothing.
*/
virtual void draw(const Matrix4& transformationMatrix, Camera* camera);
/** @{ @name Caching helpers
*
* If the object (absolute) transformation or anything depending on it
* is used many times when drawing (such as e.g. position of light
* object), it's good to cache these values, so they don't have to be
* recalculated again on every request.
*
* If setDirty() is called on an object (or the object is transformed),
* it and all its children are marked as dirty. If any object is
* already dirty, it and all its children are skipped, because they
* are already dirty too.
*
* If setClean() is called on an object, it and all its parents are
* cleaned. If any object is already clean, it and all its parents are
* skipped, because they are already clean too.
*
* These functions are used to manage dirty status of the object. If
* the object doesn't cache anything, it's no need to bother about
* them, but if does, clean() should be reimplemented and used to
* regenerate the cache.
*/
/**
* @brief Whether the object is dirty
* @return True, if transformation of the object, any parent or camera
* has changed since last asking, false otherwise.
*/
inline bool isDirty() const { return dirty; }
/**
* @brief Set object and all its children as dirty
*
* Recursively calls setDirty() on every child. If the object is
* already marked as dirty, the function does nothing. It is usually
* not needed to reimplement this function, only if you for example
* need to reset some state on object which is not child of this. All
* computations should be done in setClean().
*
* Reimplementations should call this function at the end, i.e.:
* @code
* void setDirty() {
* // ...
*
* Object::setDirty();
* }
* @endcode
*/
virtual void setDirty();
/**
* @brief Set object and all its parents as clean
*
* Recursively calls clean() on every parent which is not already
* clean.
*/
void setClean();
protected:
/**
* @brief Clean the object
*
* When reimplementing, use absolute transformation passed as
* parameter instead of absoluteTransformation(), which is not
* efficient. The reimplementation should call this function at the
* beginning, i.e.:
* @code
* void clean(const Matrix4& absoluteTransformation) {
* Object::clean(absoluteTransformation);
*
* // ...
* }
* @endcode
*/
virtual void clean(const Matrix4& absoluteTransformation);
/*@}*/
private:
Object* _parent;
std::set<Object*> _children;
Matrix4 _transformation;
bool dirty;
};
/* Implementations for inline functions with unused parameters */
inline void Object::draw(const Matrix4&, Camera*) {}
inline void Object::clean(const Matrix4&) { dirty = false; }
}
#endif

2
src/Physics/ShapeGroup.h

@ -31,7 +31,7 @@ namespace Magnum { namespace Physics {
/**
@brief Collider group with defined set operation
Result of union, intersection, substraction or XOR of two collider objects.
Result of union, intersection, subtraction or XOR of two collider objects.
See @ref collision-detection for brief introduction.
*/
class PHYSICS_EXPORT ShapeGroup: public AbstractShape {

2
src/Primitives/Capsule.h

@ -23,7 +23,7 @@
namespace Magnum { namespace Primitives {
/** @ingroup mesh
/**
@brief %Capsule primitive
Cylinder along Y axis with hemispheres instead of caps.

4
src/Primitives/Cube.h

@ -23,9 +23,7 @@
namespace Magnum { namespace Primitives {
/** @ingroup mesh
@brief %Cube primitive
*/
/** @brief %Cube primitive */
class Cube: public Trade::MeshData {
public:
/** @brief Constructor */

4
src/Primitives/Icosphere.h

@ -27,7 +27,7 @@ namespace Magnum { namespace Primitives {
template<size_t subdivisions> class Icosphere;
/** @ingroup mesh
/**
@brief %Icosphere primitive with zero subdivisions
@todo Use own computed (and more precise) icosahedron data, not these stolen
@ -39,7 +39,7 @@ template<> class Icosphere<0>: public Trade::MeshData {
Icosphere();
};
/** @ingroup mesh
/**
* @brief %Icosphere primitive
* @tparam subdivisions Number of subdivisions
*/

2
src/Primitives/Plane.h

@ -23,7 +23,7 @@
namespace Magnum { namespace Primitives {
/** @ingroup mesh
/**
@brief %Plane primitive
2x2 plane with normals in positive Z direction.

4
src/Primitives/UVSphere.h

@ -23,9 +23,7 @@
namespace Magnum { namespace Primitives {
/** @ingroup mesh
@brief UV Sphere primitive
*/
/** @brief UV Sphere primitive */
class UVSphere: public Capsule {
public:
/**

5
src/Query.h

@ -24,10 +24,6 @@
namespace Magnum {
#ifndef MAGNUM_TARGET_GLES
/** @addtogroup rendering
* @{
*/
/**
@brief Base class for queries
@ -301,7 +297,6 @@ class TimeQuery: public AbstractQuery {
}
};
/*@}*/
#endif
}

2
src/Renderbuffer.h

@ -23,7 +23,7 @@
namespace Magnum {
/** @ingroup textures
/**
@brief %Renderbuffer
Attachable to Framebuffer as render target.

47
src/Scene.h

@ -1,47 +0,0 @@
#ifndef Magnum_Scene_h
#define Magnum_Scene_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::Scene
*/
#include "Object.h"
namespace Magnum {
/** @ingroup scene
@brief %Scene
*/
class MAGNUM_EXPORT Scene: public Object {
public:
/** @brief Constructor */
inline Scene() { _parent = this; }
void setParent(Object* parent) = delete;
void setTransformation(const Matrix4& transformation) = delete;
void multiplyTransformation(const Matrix4& transformation, Transformation type = Transformation::Global) = delete;
void translate(Vector3 vec, Transformation type = Transformation::Global) = delete;
void scale(Vector3 vec, Transformation type = Transformation::Global) = delete;
void rotate(GLfloat angle, Vector3 vec, Transformation type = Transformation::Global) = delete;
private:
inline void draw(const Magnum::Matrix4&, Camera*) {}
};
}
#endif

42
src/SceneGraph/CMakeLists.txt

@ -0,0 +1,42 @@
# Files shared between main library and unit test library
set(MagnumSceneGraph_SRCS
Camera.cpp
Light.cpp)
set(MagnumSceneGraph_HEADERS
Camera.h
Light.h
Object.h
Scene.h
magnumSceneGraphVisibility.h)
add_library(MagnumSceneGraphObjects OBJECT ${MagnumSceneGraph_SRCS})
# Files compiled with different flags for main library and unit test library
set(MagnumSceneGraph_GracefulAssert_SRCS
Object.cpp)
# Set shared library flags for the objects, as they will be part of shared lib
# TODO: fix when CMake sets target_EXPORTS for OBJECT targets as well
set_target_properties(MagnumSceneGraphObjects PROPERTIES COMPILE_FLAGS "-DMagnumSceneGraphObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
# SceneGraph library
add_library(MagnumSceneGraph SHARED
$<TARGET_OBJECTS:MagnumSceneGraphObjects>
${MagnumSceneGraph_GracefulAssert_SRCS})
target_link_libraries(MagnumSceneGraph Magnum)
install(TARGETS MagnumSceneGraph DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
install(FILES ${MagnumSceneGraph_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/SceneGraph)
if(BUILD_TESTS)
enable_testing()
# Library with graceful assert for testing
add_library(MagnumSceneGraphTestLib SHARED
$<TARGET_OBJECTS:MagnumSceneGraphObjects>
${MagnumSceneGraph_GracefulAssert_SRCS})
set_target_properties(MagnumSceneGraphTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
target_link_libraries(MagnumSceneGraphTestLib Magnum)
add_subdirectory(Test)
endif()

130
src/SceneGraph/Camera.cpp

@ -0,0 +1,130 @@
/*
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 "Camera.h"
#include "Framebuffer.h"
#include "Scene.h"
using namespace std;
namespace Magnum { namespace SceneGraph {
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<class MatrixType> MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Vector2& projectionScale, const Math::Vector2<GLsizei>& viewport) {
/* Don't divide by zero / don't preserve anything */
if(projectionScale.x() == 0 || projectionScale.y() == 0 || viewport.x() == 0 || viewport.y() == 0 || aspectRatioPolicy == AspectRatioPolicy::NotPreserved)
return MatrixType();
Vector2 relativeAspectRatio = Vector2::from(viewport)*projectionScale;
/* Extend on larger side = scale larger side down
Clip on smaller side = scale smaller side up */
return Camera<MatrixType::Size-1>::aspectRatioScale(
(relativeAspectRatio.x() > relativeAspectRatio.y()) == (aspectRatioPolicy == AspectRatioPolicy::Extend) ?
Vector2(relativeAspectRatio.y()/relativeAspectRatio.x(), 1.0f) :
Vector2(1.0f, relativeAspectRatio.x()/relativeAspectRatio.y()));
}
/* Explicitly instantiate the templates */
template Matrix3 aspectRatioFix<Matrix3>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&);
template Matrix4 aspectRatioFix<Matrix4>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&);
}
#endif
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::Camera(ObjectType* parent): ObjectType(parent), _aspectRatioPolicy(AspectRatioPolicy::NotPreserved) {}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setViewport(const Math::Vector2<GLsizei>& size) {
Framebuffer::setViewport({0, 0}, size);
_viewport = size;
fixAspectRatio();
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::clean(const MatrixType& absoluteTransformation) {
ObjectType::clean(absoluteTransformation);
_cameraMatrix = absoluteTransformation.inverted();
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::draw() {
SceneType* s = this->scene();
CORRADE_ASSERT(s, "Camera: cannot draw without camera attached to scene", );
Framebuffer::clear();
/* Recursively draw child objects */
drawChildren(s, cameraMatrix());
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::drawChildren(ObjectType* object, const MatrixType& transformationMatrix) {
for(ObjectType* i = object->firstChild(); i; i = i->nextSibling()) {
/* Transformation matrix for the object */
MatrixType matrix = transformationMatrix*i->transformation();
/* Draw the object and its children */
i->draw(matrix, static_cast<CameraType*>(this));
drawChildren(i, matrix);
}
}
void Camera2D::setProjection(const Vector2& size) {
/* Scale the volume down so it fits in (-1, 1) in all directions */
rawProjectionMatrix = Matrix3::scaling(2.0f/size);
fixAspectRatio();
}
void Camera3D::setOrthographic(const Vector2& size, GLfloat near, GLfloat far) {
_near = near;
_far = far;
Vector2 xyScale = 2.0f/size;
GLfloat zScale = 2.0f/(near-far);
rawProjectionMatrix = Matrix4(
xyScale.x(), 0.0f, 0.0f, 0.0f,
0.0f, xyScale.y(), 0.0f, 0.0f,
0.0f, 0.0f, zScale, 0.0f,
0.0f, 0.0f, near*zScale-1, 1.0f
);
fixAspectRatio();
}
void Camera3D::setPerspective(GLfloat fov, GLfloat near, GLfloat far) {
_near = near;
_far = far;
GLfloat xyScale = 1.0f/tan(fov/2); /* == near/size */
GLfloat zScale = 1.0f/(near-far);
rawProjectionMatrix = Matrix4(
xyScale, 0.0f, 0.0f, 0.0f,
0.0f, xyScale, 0.0f, 0.0f,
0.0f, 0.0f, (far+near)*zScale, -1.0f,
0.0f, 0.0f, (2*far*near)*zScale, 0.0f
);
fixAspectRatio();
}
/* Explicitly instantiate the templates */
template class Camera<Matrix3, Vector2, Object2D, Scene2D, Camera2D>;
template class Camera<Matrix4, Vector3, Object3D, Scene3D, Camera3D>;
}}

247
src/SceneGraph/Camera.h

@ -0,0 +1,247 @@
#ifndef Magnum_SceneGraph_Camera_h
#define Magnum_SceneGraph_Camera_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::SceneGraph::Camera, Magnum::SceneGraph::Camera2D, Magnum::SceneGraph::Camera3D
*/
#include "Object.h"
#ifdef WIN32 /* I so HATE windows.h */
#undef near
#undef far
#endif
namespace Magnum { namespace SceneGraph {
/** @todo Export implementation symbols only for tests */
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
enum class AspectRatioPolicy {
NotPreserved, Extend, Clip
};
template<size_t dimensions> class Camera {};
template<class MatrixType> MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Vector2& projectionScale, const Math::Vector2<GLsizei>& viewport);
/* These templates are instantiated in source file */
extern template SCENEGRAPH_EXPORT Matrix3 aspectRatioFix<Matrix3>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&);
extern template SCENEGRAPH_EXPORT Matrix4 aspectRatioFix<Matrix4>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&);
}
#endif
/**
@brief %Camera object
*/
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> class SCENEGRAPH_EXPORT Camera: public ObjectType {
public:
/**
* @brief Aspect ratio policy
*
* @see aspectRatioPolicy(), setAspectRatioPolicy()
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
typedef Implementation::AspectRatioPolicy AspectRatioPolicy;
#else
enum class AspectRatioPolicy {
NotPreserved, /**< Don't preserve aspect ratio (default) */
Extend, /**< Extend on larger side of view */
Clip /**< Clip on smaller side of view */
};
#endif
/** @copydoc Object::Object */
Camera(ObjectType* parent = nullptr);
/** @brief Aspect ratio policy */
inline AspectRatioPolicy aspectRatioPolicy() const { return _aspectRatioPolicy; }
/** @brief Set aspect ratio policy */
void setAspectRatioPolicy(AspectRatioPolicy policy) { _aspectRatioPolicy = policy; }
/**
* @brief Camera matrix
*
* Camera matrix describes world position relative to the camera and is
* applied as first.
*/
inline MatrixType cameraMatrix() {
this->setClean();
return _cameraMatrix;
}
/**
* @brief Projection matrix
*
* Projection matrix handles e.g. perspective distortion and is applied
* as last.
* @see projectionSize()
*/
inline MatrixType projectionMatrix() const { return _projectionMatrix; }
/**
* @brief Size of (near) XY plane in current projection
*
* Returns size of near XY plane computed from projection matrix.
* @see projectionMatrix()
*/
inline Vector2 projectionSize() const {
return {2.0f/rawProjectionMatrix[0].x(), 2.0f/rawProjectionMatrix[1].y()};
}
/** @brief Viewport size */
inline Math::Vector2<GLsizei> viewport() const { return _viewport; }
/**
* @brief Set viewport size
*
* Call when window size changes.
*
* Calls Framebuffer::setViewport() and stores viewport size
* internally.
*/
virtual void setViewport(const Math::Vector2<GLsizei>& size);
/**
* @brief Draw the scene
*
* Calls Framebuffer::clear() and draws the scene using drawChildren().
*/
virtual void draw();
using ObjectType::draw; /* Don't hide Object's draw() */
protected:
/**
* Recalculates camera matrix.
*/
void clean(const MatrixType& absoluteTransformation);
/**
* @brief Draw object children
*
* Recursively draws all children of the object.
*/
void drawChildren(ObjectType* object, const MatrixType& transformationMatrix);
#ifndef DOXYGEN_GENERATING_OUTPUT
inline void fixAspectRatio() {
_projectionMatrix = Implementation::aspectRatioFix<MatrixType>(_aspectRatioPolicy, {rawProjectionMatrix[0].x(), rawProjectionMatrix[1].y()}, _viewport)*rawProjectionMatrix;
}
MatrixType rawProjectionMatrix;
AspectRatioPolicy _aspectRatioPolicy;
#endif
private:
MatrixType _projectionMatrix;
MatrixType _cameraMatrix;
Math::Vector2<GLsizei> _viewport;
};
#ifndef DOXYGEN_GENERATING_OUTPUT
/* These templates are instantiated in source file */
extern template class SCENEGRAPH_EXPORT Camera<Matrix3, Vector2, Object2D, Scene2D, Camera2D>;
extern template class SCENEGRAPH_EXPORT Camera<Matrix4, Vector3, Object3D, Scene3D, Camera3D>;
namespace Implementation {
template<> class Camera<2> {
public:
inline constexpr static Matrix3 aspectRatioScale(const Vector2& scale) {
return Matrix3::scaling({scale.x(), scale.y()});
}
};
template<> class Camera<3> {
public:
inline constexpr static Matrix4 aspectRatioScale(const Vector2& scale) {
return Matrix4::scaling({scale.x(), scale.y(), 1.0f});
}
};
}
#endif
/** @brief %Camera for two-dimensional scenes */
class SCENEGRAPH_EXPORT Camera2D: public Camera<Matrix3, Vector2, Object2D, Scene2D, Camera2D> {
public:
/**
* @brief Constructor
* @param parent Parent object
*
* Sets orthographic projection to the default OpenGL cube (range @f$ [-1; 1] @f$ in all directions).
* @see setOrthographic()
*/
inline Camera2D(Object2D* parent = nullptr): Camera(parent) {}
/**
* @brief Set projection
* @param size Size of the view
*
* The area of given size will be scaled down to range @f$ [-1; 1] @f$
* on all directions.
*/
void setProjection(const Vector2& size);
};
/** @brief %Camera for three-dimensional scenes */
class SCENEGRAPH_EXPORT Camera3D: public Camera<Matrix4, Vector3, Object3D, Scene3D, Camera3D> {
public:
/**
* @brief Constructor
* @param parent Parent object
*
* Sets orthographic projection to the default OpenGL cube (range @f$ [-1; 1] @f$ in all directions).
* @see setOrthographic(), setPerspective()
*/
inline Camera3D(Object3D* parent = nullptr): Camera(parent), _near(0.0f), _far(0.0f) {}
/**
* @brief Set orthographic projection
* @param size Size of the view
* @param near Near clipping plane
* @param far Far clipping plane
*
* The volume of given size will be scaled down to range @f$ [-1; 1] @f$
* on all directions.
*/
void setOrthographic(const Vector2& size, GLfloat near, GLfloat far);
/**
* @brief Set perspective projection
* @param fov Field of view angle
* @param near Near clipping plane
* @param far Far clipping plane
*
* @todo Aspect ratio
*/
void setPerspective(GLfloat fov, GLfloat near, GLfloat far);
/** @brief Near clipping plane */
inline GLfloat near() const { return _near; }
/** @brief Far clipping plane */
inline GLfloat far() const { return _far; }
private:
GLfloat _near, _far;
};
}}
#endif

4
src/Light.cpp → src/SceneGraph/Light.cpp

@ -15,7 +15,7 @@
#include "Light.h"
namespace Magnum {
namespace Magnum { namespace SceneGraph {
void Light::clean(const Matrix4& absoluteTransformation) {
Object::clean(absoluteTransformation);
@ -23,4 +23,4 @@ void Light::clean(const Matrix4& absoluteTransformation) {
_position = absoluteTransformation[3];
}
}
}}

16
src/Light.h → src/SceneGraph/Light.h

@ -1,5 +1,5 @@
#ifndef Magnum_Light_h
#define Magnum_Light_h
#ifndef Magnum_SceneGraph_Light_h
#define Magnum_SceneGraph_Light_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,25 +16,25 @@
*/
/** @file
* @brief Class Magnum::Light
* @brief Class Magnum::SceneGraph::Light
*/
#include "Object.h"
namespace Magnum {
namespace Magnum { namespace SceneGraph {
/** @ingroup scene
/**
* @brief Basic light object
*
* Provides cached light position.
*/
class MAGNUM_EXPORT Light: public Object {
class SCENEGRAPH_EXPORT Light: public Object3D {
public:
/**
* @brief Constructor
* @param parent Parent object
*/
inline Light(Object* parent = nullptr): Object(parent) {}
inline Light(Object3D* parent = nullptr): Object3D(parent) {}
/**
* @brief Light position relative to root object (scene)
@ -54,6 +54,6 @@ class MAGNUM_EXPORT Light: public Object {
Vector4 _position;
};
}
}}
#endif

147
src/SceneGraph/Object.cpp

@ -0,0 +1,147 @@
/*
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 "Object.h"
#include <stack>
#include "Scene.h"
#include "Camera.h"
using namespace std;
using namespace Magnum::Math;
namespace Magnum { namespace SceneGraph {
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> ObjectType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setParent(ObjectType* parent) {
/* Skip if nothing to do or this is scene */
if(this->parent() == parent || isScene()) return static_cast<ObjectType*>(this);
/* Only Fry can be his own grandfather */
ObjectType* p = parent;
while(p) {
/** @todo Assert for this */
if(p == this) return static_cast<ObjectType*>(this);
p = p->parent();
}
/* Remove the object from old parent children list */
if(this->parent())
this->parent()->cut(static_cast<ObjectType*>(this));
/* Add the object to list of new parent */
if(parent)
parent->insert(static_cast<ObjectType*>(this));
setDirty();
return static_cast<ObjectType*>(this);
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> MatrixType Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::absoluteTransformation(CameraType* camera) {
/* Shortcut for absolute transformation of camera relative to itself */
if(camera == this) return MatrixType();
MatrixType t = _transformation;
ObjectType* p = parent();
while(p != nullptr) {
t = p->transformation()*t;
/* We got to the scene, multiply with camera matrix */
if(p->isScene()) {
if(camera) {
CORRADE_ASSERT(camera->scene() == scene(), "Object::absoluteTransformation(): the camera is not part of the same scene as object!", t);
t = camera->cameraMatrix()*t;
}
break;
}
p = p->parent();
}
CORRADE_ASSERT(p != nullptr || camera == nullptr, "Object::absoluteTransformation(): the object is not part of camera scene!", t);
return t;
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> SceneType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::scene() {
/* Goes up the family tree until it finds object which is parent of itself
(that's the scene) */
ObjectType* p = parent();
while(p != nullptr) {
if(p->isScene()) return static_cast<SceneType*>(p);
p = p->parent();
}
return nullptr;
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> ObjectType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setTransformation(const MatrixType& transformation) {
/* Setting transformation is forbidden for the scene */
/** @todo Assert for this? */
if(isScene()) return static_cast<ObjectType*>(this);
_transformation = transformation;
setDirty();
return static_cast<ObjectType*>(this);
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setDirty() {
/* The object (and all its children) are already dirty, nothing to do */
if(dirty) return;
dirty = true;
/* Make all children dirty */
for(ObjectType* i = firstChild(); i; i = i->nextSibling())
i->setDirty();
}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setClean() {
/* The object (and all its parents) are already clean, nothing to do */
if(!dirty) return;
/* Collect all parents */
stack<ObjectType*> objects;
ObjectType* p = static_cast<ObjectType*>(this);
for(;;) {
objects.push(p);
/* Stop on root object / clean object */
if(p->parent() == nullptr || !p->parent()->isDirty())
break;
p = p->parent();
}
/* Call setClean(const Matrix4&) for every parent and also this object */
ObjectType* o = objects.top();
objects.pop();
MatrixType absoluteTransformation = o->absoluteTransformation();
o->clean(absoluteTransformation);
while(!objects.empty()) {
o = objects.top();
objects.pop();
absoluteTransformation = absoluteTransformation*o->transformation();
o->clean(absoluteTransformation);
}
}
/* Explicitly instantiate the templates */
template class Object<Matrix3, Vector2, Object2D, Scene2D, Camera2D>;
template class Object<Matrix4, Vector3, Object3D, Scene3D, Camera3D>;
}}

366
src/SceneGraph/Object.h

@ -0,0 +1,366 @@
#ifndef Magnum_SceneGraph_Object_h
#define Magnum_SceneGraph_Object_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::SceneGraph::Object, Magnum::SceneGraph::Object2D, Magnum::SceneGraph::Object3D
*/
#include <Containers/LinkedList.h>
#include "Magnum.h"
#include "magnumSceneGraphVisibility.h"
namespace Magnum { namespace SceneGraph {
/**
@todo User-specified Object implementation:
- for front-to-back sorting, LoD changes etc.
- for different parent/children implementation (e.g. no std::set, direct
access to scene etc.)
- for using doubles/halves instead of floats
- for using quat + position instead of matrices (where (asymmetric) scaling is
not needed)
*/
/**
* @brief Base for all positioned objects
*
* @todo Transform transformation when changing parent, so the object stays in
* place.
*/
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> class SCENEGRAPH_EXPORT Object: public Corrade::Containers::LinkedList<ObjectType>, public Corrade::Containers::LinkedListItem<ObjectType, ObjectType> {
#ifndef DOXYGEN_GENERATING_OUTPUT
Object(const Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& other) = delete;
Object(Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>&& other) = delete;
Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& operator=(const Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& other) = delete;
Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& operator=(Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>&& other) = delete;
#endif
public:
/**
* @brief Constructor
* @param parent Parent object
*
* Sets all transformations to their default values.
*/
inline Object(ObjectType* parent = nullptr): dirty(true) {
setParent(parent);
}
/**
* @brief Destructor
*
* Removes itself from parent's children list and destroys all own
* children.
*/
virtual inline ~Object() {}
/** @{ @name Scene hierarchy */
/** @brief Whether this object is scene */
virtual inline bool isScene() const { return false; }
/**
* @brief %Scene
* @return If the object is not assigned to any scene, returns nullptr.
*/
SceneType* scene();
/** @brief Parent object or `nullptr`, if this is root object */
inline ObjectType* parent() { return Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::list(); }
/** @brief Previous sibling object or `nullptr`, if this is first object */
inline ObjectType* previousSibling() { return Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::previous(); }
/** @brief Next sibling object or `nullptr`, if this is last object */
inline ObjectType* nextSibling() { return Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::next(); }
/** @brief Whether this object has children */
inline bool hasChildren() const { return !Corrade::Containers::LinkedList<ObjectType>::isEmpty(); }
/** @brief First child object or `nullptr`, if this object has no children */
inline ObjectType* firstChild() { return Corrade::Containers::LinkedList<ObjectType>::first(); }
/** @brief Last child object or `nullptr`, if this object has no children */
inline ObjectType* lastChild() { return Corrade::Containers::LinkedList<ObjectType>::last(); }
/** @brief Set parent object */
ObjectType* setParent(ObjectType* parent);
/*@}*/
/** @{ @name Object transformation
*
* All transformations (except absoluteTransformation()) are relative
* to parent.
*/
/** @brief Transformation type */
enum class Transformation: char {
/** Global transformation, applied after all other transformations. */
Global = 0x00,
/** Local transformation, applied before all other transformations. */
Local = 0x01
};
/** @brief Transformation */
inline MatrixType transformation() const {
return _transformation;
}
/**
* @brief Absolute transformation
*
* Returns absolute transformation matrix relative to the camera or
* root object, if no camera is specified. If the camera is specified,
* it should be part of the same scene as object.
*
* Note that the absolute transformation is computed from all parent
* objects every time it is asked, unless this function is
* reimplemented in a different way.
*/
virtual MatrixType absoluteTransformation(CameraType* camera = nullptr);
/** @brief Set transformation */
ObjectType* setTransformation(const MatrixType& transformation);
/**
* @brief Multiply transformation
* @param transformation Transformation
* @param type Transformation type
*/
inline ObjectType* multiplyTransformation(const MatrixType& transformation, Transformation type = Transformation::Global) {
setTransformation(type == Transformation::Global ?
transformation*_transformation : _transformation*transformation);
return static_cast<ObjectType*>(this);
}
/*@}*/
/**
* @brief Draw object
* @param transformationMatrix %Matrix specifying object
* transformation relative to the scene.
* @param camera Active camera (containing
* projection matrix)
*
* Default implementation does nothing.
*/
virtual void draw(const MatrixType& transformationMatrix, CameraType* camera);
/** @{ @name Caching helpers
*
* If the object (absolute) transformation or anything depending on it
* is used many times when drawing (such as e.g. position of light
* object), it's good to cache these values, so they don't have to be
* recalculated again on every request.
*
* If setDirty() is called on an object (or the object is transformed),
* it and all its children are marked as dirty. If any object is
* already dirty, it and all its children are skipped, because they
* are already dirty too.
*
* If setClean() is called on an object, it and all its parents are
* cleaned. If any object is already clean, it and all its parents are
* skipped, because they are already clean too.
*
* These functions are used to manage dirty status of the object. If
* the object doesn't cache anything, it's no need to bother about
* them, but if does, clean() should be reimplemented and used to
* regenerate the cache.
*/
/**
* @brief Whether the object is dirty
* @return True, if transformation of the object, any parent or camera
* has changed since last asking, false otherwise.
*/
inline bool isDirty() const { return dirty; }
/**
* @brief Set object and all its children as dirty
*
* Recursively calls setDirty() on every child. If the object is
* already marked as dirty, the function does nothing. It is usually
* not needed to reimplement this function, only if you for example
* need to reset some state on object which is not child of this. All
* computations should be done in setClean().
*
* Reimplementations should call this function at the end, i.e.:
* @code
* void setDirty() {
* // ...
*
* Object::setDirty();
* }
* @endcode
*/
virtual void setDirty();
/**
* @brief Set object and all its parents as clean
*
* Recursively calls clean() on every parent which is not already
* clean.
*/
void setClean();
protected:
/**
* @brief Clean the object
*
* When reimplementing, use absolute transformation passed as
* parameter instead of absoluteTransformation(), which is not
* efficient. The reimplementation should call this function at the
* beginning, i.e.:
* @code
* void clean(const Matrix4& absoluteTransformation) {
* Object::clean(absoluteTransformation);
*
* // ...
* }
* @endcode
*/
virtual void clean(const MatrixType& absoluteTransformation);
/*@}*/
private:
/* Hide base class members, as they are aliased to more meaningful names */
using Corrade::Containers::LinkedList<ObjectType>::first;
using Corrade::Containers::LinkedList<ObjectType>::last;
using Corrade::Containers::LinkedList<ObjectType>::isEmpty;
using Corrade::Containers::LinkedList<ObjectType>::insert;
using Corrade::Containers::LinkedList<ObjectType>::cut;
using Corrade::Containers::LinkedList<ObjectType>::move;
using Corrade::Containers::LinkedList<ObjectType>::erase;
using Corrade::Containers::LinkedList<ObjectType>::clear;
using Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::list;
using Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::previous;
using Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::next;
MatrixType _transformation;
bool dirty;
};
/* Implementations for inline functions with unused parameters */
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> inline void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::draw(const MatrixType&, CameraType*) {}
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> inline void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::clean(const MatrixType&) { dirty = false; }
class Camera2D;
class Camera3D;
class Object2D;
class Object3D;
template<class MatrixType, class VectorType, class ObjectType, class CameraType> class Scene;
typedef Scene<Matrix3, Vector2, Object2D, Camera2D> Scene2D;
typedef Scene<Matrix4, Vector3, Object3D, Camera3D> Scene3D;
#ifndef DOXYGEN_GENERATING_OUTPUT
/* These templates are instantiated in source file */
extern template class SCENEGRAPH_EXPORT Object<Matrix3, Vector2, Object2D, Scene2D, Camera2D>;
extern template class SCENEGRAPH_EXPORT Object<Matrix4, Vector3, Object3D, Scene3D, Camera3D>;
#endif
/** @brief Two-dimensional object */
class SCENEGRAPH_EXPORT Object2D: public Object<Matrix3, Vector2, Object2D, Scene2D, Camera2D> {
public:
/** @copydoc Object::Object */
inline Object2D(Object2D* parent = nullptr): Object(parent) {}
/**
* @brief Translate object
*
* Same as calling multiplyTransformation() with Matrix3::translation().
*/
inline Object2D* translate(const Vector2& vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix3::translation(vec), type);
return this;
}
/**
* @brief Scale object
*
* Same as calling multiplyTransformation() with Matrix3::scaling().
*/
inline Object2D* scale(const Vector2& vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix3::scaling(vec), type);
return this;
}
/**
* @brief Rotate object
*
* Same as calling multiplyTransformation() with Matrix3::rotation().
*/
inline Object2D* rotate(GLfloat angle, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix3::rotation(angle), type);
return this;
}
/**
* @brief Move object in stacking order
* @param under Sibling object under which to move or `nullptr`,
* if you want to move it above all.
*/
inline Object2D* move(Object2D* under) {
parent()->Corrade::Containers::LinkedList<Object2D>::move(this, under);
return this;
}
};
/** @brief Three-dimensional object */
class SCENEGRAPH_EXPORT Object3D: public Object<Matrix4, Vector3, Object3D, Scene3D, Camera3D> {
public:
/** @copydoc Object::Object */
inline Object3D(Object3D* parent = nullptr): Object(parent) {}
/**
* @brief Translate object
*
* Same as calling multiplyTransformation() with Matrix4::translation().
*/
inline Object3D* translate(const Vector3& vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::translation(vec), type);
return this;
}
/**
* @brief Scale object
*
* Same as calling multiplyTransformation() with Matrix4::scaling().
*/
inline Object3D* scale(const Vector3& vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::scaling(vec), type);
return this;
}
/**
* @brief Rotate object
*
* Same as calling multiplyTransformation() with Matrix4::rotation().
*/
inline Object3D* rotate(GLfloat angle, const Vector3& vec, Transformation type = Transformation::Global) {
multiplyTransformation(Matrix4::rotation(angle, vec), type);
return this;
}
};
}}
#endif

54
src/SceneGraph/Scene.h

@ -0,0 +1,54 @@
#ifndef Magnum_SceneGraph_Scene_h
#define Magnum_SceneGraph_Scene_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::SceneGraph::Scene, typedef Magnum::SceneGraph::Scene2D, Magnum::SceneGraph::Scene3D
*/
#include "Object.h"
namespace Magnum { namespace SceneGraph {
/** @brief %Scene */
template<class MatrixType, class VectorType, class ObjectType, class CameraType> class SCENEGRAPH_EXPORT Scene: public ObjectType {
public:
/** @copydoc Object::isScene() */
inline bool isScene() const { return true; }
/** @todo Some deleted functions belong only to Scene2D, some only to Scene3D - what to do? */
#ifndef DOXYGEN_GENERATING_OUTPUT
void setParent(ObjectType* parent) = delete;
void setTransformation(const MatrixType& transformation) = delete;
void multiplyTransformation(const MatrixType& transformation, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete;
void translate(const VectorType& vec, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete;
void scale(const VectorType& vec, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete;
void rotate(GLfloat angle, const VectorType& vec, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete;
#endif
private:
inline void draw(const MatrixType&, CameraType*) {}
};
/** @brief Two-dimensional scene */
typedef Scene<Matrix3, Vector2, Object2D, Camera2D> Scene2D;
/** @brief Three-dimensional scene */
typedef Scene<Matrix4, Vector3, Object3D, Camera3D> Scene3D;
}}
#endif

3
src/SceneGraph/Test/CMakeLists.txt

@ -0,0 +1,3 @@
corrade_add_test2(SceneGraphObjectTest ObjectTest.cpp LIBRARIES MagnumSceneGraphTestLib)
corrade_add_test2(SceneGraphCameraTest CameraTest.cpp LIBRARIES MagnumSceneGraph)
corrade_add_test2(SceneGraphSceneTest SceneTest.cpp LIBRARIES MagnumSceneGraph)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save