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_MESHTOOLS "Build MeshTools library" OFF)
option(WITH_PHYSICS "Build Physics library" OFF) option(WITH_PHYSICS "Build Physics library" OFF)
option(WITH_PRIMITIVES "Builf Primitives library" OFF) option(WITH_PRIMITIVES "Builf Primitives library" OFF)
option(WITH_SCENEGRAPH "Build SceneGraph library" OFF)
option(WITH_SHADERS "Build Shaders 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) cmake_dependent_option(WITH_GLUTCONTEXT "Build GlutContext library" OFF "NOT TARGET_GLES" OFF)
option(WITH_SDL2CONTEXT "Build Sdl2Context library" OFF) option(WITH_SDL2CONTEXT "Build Sdl2Context library" OFF)
@ -25,6 +27,7 @@ if(WITH_EVERYTHING)
set(WITH_MESHTOOLS ON) set(WITH_MESHTOOLS ON)
set(WITH_PHYSICS ON) set(WITH_PHYSICS ON)
set(WITH_PRIMITIVES ON) set(WITH_PRIMITIVES ON)
set(WITH_SCENEGRAPH ON)
set(WITH_SHADERS ON) set(WITH_SHADERS ON)
endif() 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. # You can put \n's in the value part of an alias to insert newlines.
ALIASES = \ 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" \ "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\"" \ "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." \ "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_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_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_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\"" \ "requires_gl43=@xrefitem requires-gl43 \"Requires OpenGL 4.3\" \"Functionality requiring OpenGL 4.3\"" \
"extension{2}=<a href=\"http://www.opengl.org/registry/specs/\1/\2.txt\"><tt>\1_\2</tt></a>" "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). # 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 # 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** which are tested to support everything needed: **GCC** >= 4.6 and **Clang**
>= 3.1. >= 3.1.
- **CMake** >= 2.8.8 (needed for `OBJECT` library target) - **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). **OpenGL ES 2** headers, if targeting OpenGL ES (see below).
- **GLEW** - OpenGL extension wrangler - **GLEW** - OpenGL extension wrangler
- **Corrade** - Plugin management and utility library. You can get it at - **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 @subsection documentation-commands Special documentation commands
Additionally to @c \@todoc and @c \@debugoperator (same as in Corrade), these Additionally to @c \@todoc, @c \@debugoperator @c \@configurationvalue and
are defined: @c \@configurationvalueref (same as in Corrade), these are defined:
@subsubsection documentation-commands-collisionoperator Physics collision operators @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 - Easy-to-use templated @ref Math "mathematical library" for matrix/vector
calculations and @ref Math::Geometry "geometry". calculations and @ref Math::Geometry "geometry".
- Hierarchical @ref Object "scene graph" which supports transformation caching - Hierarchical @ref SceneGraph "scene graph" which supports transformation
for better performance, classes for convenient usage of caching for better performance, classes for convenient usage of
@ref AbstractShaderProgram "shaders", @ref Buffer "buffers" and @ref AbstractShaderProgram "shaders", @ref Buffer "buffers" and
@ref AbstractTexture "textures". Access to @ref Framebuffer "framebuffer" @ref AbstractTexture "textures". Access to @ref Framebuffer "framebuffer"
and @ref AbstractQuery "occlusion queries". 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 "other examples", read about fundamental principles in the documentation or
start experimenting on your own! 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 @subsection getting-started-hacking Hacking Magnum
If you want to hack on this engine, if you spotted a bug, need an feature or 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 /** @namespace Magnum
@brief Root namespace @brief Root namespace
Contains classes needed for building meshes, setting up and rendering the Contains classes for interacting with OpenGL.
scene.
*/ */
/** @dir Contexts /** @dir Contexts
@ -41,8 +40,7 @@ Functions for computing intersections, distances, areas and volumes.
/** @dir MeshTools /** @dir MeshTools
* @brief Namespace Magnum::MeshTools * @brief Namespace Magnum::MeshTools
*/ */
/** @ingroup mesh /** @namespace Magnum::MeshTools
@namespace Magnum::MeshTools
@brief %Mesh tools @brief %Mesh tools
Tools for generating, optimizing and cleaning meshes. Tools for generating, optimizing and cleaning meshes.
@ -51,18 +49,26 @@ Tools for generating, optimizing and cleaning meshes.
/** @dir Primitives /** @dir Primitives
* @brief Namespace Magnum::Primitives * @brief Namespace Magnum::Primitives
*/ */
/** @ingroup mesh /** @namespace Magnum::Primitives
@namespace Magnum::Primitives
@brief Primitive library @brief Primitive library
Basic primitives for testing purposes. 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 /** @dir Shaders
* @brief Namespace Magnum::Shaders * @brief Namespace Magnum::Shaders
*/ */
/** @ingroup rendering /** @namespace Magnum::Shaders
@namespace Magnum::Shaders
@brief Sample shaders @brief Sample shaders
Collection of shaders for testing purposes. 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-gl40
- @subpage requires-gl41 - @subpage requires-gl41
- @subpage requires-gl42 - @subpage requires-gl42
- @subpage requires-gl43
- @subpage requires-extension - @subpage requires-extension
- @subpage requires-gles30
- @subpage requires-es-extension
@page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES) @page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES)
@page requires-gl30 Functionality requiring OpenGL 3.0 @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-gl40 Functionality requiring OpenGL 4.0
@page requires-gl41 Functionality requiring OpenGL 4.1 @page requires-gl41 Functionality requiring OpenGL 4.1
@page requires-gl42 Functionality requiring OpenGL 4.2 @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-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 # MeshTools - MeshTools library
# Physics - Physics library # Physics - Physics library
# Primitives - Library with stock geometric primitives (static) # Primitives - Library with stock geometric primitives (static)
# SceneGraph - Scene graph library
# Shaders - Library with stock shaders # 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) # GlutContext - GLUT context (depends on GLUT library)
# Sdl2Context - SDL2 context (depends on SDL2 library) # Sdl2Context - SDL2 context (depends on SDL2 library)
# Example usage with specifying additional components is: # Example usage with specifying additional components is:
@ -110,8 +112,18 @@ foreach(component ${Magnum_FIND_COMPONENTS})
endif() endif()
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 # X/EGL context dependencies
if(${component} STREQUAL EglContext) if(${component} STREQUAL XEglContext)
find_package(EGL) find_package(EGL)
find_package(X11) find_package(X11)
if(EGL_FOUND AND X11_FOUND) if(EGL_FOUND AND X11_FOUND)
@ -137,6 +149,11 @@ foreach(component ${Magnum_FIND_COMPONENTS})
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Cube.h) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Cube.h)
endif() endif()
# Scene graph library
if(${component} STREQUAL SceneGraph)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Scene.h)
endif()
# Shaders library # Shaders library
if(${component} STREQUAL Shaders) if(${component} STREQUAL Shaders)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES PhongShader.h) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES PhongShader.h)

3
src/AbstractImage.h

@ -23,7 +23,7 @@
namespace Magnum { namespace Magnum {
/** @ingroup textures /**
@brief Non-templated base for one-, two- or three-dimensional images @brief Non-templated base for one-, two- or three-dimensional images
See Image, BufferedImage, Trade::ImageData documentation for more information. See Image, BufferedImage, Trade::ImageData documentation for more information.
@ -44,6 +44,7 @@ class MAGNUM_EXPORT AbstractImage {
*/ */
/** @brief Color components */ /** @brief Color components */
/** @todo Support *_INTEGER types */
enum class Components: GLenum { enum class Components: GLenum {
#ifndef MAGNUM_TARGET_GLES #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()); 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 #endif
void AbstractShaderProgram::link() { void AbstractShaderProgram::link() {

48
src/AbstractShaderProgram.h

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

40
src/AbstractTexture.h

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

7
src/Buffer.h

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

8
src/BufferedImage.h

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

2
src/BufferedTexture.h

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

27
src/CMakeLists.txt

@ -33,10 +33,8 @@ set(Magnum_SRCS
AbstractTexture.cpp AbstractTexture.cpp
AbstractShaderProgram.cpp AbstractShaderProgram.cpp
BufferedTexture.cpp BufferedTexture.cpp
Camera.cpp
Framebuffer.cpp Framebuffer.cpp
IndexedMesh.cpp IndexedMesh.cpp
Light.cpp
Mesh.cpp Mesh.cpp
Query.cpp Query.cpp
Renderbuffer.cpp Renderbuffer.cpp
@ -53,7 +51,6 @@ set(Magnum_HEADERS
BufferedImage.h BufferedImage.h
BufferedTexture.h BufferedTexture.h
Buffer.h Buffer.h
Camera.h
Color.h Color.h
CubeMapTextureArray.h CubeMapTextureArray.h
CubeMapTexture.h CubeMapTexture.h
@ -61,15 +58,13 @@ set(Magnum_HEADERS
Image.h Image.h
ImageWrapper.h ImageWrapper.h
IndexedMesh.h IndexedMesh.h
Light.h
Magnum.h Magnum.h
Mesh.h Mesh.h
Object.h
Query.h Query.h
Renderbuffer.h Renderbuffer.h
Scene.h
Shader.h Shader.h
SizeTraits.h SizeTraits.h
Swizzle.h
Texture.h Texture.h
TypeTraits.h TypeTraits.h
@ -86,10 +81,6 @@ if(NOT CMAKE_NO_OBJECT_TARGET)
add_library(MagnumMathObjects OBJECT ${MagnumMath_SRCS}) add_library(MagnumMathObjects OBJECT ${MagnumMath_SRCS})
endif() 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 # 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 # TODO: fix when CMake sets target_EXPORTS for OBJECT targets as well
if(NOT CMAKE_NO_OBJECT_TARGET) if(NOT CMAKE_NO_OBJECT_TARGET)
@ -100,13 +91,11 @@ endif()
if(NOT CMAKE_NO_OBJECT_TARGET) if(NOT CMAKE_NO_OBJECT_TARGET)
add_library(Magnum SHARED add_library(Magnum SHARED
$<TARGET_OBJECTS:MagnumObjects> $<TARGET_OBJECTS:MagnumObjects>
$<TARGET_OBJECTS:MagnumMathObjects> $<TARGET_OBJECTS:MagnumMathObjects>)
${Magnum_GracefulAssert_SRCS})
else() else()
add_library(Magnum SHARED add_library(Magnum SHARED
${Magnum_SRCS} ${Magnum_SRCS}
${MagnumMath_SRCS} ${MagnumMath_SRCS})
${Magnum_GracefulAssert_SRCS})
endif() endif()
target_link_libraries(Magnum ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY}) target_link_libraries(Magnum ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY})
if(NOT TARGET_GLES) if(NOT TARGET_GLES)
@ -137,6 +126,10 @@ if(WITH_PRIMITIVES)
add_subdirectory(Primitives) add_subdirectory(Primitives)
endif() endif()
if(WITH_SCENEGRAPH)
add_subdirectory(SceneGraph)
endif()
if(WITH_SHADERS) if(WITH_SHADERS)
add_subdirectory(Shaders) add_subdirectory(Shaders)
endif() endif()
@ -147,12 +140,10 @@ if(BUILD_TESTS)
# Library with graceful assert for testing # Library with graceful assert for testing
if(NOT CMAKE_NO_OBJECT_TARGET) if(NOT CMAKE_NO_OBJECT_TARGET)
add_library(MagnumTestLib SHARED add_library(MagnumTestLib SHARED
$<TARGET_OBJECTS:MagnumObjects> $<TARGET_OBJECTS:MagnumObjects>)
${Magnum_GracefulAssert_SRCS})
else() else()
add_library(MagnumTestLib SHARED add_library(MagnumTestLib SHARED
${Magnum_SRCS} ${Magnum_SRCS})
${Magnum_GracefulAssert_SRCS})
endif() endif()
set_target_properties(MagnumTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) set_target_properties(MagnumTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
target_link_libraries(MagnumTestLib ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY}) 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$. range @f$ [0.0, 1.0] @f$.
@see Color4 @see Color4
@todo Signed normalization to [-1.0, 1.0] like in OpenGL?
*/ */
template<class T> class Color3: public Math::Vector3<T> { template<class T> class Color3: public Math::Vector3<T> {
public: 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) { 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); 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) { 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); 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 #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 #ifndef Magnum_Contexts_AbstractXContext_h
#define Magnum_Contexts_EglContext_h #define Magnum_Contexts_AbstractXContext_h
/* /*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,52 +16,57 @@
*/ */
/** @file /** @file
* @brief Class Magnum::Contexts::EglContext * @brief Class Magnum::Contexts::AbstractXContext
*/ */
#include "Magnum.h" #include "Magnum.h"
#include <X11/Xlib.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 #undef None
#endif #undef Always
#ifndef SUPPORT_X11 #include <Containers/EnumSet.h>
#define SUPPORT_X11 // OpenGL ES on BeagleBoard needs this (?)
#endif
#include <EGL/egl.h>
#include "AbstractContext.h" #include "AbstractContext.h"
#include "AbstractGlInterface.h"
namespace Magnum { namespace Contexts { namespace Magnum { namespace Contexts {
/** /** @nosubgrouping
@brief X/EGL context @brief Base for X11-based contexts
Supports keyboard and mouse handling. Supports keyboard and mouse handling.
@note Not meant to be used directly, see subclasses.
*/ */
class EglContext: public AbstractContext { class AbstractXContext: public AbstractContext {
public: public:
/** /**
* @brief Constructor * @brief Constructor
* @param argc Count of arguments of `main()` function * @param glInterface Interface to OpenGL
* @param argv Arguments of `main()` function * @param argc Count of arguments of `main()` function
* @param title Window title * @param argv Arguments of `main()` function
* @param size Window size * @param title Window title
* @param size Window size
* *
* Creates window with double-buffered OpenGL ES 2 context. * 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 * @brief Destructor
* *
* Deletes context and destroys the window. * Deletes context and destroys the window.
*/ */
~EglContext(); virtual ~AbstractXContext() = 0;
int exec(); int exec();
/** @brief Exit application main loop */
inline void exit() { flags |= Flag::Exit; }
/** @{ @name Drawing functions */ /** @{ @name Drawing functions */
protected: protected:
@ -72,18 +77,50 @@ class EglContext: public AbstractContext {
virtual void drawEvent() = 0; virtual void drawEvent() = 0;
/** @copydoc GlutContext::swapBuffers() */ /** @copydoc GlutContext::swapBuffers() */
inline void swapBuffers() { eglSwapBuffers(display, surface); } inline void swapBuffers() { glInterface->swapBuffers(); }
/** @todo implement */ /** @copydoc GlutContext::redraw() */
inline void redraw() {} inline void redraw() { flags |= Flag::Redraw; }
/*@}*/ /*@}*/
/** @{ @name Keyboard handling */ /** @{ @name Keyboard handling */
public: 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 { enum class Key: KeySym {
Esc = XK_Escape, /**< Escape */
Up = XK_Up, /**< Up arrow */ Up = XK_Up, /**< Up arrow */
Down = XK_Down, /**< Down arrow */ Down = XK_Down, /**< Down arrow */
Left = XK_Left, /**< Left arrow */ Left = XK_Left, /**< Left arrow */
@ -157,27 +194,33 @@ class EglContext: public AbstractContext {
/** /**
* @brief Key press event * @brief Key press event
* @param key Key pressed * @param key Key pressed
* @param modifiers Active modifiers
* @param position Cursor position * @param position Cursor position
* *
* Called when an key is pressed. Default implementation does nothing. * 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 * @brief Key press event
* @param key Key released * @param key Key released
* @param modifiers Active modifiers
* @param position Cursor position * @param position Cursor position
* *
* Called when an key is released. Default implementation does nothing. * 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 */ /** @{ @name Mouse handling */
public: public:
/** @brief Mouse button */ /**
* @brief Mouse button
*
* @see mousePressEvent(), mouseReleaseEvent()
*/
enum class MouseButton: unsigned int { enum class MouseButton: unsigned int {
Left = Button1, /**< Left button */ Left = Button1, /**< Left button */
Middle = Button2, /**< Middle button */ Middle = Button2, /**< Middle button */
@ -189,40 +232,67 @@ class EglContext: public AbstractContext {
protected: protected:
/** /**
* @brief Mouse press event * @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 * Called when mouse button is pressed. Default implementation does
* nothing. * 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 * @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 * Called when mouse button is released. Default implementation does
* nothing. * 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: private:
Display* xDisplay; enum class Flag: unsigned int {
Window xWindow; 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; Atom deleteWindow;
EGLDisplay display; AbstractGlInterface<Display*, VisualID, Window>* glInterface;
EGLSurface surface;
EGLContext context;
/** @todo Get this from the created window */ /** @todo Get this from the created window */
Math::Vector2<GLsizei> viewportSize; Math::Vector2<GLsizei> viewportSize;
Flags flags;
}; };
inline void EglContext::keyPressEvent(EglContext::Key, const Math::Vector2<int>&) {} CORRADE_ENUMSET_OPERATORS(AbstractXContext::Modifiers)
inline void EglContext::keyReleaseEvent(EglContext::Key, const Math::Vector2<int>&) {} CORRADE_ENUMSET_OPERATORS(AbstractXContext::Flags)
inline void EglContext::mousePressEvent(EglContext::MouseButton, const Math::Vector2<int>&) {}
inline void EglContext::mouseReleaseEvent(EglContext::MouseButton, const Math::Vector2<int>&) {}
/* 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 # GLUT context
if(WITH_GLUTCONTEXT) if(WITH_GLUTCONTEXT)
find_package(GLUT) find_package(GLUT)
if(GLUT_FOUND) 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(FILES GlutContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumGlutContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(TARGETS MagnumGlutContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
else() else()
@ -17,7 +26,9 @@ if(WITH_SDL2CONTEXT)
find_package(SDL2) find_package(SDL2)
if(SDL2_FOUND) if(SDL2_FOUND)
include_directories(${SDL2_INCLUDE_DIR}) 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(FILES Sdl2Context.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumSdl2Context DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(TARGETS MagnumSdl2Context DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
else() else()
@ -25,17 +36,58 @@ if(WITH_SDL2CONTEXT)
endif() endif()
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 # X/EGL context
if(WITH_EGLCONTEXT) if(WITH_XEGLCONTEXT)
find_package(EGL) 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) find_package(X11)
if(EGL_FOUND AND X11_FOUND) if(NOT X11_FOUND)
add_library(MagnumEglContext STATIC EglContext.cpp) message(FATAL_ERROR "X11 library, required by some contexts, was not found. Set WITH_*X*CONTEXT to OFF to skip building them.")
# X11 macros are a mess, disable warnings for C-style casts endif()
set_target_properties(MagnumEglContext PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast") add_library(MagnumAbstractXContext OBJECT AbstractXContext.cpp)
install(FILES EglContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) # X11 macros are a mess, disable warnings for C-style casts
install(TARGETS MagnumEglContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) set_target_properties(MagnumAbstractXContext PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
else() install(FILES AbstractXContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
message(FATAL_ERROR "EGL or X11 libraries, required by EglContext, were not found. Set WITH_EGLCONTEXT to OFF to skip building it.") 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() 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() 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 "GlutContext.h"
#include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts { namespace Magnum { namespace Contexts {
GlutContext* GlutContext::instance = nullptr; GlutContext* GlutContext::instance = nullptr;
@ -35,12 +37,7 @@ GlutContext::GlutContext(int& argc, char** argv, const std::string& title, const
glutMotionFunc(staticMouseMotionEvent); glutMotionFunc(staticMouseMotionEvent);
glutDisplayFunc(staticDrawEvent); glutDisplayFunc(staticDrawEvent);
/* Init GLEW */ ExtensionWrangler::initialize();
GLenum err = glewInit();
if(err != GLEW_OK) {
Error() << "GlutContext: cannot initialize GLEW:" << glewGetErrorString(err);
exit(1);
}
} }
}} }}

32
src/Contexts/GlutContext.h

@ -60,7 +60,8 @@ class GlutContext: public AbstractContext {
* @brief Viewport event * @brief Viewport event
* *
* Called when viewport size changes. You should pass the new size to * 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; virtual void viewportEvent(const Math::Vector2<GLsizei>& size) = 0;
@ -68,8 +69,9 @@ class GlutContext: public AbstractContext {
* @brief Draw event * @brief Draw event
* *
* Here implement your drawing functions, such as calling * Here implement your drawing functions, such as calling
* Camera::draw(). After drawing is finished, call swapBuffers(). If * SceneGraph::Camera::draw(). After drawing is finished, call
* you want to draw immediately again, call also redraw(). * swapBuffers(). If you want to draw immediately again, call also
* redraw().
*/ */
virtual void drawEvent() = 0; virtual void drawEvent() = 0;
@ -97,7 +99,11 @@ class GlutContext: public AbstractContext {
/** @{ @name Keyboard handling */ /** @{ @name Keyboard handling */
public: public:
/** @brief Key */ /**
* @brief Key
*
* @see keyPressEvent()
*/
enum class Key: int { enum class Key: int {
Up = GLUT_KEY_UP, /**< Up arrow */ Up = GLUT_KEY_UP, /**< Up arrow */
Down = GLUT_KEY_DOWN, /**< Down arrow */ Down = GLUT_KEY_DOWN, /**< Down arrow */
@ -136,7 +142,11 @@ class GlutContext: public AbstractContext {
/** @{ @name Mouse handling */ /** @{ @name Mouse handling */
public: public:
/** @brief Mouse button */ /**
* @brief Mouse button
*
* @see mousePressEvent(), mouseReleaseEvent()
*/
enum class MouseButton: int { enum class MouseButton: int {
Left = GLUT_LEFT_BUTTON, /**< Left button */ Left = GLUT_LEFT_BUTTON, /**< Left button */
Middle = GLUT_MIDDLE_BUTTON, /**< Middle button */ Middle = GLUT_MIDDLE_BUTTON, /**< Middle button */
@ -145,7 +155,11 @@ class GlutContext: public AbstractContext {
WheelDown = 4 /**< Wheel down */ WheelDown = 4 /**< Wheel down */
}; };
/** @brief Mouse cursor */ /**
* @brief Mouse cursor
*
* @see setMouseCursor()
*/
enum class MouseCursor: int { enum class MouseCursor: int {
Default = GLUT_CURSOR_INHERIT, /**< Default cursor provided by parent window */ Default = GLUT_CURSOR_INHERIT, /**< Default cursor provided by parent window */
None = GLUT_CURSOR_NONE /**< No cursor */ None = GLUT_CURSOR_NONE /**< No cursor */
@ -231,9 +245,9 @@ class GlutContext: public AbstractContext {
}; };
/* Implementations for inline functions with unused parameters */ /* Implementations for inline functions with unused parameters */
inline void GlutContext::keyPressEvent(GlutContext::Key, const Math::Vector2<int>&) {} inline void GlutContext::keyPressEvent(Key, const Math::Vector2<int>&) {}
inline void GlutContext::mousePressEvent(GlutContext::MouseButton, const Math::Vector2<int>&) {} inline void GlutContext::mousePressEvent(MouseButton, const Math::Vector2<int>&) {}
inline void GlutContext::mouseReleaseEvent(GlutContext::MouseButton, const Math::Vector2<int>&) {} inline void GlutContext::mouseReleaseEvent(MouseButton, const Math::Vector2<int>&) {}
inline void GlutContext::mouseMotionEvent(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 "Sdl2Context.h"
#include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts { namespace Magnum { namespace Contexts {
@ -40,18 +41,9 @@ Sdl2Context::Sdl2Context(int, char**, const std::string& name, const Math::Vecto
context = SDL_GL_CreateContext(window); context = SDL_GL_CreateContext(window);
#ifndef MAGNUM_TARGET_GLES
/* This must be enabled, otherwise (on my NVidia) it crashes when creating /* This must be enabled, otherwise (on my NVidia) it crashes when creating
VAO. WTF. */ VAO. WTF. */
glewExperimental = true; ExtensionWrangler::initialize(ExtensionWrangler::ExperimentalFeatures::Enable);
/* Init GLEW */
GLenum err = glewInit();
if(err != GLEW_OK) {
Error() << "Sdl2Context: cannot initialize GLEW:" << glewGetErrorString(err);
exit(1);
}
#endif
/* Push resize event, so viewportEvent() is called at startup */ /* Push resize event, so viewportEvent() is called at startup */
SDL_Event* sizeEvent = new SDL_Event; SDL_Event* sizeEvent = new SDL_Event;
@ -91,10 +83,10 @@ int Sdl2Context::exec() {
keyReleaseEvent(static_cast<Key>(event.key.keysym.sym)); keyReleaseEvent(static_cast<Key>(event.key.keysym.sym));
break; break;
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
mousePressEvent(static_cast<MouseButton>(event.button.button), {event.button.x, event.button.y});
break;
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
mouseEvent(static_cast<MouseButton>(event.button.button), mouseReleaseEvent(static_cast<MouseButton>(event.button.button), {event.button.x, event.button.y});
static_cast<MouseState>(event.button.state),
{event.button.x, event.button.y});
break; break;
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
mouseWheelEvent({event.wheel.x, event.wheel.y}); mouseWheelEvent({event.wheel.x, event.wheel.y});
@ -109,8 +101,8 @@ int Sdl2Context::exec() {
} }
if(_redraw) { if(_redraw) {
drawEvent();
_redraw = false; _redraw = false;
drawEvent();
} else Corrade::Utility::sleep(5); } else Corrade::Utility::sleep(5);
} }

33
src/Contexts/Sdl2Context.h

@ -79,6 +79,7 @@ class Sdl2Context: public AbstractContext {
public: public:
/** /**
* @brief Key * @brief Key
*
* @see keyPressEvent(), keyReleaseEvent() * @see keyPressEvent(), keyReleaseEvent()
*/ */
enum class Key: SDL_Keycode { enum class Key: SDL_Keycode {
@ -111,6 +112,7 @@ class Sdl2Context: public AbstractContext {
public: public:
/** /**
* @brief Mouse button * @brief Mouse button
*
* @see mouseEvent() * @see mouseEvent()
*/ */
enum class MouseButton: Uint8 { enum class MouseButton: Uint8 {
@ -121,6 +123,7 @@ class Sdl2Context: public AbstractContext {
/** /**
* @brief Mouse state * @brief Mouse state
*
* @see mouseEvent() * @see mouseEvent()
*/ */
enum class MouseState: Uint8 { enum class MouseState: Uint8 {
@ -130,15 +133,24 @@ class Sdl2Context: public AbstractContext {
protected: protected:
/** /**
* @brief Mouse event * @brief Mouse press event
* @param button Mouse button * @param button Button pressed
* @param state Mouse state * @param position Cursor position
* @param position Mouse position relative to the window *
* 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 * Called when mouse button is released. Default implementation does
* implementation does nothing. * 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 * @brief Mouse wheel event
@ -169,9 +181,10 @@ class Sdl2Context: public AbstractContext {
}; };
/* Implementations for inline functions with unused parameters */ /* Implementations for inline functions with unused parameters */
inline void Sdl2Context::keyPressEvent(Sdl2Context::Key, Uint8) {} inline void Sdl2Context::keyPressEvent(Key, Uint8) {}
inline void Sdl2Context::keyReleaseEvent(Sdl2Context::Key) {} inline void Sdl2Context::keyReleaseEvent(Key) {}
inline void Sdl2Context::mouseEvent(Sdl2Context::MouseButton, Sdl2Context::MouseState, const Math::Vector2<int>&) {} 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::mouseWheelEvent(const Math::Vector2<int>&) {}
inline void Sdl2Context::mouseMotionEvent(const Math::Vector2<int>&, 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 { namespace Magnum {
/** @ingroup textures /**
@brief Cube map texture @brief Cube map texture
%Texture used mainly for environemnt maps. See AbstractTexture documentation %Texture used mainly for environemnt maps. See AbstractTexture documentation

2
src/CubeMapTextureArray.h

@ -23,7 +23,7 @@
namespace Magnum { namespace Magnum {
/** @ingroup textures /**
@brief Cube map texture array @brief Cube map texture array
For information about usage, see CubeMapTexture documentation. 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 /** @file
* @brief Class Magnum::Image * @brief Class Magnum::Image, typedef Magnum::Image1D, Magnum::Image2D, Magnum::Image3D
*/ */
#include "AbstractImage.h" #include "AbstractImage.h"
@ -24,10 +24,6 @@
namespace Magnum { namespace Magnum {
/** @addtogroup textures
* @{
*/
/** /**
@brief %Image @brief %Image
@ -128,8 +124,6 @@ typedef Image<2> Image2D;
/** @brief Three-dimensional image */ /** @brief Three-dimensional image */
typedef Image<3> Image3D; typedef Image<3> Image3D;
/*@}*/
} }
#endif #endif

6
src/ImageWrapper.h

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

2
src/IndexedMesh.h

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

1
src/Math/CMakeLists.txt

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

32
src/Math/Math.h

@ -51,14 +51,14 @@ template<class T> struct Constants {
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
template<> struct Constants<double> { template<> struct Constants<double> {
static inline constexpr double pi() { return 3.14159265359; } static inline constexpr double pi() { return 3.141592653589793; }
static inline constexpr double sqrt2() { return 1.41421356237; } static inline constexpr double sqrt2() { return 1.414213562373095; }
static inline constexpr double sqrt3() { return 1.73205080757; } static inline constexpr double sqrt3() { return 1.732050807568877; }
}; };
template<> struct Constants<float> { template<> struct Constants<float> {
static inline constexpr float pi() { return 3.14159265359f; } static inline constexpr float pi() { return 3.141592654f; }
static inline constexpr float sqrt2() { return 1.41421356237f; } static inline constexpr float sqrt2() { return 1.414213562f; }
static inline constexpr float sqrt3() { return 1.73205080757f; } static inline constexpr float sqrt3() { return 1.732050808f; }
}; };
namespace Implementation { namespace Implementation {
@ -105,6 +105,8 @@ float a = normalize<float>('\127');
// b = 1.0f // b = 1.0f
float b = normalize<float, char>('\127'); float b = normalize<float, char>('\127');
@endcode @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) { 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()))/ 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 @note For best precision, `FloatingPoint` type should be always larger that
resulting `Integral` type (e.g. `double` to `int`, `long double` to `long long`). 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) { 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() + return std::numeric_limits<Integral>::min() +
@ -127,17 +131,23 @@ template<class Integral, class FloatingPoint> inline constexpr typename std::ena
} }
/** /**
* @brief Angle in degrees @brief Angle in degrees
*
* Function to make angle entering less error-prone. Converts the value to 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`. 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; } template<class T> inline constexpr T deg(T value) { return value*Constants<T>::pi()/180; }
/** /**
* @brief Angle in radians * @brief Angle in radians
* *
* See also deg(). * See deg() for more information.
*/ */
template<class T> inline constexpr T rad(T value) { return value; } template<class T> inline constexpr T rad(T value) { return value; }

2
src/Math/MathTypeTraits.h

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

95
src/Math/Matrix.h

@ -30,10 +30,11 @@ namespace Implementation {
#endif #endif
/** /**
* @brief %Matrix @brief %Matrix
*
* @todo @c PERFORMANCE - loop unrolling for Matrix<3, T> and Matrix<4, T> @configurationvalueref{Magnum::Math::Matrix}
* @todo first col, then row (cache adjacency) @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 { template<size_t size, class T> class Matrix {
static_assert(size != 0, "Matrix cannot have zero elements"); 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() */ friend class Matrix<size+1, T>; /* for ij() */
public: public:
const static size_t Size = size; /**< @brief %Matrix size */
typedef T Type; /**< @brief %Matrix data type */
/** /**
* @brief %Matrix from array * @brief %Matrix from array
* @return Reference to the data as if it was Matrix, thus doesn't * @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 T* data() { return _data; }
inline constexpr const T* data() const { return _data; } /**< @overload */ 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) { inline Vector<size, T>& operator[](size_t col) {
return Vector<size, T>::from(_data+col*size); 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); 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 */ /** @brief Equality operator */
inline bool operator==(const Matrix<size, T>& other) const { inline bool operator==(const Matrix<size, T>& other) const {
for(size_t i = 0; i != size*size; ++i) 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...); 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]; T _data[size*size];
}; };
/** @debugoperator{Matrix} */ /** @debugoperator{Magnum::Math::Matrix} */
template<class T, size_t size> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix<size, T>& value) { template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix<size, T>& value) {
debug << "Matrix("; debug << "Matrix(";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
for(size_t row = 0; row != size; ++row) { for(size_t row = 0; row != size; ++row) {
@ -321,7 +329,7 @@ template<size_t size, class T> class MatrixDeterminant {
T out(0); T out(0);
for(size_t col = 0; col != size; ++col) 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; return out;
} }
@ -331,7 +339,7 @@ template<class T> class MatrixDeterminant<2, T> {
public: public:
/** @brief Functor */ /** @brief Functor */
inline constexpr T operator()(const Matrix<2, T>& m) { 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: public:
/** @brief Functor */ /** @brief Functor */
inline constexpr T operator()(const Matrix<1, T>& m) { 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 #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 Provides functions for transformations in 2D. See also Matrix4 for 3D
transformations. transformations.
@configurationvalueref{Magnum::Math::Matrix3}
*/ */
template<class T> class Matrix3: public Matrix<3, T> { template<class T> class Matrix3: public Matrix<3, T> {
public: public:
@ -36,7 +37,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @brief 2D translation matrix * @brief 2D translation matrix
* @param vec Translation vector * @param vec Translation vector
* *
* @see Matrix4::translation() * @see Matrix4::translation(), Vector2::xAxis(), Vector2::yAxis()
*/ */
inline constexpr static Matrix3<T> translation(const Vector2<T>& vec) { inline constexpr static Matrix3<T> translation(const Vector2<T>& vec) {
return Matrix3<T>( /* Column-major! */ return Matrix3<T>( /* Column-major! */
@ -50,7 +51,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @brief 2D scaling matrix * @brief 2D scaling matrix
* @param vec Scaling vector * @param vec Scaling vector
* *
* @see Matrix4::scaling() * @see Matrix4::scaling(), Vector2::xScale(), Vector2::yScale()
*/ */
inline constexpr static Matrix3<T> scaling(const Vector2<T>& vec) { inline constexpr static Matrix3<T> scaling(const Vector2<T>& vec) {
return Matrix3<T>( /* Column-major! */ return Matrix3<T>( /* Column-major! */
@ -64,7 +65,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @brief 3D rotation matrix * @brief 3D rotation matrix
* @param angle Rotation angle (counterclockwise, in radians) * @param angle Rotation angle (counterclockwise, in radians)
* *
* @see Matrix4::rotation() * @see Matrix4::rotation(), deg(), rad()
*/ */
static Matrix3<T> rotation(T angle) { static Matrix3<T> rotation(T angle) {
return Matrix3<T>( /* Column-major! */ 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) 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) { 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); 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 #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 Provides functions for transformations in 3D. See also Matrix3 for 2D
transformations. transformations.
@configurationvalueref{Magnum::Math::Matrix4}
@todo Shearing @todo Shearing
@todo Reflection @todo Reflection
*/ */
@ -38,7 +39,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @brief 3D translation matrix * @brief 3D translation matrix
* @param vec Translation vector * @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) { inline constexpr static Matrix4<T> translation(const Vector3<T>& vec) {
return Matrix4<T>( /* Column-major! */ return Matrix4<T>( /* Column-major! */
@ -53,7 +54,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @brief 3D scaling matrix * @brief 3D scaling matrix
* @param vec Scaling vector * @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) { inline constexpr static Matrix4<T> scaling(const Vector3<T>& vec) {
return Matrix4<T>( /* Column-major! */ 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 angle Rotation angle (counterclockwise, in radians)
* @param vec Rotation vector * @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? * @todo optimize - Assume the vectors are normalized?
*/ */
static Matrix4<T> rotation(T angle, const Vector3<T>& vec) { 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) 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) { 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); 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 #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(MathVector3Test Vector3Test.cpp)
corrade_add_test2(MathVector4Test Vector4Test.cpp) corrade_add_test2(MathVector4Test Vector4Test.cpp)
corrade_add_test2(MathSwizzleTest SwizzleTest.cpp)
corrade_add_test2(MathMatrixTest MatrixTest.cpp) corrade_add_test2(MathMatrixTest MatrixTest.cpp)
corrade_add_test2(MathMatrix3Test Matrix3Test.cpp) corrade_add_test2(MathMatrix3Test Matrix3Test.cpp)
corrade_add_test2(MathMatrix4Test Matrix4Test.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 { namespace Magnum { namespace Math { namespace Test {
MathTest::MathTest() { MathTest::MathTest() {
addTests(&MathTest::degrad, addTests(&MathTest::constants,
&MathTest::degrad,
&MathTest::normalize, &MathTest::normalize,
&MathTest::denormalize, &MathTest::denormalize,
&MathTest::pow, &MathTest::pow,
&MathTest::log); &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() { void MathTest::degrad() {
CORRADE_COMPARE(deg(90.0), Constants<double>::pi()/2); CORRADE_COMPARE(deg(90.0), Constants<double>::pi()/2);
CORRADE_COMPARE(deg(90.0f), Constants<float>::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: public:
MathTest(); MathTest();
void constants();
void degrad(); void degrad();
void normalize(); void normalize();
void denormalize(); void denormalize();

14
src/Math/Test/Matrix3Test.cpp

@ -34,7 +34,8 @@ Matrix3Test::Matrix3Test() {
&Matrix3Test::translation, &Matrix3Test::translation,
&Matrix3Test::scaling, &Matrix3Test::scaling,
&Matrix3Test::rotation, &Matrix3Test::rotation,
&Matrix3Test::debug); &Matrix3Test::debug,
&Matrix3Test::configuration);
} }
void Matrix3Test::constructIdentity() { void Matrix3Test::constructIdentity() {
@ -103,4 +104,15 @@ void Matrix3Test::debug() {
" 8, 7, 8)\n"); " 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 translation();
void scaling(); void scaling();
void rotation(); void rotation();
void debug(); void debug();
void configuration();
}; };
}}} }}}

15
src/Math/Test/Matrix4Test.cpp

@ -37,7 +37,8 @@ Matrix4Test::Matrix4Test() {
&Matrix4Test::rotation, &Matrix4Test::rotation,
&Matrix4Test::rotationScalingPart, &Matrix4Test::rotationScalingPart,
&Matrix4Test::rotationPart, &Matrix4Test::rotationPart,
&Matrix4Test::debug); &Matrix4Test::debug,
&Matrix4Test::configuration);
} }
void Matrix4Test::constructIdentity() { void Matrix4Test::constructIdentity() {
@ -144,4 +145,16 @@ void Matrix4Test::debug() {
" 4, 3, 0, 9)\n"); " 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 rotationPart();
void debug(); void debug();
void configuration();
}; };
}}} }}}

28
src/Math/Test/MatrixTest.cpp

@ -44,7 +44,8 @@ MatrixTest::MatrixTest() {
&MatrixTest::ij, &MatrixTest::ij,
&MatrixTest::determinant, &MatrixTest::determinant,
&MatrixTest::inverted, &MatrixTest::inverted,
&MatrixTest::debug); &MatrixTest::debug,
&MatrixTest::configuration);
} }
void MatrixTest::construct() { void MatrixTest::construct() {
@ -124,9 +125,10 @@ void MatrixTest::data() {
m[3] = vector; m[3] = vector;
m[2][1] = 1.0f; 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); CORRADE_COMPARE(m[3], vector);
Matrix4 expected( Matrix4 expected(
@ -142,20 +144,20 @@ void MatrixTest::data() {
void MatrixTest::copy() { void MatrixTest::copy() {
Matrix4 m1(Matrix4::Zero); Matrix4 m1(Matrix4::Zero);
m1[2][3] = 1.0f; m1(2, 3) = 1.0f;
/* Copy */ /* Copy */
Matrix4 m2(m1); Matrix4 m2(m1);
Matrix4 m3; 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; m3 = m1;
/* Change original */ /* Change original */
m1[3][2] = 1.0f; m1(3, 2) = 1.0f;
/* Verify the copy is the same as original */ /* Verify the copy is the same as original */
Matrix4 original(Matrix4::Zero); Matrix4 original(Matrix4::Zero);
original[2][3] = 1.0f; original(2, 3) = 1.0f;
CORRADE_COMPARE(m2, original); CORRADE_COMPARE(m2, original);
CORRADE_COMPARE(m3, original); CORRADE_COMPARE(m3, original);
@ -307,4 +309,16 @@ void MatrixTest::debug() {
" 0, 0, 0, 1)\n"); " 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 inverted();
void debug(); void debug();
void configuration();
}; };
}}} }}}

22
src/Math/Test/Vector2Test.cpp

@ -30,17 +30,37 @@ typedef Math::Vector2<float> Vector2;
Vector2Test::Vector2Test() { Vector2Test::Vector2Test() {
addTests(&Vector2Test::construct, addTests(&Vector2Test::construct,
&Vector2Test::debug); &Vector2Test::axes,
&Vector2Test::scales,
&Vector2Test::debug,
&Vector2Test::configuration);
} }
void Vector2Test::construct() { void Vector2Test::construct() {
CORRADE_COMPARE(Vector2(1, 2), (Vector<2, float>(1.0f, 2.0f))); 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() { void Vector2Test::debug() {
ostringstream o; ostringstream o;
Debug(&o) << Vector2(0.5f, 15.0f); Debug(&o) << Vector2(0.5f, 15.0f);
CORRADE_COMPARE(o.str(), "Vector(0.5, 15)\n"); 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(); Vector2Test();
void construct(); void construct();
void axes();
void scales();
void debug(); void debug();
void configuration();
}; };
}}} }}}

21
src/Math/Test/Vector3Test.cpp

@ -32,9 +32,11 @@ typedef Math::Vector2<float> Vector2;
Vector3Test::Vector3Test() { Vector3Test::Vector3Test() {
addTests(&Vector3Test::construct, addTests(&Vector3Test::construct,
&Vector3Test::cross, &Vector3Test::cross,
&Vector3Test::axis, &Vector3Test::axes,
&Vector3Test::scales,
&Vector3Test::twoComponent, &Vector3Test::twoComponent,
&Vector3Test::debug); &Vector3Test::debug,
&Vector3Test::configuration);
} }
void Vector3Test::construct() { void Vector3Test::construct() {
@ -49,12 +51,18 @@ void Vector3Test::cross() {
CORRADE_COMPARE(Vector3::cross(a, b), Vector3(-10, -3, 7)); 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::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::yAxis(6.0f), Vector3(0.0f, 6.0f, 0.0f));
CORRADE_COMPARE(Vector3::zAxis(7.0f), Vector3(0.0f, 0.0f, 7.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() { void Vector3Test::twoComponent() {
CORRADE_COMPARE(Vector3(1.0f, 2.0f, 3.0f).xy(), Vector2(1.0f, 2.0f)); 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"); 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 construct();
void cross(); void cross();
void axis(); void axes();
void scales();
void twoComponent(); void twoComponent();
void debug(); void debug();
void configuration();
}; };
}}} }}}

10
src/Math/Test/Vector4Test.cpp

@ -34,7 +34,8 @@ Vector4Test::Vector4Test() {
addTests(&Vector4Test::construct, addTests(&Vector4Test::construct,
&Vector4Test::threeComponent, &Vector4Test::threeComponent,
&Vector4Test::twoComponent, &Vector4Test::twoComponent,
&Vector4Test::debug); &Vector4Test::debug,
&Vector4Test::configuration);
} }
void Vector4Test::construct() { void Vector4Test::construct() {
@ -57,4 +58,11 @@ void Vector4Test::debug() {
CORRADE_COMPARE(o.str(), "Vector(0.5, 15, 1, 1)\n"); 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 twoComponent();
void debug(); void debug();
void configuration();
}; };
}}} }}}

43
src/Math/Test/VectorTest.cpp

@ -28,15 +28,18 @@ using namespace Corrade::Utility;
namespace Magnum { namespace Math { namespace Test { namespace Magnum { namespace Math { namespace Test {
typedef Vector<4, float> Vector4; typedef Vector<4, float> Vector4;
typedef Vector<4, int> Vector4i;
typedef Vector<3, float> Vector3; typedef Vector<3, float> Vector3;
VectorTest::VectorTest() { VectorTest::VectorTest() {
addTests(&VectorTest::construct, addTests(&VectorTest::construct,
&VectorTest::constructFrom,
&VectorTest::data, &VectorTest::data,
&VectorTest::copy, &VectorTest::copy,
&VectorTest::dot, &VectorTest::dot,
&VectorTest::multiplyDivide, &VectorTest::multiplyDivide,
&VectorTest::addSubstract, &VectorTest::multiplyDivideComponentWise,
&VectorTest::addSubtract,
&VectorTest::dotSelf, &VectorTest::dotSelf,
&VectorTest::length, &VectorTest::length,
&VectorTest::normalized, &VectorTest::normalized,
@ -46,7 +49,8 @@ VectorTest::VectorTest() {
&VectorTest::max, &VectorTest::max,
&VectorTest::angle, &VectorTest::angle,
&VectorTest::negative, &VectorTest::negative,
&VectorTest::debug); &VectorTest::debug,
&VectorTest::configuration);
} }
void VectorTest::construct() { void VectorTest::construct() {
@ -56,6 +60,15 @@ void VectorTest::construct() {
CORRADE_COMPARE(Vector4::from(data), Vector4(1.0f, 2.0f, 3.0f, 4.0f)); 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() { void VectorTest::data() {
Vector4 v; Vector4 v;
v[2] = 1.5f; v[2] = 1.5f;
@ -95,15 +108,32 @@ void VectorTest::multiplyDivide() {
Vector4 multiplied(-1.5f, -3.0f, -4.5f, -6.0f); Vector4 multiplied(-1.5f, -3.0f, -4.5f, -6.0f);
CORRADE_COMPARE(vec*-1.5f, multiplied); CORRADE_COMPARE(vec*-1.5f, multiplied);
CORRADE_COMPARE(-1.5f*vec, multiplied);
CORRADE_COMPARE(multiplied/-1.5f, vec); CORRADE_COMPARE(multiplied/-1.5f, vec);
Math::Vector<1, char> vecChar(32); Math::Vector<1, char> vecChar(32);
Math::Vector<1, char> multipliedChar(-48); Math::Vector<1, char> multipliedChar(-48);
CORRADE_COMPARE(vecChar*-1.5f, multipliedChar); CORRADE_COMPARE(vecChar*-1.5f, multipliedChar);
CORRADE_COMPARE(multipliedChar/-1.5f, vecChar); 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 a(0.5f, -7.5f, 9.0f, -11.0f);
Vector4 b(-0.5, 1.0f, 0.0f, 7.5f); Vector4 b(-0.5, 1.0f, 0.0f, 7.5f);
Vector4 expected(0.0f, -6.5f, 9.0f, -3.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"); 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(); VectorTest();
void construct(); void construct();
void constructFrom();
void data(); void data();
void copy(); void copy();
void dot(); void dot();
void multiplyDivide(); void multiplyDivide();
void addSubstract(); void multiplyDivideComponentWise();
void addSubtract();
void dotSelf(); void dotSelf();
void length(); void length();
void normalized(); void normalized();
@ -40,6 +42,7 @@ class VectorTest: public Corrade::TestSuite::Tester<VectorTest> {
void negative(); void negative();
void debug(); void debug();
void configuration();
}; };
}}} }}}

214
src/Math/Vector.h

@ -22,11 +22,14 @@
#include <cmath> #include <cmath>
#include <limits> #include <limits>
#include <Utility/Debug.h> #include <Utility/Debug.h>
#include <Utility/Configuration.h>
#include "MathTypeTraits.h" #include "MathTypeTraits.h"
namespace Magnum { namespace Math { namespace Magnum { namespace Math {
template<size_t size, class T> class Vector;
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation { namespace Implementation {
template<size_t ...> struct Sequence {}; template<size_t ...> struct Sequence {};
@ -38,10 +41,20 @@ namespace Implementation {
template<size_t ...sequence> struct GenerateSequence<0, sequence...> { template<size_t ...sequence> struct GenerateSequence<0, sequence...> {
typedef Sequence<sequence...> Type; 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 #endif
/** @brief %Vector */ /**
@brief %Vector
@configurationvalueref{Magnum::Math::Vector}
@todo Constexprize all for loops
*/
template<size_t size, class T> class Vector { template<size_t size, class T> class Vector {
static_assert(size != 0, "Vector cannot have zero elements"); 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); 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 * @brief Dot product
* *
@ -161,45 +189,107 @@ template<size_t size, class T> class Vector {
/** /**
* @brief Multiply vector * @brief Multiply vector
* *
* Note that corresponding operator with swapped type order * @see operator*=(U), operator*(U, const Vector<size, T>&)
* (multiplying number with vector) is not available, because it would
* cause ambiguity in some cases.
*/ */
#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 { template<class U> inline Vector<size, T> operator*(U number) const {
#endif
return Vector<size, T>(*this)*=number; 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 * More efficient than operator*(U) const, because it does the
* in-place. * 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) { template<class U> Vector<size, T>& operator*=(U number) {
#endif
for(size_t i = 0; i != size; ++i) for(size_t i = 0; i != size; ++i)
(*this)[i] *= number; (*this)[i] *= number;
return *this; 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 { template<class U> inline Vector<size, T> operator/(U number) const {
#endif
return Vector<size, T>(*this)/=number; 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 * More efficient than operator/(U) const, because it does the
* in-place. * 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) { template<class U> Vector<size, T>& operator/=(U number) {
#endif
for(size_t i = 0; i != size; ++i) for(size_t i = 0; i != size; ++i)
(*this)[i] /= number; (*this)[i] /= number;
return *this; 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 */ /** @brief Add two vectors */
inline Vector<size, T> operator+(const Vector<size, T>& other) const { inline Vector<size, T> operator+(const Vector<size, T>& other) const {
return Vector<size, T>(*this)+=other; return Vector<size, T>(*this)+=other;
@ -218,13 +308,13 @@ template<size_t size, class T> class Vector {
return *this; return *this;
} }
/** @brief Substract two vectors */ /** @brief Subtract two vectors */
inline Vector<size, T> operator-(const Vector<size, T>& other) const { inline Vector<size, T> operator-(const Vector<size, T>& other) const {
return Vector<size, T>(*this)-=other; 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 * More efficient than operator-(), because it does the computation
* in-place. * in-place.
@ -318,8 +408,44 @@ template<size_t size, class T> class Vector {
T _data[size]; T _data[size];
}; };
/** @debugoperator{Vector} */ /** @relates Vector
template<class T, size_t size> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Vector<size, T>& value) { @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 << "Vector(";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
for(size_t i = 0; i != size; ++i) { 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) { \ inline constexpr static const Type<T>& from(const T* data) { \
return *reinterpret_cast<const Type<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) { \ 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); \ Vector<size, T>::operator*=(number); \
return *this; \ 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 { \ template<class U> inline Type<T> operator/(U number) const { \
return Vector<size, T>::operator/(number); \ return Vector<size, T>::operator/(number); \
} \ } \
template<class U> inline Type<T>& operator/=(U number) { \ template<class U> inline Type<T>& operator/=(U number) { \
Vector<size, T>::operator/=(number); \ Vector<size, T>::operator/=(number); \
return *this; \ 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 { \ 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> operator-() const { return Vector<size, T>::operator-(); } \
inline Type<T> normalized() const { return Vector<size, T>::normalized(); } 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 #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 #endif

53
src/Math/Vector2.h

@ -23,9 +23,51 @@
namespace Magnum { namespace Math { 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> { template<class T> class Vector2: public Vector<2, T> {
public: 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) */ /** @copydoc Vector::Vector(T) */
inline constexpr explicit Vector2(T value = T()): Vector<2, T>(value, value) {} 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) 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) { 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); 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 #endif

67
src/Math/Vector3.h

@ -23,18 +23,68 @@
namespace Magnum { namespace Math { 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> { template<class T> class Vector3: public Vector<3, T> {
public: 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()); } 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()); } 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); } 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 * @brief Cross product
* *
@ -92,11 +142,18 @@ template<class T> class Vector3: public Vector<3, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3) 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) { 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); 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 #endif

15
src/Math/Vector4.h

@ -23,7 +23,11 @@
namespace Magnum { namespace Math { 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> { template<class T> class Vector4: public Vector<4, T> {
public: public:
/** /**
@ -86,11 +90,18 @@ template<class T> class Vector4: public Vector<4, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4) 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) { 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); 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 #endif

32
src/Mesh.cpp

@ -20,7 +20,18 @@ using namespace std;
namespace Magnum { 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) for(auto it = _buffers.begin(); it != _buffers.end(); ++it)
delete it->first; delete it->first;
@ -29,6 +40,25 @@ Mesh::~Mesh() {
#endif #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* Mesh::addBuffer(BufferType interleaved) {
Buffer* buffer = new Buffer(Buffer::Target::Array); Buffer* buffer = new Buffer(Buffer::Target::Array);
_buffers.insert(make_pair(buffer, make_pair(interleaved, vector<Attribute>()))); _buffers.insert(make_pair(buffer, make_pair(interleaved, vector<Attribute>())));

14
src/Mesh.h

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

2
src/MeshTools/CombineIndexedArrays.h

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

6
src/MeshTools/CompressIndices.h

@ -78,10 +78,6 @@ class CompressIndices {
} }
#endif #endif
/** @addtogroup mesh
* @{
*/
/** /**
@brief Compress vertex indices @brief Compress vertex indices
@param indices Index array @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); return Implementation::CompressIndices{indices}(mesh, usage);
} }
/*@}*/
}} }}
#endif #endif

6
src/MeshTools/FlipNormals.h

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

2
src/MeshTools/GenerateFlatNormals.h

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

6
src/MeshTools/Interleave.h

@ -96,10 +96,6 @@ class Interleave {
} }
#endif #endif
/** @addtogroup mesh
* @{
*/
/** /**
@brief %Interleave vertex attributes @brief %Interleave vertex attributes
@param attribute First attribute array @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...); return Implementation::Interleave()(mesh, buffer, usage, attributes...);
} }
/*@}*/
}} }}
#endif #endif

2
src/MeshTools/Subdivide.h

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

2
src/MeshTools/Tipsify.h

@ -51,7 +51,7 @@ class MESHTOOLS_EXPORT Tipsify {
} }
#endif #endif
/** @ingroup mesh /**
@brief %Tipsify the mesh @brief %Tipsify the mesh
@param[in,out] indices Indices array to operate on @param[in,out] indices Indices array to operate on
@param[in] vertexCount Vertex count @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 @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. See @ref collision-detection for brief introduction.
*/ */
class PHYSICS_EXPORT ShapeGroup: public AbstractShape { class PHYSICS_EXPORT ShapeGroup: public AbstractShape {

2
src/Primitives/Capsule.h

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

4
src/Primitives/Cube.h

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

4
src/Primitives/Icosphere.h

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

2
src/Primitives/Plane.h

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

4
src/Primitives/UVSphere.h

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

5
src/Query.h

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

2
src/Renderbuffer.h

@ -23,7 +23,7 @@
namespace Magnum { namespace Magnum {
/** @ingroup textures /**
@brief %Renderbuffer @brief %Renderbuffer
Attachable to Framebuffer as render target. 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" #include "Light.h"
namespace Magnum { namespace Magnum { namespace SceneGraph {
void Light::clean(const Matrix4& absoluteTransformation) { void Light::clean(const Matrix4& absoluteTransformation) {
Object::clean(absoluteTransformation); Object::clean(absoluteTransformation);
@ -23,4 +23,4 @@ void Light::clean(const Matrix4& absoluteTransformation) {
_position = absoluteTransformation[3]; _position = absoluteTransformation[3];
} }
} }}

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

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