Browse Source

Merge branch 'master' into compatibility

Builds and passes tests at least with GCC 4.6 and 4.7.

Conflicts:
	src/CMakeLists.txt
	src/Math/Matrix4.h
	src/Math/Test/CMakeLists.txt
	src/Mesh.cpp
	src/MeshTools/CompressIndices.h
	src/MeshTools/Tipsify.cpp
	src/Physics/Test/ShapeGroupTest.cpp
	src/Primitives/Icosphere.h
	src/SceneGraph/Camera.cpp
	src/Test/SwizzleTest.cpp
	src/Trade/MeshData3D.cpp
	src/magnumCompatibility.h
Vladimír Vondruš 14 years ago
parent
commit
cd6113a29d
  1. 34
      CMakeLists.txt
  2. 49
      CONTRIBUTING.md
  3. 14
      Doxyfile
  4. 25
      README.md
  5. 29
      doc/building.dox
  6. 42
      doc/coding-style.dox
  7. 84
      doc/collision-detection.dox
  8. 8
      doc/features.dox
  9. 47
      doc/mainpage.dox
  10. 181
      doc/matrix-vector.dox
  11. 5
      doc/namespaces.dox
  12. 7
      doc/physics.dox
  13. 3
      doc/required-extensions.dox
  14. 22
      doc/unsupported.dox
  15. 6
      external/CMakeLists.txt
  16. 1
      external/GL/CMakeLists.txt
  17. 4552
      external/GL/glcorearb.h
  18. 1
      external/GLES3/CMakeLists.txt
  19. 1063
      external/GLES3/gl3.h
  20. 30
      external/GLES3/gl3platform.h
  21. 1
      external/KHR/CMakeLists.txt
  22. 269
      external/KHR/khrplatform.h
  23. 39
      modules/FindMagnum.cmake
  24. 18
      src/AbstractImage.cpp
  25. 6
      src/AbstractImage.h
  26. 482
      src/AbstractShaderProgram.cpp
  27. 1054
      src/AbstractShaderProgram.h
  28. 312
      src/AbstractTexture.cpp
  29. 365
      src/AbstractTexture.h
  30. 117
      src/Buffer.cpp
  31. 400
      src/Buffer.h
  32. 31
      src/BufferedImage.cpp
  33. 46
      src/BufferedImage.h
  34. 27
      src/BufferedTexture.cpp
  35. 63
      src/BufferedTexture.h
  36. 70
      src/CMakeLists.txt
  37. 47
      src/Color.h
  38. 265
      src/Context.cpp
  39. 273
      src/Context.h
  40. 16
      src/Contexts/AbstractContextHandler.h
  41. 12
      src/Contexts/AbstractWindowContext.h
  42. 25
      src/Contexts/AbstractXWindowContext.cpp
  43. 59
      src/Contexts/AbstractXWindowContext.h
  44. 102
      src/Contexts/CMakeLists.txt
  45. 125
      src/Contexts/EglContextHandler.cpp
  46. 29
      src/Contexts/EglContextHandler.h
  47. 86
      src/Contexts/EglInterface.cpp
  48. 2
      src/Contexts/ExtensionWrangler.cpp
  49. 13
      src/Contexts/GlutWindowContext.cpp
  50. 41
      src/Contexts/GlutWindowContext.h
  51. 21
      src/Contexts/GlxContextHandler.cpp
  52. 31
      src/Contexts/GlxContextHandler.h
  53. 18
      src/Contexts/GlxWindowContext.h
  54. 32
      src/Contexts/Sdl2WindowContext.cpp
  55. 100
      src/Contexts/Sdl2WindowContext.h
  56. 16
      src/Contexts/XEglWindowContext.h
  57. 60
      src/CubeMapTexture.h
  58. 68
      src/CubeMapTextureArray.h
  59. 109
      src/DimensionTraits.h
  60. 153
      src/Extensions.h
  61. 49
      src/Framebuffer.cpp
  62. 426
      src/Framebuffer.h
  63. 32
      src/Image.cpp
  64. 47
      src/Image.h
  65. 30
      src/ImageWrapper.h
  66. 63
      src/Implementation/BufferState.cpp
  67. 43
      src/Implementation/BufferState.h
  68. 30
      src/Implementation/MeshState.h
  69. 31
      src/Implementation/ShaderProgramState.h
  70. 34
      src/Implementation/State.cpp
  71. 39
      src/Implementation/State.h
  72. 34
      src/Implementation/TextureState.h
  73. 60
      src/IndexedMesh.cpp
  74. 113
      src/IndexedMesh.h
  75. 40
      src/Magnum.h
  76. 20
      src/Math/Algorithms/GaussJordan.h
  77. 3
      src/Math/CMakeLists.txt
  78. 79
      src/Math/Constants.h
  79. 126
      src/Math/Geometry/Distance.h
  80. 6
      src/Math/Geometry/Intersection.h
  81. 62
      src/Math/Geometry/Test/DistanceTest.cpp
  82. 6
      src/Math/Geometry/Test/DistanceTest.h
  83. 6
      src/Math/Math.cpp
  84. 63
      src/Math/Math.h
  85. 58
      src/Math/MathTypeTraits.h
  86. 74
      src/Math/Matrix.h
  87. 98
      src/Math/Matrix3.h
  88. 202
      src/Math/Matrix4.h
  89. 89
      src/Math/Point2D.h
  90. 90
      src/Math/Point3D.h
  91. 130
      src/Math/RectangularMatrix.h
  92. 18
      src/Math/Test/CMakeLists.txt
  93. 44
      src/Math/Test/ConstantsTest.cpp
  94. 32
      src/Math/Test/ConstantsTest.h
  95. 86
      src/Math/Test/MathTest.cpp
  96. 2
      src/Math/Test/MathTest.h
  97. 20
      src/Math/Test/MathTypeTraitsTest.cpp
  98. 43
      src/Math/Test/Matrix3Test.cpp
  99. 3
      src/Math/Test/Matrix3Test.h
  100. 64
      src/Math/Test/Matrix4Test.cpp
  101. Some files were not shown because too many files have changed in this diff Show More

34
CMakeLists.txt

@ -4,31 +4,26 @@ project(Magnum)
include(CMakeDependentOption)
option(TARGET_GLES "Build for OpenGL ES 2 instead of desktop OpenGL" OFF)
option(GCC46_COMPATIBILITY "Enable compatibility mode for GCC 4.6 (might disable some features)" OFF)
option(TARGET_GLES "Build for OpenGL ES instead of desktop OpenGL" OFF)
cmake_dependent_option(TARGET_GLES2 "Build for OpenGL ES 2" ON "TARGET_GLES" OFF)
# Parts of the library
option(WITH_EVERYTHING "Build everything (doesn't include contexts)" ON)
option(WITH_MESHTOOLS "Build MeshTools library" OFF)
option(WITH_PHYSICS "Build Physics library" OFF)
option(WITH_PRIMITIVES "Builf Primitives library" OFF)
option(WITH_SCENEGRAPH "Build SceneGraph library" OFF)
option(WITH_SHADERS "Build Shaders library" OFF)
cmake_dependent_option(WITH_MESHTOOLS "Build MeshTools library" OFF "NOT WITH_EVERYTHING" ON)
cmake_dependent_option(WITH_PHYSICS "Build Physics library" OFF "NOT WITH_EVERYTHING" ON)
cmake_dependent_option(WITH_PRIMITIVES "Builf Primitives library" OFF "NOT WITH_EVERYTHING" ON)
cmake_dependent_option(WITH_SCENEGRAPH "Build SceneGraph library" OFF "NOT WITH_EVERYTHING;NOT WITH_PHYSICS" ON)
cmake_dependent_option(WITH_SHADERS "Build Shaders library" OFF "NOT WITH_EVERYTHING;NOT WITH_PHYSICS" ON)
option(WITH_GLXCONTEXT "Build GlxContext library" OFF)
cmake_dependent_option(WITH_XEGLCONTEXT "Build XEglContext library" OFF "TARGET_GLES" OFF)
cmake_dependent_option(WITH_GLUTCONTEXT "Build GlutContext library" OFF "NOT TARGET_GLES" OFF)
option(WITH_SDL2CONTEXT "Build Sdl2Context library" OFF)
option(WITH_GLXWINDOWCONTEXT "Build GlxWindowContext library" OFF)
cmake_dependent_option(WITH_XEGLWINDOWCONTEXT "Build XEglWindowContext library" OFF "TARGET_GLES" OFF)
cmake_dependent_option(WITH_GLUTWINDOWCONTEXT "Build GlutWindowContext library" OFF "NOT TARGET_GLES" OFF)
option(WITH_SDL2WINDOWCONTEXT "Build Sdl2WindowContext library" OFF)
option(BUILD_TESTS "Build unit tests." OFF)
if(WITH_EVERYTHING)
set(WITH_MESHTOOLS ON)
set(WITH_PHYSICS ON)
set(WITH_PRIMITIVES ON)
set(WITH_SCENEGRAPH ON)
set(WITH_SHADERS ON)
endif()
if(BUILD_TESTS)
enable_testing()
endif()
@ -57,5 +52,8 @@ set(MAGNUM_LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX})
set(MAGNUM_CMAKE_MODULE_INSTALL_DIR ${CMAKE_ROOT}/Modules)
set(MAGNUM_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/Magnum)
include_directories(${CMAKE_SOURCE_DIR}/external)
add_subdirectory(external)
add_subdirectory(modules)
add_subdirectory(src)

49
CONTRIBUTING.md

@ -0,0 +1,49 @@
Bug reports, feature requests or code contributions are always very welcome.
To make things easier, here are a few tips:
Reporting bugs, requesting features
-----------------------------------
- Best way to report bugs and request new features is to use GitHub
[issues](https://github.com/mosra/magnum/issues), but you can contact me
also any other way.
Code contribution
-----------------
- Building and installing Magnum is described in the
[documentation](http://mosra.cz/blog/magnum-doc/building.html).
- Follow the project coding guidelines. In short - try to match style of
surrounding code and avoid any trailing whitespace. When in doubt, consult
coding guidelines, which are available also
[online](http://mosra.cz/blog/magnum-doc/coding-style.html).
- Document your code. When updating or adding new API, make sure that Doxygen
documentation is up to date. Run
doxygen
in project root to generate the documentation and check that your
modifications didn't add any warnings.
- Build unit tests (`-DBUILD_TESTS=ON` parameter to CMake) and run them
using
ctest --output-on-failure
in build directory. All tests should always pass. Add new tests or modify
the existing to make sure new code is properly covered (if possible). Here
is a [short tutorial](http://mosra.cz/blog/corrade-doc/unit-testing.html) to
help you with creating unit tests.
- Best way to contribute is by using GitHub
[pull requests](https://github.com/mosra/magnum/pulls) - fork the repository
and make pull request from feature branch. You can also send patches via
e-mail or contact me any other way.
- All your code will be released under license of the project, so make sure
you (or your employers) have no problems with it.
Contact
-------
- Website - http://mosra.cz/blog/
- GitHub - https://github.com/mosra/magnum
- E-mail - mosra@centrum.cz
- Jabber - mosra@jabbim.cz

14
Doxyfile

@ -200,7 +200,9 @@ ALIASES = \
"configurationvalue{1}=@brief %Configuration value parser and writer @xrefitem configurationvalues \"Configuration value parser and writer\" \"Configuration value parsers and writers for custom types\" Allows parsing and writing \1 from and to Corrade::Utility::Configuration." \
"collisionoperator{2}=@relates \1\n@brief Collision of %\1 and %\2\n@see \2::operator%(const \1&) const" \
"todoc=@xrefitem todoc \"Documentation todo\" \"Documentation-related todo list\"" \
"requires_gl=@xrefitem requires-gl \"Requires desktop OpenGL\" \"Functionality requiring desktop OpenGL (not available on OpenGL ES)\" Not available on OpenGL ES." \
"fn_gl{1}=<a href=\"http://www.opengl.org/sdk/docs/man4/xhtml/gl\1.xml\">gl\1()</a>" \
"fn_gl_extension{3}=<a href=\"http://www.opengl.org/registry/specs/\2/\3.txt\">gl\1<b></b>\2()</a>" \
"def_gl{1}=`GL_\1`" \
"requires_gl30=@xrefitem requires-gl30 \"Requires OpenGL 3.0\" \"Functionality requiring OpenGL 3.0\"" \
"requires_gl31=@xrefitem requires-gl31 \"Requires OpenGL 3.1\" \"Functionality requiring OpenGL 3.1\"" \
"requires_gl32=@xrefitem requires-gl32 \"Requires OpenGL 3.2\" \"Functionality requiring OpenGL 3.2\"" \
@ -212,8 +214,10 @@ ALIASES = \
"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_gl=@xrefitem requires-gl \"Requires desktop OpenGL\" \"Functionality requiring desktop OpenGL (not available in OpenGL ES)\"" \
"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>"
"es_extension{2}=<a href=\"http://www.khronos.org/registry/gles/extensions/\1/\1_\2.txt\"><tt>\1_\2</tt></a>" \
"es_extension2{3}=<a href=\"http://www.khronos.org/registry/gles/extensions/\1/\3.txt\"><tt>\1_\2</tt></a>"
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding
@ -396,7 +400,7 @@ EXTRACT_STATIC = NO
# defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included.
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_CLASSES = NO
# This flag is only useful for Objective-C code. When set to YES local
# methods, which are defined in the implementation section but not in
@ -700,6 +704,7 @@ INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.cpp \
*.h \
*.hpp \
*.dox
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
@ -729,6 +734,7 @@ EXCLUDE_SYMLINKS = NO
# for example use the pattern */test/*
EXCLUDE_PATTERNS = */Test/* \
*/Implementation/* \
*Visibility.h
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
@ -855,7 +861,7 @@ USE_HTAGS = NO
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
VERBATIM_HEADERS = YES
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index

25
README.md

@ -3,20 +3,23 @@ Features:
* Easy-to-use templated mathematical library for matrix/vector calculations
and geometry.
* Classes wrapping OpenGL objects and simplifying their usage - shaders,
buffers, meshes and textures. Access to framebuffer and occlusion queries.
* Mesh tools for cleaning, optimizing and generating meshes, utility classes
for color conversion, timeline and profiling.
* Hierarchical scene graph which supports transformation caching for better
performance, classes for convenient usage of shaders, buffers and textures.
Access to framebuffer and occlusion queries.
* Physics library for collision detection and rigid body dynamics. Mesh tools
for cleaning, optimizing and generating meshes.
performance, physics library for collision detection and rigid body
dynamics.
* Plugin-based data exchange framework for importing image, mesh, material
and scene data in various formats.
* Collection of pre-made graphic primitives and shaders for testing purposes.
* Classes for easy creation of OpenGL context with various toolkits.
* Classes for easy creation of OpenGL context with various toolkits, methods
for querying supported OpenGL version and available extensions.
* Comprehensive use of C++11 features for safety, performance and ease of
development. All code which doesn't directly interact with OpenGL is
covered with unit tests.
* Actively maintained Doxygen documentation. Occasionally updated snapshot is
also available online at http://mosra.cz/blog/magnum-doc .
also available online at http://mosra.cz/blog/magnum-doc/ .
INSTALLATION
============
@ -37,18 +40,18 @@ Minimal dependencies
**OpenGL ES 2** headers, if targeting OpenGL ES.
* **GLEW** - OpenGL extension wrangler
* **Corrade** - Plugin management and utility library. You can get it at
http://mosra.cz/blog/corrade.php
http://github.com/mosra/corrade or at http://mosra.cz/blog/corrade.php.
Compilation, installation
-------------------------
The library (for example with GLUT context) can be built and installed using
these four commands:
The library (for example with GLUT window context) can be built and installed
using these four commands:
mkdir -p build && cd build
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr \
-DWITH_GLUTCONTEXT=ON
-DWITH_GLUTWINDOWCONTEXT=ON
make
make install
@ -59,7 +62,7 @@ If you want to build also unit tests (which are not built by default), pass
`-DBUILD_TESTS=True` to CMake. Unit tests use Corrade's TestSuite framework
and can be run using
ctest -V
ctest --output-on-failure
in build directory. Everything should pass ;-)

29
doc/building.dox

@ -37,13 +37,14 @@ subdirectory:
git submodule update
@section building-compilation Compilation, installation
The library (for example with GLUT context) can be built and installed using
these four commands. See below for more information about optional features.
The library (for example with GLUT window context) can be built and installed
using these four commands. See below for more information about optional
features.
mkdir -p build && cd build
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr \
-DWITH_GLUTCONTEXT=ON
-DWITH_GLUTWINDOWCONTEXT=ON
make
make install
@ -59,29 +60,31 @@ By default the engine is built with everything except
@ref Contexts "context libraries". Using `WITH_*` CMake parameters you can
specify which parts will be built and which not:
- `WITH_EVERYTHING` - Defaults to `ON`, builds everything except contexts. If
set to `OFF`, only the main library is built and you can select additional
libraries with the following:
- `WITH_EVERYTHING` - Defaults to `ON`, builds everything except window
contexts. If set to `OFF`, only the main library is built and you can
select additional libraries with the following:
- `WITH_MESHTOOLS` - MeshTools library.
- `WITH_PHYSICS` - Physics library.
- `WITH_PRIMITIVES` - Primitives library.
- `WITH_SHADERS` - Shaders library.
None of the context libraries is built by default, regardless to
None of the window context libraries is built by default, regardless to
`WITH_EVERYTHING` is enabled or not:
- `WITH_EGLCONTEXT` - X/EGL context, available only if targeting OpenGL ES
(see above). Requires **X11** and **EGL** libraries.
- `WITH_GLUTCONTEXT` - GLUT context, available only if targeting desktop
OpenGL. Requires **GLUT** library.
- `WITH_SDL2CONTEXT` - SDL2 context. Requires **SDL2** library.
- `WITH_XEGLWINDOWCONTEXT` - X/EGL window context, available only if
targeting OpenGL ES (see above). Requires **X11** and **EGL** libraries.
- `WITH_GLXWINDOWCONTEXT` - GLX window context. Requires **X11** and **GLX**
libraries.
- `WITH_GLUTWINDOWCONTEXT` - GLUT window context, available only if targeting
desktop OpenGL. Requires **GLUT** library.
- `WITH_SDL2WINDOWCONTEXT` - SDL2 window context. Requires **SDL2** library.
@subsection building-tests Building and running unit tests
If you want to build also unit tests (which are not built by default), pass
`-DBUILD_TESTS=True` to CMake. Unit tests use Corrade's @ref Corrade::TestSuite
"TestSuite" framework and can be run using
ctest -V
ctest --output-on-failure
in build directory. Everything should pass ;-)

42
doc/coding-style.dox

@ -57,7 +57,39 @@ with @c \@extension command:
@extension{ARB,timer_query}
@endcode
It produces link to the specification of the extension in OpenGL registry,
e.g. @extension{ARB,timer_query}.
e.g. @extension{ARB,timer_query}. Similarly for OpenGL ES extensions there is
@c \@es_extension command. Some extensions have slightly different URL,
with command @c \@es_extension2 you can specify extension filename, if the
previous command gives 404 error. The following produces link to
@es_extension2{NV,read_buffer_front,GL_NV_read_buffer} extension:
@code
@es_extension2{NV,read_buffer_front,GL_NV_read_buffer}
@endcode
@subsubsection documentation-commands-ref_gl Links to related OpenGL functions and definitions
If an function touches OpenGL, related OpenGL functions should be documented
in @c \@see block with @c \@fn_gl command. If only specific definition is used
in the function, document it with @c \@def_gl command. Example usage:
@code
// @see @fn_gl{Enable}/@fn_gl{Disable} with @def_gl{TEXTURE_CUBE_MAP_SEAMLESS}
inline static void setSeamless(bool enabled) {
enabled ? glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) : glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
}
@endcode
It produces link to the online manual, in this case @fn_gl{Enable}/@fn_gl{Disable}
with @def_gl{TEXTURE_CUBE_MAP_SEAMLESS}.
For functions which are not part of OpenGL core specification, but only as
extensions, use @c \@fn_gl_extension command, e.g.
@code
@fn_gl_extension{NamedCopyBufferSubData,EXT,direct_state_access}
@endcode
First parameter is function name without the suffix, the second two parameters
are the same as in @c \@extension command. It produced link to extension
specification, with function name as link text, in this case
@fn_gl_extension{NamedCopyBufferSubData,EXT,direct_state_access}.
@subsubsection documentation-commands-requires Classes and functions requiring specific OpenGL version or extensions
@ -77,6 +109,14 @@ function, only the function should be marked. If the extension is needed only
for some functionality (not related to any member function), it should be
noted in the description.
Similarly for OpenGL ES there is command @c \@requires_gl for functionality
not available in OpenGL ES at all, @c \@requires_gles30 for functionality
requiring OpenGL ES 3.0 (i.e. not part of OpenGL 2.0) and
@c \@requires_es_extension for specific extensions not part of OpenGL ES
specification. When there is both required desktop OpenGL version/extension
and OpenGL ES version/extension, first come desktop requirements, then ES
requirements.
All classes and functions using those commands are cross-referenced in page
@ref required-extensions.

84
doc/collision-detection.dox

@ -5,56 +5,60 @@ namespace Magnum { namespace Physics {
The essential thing in collision detection is to define a complex object with
collection of simple shapes, for which it is easy to detect collisions. These
shapes can be either one-, two- or three-dimensional and they can be grouped
together using five different set operations.
together using various operations.
@tableofcontents
@section CollisionDetectionShapeCollection Available shapes
@section collision-detection-shape-collection Available shapes
@subsection CollisionDetectionShapes1D One-dimensional shapes
@subsection collision-detection-shapes1D One-dimensional shapes
- Physics::Point - @copybrief Physics::Point
- Physics::Line - @copybrief Physics::Line
- Physics::LineSegment - @copybrief Physics::LineSegment
- @ref Physics::Point "Physics::Point*D" - @copybrief Physics::Point
- @ref Physics::Line "Physics::Line*D" - @copybrief Physics::Line
- @ref Physics::LineSegment "Physics::LineSegment*D" - @copybrief Physics::LineSegment
One-dimensional shapes don't provide collision detection with each other
because of numerical instability.
Because of numerical instability it's not possible to detect collisions of
line and point. Collision of two lines can be detected only in 2D.
@subsection CollisionDetectionShapes2D Two-dimensional shapes
@subsection collision-detection-shapes2D Two-dimensional shapes
- Physics::Plane - @copybrief Physics::Plane
@subsection CollisionDetectionShapes3D Three-dimensional shapes
@subsection collision-detection-shapes3D Three-dimensional shapes
- Physics::Sphere - @copybrief Physics::Sphere
- Physics::Capsule - @copybrief Physics::Capsule
- Physics::AxisAlignedBox - @copybrief Physics::AxisAlignedBox
- Physics::Box - @copybrief Physics::Box
- @ref Physics::Sphere "Physics::Sphere*D" - @copybrief Physics::Sphere
- @ref Physics::Capsule "Physics::Capsule*D" - @copybrief Physics::Capsule
- @ref Physics::AxisAlignedBox "Physics::AxisAlignedBox*D" - @copybrief Physics::AxisAlignedBox
- @ref Physics::Box "Physics::Box*D" - @copybrief Physics::Box
The easiest (and most efficient) shape combination for detecting collisions
is point and sphere, followed by two spheres. Computing collision of two boxes
is least efficient.
@section CollisionDetectionShapeGroups Creating hierarchic groups of shapes
@section collision-detection-shape-groups Creating hierarchic groups of shapes
Shapes can be grouped together using one of five set operations: complement,
union, intersection, difference and XOR. These operations are mapped to
operator~(), operator|(), operator&(), operator-() and operator^(), so for
example creating complement of union of sphere and box is simple as this:
Shapes can be grouped together using one of three available logical
operations: AND, OR and NOT. These operations are mapped to operator&&(),
operator||() and operator!(), so for example creating negation of logical OR
of line segment and point is simple as this:
@code
Physics::Sphere sphere;
Physics::Box box;
Physics::LineSegment3D segment;
Physics::Point3D point;
Physics::ShapeGroup group = ~(sphere|box);
Physics::ShapeGroup3D group = !(segment || point);
@endcode
@note Logical operations are not the same as set operations -- intersection of
two spheres will not generate any collision if they are disjoint, but
logical AND will if the object collides with both of them.
The resulting object internally stores copies of both shapes, so the original
instances can be destroyed. For simple combinations appropriate resulting
shape is generated (e.g. intersection of line and three-dimensional object
can be a line segment) and stored inside ShapeGroup instead of two original
shape is generated (e.g. logical OR of point and sphere can be only the sphere,
if the point lies inside) and stored inside ShapeGroup instead of two original
objects.
@subsection CollisionDetectionShapeReference Referencing the shapes for later changes
@subsection collision-detection-shape-reference Referencing the shapes for later changes
Sometimes you may want to modify the shape based on changes of the object
itself. In previous example all the shapes were copied into ShapeGroup, so it
@ -62,40 +66,42 @@ was not possible to change their properties such as sphere radius without
recreating the group again. You can, however, explicitly pass a reference to
original object, so you can change it later:
@code
Physics::Sphere sphere;
Physics::Box box;
Physics::LineSegment3D segment;
Physics::Point3D point;
Physics::ShapeGroup group = ~(std::ref(sphere)|box);
Physics::ShapeGroup3D group = !(segment || std::ref(point));
sphere.setRadius(2.0f);
point.setPosition({1.0f, -6.0f, 0.5f});
@endcode
Note that passing a reference implies that you must not destroy the original
instance (in this case the sphere). Also because the referenced instance could
instance (in this case the point). Also because the referenced instance could
change, there are no shape optimizations done, unlike above.
@subsection CollisionDetectionShapeSimplification Providing simplified version of shape for better performance
@subsection collision-detection-shape-simplification Providing simplified version of shape for better performance
If there are many shapes grouped together, it might hurt performance of
collision detection, because it might be testing collision with more shapes
than necessary. It's then good to specify simplified version of such shape,
so the collision detection is done on the original if and only if collision
was detected with the simplified shape. It is in fact intersection group -
the collision is initially detected on first (simplified) shape and then on
the other:
was detected with the simplified shape. It is in fact logical AND using
operator&&() - the collision is initially detected on first (simplified) shape
and then on the other:
@code
Physics::AxisAlignedBox simplified;
Physics::Sphere3D sphere;
Physics::Box3D box;
Physics::AxisAlignedBox3D simplified;
Physics::ShapeGroup object = simplified & (sphere|box);
Physics::ShapeGroup3D object = simplified && (sphere || box);
@endcode
@section CollisionDetectionShapeCollisions Detecting shape collisions
@section collision-detection-shape-collisions Detecting shape collisions
Shape pairs which have collision detection implemented can be tested for
collision using operator%(), for example:
@code
Physics::Point point;
Physics::Sphere sphere;
Physics::Point3D point;
Physics::Sphere3D sphere;
bool collide = point % sphere;
@endcode

8
doc/features.dox

@ -0,0 +1,8 @@
namespace Magnum {
/** @page features Feature overview
@brief Fundamental principles and design goals
- @subpage matrix-vector - @copybrief matrix-vector
- @subpage collision-detection - @copybrief collision-detection
*/
}

47
doc/mainpage.dox

@ -4,22 +4,26 @@ namespace Magnum {
%Magnum is 3D graphics engine written in C++11 and OpenGL 3 Core Profile.
Features:
- Easy-to-use templated @ref Math "mathematical library" for matrix/vector
calculations and @ref Math::Geometry "geometry".
- Easy-to-use templated @ref Math "mathematical library" for
@ref matrix-vector "matrix/vector calculations" and
@ref Math::Geometry "geometry".
- Classes wrapping OpenGL objects and simplifying their usage -
@ref AbstractShaderProgram "shaders", @ref Buffer "buffers",
@ref Mesh "meshes" and @ref AbstractTexture "textures". Access to
@ref Framebuffer "framebuffer" and @ref AbstractQuery "occlusion queries".
- @ref MeshTools "Mesh tools" for cleaning, optimizing and generating meshes,
utility classes for @ref Color.h "color conversion", @ref Timeline "timeline"
and @ref Profiler "profiling".
- Hierarchical @ref SceneGraph "scene graph" which supports transformation
caching for better performance, classes for convenient usage of
@ref AbstractShaderProgram "shaders", @ref Buffer "buffers" and
@ref AbstractTexture "textures". Access to @ref Framebuffer "framebuffer"
and @ref AbstractQuery "occlusion queries".
- @ref Physics "Physics library" for collision detection and rigid body
dynamics, @ref MeshTools "Mesh tools" for cleaning, optimizing and
generating meshes.
caching for better performance, @ref Physics "physics library" for collision
detection and rigid body dynamics.
- Plugin-based @ref Trade "data exchange framework" for importing image, mesh,
material and scene data in various formats.
- Collection of pre-made @ref Primitives "graphic primitives" and
@ref Shaders "shaders" for testing purposes.
- Classes for easy creation of OpenGL context with @ref Contexts
"various toolkits".
"various toolkits", methods for querying
@ref Context "supported OpenGL version and available extensions".
- Comprehensive use of C++11 features for safety, performance and ease of
development. All code which doesn't directly interact with OpenGL is
covered with unit tests.
@ -34,21 +38,20 @@ Guide @ref building "how to download and build Magnum" on different platforms.
@section getting-started Getting started
Applications using %Magnum have at least two parts. One part manages OpenGL
context using some toolkit and takes care of window resizing, mouse and
keyboard input, while the other manages the scene and does the rendering.
While it is possible for you to manage the OpenGL context and events on your
own, %Magnum provides implementations for the most common toolkits (such as
GLUT, SDL or Qt) in Contexts namespace. %Scene in %Magnum is composed of
hierarchically connected object instances. To build the scene you need Scene
object with assigned camera and at least one Object instance.
To get up and running, you must first subclass one of the provided window
context classes and implement required functions. %Magnum provides
implementations for the most common toolkits (such as GLUT, Xlib, or SDL2) in
Contexts namespace.
Then you can either draw your meshes directly or use SceneGraph which will
help you with object hierarchy, transformations and resource management.
@subsection getting-started-examples Tutorials and examples
The best way to get started is to @ref examples-triangle "render your first triangle"
in step-by-step tutorial. Then you can dig deeper and try @ref example-index
"other examples", read about fundamental principles in the documentation or
start experimenting on your own!
The best way to get started is to render your first triangle in
@ref example-index "step-by-step tutorial". Then you can dig deeper and try
other examples, read about @ref features "fundamental principles" in the
documentation or start experimenting on your own!
@subsection getting-started-hacking Hacking Magnum

181
doc/matrix-vector.dox

@ -0,0 +1,181 @@
namespace Magnum { namespace Math {
/** @page matrix-vector Operations with matrices and vectors
@brief Introduction to essential classes of the graphics pipeline.
@tableofcontents
Matrices and vectors are the most important part of graphics programming and
one of goals of %Magnum is to make their usage as intuitive as possible. This
page will overview their usage and introduce some tricks to make your life
easier.
@section matrix-vector-hierarchy Matrix and vector classes
%Magnum has three main matrix and vector classes: RectangularMatrix, (square)
Matrix and Vector. To achieve greatest code reuse, %Matrix is internally
square %RectangularMatrix and %Vector is internally one-column
%RectangularMatrix. Both vectors and matrices can have arbitrary size (known
at compile time) and can store any meaningful type.
Each subclass brings some specialization to its superclass and for most common
vector and matrix sizes there are specialized classes Matrix3 and Matrix4,
implementing various transformation in 2D and 3D, Vector2, Vector3 and Vector4,
implementing direct access to named components. Functions of each class try to
return the most specialized type known to make subsequent operations more
convenient - columns of %RectangularMatrix are returned as %Vector, but when
accessing columns of e.g. %Matrix3, they are returned as %Vector3.
There are also even more specialized subclasses - Point2D, Point3D for
creating points with homogeneous coordinates and Color3, Color4 for color
handling and conversion.
@section matrix-vector-construction Constructing matrices and vectors
Default constructors of RectangularMatrix and Vector (and Vector2, Vector3,
Vector4, Color3) create zero-filled objects. Matrix (and Matrix3, Matrix4) is
by default constructed as identity matrix. Point2D and Point3D have
homogeneous component set to one, Color4 has alpha value set to opaque.
@code
RectangularMatrix<2, 3, int> a; // zero-filled
Vector<3, int> b; // zero-filled
Matrix<3, int> identity; // diagonal set to 1
Matrix<3, int> zero(Matrix<3, int>::Zero); // zero-filled
Point2D<int> c; // {0, 0, 1}
Point3D<int> d; // {0, 0, 0, 1}
Color4<float> black1; // {0.0f, 0.0f, 0.0f, 1.0f}
Color4<unsigned char> black2; // {0, 0, 0, 255}
@endcode
Most common and most efficient way to create matrix or vector is to pass
values of all components to the constructor.
@code
Matrix3<int> mat(0, 1, 2,
3, 4, 5,
6, 7, 8); // column-major (see explanation why below)
Vector3<int> vec(0, 1, 2);
@endcode
All constructors check number of passed arguments and the errors are catched
at compile time.
You can specify all components of vector or whole diagonal of square matrix at
once:
@code
Matrix3<int> diag(Matrix3<int>::Identity, 2); // diagonal set to 2, zeros elsewhere
Vector3<int> fill(10); // {10, 10, 10}
@endcode
Vectors are commonly used to specify various axes and scaling coefficients in
transformations, you can use convenience functions instead of typing out all
other elements:
@code
Matrix4::rotation(deg(5.0f), Vector3::xAxis()); // {1.0f, 0.0f, 0.0f}
Matrix3::translation(Vector2::yAxis(2.0f)); // {0.0f, 2.0f}
Matrix4::scaling(Vector3::zScale(-10.0f)); // {1.0f, 1.0f, -10.0f}
@endcode
It is possible to create matrices from other matrices and vectors with the
same row count; vectors from vector and scalar:
@code
RectangularMatrix<2, 3, int> a;
Vector3<int> b, c;
Matrix3<int> mat = Matrix3<int>::from(b, a, c);
Vector<8, int> vec = Vector<8, int>::from(1, b, 2, c);
@endcode
It is also possible to create them from an C-style array. The function does
simple type cast without any copying, so it's possible to conveniently operate
on the array itself:
@code
int[] mat = { 2, 4, 6,
1, 3, 5 };
RectangularMatrix<2, 3, int>::from(mat) *= 2; // mat == { 4, 8, 12, 2, 6, 10 }
@endcode
Note that unlike constructors, this function has no way to check whether the
array is long enough to contain all elements, so use with caution.
You can also convert between data types:
@code
Vector4<float> floating(1.3f, 2.7f, -15.0f, 7.0f);
Vector4<int> integral(Vector4<int>::from(floating)); // {1, 2, -15, 7}
@endcode
@section matrix-vector-component-access Accessing matrix and vector components
Column vectors of matrices and vector components can be accessed using square
brackets, there is also round bracket operator for accessing matrix components
directly:
@code
RectangularMatrix<3, 2, int> a;
a[2] /= 2; // third column (column major indexing, see explanation below)
a[0][1] = 5; // first column, second element
a(0, 1) += 3; // first column, second element (preferred)
Vector<3, int> b;
b[1] = 1; // second element
@endcode
For accessing matrix element prefer round bracket operator, as it is possibly
faster than the double square brackets (but never slower) and isn't prone to
compiler mis-optimizations.
Fixed-size vector subclasses have functions for accessing named components
and subparts:
@code
Vector4<int> a;
int x = a.x();
a.y() += 5;
Vector3<int> xyz = a.xyz();
xyz.xy() *= 5;
@endcode
Color3 and Color4 name their components `rgba` instead of `xyzw`.
For more involved operations with components there are two swizzle() functions,
they have the same features, but one is guaranteed to do most of the work at
compile-time, while the second has more convenient syntax:
@code
Vector4<int> original(-1, 2, 3, 4);
Vector4<int> bgra = swizzle<'b', 'g', 'r', 'a'>(original); // { 3, 2, -1, 4 }
Vector<6, int> a10rgb = swizzle(original, "a10rgb"); // { 4, 1, 0, -1, 2, 3 }
@endcode
@section matrix-vector-column-major Matrices are column-major and vectors are columns
OpenGL matrices are column-major, thus it is reasonable to have matrices in
%Magnum also column major (and vectors as columns). This has naturally some
implications and it may differ from what is common in mathematics:
- Order of template arguments in specification of RectangularMatrix is also
column-major:
@code
RectangularMatrix<2, 3, int> mat; // two columns, three rows
@endcode
- Order of components in matrix constructors is also column-major, so the
elements passed in constructor doesn't need to be reordered internally
before putting them into data array:
@code
Matrix3<int> mat(0, 1, 2,
3, 4, 5,
6, 7, 8); // first column is {0, 1, 2}
@endcode
- Element accessing order is also column-major. It costs virtually no time to
return reference to portion of data array as column vector, thus the bracket
operator is accessing columns. Returned vector has also its own bracket
operator, which is indexing rows. To avoid confusion, first parameter of
round bracket operator is thus also column index.
@code
mat[0] *= 2; // first column
mat[2][0] = 5; // first element of first column vector
mat(2, 0) += 3; // first element of first column
@endcode
- Various algorithms which commonly operate on matrix rows (such as
@ref Algorithms::GaussJordan "Gauss-Jordan elimination") have faster
alternatives which operate on columns. It's then up to user decision to
operate with transposed matrices or use the slower non-transposed
alternative of the algorithm.
*/
}}

5
doc/namespaces.dox

@ -25,7 +25,8 @@ Base classes for creating OpenGL contexts with various toolkits.
/** @namespace Magnum::Math
@brief %Math library
Template classes for matrix and vector calculations.
Template classes for matrix and vector calculations. See @ref matrix-vector
for brief introduction.
*/
/** @dir Math/Algorithms
@ -89,7 +90,7 @@ Collection of shaders for testing purposes.
/** @namespace Magnum::Physics
@brief %Physics library
Collision detection system and rigid body objects. See @ref physics
Collision detection system and rigid body objects. See @ref collision-detection
for introduction.
*/

7
doc/physics.dox

@ -1,7 +0,0 @@
namespace Magnum { namespace Physics {
/** @page physics Physics library
@brief Collision detection and rigid body dynamics.
@subpage collision-detection
*/
}}

3
doc/required-extensions.dox

@ -12,7 +12,6 @@ functionality, so if given hardware supports required extension, it doesn't
need to have required OpenGL version too (e.g. `APPLE_vertex_array_object` is
supported on Intel GPUs even if they are capable of OpenGL 2.1 only).
- @subpage requires-gl
- @subpage requires-gl30
- @subpage requires-gl31
- @subpage requires-gl32
@ -22,8 +21,10 @@ supported on Intel GPUs even if they are capable of OpenGL 2.1 only).
- @subpage requires-gl42
- @subpage requires-gl43
- @subpage requires-extension
- @subpage requires-gl
- @subpage requires-gles30
- @subpage requires-es-extension
- @subpage unsupported
@page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES)
@page requires-gl30 Functionality requiring OpenGL 3.0

22
doc/unsupported.dox

@ -0,0 +1,22 @@
/** @page unsupported Unsupported OpenGL features
Some functionality, which is either soon-to-be deprecated or isn't proven to
add any performance gains, is not supported in %Magnum.
@section unsupported-features Unsupported features
- Luminance texture formats (OpenGL ES) are not supported, as they are
deprecated in OpenGL ES 3.0 and not present in core desktop OpenGL.
- Fixed precision data types (OpenGL ES) are not supported, as they occupy the
same memory as floats and they aren't faster than floats on current hardware
anymore.
@section unsupported-extensions Unsupported extensions
- @extension{INTEL,map_texture} negatively affects texture access performance.
Combination of buffer mapping and pixel buffers might be of the same or
better performance, without affecting texture access speed.
- @extension{NV,draw_texture} can be done with framebuffer blitting and
doesn't make any full-screen postprocessing easier, as shaders are excluded.
*/

6
external/CMakeLists.txt vendored

@ -0,0 +1,6 @@
if(NOT TARGET_GLES)
add_subdirectory(GL)
else()
add_subdirectory(GLES3)
add_subdirectory(KHR)
endif()

1
external/GL/CMakeLists.txt vendored

@ -0,0 +1 @@
install(FILES glcorearb.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/external/GL)

4552
external/GL/glcorearb.h vendored

File diff suppressed because it is too large Load Diff

1
external/GLES3/CMakeLists.txt vendored

@ -0,0 +1 @@
install(FILES gl3.h gl3platform.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/external/GLES3)

1063
external/GLES3/gl3.h vendored

File diff suppressed because it is too large Load Diff

30
external/GLES3/gl3platform.h vendored

@ -0,0 +1,30 @@
#ifndef __gl3platform_h_
#define __gl3platform_h_
/* $Revision: 18437 $ on $Date:: 2012-07-08 23:31:39 -0700 #$ */
/*
* This document is licensed under the SGI Free Software B License Version
* 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
*/
/* Platform-specific types and definitions for OpenGL ES 3.X gl3.h
*
* Adopters may modify khrplatform.h and this file to suit their platform.
* You are encouraged to submit all modifications to the Khronos group so that
* they can be included in future versions of this file. Please submit changes
* by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
* by filing a bug against product "OpenGL-ES" component "Registry".
*/
#include <KHR/khrplatform.h>
#ifndef GL_APICALL
#define GL_APICALL KHRONOS_APICALL
#endif
#ifndef GL_APIENTRY
#define GL_APIENTRY KHRONOS_APIENTRY
#endif
#endif /* __gl3platform_h_ */

1
external/KHR/CMakeLists.txt vendored

@ -0,0 +1 @@
install(FILES khrplatform.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/external/KHR)

269
external/KHR/khrplatform.h vendored

@ -0,0 +1,269 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2009 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by sending them to the public Khronos Bugzilla
* (http://khronos.org/bugzilla) by filing a bug against product
* "Khronos (general)" component "Registry".
*
* A predefined template which fills in some of the bug fields can be
* reached using http://tinyurl.com/khrplatform-h-bugreport, but you
* must create a Bugzilla login first.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */

39
modules/FindMagnum.cmake

@ -16,7 +16,8 @@
# libraries. Additional dependencies are specified by the components. The
# optional components are:
# MeshTools - MeshTools library
# Physics - Physics library
# Physics - Physics library (depends on Primitives, SceneGraph and
# Shaders components)
# Primitives - Library with stock geometric primitives (static)
# SceneGraph - Scene graph library
# Shaders - Library with stock shaders
@ -77,6 +78,13 @@ else()
find_package(OpenGLES2 REQUIRED)
endif()
# On Windows, *WindowContext libraries need to have ${MAGNUM_LIBRARY} listed
# in dependencies also after *WindowContext.lib static library name to avoid
# linker errors
if(WIN32)
set(_WINDOWCONTEXT_MAGNUM_LIBRARY_DEPENDENCY ${MAGNUM_LIBRARY})
endif()
# Additional components
foreach(component ${Magnum_FIND_COMPONENTS})
string(TOUPPER ${component} _COMPONENT)
@ -86,48 +94,48 @@ foreach(component ${Magnum_FIND_COMPONENTS})
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX ${component})
# Contexts
if(${component} MATCHES .+Context)
# Window contexts
if(${component} MATCHES .+WindowContext)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Contexts)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES ${component}.h)
# GLUT context dependencies
if(${component} STREQUAL GlutContext)
# GLUT window context dependencies
if(${component} STREQUAL GlutWindowContext)
find_package(GLUT)
if(GLUT_FOUND)
set(_MAGNUM_${_COMPONENT}_LIBRARIES ${GLUT_LIBRARIES})
set(_MAGNUM_${_COMPONENT}_LIBRARIES ${GLUT_LIBRARIES} ${_WINDOWCONTEXT_MAGNUM_LIBRARY_DEPENDENCY})
else()
unset(MAGNUM_${_COMPONENT}_LIBRARY)
endif()
endif()
# SDL2 context dependencies
if(${component} STREQUAL Sdl2Context)
# SDL2 window context dependencies
if(${component} STREQUAL Sdl2WindowContext)
find_package(SDL2)
if(SDL2_FOUND)
set(_MAGNUM_${_COMPONENT}_LIBRARIES ${SDL2_LIBRARY})
set(_MAGNUM_${_COMPONENT}_LIBRARIES ${SDL2_LIBRARY} ${_WINDOWCONTEXT_MAGNUM_LIBRARY_DEPENDENCY})
set(_MAGNUM_${_COMPONENT}_INCLUDE_DIRS ${SDL2_INCLUDE_DIR})
else()
unset(MAGNUM_${_COMPONENT}_LIBRARY)
endif()
endif()
# GLX context dependencies
if(${component} STREQUAL GlxContext)
# GLX window context dependencies
if(${component} STREQUAL GlxWindowContext)
find_package(X11)
if(X11_FOUND)
set(_MAGNUM_${_COMPONENT}_LIBRARIES ${X11_LIBRARIES})
set(_MAGNUM_${_COMPONENT}_LIBRARIES ${X11_LIBRARIES} ${_WINDOWCONTEXT_MAGNUM_LIBRARY_DEPENDENCY})
else()
unset(MAGNUM_${_COMPONENT}_LIBRARY)
endif()
endif()
# X/EGL context dependencies
if(${component} STREQUAL XEglContext)
# X/EGL window context dependencies
if(${component} STREQUAL XEglWindowContext)
find_package(EGL)
find_package(X11)
if(EGL_FOUND AND X11_FOUND)
set(_MAGNUM_${_COMPONENT}_LIBRARIES ${EGL_LIBRARY} ${X11_LIBRARIES})
set(_MAGNUM_${_COMPONENT}_LIBRARIES ${EGL_LIBRARY} ${X11_LIBRARIES} ${_WINDOWCONTEXT_MAGNUM_LIBRARY_DEPENDENCY})
else()
unset(MAGNUM_${_COMPONENT}_LIBRARY)
endif()
@ -186,6 +194,7 @@ find_package_handle_standard_args(Magnum
# Dependent libraries and includes
set(MAGNUM_INCLUDE_DIRS ${MAGNUM_INCLUDE_DIR}
${MAGNUM_INCLUDE_DIR}/external
${CORRADE_INCLUDE_DIR})
set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARY}
${CORRADE_UTILITY_LIBRARY}

18
src/AbstractImage.cpp

@ -14,8 +14,13 @@
*/
#include "AbstractImage.h"
#include <Utility/Debug.h>
#include "TypeTraits.h"
using namespace std;
namespace Magnum {
size_t AbstractImage::pixelSize(Components format, ComponentType type) {
@ -69,6 +74,8 @@ size_t AbstractImage::pixelSize(Components format, ComponentType type) {
switch(format) {
#ifndef MAGNUM_TARGET_GLES
case Components::Red:
case Components::Green:
case Components::Blue:
return 1*size;
case Components::RedGreen:
return 2*size;
@ -83,9 +90,16 @@ size_t AbstractImage::pixelSize(Components format, ComponentType type) {
case Components::BGRA:
#endif
return 4*size;
default:
return 0;
#ifndef MAGNUM_TARGET_GLES
case Components::Depth:
case Components::StencilIndex:
case Components::DepthStencil:
CORRADE_INTERNAL_ASSERT(false);
#endif
}
return 0;
}
}

6
src/AbstractImage.h

@ -19,8 +19,12 @@
* @brief Class Magnum::AbstractImage
*/
#include <cstddef>
#include "Magnum.h"
#include "magnumVisibility.h"
namespace Magnum {
/**
@ -264,7 +268,7 @@ class MAGNUM_EXPORT AbstractImage {
* @param components Color components
* @param type Data type
*/
static size_t pixelSize(Components components, ComponentType type);
static std::size_t pixelSize(Components components, ComponentType type);
/**
* @brief Constructor

482
src/AbstractShaderProgram.cpp

@ -17,16 +17,76 @@
#include <fstream>
#include "Math/Matrix.h"
#include "Shader.h"
#include "Implementation/State.h"
#include "Implementation/ShaderProgramState.h"
#include "Extensions.h"
#define LINKER_MESSAGE_MAX_LENGTH 1024
using namespace std;
namespace Magnum {
AbstractShaderProgram::Uniform1fImplementation AbstractShaderProgram::uniform1fImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform2fvImplementation AbstractShaderProgram::uniform2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform3fvImplementation AbstractShaderProgram::uniform3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform4fvImplementation AbstractShaderProgram::uniform4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform1iImplementation AbstractShaderProgram::uniform1iImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform2ivImplementation AbstractShaderProgram::uniform2ivImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform3ivImplementation AbstractShaderProgram::uniform3ivImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform4ivImplementation AbstractShaderProgram::uniform4ivImplementation = &AbstractShaderProgram::uniformImplementationDefault;
#ifndef MAGNUM_TARGET_GLES2
AbstractShaderProgram::Uniform1uiImplementation AbstractShaderProgram::uniform1uiImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform2uivImplementation AbstractShaderProgram::uniform2uivImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform3uivImplementation AbstractShaderProgram::uniform3uivImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform4uivImplementation AbstractShaderProgram::uniform4uivImplementation = &AbstractShaderProgram::uniformImplementationDefault;
#endif
#ifndef MAGNUM_TARGET_GLES
AbstractShaderProgram::Uniform1dImplementation AbstractShaderProgram::uniform1dImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform2dvImplementation AbstractShaderProgram::uniform2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform3dvImplementation AbstractShaderProgram::uniform3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::Uniform4dvImplementation AbstractShaderProgram::uniform4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
#endif
AbstractShaderProgram::UniformMatrix2fvImplementation AbstractShaderProgram::uniformMatrix2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix3fvImplementation AbstractShaderProgram::uniformMatrix3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix4fvImplementation AbstractShaderProgram::uniformMatrix4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
#ifndef MAGNUM_TARGET_GLES2
AbstractShaderProgram::UniformMatrix2x3fvImplementation AbstractShaderProgram::uniformMatrix2x3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix3x2fvImplementation AbstractShaderProgram::uniformMatrix3x2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix2x4fvImplementation AbstractShaderProgram::uniformMatrix2x4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix4x2fvImplementation AbstractShaderProgram::uniformMatrix4x2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix3x4fvImplementation AbstractShaderProgram::uniformMatrix3x4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix4x3fvImplementation AbstractShaderProgram::uniformMatrix4x3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
#endif
#ifndef MAGNUM_TARGET_GLES
AbstractShaderProgram::UniformMatrix2dvImplementation AbstractShaderProgram::uniformMatrix2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix3dvImplementation AbstractShaderProgram::uniformMatrix3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix4dvImplementation AbstractShaderProgram::uniformMatrix4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix2x3dvImplementation AbstractShaderProgram::uniformMatrix2x3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix3x2dvImplementation AbstractShaderProgram::uniformMatrix3x2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix2x4dvImplementation AbstractShaderProgram::uniformMatrix2x4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix4x2dvImplementation AbstractShaderProgram::uniformMatrix4x2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix3x4dvImplementation AbstractShaderProgram::uniformMatrix3x4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
AbstractShaderProgram::UniformMatrix4x3dvImplementation AbstractShaderProgram::uniformMatrix4x3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
#endif
AbstractShaderProgram::~AbstractShaderProgram() {
/* Remove current usage from the state */
GLuint& current = Context::current()->state()->shaderProgram->current;
if(current == _id) current = 0;
glDeleteProgram(_id);
}
bool AbstractShaderProgram::use() {
if(state != Linked) return false;
glUseProgram(program);
/* Use only if the program isn't already in use */
GLuint& current = Context::current()->state()->shaderProgram->current;
if(current != _id) glUseProgram(current = _id);
return true;
}
@ -34,26 +94,26 @@ bool AbstractShaderProgram::attachShader(Shader& shader) {
GLuint _shader = shader.compile();
if(!_shader) return false;
glAttachShader(program, _shader);
glAttachShader(_id, _shader);
return true;
}
void AbstractShaderProgram::bindAttributeLocation(GLuint location, const string& name) {
CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: attribute cannot be bound after linking.", );
glBindAttribLocation(program, location, name.c_str());
glBindAttribLocation(_id, location, name.c_str());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::bindFragmentDataLocation(GLuint location, const std::string& name) {
CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", );
glBindFragDataLocation(program, location, name.c_str());
glBindFragDataLocation(_id, 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());
glBindFragDataLocationIndexed(_id, location, index, name.c_str());
}
#endif
@ -62,15 +122,15 @@ void AbstractShaderProgram::link() {
if(state != Initialized) return;
/* Link shader program */
glLinkProgram(program);
glLinkProgram(_id);
/* Check link status */
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
glGetProgramiv(_id, GL_LINK_STATUS, &status);
/* Display errors or warnings */
char message[LINKER_MESSAGE_MAX_LENGTH];
glGetProgramInfoLog(program, LINKER_MESSAGE_MAX_LENGTH, nullptr, message);
glGetProgramInfoLog(_id, LINKER_MESSAGE_MAX_LENGTH, nullptr, message);
/* Show error log and delete shader */
if(status == GL_FALSE) {
@ -90,10 +150,414 @@ GLint AbstractShaderProgram::uniformLocation(const std::string& name) {
/** @todo What if linking just failed (not programmer error?) */
CORRADE_ASSERT(state == Linked, "AbstractShaderProgram: uniform location cannot be retrieved before linking.", -1);
GLint location = glGetUniformLocation(program, name.c_str());
GLint location = glGetUniformLocation(_id, name.c_str());
if(location == -1)
Warning() << "AbstractShaderProgram: location of uniform \'" + name + "\' cannot be retrieved!";
return location;
}
void AbstractShaderProgram::initializeContextBasedFunctionality(Context* context) {
/** @todo OpenGL ES 2 has extension @es_extension{EXT,separate_shader_objects} for this */
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::ARB::separate_shader_objects>() ||
context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "AbstractShaderProgram: using" << (context->isExtensionSupported<Extensions::GL::ARB::separate_shader_objects>() ?
Extensions::GL::ARB::separate_shader_objects::string() : Extensions::GL::EXT::direct_state_access::string()) << "features";
uniform1fImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform1iImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform2ivImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform3ivImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform4ivImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform1uiImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform2uivImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform3uivImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform4uivImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform1dImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix2x3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix3x2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix2x4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix4x2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix3x4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix4x3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix2x3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix3x2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix2x4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix4x2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix3x4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniformMatrix4x3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
}
#else
static_cast<void>(context);
#endif
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, GLfloat value) {
use();
glUniform1f(location, value);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, GLfloat value) {
glProgramUniform1f(_id, location, value);
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<2, GLfloat>& value) {
use();
glUniform2fv(location, 1, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<2, GLfloat>& value) {
glProgramUniform2fv(_id, location, 1, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<3, GLfloat>& value) {
use();
glUniform3fv(location, 1, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<3, GLfloat>& value) {
glProgramUniform3fv(_id, location, 1, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<4, GLfloat>& value) {
use();
glUniform4fv(location, 1, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<4, GLfloat>& value) {
glProgramUniform4fv(_id, location, 1, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, GLint value) {
use();
glUniform1i(location, value);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, GLint value) {
glProgramUniform1i(_id, location, value);
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<2, GLint>& value) {
use();
glUniform2iv(location, 1, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<2, GLint>& value) {
glProgramUniform2iv(_id, location, 1, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<3, GLint>& value) {
use();
glUniform3iv(location, 1, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<3, GLint>& value) {
glProgramUniform3iv(_id, location, 1, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<4, GLint>& value) {
use();
glUniform4iv(location, 1, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<4, GLint>& value) {
glProgramUniform4iv(_id, location, 1, value.data());
}
#endif
#ifndef MAGNUM_TARGET_GLES2
void AbstractShaderProgram::uniformImplementationDefault(GLint location, GLuint value) {
use();
glUniform1ui(location, value);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, GLuint value) {
glProgramUniform1ui(_id, location, value);
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<2, GLuint>& value) {
use();
glUniform2uiv(location, 1, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<2, GLuint>& value) {
glProgramUniform2uiv(_id, location, 1, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<3, GLuint>& value) {
use();
glUniform3uiv(location, 1, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<3, GLuint>& value) {
glProgramUniform3uiv(_id, location, 1, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<4, GLuint>& value) {
use();
glUniform4uiv(location, 1, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<4, GLuint>& value) {
glProgramUniform4uiv(_id, location, 1, value.data());
}
#endif
#endif
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDefault(GLint location, GLdouble value) {
use();
glUniform1d(location, value);
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, GLdouble value) {
glProgramUniform1d(_id, location, value);
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<2, GLdouble>& value) {
use();
glUniform2dv(location, 1, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<2, GLdouble>& value) {
glProgramUniform2dv(_id, location, 1, value.data());
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<3, GLdouble>& value) {
use();
glUniform3dv(location, 1, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<3, GLdouble>& value) {
glProgramUniform3dv(_id, location, 1, value.data());
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Vector<4, GLdouble>& value) {
use();
glUniform4dv(location, 1, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Vector<4, GLdouble>& value) {
glProgramUniform4dv(_id, location, 1, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Matrix<2, GLfloat>& value) {
use();
glUniformMatrix2fv(location, 1, GL_FALSE, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Matrix<2, GLfloat>& value) {
glProgramUniformMatrix2fv(_id, location, 1, GL_FALSE, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Matrix<3, GLfloat>& value) {
use();
glUniformMatrix3fv(location, 1, GL_FALSE, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Matrix<3, GLfloat>& value) {
glProgramUniformMatrix3fv(_id, location, 1, GL_FALSE, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Matrix<4, GLfloat>& value) {
use();
glUniformMatrix4fv(location, 1, GL_FALSE, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Matrix<4, GLfloat>& value) {
glProgramUniformMatrix4fv(_id, location, 1, GL_FALSE, value.data());
}
#endif
#ifndef MAGNUM_TARGET_GLES2
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<2, 3, GLfloat>& value) {
use();
glUniformMatrix2x3fv(location, 1, GL_FALSE, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<2, 3, GLfloat>& value) {
glProgramUniformMatrix2x3fv(_id, location, 1, GL_FALSE, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<3, 2, GLfloat>& value) {
use();
glUniformMatrix3x2fv(location, 1, GL_FALSE, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<3, 2, GLfloat>& value) {
glProgramUniformMatrix3x2fv(_id, location, 1, GL_FALSE, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<2, 4, GLfloat>& value) {
use();
glUniformMatrix2x4fv(location, 1, GL_FALSE, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<2, 4, GLfloat>& value) {
glProgramUniformMatrix2x4fv(_id, location, 1, GL_FALSE, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<4, 2, GLfloat>& value) {
use();
glUniformMatrix4x2fv(location, 1, GL_FALSE, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<4, 2, GLfloat>& value) {
glProgramUniformMatrix4x2fv(_id, location, 1, GL_FALSE, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<3, 4, GLfloat>& value) {
use();
glUniformMatrix3x4fv(location, 1, GL_FALSE, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<3, 4, GLfloat>& value) {
glProgramUniformMatrix3x4fv(_id, location, 1, GL_FALSE, value.data());
}
#endif
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<4, 3, GLfloat>& value) {
use();
glUniformMatrix4x3fv(location, 1, GL_FALSE, value.data());
}
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<4, 3, GLfloat>& value) {
glProgramUniformMatrix4x3fv(_id, location, 1, GL_FALSE, value.data());
}
#endif
#endif
#ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Matrix<2, GLdouble>& value) {
use();
glUniformMatrix2dv(location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Matrix<2, GLdouble>& value) {
glProgramUniformMatrix2dv(_id, location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Matrix<3, GLdouble>& value) {
use();
glUniformMatrix3dv(location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Matrix<3, GLdouble>& value) {
glProgramUniformMatrix3dv(_id, location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::Matrix<4, GLdouble>& value) {
use();
glUniformMatrix4dv(location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::Matrix<4, GLdouble>& value) {
glProgramUniformMatrix4dv(_id, location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<2, 3, GLdouble>& value) {
use();
glUniformMatrix2x3dv(location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<2, 3, GLdouble>& value) {
glProgramUniformMatrix2x3dv(_id, location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<3, 2, GLdouble>& value) {
use();
glUniformMatrix3x2dv(location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<3, 2, GLdouble>& value) {
glProgramUniformMatrix3x2dv(_id, location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<2, 4, GLdouble>& value) {
use();
glUniformMatrix2x4dv(location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<2, 4, GLdouble>& value) {
glProgramUniformMatrix2x4dv(_id, location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<4, 2, GLdouble>& value) {
use();
glUniformMatrix4x2dv(location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<4, 2, GLdouble>& value) {
glProgramUniformMatrix4x2dv(_id, location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<3, 4, GLdouble>& value) {
use();
glUniformMatrix3x4dv(location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<3, 4, GLdouble>& value) {
glProgramUniformMatrix3x4dv(_id, location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDefault(GLint location, const Math::RectangularMatrix<4, 3, GLdouble>& value) {
use();
glUniformMatrix4x3dv(location, 1, GL_FALSE, value.data());
}
void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math::RectangularMatrix<4, 3, GLdouble>& value) {
glProgramUniformMatrix4x3dv(_id, location, 1, GL_FALSE, value.data());
}
#endif
}

1054
src/AbstractShaderProgram.h

File diff suppressed because it is too large Load Diff

312
src/AbstractTexture.cpp

@ -15,8 +15,40 @@
#include "AbstractTexture.h"
#include "Context.h"
#include "Extensions.h"
#include "Implementation/State.h"
#include "Implementation/TextureState.h"
namespace Magnum {
AbstractTexture::BindImplementation AbstractTexture::bindImplementation =
&AbstractTexture::bindImplementationDefault;
AbstractTexture::ParameteriImplementation AbstractTexture::parameteriImplementation =
&AbstractTexture::parameterImplementationDefault;
AbstractTexture::ParameterfImplementation AbstractTexture::parameterfImplementation =
&AbstractTexture::parameterImplementationDefault;
AbstractTexture::ParameterfvImplementation AbstractTexture::parameterfvImplementation =
&AbstractTexture::parameterImplementationDefault;
AbstractTexture::MipmapImplementation AbstractTexture::mipmapImplementation =
&AbstractTexture::mipmapImplementationDefault;
#ifndef MAGNUM_TARGET_GLES
AbstractTexture::Image1DImplementation AbstractTexture::image1DImplementation =
&AbstractTexture::imageImplementationDefault;
#endif
AbstractTexture::Image2DImplementation AbstractTexture::image2DImplementation =
&AbstractTexture::imageImplementationDefault;
AbstractTexture::Image3DImplementation AbstractTexture::image3DImplementation =
&AbstractTexture::imageImplementationDefault;
#ifndef MAGNUM_TARGET_GLES
AbstractTexture::SubImage1DImplementation AbstractTexture::subImage1DImplementation =
&AbstractTexture::subImageImplementationDefault;
#endif
AbstractTexture::SubImage2DImplementation AbstractTexture::subImage2DImplementation =
&AbstractTexture::subImageImplementationDefault;
AbstractTexture::SubImage3DImplementation AbstractTexture::subImage3DImplementation =
&AbstractTexture::subImageImplementationDefault;
#ifndef DOXYGEN_GENERATING_OUTPUT
/* Check correctness of binary OR in setMinificationFilter(). If nobody fucks
@ -35,40 +67,253 @@ static_assert((filter_or(NearestNeighbor, BaseLevel) == GL_NEAREST) &&
#endif
GLint AbstractTexture::maxSupportedLayerCount() {
GLint value;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &value);
return value;
return Context::current()->state()->texture->maxSupportedLayerCount;
}
#ifndef MAGNUM_TARGET_GLES
GLfloat AbstractTexture::maxSupportedAnisotropy() {
GLfloat value;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &value);
GLfloat& value = Context::current()->state()->texture->maxSupportedAnisotropy;
/** @todo Re-enable when extension header is available */
#ifndef MAGNUM_TARGET_GLES
/* Get the value, if not already cached */
if(value == 0.0f)
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &value);
#endif
return value;
}
AbstractTexture::~AbstractTexture() {
/* Remove all bindings */
for(GLuint& binding: Context::current()->state()->texture->bindings)
if(binding == _id) binding = 0;
glDeleteTextures(1, &_id);
}
void AbstractTexture::bind(GLint layer) {
Implementation::TextureState* const textureState = Context::current()->state()->texture;
/* If already bound in given layer, nothing to do */
if(textureState->bindings[layer] == _id) return;
(this->*bindImplementation)(layer);
}
void AbstractTexture::bindImplementationDefault(GLint layer) {
Implementation::TextureState* const textureState = Context::current()->state()->texture;
/* Change to given layer, if not already there */
if(textureState->currentLayer != layer)
glActiveTexture(GL_TEXTURE0 + (textureState->currentLayer = layer));
/* Bind the texture to the layer */
glBindTexture(_target, (textureState->bindings[layer] = _id));
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::bindImplementationDSA(GLint layer) {
glBindMultiTextureEXT(GL_TEXTURE0 + layer, _target, (Context::current()->state()->texture->bindings[layer] = _id));
}
#endif
void AbstractTexture::setMinificationFilter(Filter filter, Mipmap mipmap) {
AbstractTexture* AbstractTexture::setMinificationFilter(Filter filter, Mipmap mipmap) {
#ifndef MAGNUM_TARGET_GLES
CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Mipmap::BaseLevel, "AbstractTexture: rectangle textures cannot have mipmaps", );
CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Mipmap::BaseLevel, "AbstractTexture: rectangle textures cannot have mipmaps", this);
#endif
bind();
glTexParameteri(_target, GL_TEXTURE_MIN_FILTER,
(this->*parameteriImplementation)(GL_TEXTURE_MIN_FILTER,
static_cast<GLint>(filter)|static_cast<GLint>(mipmap));
return this;
}
void AbstractTexture::generateMipmap() {
AbstractTexture* AbstractTexture::generateMipmap() {
#ifndef MAGNUM_TARGET_GLES
CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE, "AbstractTexture: rectangle textures cannot have mipmaps", );
CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE, "AbstractTexture: rectangle textures cannot have mipmaps", this);
#endif
bind();
(this->*mipmapImplementation)();
return this;
}
void AbstractTexture::mipmapImplementationDefault() {
bindInternal();
glGenerateMipmap(_target);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::mipmapImplementationDSA() {
glGenerateTextureMipmapEXT(_id, _target);
}
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT
void AbstractTexture::bindInternal() {
Implementation::TextureState* const textureState = Context::current()->state()->texture;
/* If the texture is already bound in current layer, nothing to do */
if(textureState->bindings[textureState->currentLayer] == _id)
return;
/* Set internal layer as active if not already */
const GLint internalLayer = textureState->maxSupportedLayerCount-1;
if(textureState->currentLayer != internalLayer)
glActiveTexture(GL_TEXTURE0 + (textureState->currentLayer = internalLayer));
/* Bind the texture to internal layer, if not already */
if(textureState->bindings[internalLayer] != _id)
glBindTexture(_target, (textureState->bindings[internalLayer] = _id));
}
#endif
void AbstractTexture::initializeContextBasedFunctionality(Context* context) {
Implementation::TextureState* const textureState = context->state()->texture;
GLint& value = textureState->maxSupportedLayerCount;
/* Get the value and resize bindings array */
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &value);
textureState->bindings.resize(value);
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "AbstractTexture: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
bindImplementation = &AbstractTexture::bindImplementationDSA;
parameteriImplementation = &AbstractTexture::parameterImplementationDSA;
parameterfImplementation = &AbstractTexture::parameterImplementationDSA;
parameterfvImplementation = &AbstractTexture::parameterImplementationDSA;
mipmapImplementation = &AbstractTexture::mipmapImplementationDSA;
image1DImplementation = &AbstractTexture::imageImplementationDSA;
image2DImplementation = &AbstractTexture::imageImplementationDSA;
image3DImplementation = &AbstractTexture::imageImplementationDSA;
subImage1DImplementation = &AbstractTexture::subImageImplementationDSA;
subImage2DImplementation = &AbstractTexture::subImageImplementationDSA;
subImage3DImplementation = &AbstractTexture::subImageImplementationDSA;
}
#endif
}
void AbstractTexture::parameterImplementationDefault(GLenum parameter, GLint value) {
bindInternal();
glTexParameteri(_target, parameter, value);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::parameterImplementationDSA(GLenum parameter, GLint value) {
glTextureParameteriEXT(_id, _target, parameter, value);
}
#endif
void AbstractTexture::parameterImplementationDefault(GLenum parameter, GLfloat value) {
bindInternal();
glTexParameterf(_target, parameter, value);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::parameterImplementationDSA(GLenum parameter, GLfloat value) {
glTextureParameterfEXT(_id, _target, parameter, value);
}
#endif
void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLfloat* values) {
bindInternal();
glTexParameterfv(_target, parameter, values);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLfloat* values) {
glTextureParameterfvEXT(_id, _target, parameter, values);
}
void AbstractTexture::imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
bindInternal();
glTexImage1D(target, mipLevel, internalFormat, size[0], 0, static_cast<GLenum>(components), static_cast<GLenum>(type), data);
}
void AbstractTexture::imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
glTextureImage1DEXT(_id, target, mipLevel, internalFormat, size[0], 0, static_cast<GLenum>(components), static_cast<GLenum>(type), data);
}
#endif
void AbstractTexture::imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
bindInternal();
glTexImage2D(target, mipLevel, internalFormat, size.x(), size.y(), 0, static_cast<GLenum>(components), static_cast<GLenum>(type), data);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
glTextureImage2DEXT(_id, target, mipLevel, internalFormat, size.x(), size.y(), 0, static_cast<GLenum>(components), static_cast<GLenum>(type), data);
}
#endif
void AbstractTexture::imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
bindInternal();
/** @todo Get some extension wrangler instead to avoid linker errors to glTexImage3D() on ES2 */
#ifndef MAGNUM_TARGET_GLES2
glTexImage3D(target, mipLevel, internalFormat, size.x(), size.y(), size.z(), 0, static_cast<GLenum>(components), static_cast<GLenum>(type), data);
#else
static_cast<void>(target);
static_cast<void>(mipLevel);
static_cast<void>(internalFormat);
static_cast<void>(size);
static_cast<void>(components);
static_cast<void>(type);
static_cast<void>(data);
#endif
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
glTextureImage3DEXT(_id, target, mipLevel, internalFormat, size.x(), size.y(), size.z(), 0, static_cast<GLenum>(components), static_cast<GLenum>(type), data);
}
#endif
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
bindInternal();
glTexSubImage1D(target, mipLevel, offset[0], size[0], static_cast<GLenum>(components), static_cast<GLenum>(type), data);
}
void AbstractTexture::subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
glTextureSubImage1DEXT(_id, target, mipLevel, offset[0], size[0], static_cast<GLenum>(components), static_cast<GLenum>(type), data);
}
#endif
void AbstractTexture::subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
bindInternal();
glTexSubImage2D(target, mipLevel, offset.x(), offset.y(), size.x(), size.y(), static_cast<GLenum>(components), static_cast<GLenum>(type), data);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
glTextureSubImage2DEXT(_id, target, mipLevel, offset.x(), offset.y(), size.x(), size.y(), static_cast<GLenum>(components), static_cast<GLenum>(type), data);
}
#endif
void AbstractTexture::subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector3<GLint>& offset, const Math::Vector3<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
bindInternal();
/** @todo Get some extension wrangler instead to avoid linker errors to glTexSubImage3D() on ES2 */
#ifndef MAGNUM_TARGET_GLES2
glTexSubImage3D(target, mipLevel, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), static_cast<GLenum>(components), static_cast<GLenum>(type), data);
#else
static_cast<void>(target);
static_cast<void>(mipLevel);
static_cast<void>(offset);
static_cast<void>(size);
static_cast<void>(components);
static_cast<void>(type);
static_cast<void>(data);
#endif
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector3<GLint>& offset, const Math::Vector3<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) {
glTextureSubImage3DEXT(_id, target, mipLevel, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), static_cast<GLenum>(components), static_cast<GLenum>(type), data);
}
#endif
AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components components, AbstractTexture::ComponentType type) {
#ifndef MAGNUM_TARGET_GLES
#define internalFormatSwitch(c) switch(type) { \
case ComponentType::UnsignedByte: \
internalFormat = GL_##c##8UI; break; \
@ -95,6 +340,30 @@ AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components comp
case ComponentType::NormalizedShort: \
internalFormat = GL_##c##16_SNORM; break; \
}
#else
#define internalFormatSwitch(c) switch(type) { \
case ComponentType::UnsignedByte: \
internalFormat = GL_##c##8UI; break; \
case ComponentType::Byte: \
internalFormat = GL_##c##8I; break; \
case ComponentType::UnsignedShort: \
internalFormat = GL_##c##16UI; break; \
case ComponentType::Short: \
internalFormat = GL_##c##16I; break; \
case ComponentType::UnsignedInt: \
internalFormat = GL_##c##32UI; break; \
case ComponentType::Int: \
internalFormat = GL_##c##32I; break; \
case ComponentType::Half: \
internalFormat = GL_##c##16F; break; \
case ComponentType::Float: \
internalFormat = GL_##c##32F; break; \
case ComponentType::NormalizedUnsignedByte: \
internalFormat = GL_##c##8; break; \
case ComponentType::NormalizedByte: \
internalFormat = GL_##c##8_SNORM; break; \
}
#endif
if(components == Components::Red)
internalFormatSwitch(R)
else if(components == Components::RedGreen)
@ -105,23 +374,22 @@ AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components comp
internalFormatSwitch(RGBA)
#undef internalFormatSwitch
}
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT
void AbstractTexture::DataHelper<2>::setWrapping(GLenum target, const Math::Vector<2, Wrapping>& wrapping) {
void AbstractTexture::DataHelper<2>::setWrapping(AbstractTexture* texture, const Math::Vector2<Wrapping>& wrapping) {
#ifndef MAGNUM_TARGET_GLES
CORRADE_ASSERT(target != GL_TEXTURE_RECTANGLE || ((wrapping[0] == Wrapping::ClampToEdge || wrapping[0] == Wrapping::ClampToBorder) && (wrapping[0] == Wrapping::ClampToEdge || wrapping[1] == Wrapping::ClampToEdge)), "AbstractTexture: rectangle texture wrapping must either clamp to border or to edge", );
CORRADE_ASSERT(texture->_target != GL_TEXTURE_RECTANGLE || ((wrapping[0] == Wrapping::ClampToEdge || wrapping[0] == Wrapping::ClampToBorder) && (wrapping[0] == Wrapping::ClampToEdge || wrapping[1] == Wrapping::ClampToEdge)), "AbstractTexture: rectangle texture wrapping must either clamp to border or to edge", );
#endif
glTexParameteri(target, GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping[0]));
glTexParameteri(target, GL_TEXTURE_WRAP_T, static_cast<GLint>(wrapping[1]));
(texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping.x()));
(texture->*parameteriImplementation)(GL_TEXTURE_WRAP_T, static_cast<GLint>(wrapping.y()));
}
void AbstractTexture::DataHelper<3>::setWrapping(GLenum target, const Math::Vector<3, Wrapping>& wrapping) {
glTexParameteri(target, GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping[0]));
glTexParameteri(target, GL_TEXTURE_WRAP_T, static_cast<GLint>(wrapping[1]));
void AbstractTexture::DataHelper<3>::setWrapping(AbstractTexture* texture, const Math::Vector3<Wrapping>& wrapping) {
(texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping.x()));
(texture->*parameteriImplementation)(GL_TEXTURE_WRAP_T, static_cast<GLint>(wrapping.y()));
#ifndef MAGNUM_TARGET_GLES
glTexParameteri(target, GL_TEXTURE_WRAP_R, static_cast<GLint>(wrapping[2]));
(texture->*parameteriImplementation)(GL_TEXTURE_WRAP_R, static_cast<GLint>(wrapping.z()));
#endif
}
#endif

365
src/AbstractTexture.h

@ -19,11 +19,16 @@
* @brief Class Magnum::AbstractTexture
*/
#include <cstdint>
#include "Magnum.h"
#include "Color.h"
#include "AbstractImage.h"
namespace Magnum {
class Context;
/**
@brief Base for textures
@ -40,10 +45,33 @@ AbstractShaderProgram::setUniform(GLint, GLint).
See Texture, CubeMapTexture and CubeMapTextureArray documentation for more
information.
@section AbstractTexture-performance-optimization Performance optimizations
The engine tracks currently bound textures in all available layers to avoid
unnecessary calls to @fn_gl{ActiveTexture} and @fn_gl{BindTexture}. %Texture
configuration functions use dedicated highest available texture layer to not
affect active bindings in user layers. %Texture limits (such as
maxSupportedLayerCount()) are cached, so repeated queries don't result in
repeated @fn_gl{Get} calls.
If extension @extension{EXT,direct_state_access} is available, bind() uses DSA
function to avoid unnecessary calls to @fn_gl{ActiveTexture}. Also all texture
configuration functions use DSA functions to avoid unnecessary calls to
@fn_gl{ActiveTexture} and @fn_gl{BindTexture}. See respective function
documentation for more information.
To achieve least state changes, fully configure each texture in one run --
method chaining comes in handy -- and try to have often used textures in
dedicated layers, not occupied by other textures.
Always fully configure the texture before setting the texture data, so OpenGL
can optimize the data to match your settings.
@todo Add glPixelStore encapsulation
@todo Texture copying
*/
class MAGNUM_EXPORT AbstractTexture {
friend class Context;
AbstractTexture(const AbstractTexture& other) = delete;
AbstractTexture(AbstractTexture&& other) = delete;
AbstractTexture& operator=(const AbstractTexture& other) = delete;
@ -105,7 +133,7 @@ class MAGNUM_EXPORT AbstractTexture {
/**
* Clamp to border color. Coordinates out of range will be clamped
* to border color (set with setBorderColor()).
* @requires_gl
* @requires_gl Texture border is not available in OpenGL ES.
*/
ClampToBorder = GL_CLAMP_TO_BORDER
#endif
@ -113,10 +141,10 @@ class MAGNUM_EXPORT AbstractTexture {
/** @{ @name Internal texture formats */
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Color components
* @requires_gl
*
* @requires_gles30 (no extension providing this functionality)
*/
enum class Components {
/**
@ -142,7 +170,7 @@ class MAGNUM_EXPORT AbstractTexture {
*
* `NormalizedUnsignedByte` and `NormalizedUnsignedShort` are the
* main ones for general usage.
* @requires_gl
* @requires_gles30 (no extension providing this functionality)
*/
enum class ComponentType {
/**
@ -206,20 +234,23 @@ class MAGNUM_EXPORT AbstractTexture {
*/
NormalizedByte,
#ifndef MAGNUM_TARGET_GLES
/**
* Normalized unsigned short, i.e. values from range @f$ [0; 65536] @f$
* are converted to range @f$ [0.0; 1.0] @f$.
* @requires_gl
*/
NormalizedUnsignedShort,
/**
* Normalized signed short, i.e. values from range @f$ [-32768; 32767] @f$
* are converted to range @f$ [-1.0; 1.0] @f$.
* @requires_gl
* @requires_gl31 Extension @extension{EXT,texture_snorm}
*/
NormalizedShort
#endif
};
#endif
/**
* @brief Internal format
@ -228,23 +259,21 @@ class MAGNUM_EXPORT AbstractTexture {
* normalization see enums Components and ComponentType.
*/
enum class Format: GLenum {
#ifndef MAGNUM_TARGET_GLES
/**
* One-component (red channel), unsigned normalized, probably
* 8bit.
* @requires_gl
* @requires_gl30 Extension @extension{ARB,texture_rg}
* @requires_gles30 (no extension providing this functionality)
*/
Red = GL_RED,
/**
* Two-component (red and green channel), unsigned normalized,
* each component probably 8bit, 16bit total.
* @requires_gl
* @requires_gl30 Extension @extension{ARB,texture_rg}
* @requires_gles30 (no extension providing this functionality)
*/
RedGreen = GL_RG,
#endif
/**
* Three-component RGB, unsigned normalized, each component
@ -278,36 +307,36 @@ class MAGNUM_EXPORT AbstractTexture {
* @requires_gl
*/
BGRA = GL_BGRA,
#endif
/**
* Four-component sRGBA, unsigned normalized, each component
* 8bit, 32bit total.
* @requires_gl
* @requires_gles30 (no extension providing this functionality)
*/
SRGBA8 = GL_SRGB8_ALPHA8,
/**
* Three-component sRGB, unsigned normalized, each component
* 8bit, 24bit total.
* @requires_gl
* @requires_gles30 (no extension providing this functionality)
*/
SRGB8 = GL_SRGB8,
/**
* Four-component RGBA, unsigned normalized, each RGB component
* 10bit, alpha 2bit, 32bit total.
* @requires_gl
* @requires_gles30 (no extension providing this functionality)
*/
RGB10Alpha2 = GL_RGB10_A2,
/**
* Four-component RGBA, unsigned non-normalized, each RGB
* component 10bit, alpha channel 2bit, 32bit total.
* @requires_gl
* @requires_gl33 Extension @extension{ARB,texture_rgb10_a2ui}
* @requires_gles30 (no extension providing this functionality)
*/
RGB10Alpha2Unsigned = GL_RGB10_A2UI,
#endif
/**
* Four-component RGBA, unsigned normalized, each RGB component
@ -319,41 +348,35 @@ class MAGNUM_EXPORT AbstractTexture {
* Four-component RGBA, unsigned normalized, each component 4bit,
* 16bit total.
*/
RGBA4 = GL_RGBA4
#ifndef MAGNUM_TARGET_GLES
,
RGBA4 = GL_RGBA4,
/**
* Three-component RGB, float, red and green 11bit, blue 10bit,
* 32bit total.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,packed_float}
* @requires_gles30 (no extension providing this functionality)
*/
RG11B10Float = GL_R11F_G11F_B10F
#endif
RG11B10Float = GL_R11F_G11F_B10F,
/* 1.5.6 <= GLEW < 1.8.0 doesn't have this, even if there is
GL_ARB_ES2_compatibility */
#if defined(GL_RGB565) || defined(DOXYGEN_GENERATING_OUTPUT)
,
/**
* Three-component RGB, unsigned normalized, red and blue 5bit,
* green 6bit, 16bit total.
*/
RGB565 = GL_RGB565
RGB565 = GL_RGB565,
#endif
#ifndef MAGNUM_TARGET_GLES
,
/**
* Three-component RGB, unsigned with exponent, each component
* 9bit, exponent 5bit, 32bit total.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,texture_shared_exponent}
* @requires_gles30 (no extension providing this functionality)
*/
RGB9Exponent5 = GL_RGB9_E5,
#ifndef MAGNUM_TARGET_GLES
/**
* Compressed red channel, unsigned normalized.
* @requires_gl
@ -408,35 +431,39 @@ class MAGNUM_EXPORT AbstractTexture {
*/
CompressedRtgcSignedRedGreen = GL_COMPRESSED_SIGNED_RG_RGTC2,
#if defined(GL_COMPRESSED_RGBA_BPTC_UNORM) || defined(DOXYGEN_GENERATING_OUTPUT)
/* These are named with _ARB suffix, because glcorearb.h doesn't
have suffixless version (?!) and GLEW has it without suffix as
late as of 1.8.0 { */
/**
* BPTC compressed RGBA, unsigned normalized.
* @requires_gl
* @requires_gl42 Extension @extension{ARB,texture_compression_bptc}
*/
CompressedBptcRGBA = GL_COMPRESSED_RGBA_BPTC_UNORM,
CompressedBptcRGBA = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB,
/**
* BPTC compressed sRGBA, unsigned normalized.
* @requires_gl
* @requires_gl42 Extension @extension{ARB,texture_compression_bptc}
*/
CompressedBptcSRGBA = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,
CompressedBptcSRGBA = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB,
/**
* BPTC compressed RGB, signed float.
* @requires_gl
* @requires_gl42 Extension @extension{ARB,texture_compression_bptc}
*/
CompressedBptcRGBSignedFloat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,
CompressedBptcRGBSignedFloat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB,
/**
* BPTC compressed RGB, unsigned float.
* @requires_gl
* @requires_gl42 Extension @extension{ARB,texture_compression_bptc}
*/
CompressedBptcRGBUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,
#endif
CompressedBptcRGBUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB,
/*}*/
/**
* Depth component, at least 16bit.
@ -456,40 +483,40 @@ class MAGNUM_EXPORT AbstractTexture {
* @requires_gl
*/
DepthStencil = GL_DEPTH_STENCIL,
#endif
/**
* 16bit depth component.
* @requires_gl
* @requires_gles30 (no extension providing this functionality)
*/
Depth16 = GL_DEPTH_COMPONENT16,
/**
* 24bit depth component.
* @requires_gl
* @requires_gles30 (no extension providing this functionality)
*/
Depth24 = GL_DEPTH_COMPONENT24,
/**
* 32bit float depth component.
* @requires_gl
* @requires_gl30 Extension @extension{ARB,depth_buffer_float}
* @requires_gles30 (no extension providing this functionality)
*/
Depth32Float = GL_DEPTH_COMPONENT32F,
/**
* 24bit depth and 8bit stencil component.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,packed_depth_stencil}
* @requires_gles30 (no extension providing this functionality)
*/
Depth24Stencil8 = GL_DEPTH24_STENCIL8,
/**
* 32bit float depth component and 8bit stencil component.
* @requires_gl
* @requires_gl30 Extension @extension{ARB,depth_buffer_float}
* @requires_gles30 (no extension providing this functionality)
*/
Depth32FloatStencil8 = GL_DEPTH32F_STENCIL8
#endif
};
/**
@ -510,14 +537,12 @@ class MAGNUM_EXPORT AbstractTexture {
*/
class MAGNUM_EXPORT InternalFormat {
public:
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Constructor from component count and data type per component
*
* @requires_gl
* @requires_gles30 (no extension providing this functionality)
*/
InternalFormat(Components components, ComponentType type);
#endif
/** @brief Constructor from named internal format */
inline constexpr InternalFormat(Format format): internalFormat(static_cast<GLint>(format)) {}
@ -534,52 +559,54 @@ class MAGNUM_EXPORT AbstractTexture {
/**
* @brief Max supported layer count
*
* At least 48.
* @see bind(GLint)
* @see bind(GLint), @fn_gl{Get} with @def_gl{MAX_COMBINED_TEXTURE_IMAGE_UNITS},
* @fn_gl{ActiveTexture}
*/
static GLint maxSupportedLayerCount();
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Max supported anisotropy
*
* @see setMaxAnisotropy()
* @requires_extension @extension{EXT,texture_filter_anisotropic}
* @see setMaxAnisotropy(), @fn_gl{Get} with @def_gl{MAX_TEXTURE_MAX_ANISOTROPY_EXT}
* @requires_extension %Extension @extension{EXT,texture_filter_anisotropic}
* @requires_es_extension %Extension @es_extension2{EXT,texture_filter_anisotropic,texture_filter_anisotropic}
*/
static GLfloat maxSupportedAnisotropy();
#endif
/**
* @brief Constructor
* @param target Target, e.g. `GL_TEXTURE_2D`.
*
* Creates one OpenGL texture.
* @see @fn_gl{GenTextures}
*/
inline AbstractTexture(GLenum target): _target(target) {
glGenTextures(1, &texture);
glGenTextures(1, &_id);
}
/**
* @brief Destructor
*
* Deletes assigned OpenGL texture.
* @see @fn_gl{DeleteTextures}
*/
virtual ~AbstractTexture() = 0;
/** @brief OpenGL internal texture ID */
inline GLuint id() const { return texture; }
/** @brief OpenGL texture ID */
inline GLuint id() const { return _id; }
/**
* @brief Bind texture for rendering
*
* Sets current texture as active in given layer. The layer must be
* between 0 and maxSupportedLayerCount(). Note that only one texture
* can be bound to given layer.
* can be bound to given layer. If @extension{EXT,direct_state_access}
* is not available, the layer is made active before binding the
* texture.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} or
* @fn_gl_extension{BindMultiTexture,EXT,direct_state_access}
*/
inline void bind(GLint layer) {
glActiveTexture(GL_TEXTURE0 + layer);
bind();
}
void bind(GLint layer);
/**
* @brief Set minification filter
@ -587,92 +614,185 @@ class MAGNUM_EXPORT AbstractTexture {
* @param mipmap Mipmap filtering. If set to anything else than
* BaseMipLevel, make sure textures for all mip levels are set or
* call generateMipmap().
* @return Pointer to self (for method chaining)
*
* Sets filter used when the object pixel size is smaller than the
* texture size.
* texture size. If @extension{EXT,direct_state_access} is not
* available, the texture is bound to some layer before the operation.
* @attention For rectangle textures only some modes are supported,
* see @ref AbstractTexture::Filter "Filter" and
* @ref AbstractTexture::Mipmap "Mipmap" documentation for more
* information.
* see @ref AbstractTexture::Filter "Filter" and
* @ref AbstractTexture::Mipmap "Mipmap" documentation for more
* information.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter}
* or @fn_gl_extension{TextureParameter,EXT,direct_state_access}
* with @def_gl{TEXTURE_MIN_FILTER}
*/
void setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel);
AbstractTexture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel);
/**
* @brief Set magnification filter
* @param filter Filter
* @return Pointer to self (for method chaining)
*
* Sets filter used when the object pixel size is larger than largest
* texture size.
* texture size. If @extension{EXT,direct_state_access} is not
* available, the texture is bound to some layer before the operation.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter}
* or @fn_gl_extension{TextureParameter,EXT,direct_state_access}
* with @def_gl{TEXTURE_MAG_FILTER}
*/
inline void setMagnificationFilter(Filter filter) {
bind();
glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(filter));
inline AbstractTexture* setMagnificationFilter(Filter filter) {
(this->*parameteriImplementation)(GL_TEXTURE_MAG_FILTER, static_cast<GLint>(filter));
return this;
}
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Set border color
* @return Pointer to self (for method chaining)
*
* Border color when @ref AbstractTexture::Wrapping "wrapping" is set
* to `ClampToBorder`.
* @requires_gl
* to `ClampToBorder`. If @extension{EXT,direct_state_access} is not
* available, the texture is bound to some layer before the operation.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter}
* or @fn_gl_extension{TextureParameter,EXT,direct_state_access}
* with @def_gl{TEXTURE_BORDER_COLOR}
* @requires_gl Texture border is not available in OpenGL ES.
*/
inline void setBorderColor(const Color4<GLfloat>& color) {
bind();
glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, color.data());
inline AbstractTexture* setBorderColor(const Color4<GLfloat>& color) {
(this->*parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR, color.data());
return this;
}
#endif
/**
* @brief Set max anisotropy
* @return Pointer to self (for method chaining)
*
* Default value is `1.0`, which means no anisotropy. Set to value
* greater than `1.0` for anisotropic filtering.
* @see maxSupportedAnisotropy()
* @requires_extension @extension{EXT,texture_filter_anisotropic}
* Default value is `1.0f`, which means no anisotropy. Set to value
* greater than `1.0f` for anisotropic filtering. If
* @extension{EXT,direct_state_access} is not available, the texture
* is bound to some layer before the operation.
* @see maxSupportedAnisotropy(), @fn_gl{ActiveTexture},
* @fn_gl{BindTexture} and @fn_gl{TexParameter} or
* @fn_gl_extension{TextureParameter,EXT,direct_state_access} with
* @def_gl{TEXTURE_MAX_ANISOTROPY_EXT}
* @requires_extension %Extension @extension{EXT,texture_filter_anisotropic}
* @requires_es_extension %Extension @es_extension2{EXT,texture_filter_anisotropic,texture_filter_anisotropic}
*/
inline void setMaxAnisotropy(GLfloat anisotropy) {
bind();
glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
inline AbstractTexture* setMaxAnisotropy(GLfloat anisotropy) {
/** @todo Remove `ifndef` when extension header is available */
#ifndef MAGNUM_TARGET_GLES
(this->*parameterfImplementation)(GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
#else
static_cast<void>(anisotropy);
#endif
return this;
}
#endif
/**
* @brief Generate mipmap
* @return Pointer to self (for method chaining)
*
* Can not be used for rectangle textures.
* @see setMinificationFilter()
* Can not be used for rectangle textures. If
* @extension{EXT,direct_state_access} is not available, the texture
* is bound to some layer before the operation.
* @see setMinificationFilter(), @fn_gl{ActiveTexture},
* @fn_gl{BindTexture} and @fn_gl{GenerateMipmap} or
* @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
void generateMipmap();
AbstractTexture* generateMipmap();
protected:
#ifndef DOXYGEN_GENERATING_OUTPUT
template<size_t textureDimensions> struct DataHelper {};
#endif
template<std::uint8_t textureDimensions> struct DataHelper {};
const GLenum _target; /**< @brief Target */
/* Unlike bind() this also sets the binding layer as active */
void MAGNUM_LOCAL bindInternal();
/**
* @brief Bind texture for parameter modification
*
* Unlike bind(GLint) doesn't bind the texture to any particular
* layer, thus unusable for binding for rendering.
*/
inline void bind() {
glBindTexture(_target, texture);
}
const GLenum _target;
#endif
private:
GLuint texture;
};
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
inline AbstractTexture::~AbstractTexture() { glDeleteTextures(1, &texture); }
typedef void(AbstractTexture::*BindImplementation)(GLint);
void MAGNUM_LOCAL bindImplementationDefault(GLint layer);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL bindImplementationDSA(GLint layer);
#endif
static MAGNUM_LOCAL BindImplementation bindImplementation;
typedef void(AbstractTexture::*ParameteriImplementation)(GLenum, GLint);
void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLint value);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLint value);
#endif
static ParameteriImplementation parameteriImplementation;
typedef void(AbstractTexture::*ParameterfImplementation)(GLenum, GLfloat);
void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLfloat value);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLfloat value);
#endif
static ParameterfImplementation parameterfImplementation;
typedef void(AbstractTexture::*ParameterfvImplementation)(GLenum, const GLfloat*);
void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, const GLfloat* values);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, const GLfloat* values);
#endif
static ParameterfvImplementation parameterfvImplementation;
typedef void(AbstractTexture::*MipmapImplementation)();
void MAGNUM_LOCAL mipmapImplementationDefault();
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL mipmapImplementationDSA();
#endif
static MAGNUM_LOCAL MipmapImplementation mipmapImplementation;
#ifndef MAGNUM_TARGET_GLES
typedef void(AbstractTexture::*Image1DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector<1, GLsizei>&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*);
void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
static Image1DImplementation image1DImplementation;
#endif
typedef void(AbstractTexture::*Image2DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector2<GLsizei>&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*);
void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
static Image2DImplementation image2DImplementation;
typedef void(AbstractTexture::*Image3DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector3<GLsizei>&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*);
void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
static Image3DImplementation image3DImplementation;
#ifndef MAGNUM_TARGET_GLES
typedef void(AbstractTexture::*SubImage1DImplementation)(GLenum, GLint, const Math::Vector<1, GLint>&, const Math::Vector<1, GLsizei>&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*);
void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
static SubImage1DImplementation subImage1DImplementation;
#endif
typedef void(AbstractTexture::*SubImage2DImplementation)(GLenum, GLint, const Math::Vector2<GLint>&, const Math::Vector2<GLsizei>&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*);
void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
static SubImage2DImplementation subImage2DImplementation;
typedef void(AbstractTexture::*SubImage3DImplementation)(GLenum, GLint, const Math::Vector3<GLint>&, const Math::Vector3<GLsizei>&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*);
void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector3<GLint>& offset, const Math::Vector3<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector3<GLint>& offset, const Math::Vector3<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data);
static SubImage3DImplementation subImage3DImplementation;
GLuint _id;
};
#ifndef MAGNUM_TARGET_GLES
/** @relates AbstractTexture
@brief Convertor of component count and data type to InternalFormat
@requires_gl
@requires_gles30 (no extension providing this functionality)
*/
inline AbstractTexture::InternalFormat operator|(AbstractTexture::Components components, AbstractTexture::ComponentType type) {
return AbstractTexture::InternalFormat(components, type);
@ -684,7 +804,6 @@ inline AbstractTexture::InternalFormat operator|(AbstractTexture::Components com
inline AbstractTexture::InternalFormat operator|(AbstractTexture::ComponentType type, AbstractTexture::Components components) {
return AbstractTexture::InternalFormat(components, type);
}
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT
#ifndef MAGNUM_TARGET_GLES
@ -695,16 +814,16 @@ template<> struct AbstractTexture::DataHelper<1> {
inline constexpr static Target target() { return Target::Texture1D; }
inline static void setWrapping(GLenum target, const Math::Vector<1, Wrapping>& wrapping) {
glTexParameteri(target, GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping[0]));
inline static void setWrapping(AbstractTexture* texture, const Math::Vector<1, Wrapping>& wrapping) {
(texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping[0]));
}
template<class Image> inline static typename std::enable_if<Image::Dimensions == 1, void>::type set(GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) {
glTexImage1D(target, mipLevel, internalFormat, image->dimensions()[0], 0, static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data());
template<class Image> inline static typename std::enable_if<Image::Dimensions == 1, void>::type set(AbstractTexture* texture, GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) {
(texture->*image1DImplementation)(target, mipLevel, internalFormat, image->size(), image->components(), image->type(), image->data());
}
template<class Image> inline static typename std::enable_if<Image::Dimensions == 1, void>::type setSub(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, Image* image) {
glTexSubImage1D(target, mipLevel, offset[0], image->dimensions()[0], static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data());
template<class Image> inline static typename std::enable_if<Image::Dimensions == 1, void>::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, Image* image) {
(texture->*subImage1DImplementation)(target, mipLevel, offset, image->size(), image->components(), image->type(), image->data());
}
};
#endif
@ -720,47 +839,41 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> {
inline constexpr static Target target() { return Target::Texture2D; }
static void setWrapping(GLenum target, const Math::Vector<2, Wrapping>& wrapping);
static void setWrapping(AbstractTexture* texture, const Math::Vector2<Wrapping>& wrapping);
template<class Image> inline static typename std::enable_if<Image::Dimensions == 2, void>::type set(GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) {
glTexImage2D(target, mipLevel, internalFormat, image->dimensions()[0], image->dimensions()[1], 0, static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data());
template<class Image> inline static typename std::enable_if<Image::Dimensions == 2, void>::type set(AbstractTexture* texture, GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) {
(texture->*image2DImplementation)(target, mipLevel, internalFormat, image->size(), image->components(), image->type(), image->data());
}
template<class Image> inline static typename std::enable_if<Image::Dimensions == 2, void>::type setSub(GLenum target, GLint mipLevel, const Math::Vector<2, GLint>& offset, Image* image) {
glTexSubImage2D(target, mipLevel, offset[0], offset[1], image->dimensions()[0], image->dimensions()[1], static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data());
template<class Image> inline static typename std::enable_if<Image::Dimensions == 2, void>::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector2<GLint>& offset, Image* image) {
(texture->*subImage2DImplementation)(target, mipLevel, offset, image->size(), image->components(), image->type(), image->data());
}
template<class Image> inline static typename std::enable_if<Image::Dimensions == 1, void>::type setSub(GLenum target, GLint mipLevel, const Math::Vector<2, GLint>& offset, Image* image) {
glTexSubImage2D(target, mipLevel, offset[0], offset[1], image->dimensions()[0], 1, static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data());
template<class Image> inline static typename std::enable_if<Image::Dimensions == 1, void>::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector2<GLint>& offset, Image* image) {
(texture->*subImage2DImplementation)(target, mipLevel, offset, Math::Vector2<GLint>(image->size(), 1), image->components(), image->type(), image->data());
}
};
template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> {
enum class Target: GLenum {
#ifndef MAGNUM_TARGET_GLES
Texture3D = GL_TEXTURE_3D,
Texture2DArray = GL_TEXTURE_2D_ARRAY
#endif
};
#ifndef MAGNUM_TARGET_GLES
inline constexpr static Target target() { return Target::Texture3D; }
#endif
static void setWrapping(GLenum target, const Math::Vector<3, Wrapping>& wrapping);
static void setWrapping(AbstractTexture* texture, const Math::Vector3<Wrapping>& wrapping);
#ifndef MAGNUM_TARGET_GLES
template<class Image> inline static typename std::enable_if<Image::Dimensions == 3, void>::type set(GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) {
glTexImage3D(target, mipLevel, internalFormat, image->dimensions()[0], image->dimensions()[1], image->dimensions()[2], 0, static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data());
template<class Image> inline static typename std::enable_if<Image::Dimensions == 3, void>::type set(AbstractTexture* texture, GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) {
(texture->*image3DImplementation)(target, mipLevel, internalFormat, image->size(), image->components(), image->type(), image->data());
}
template<class Image> inline static typename std::enable_if<Image::Dimensions == 3, void>::type setSub(GLenum target, GLint mipLevel, const Math::Vector<3, GLint>& offset, Image* image) {
glTexSubImage3D(target, mipLevel, offset[0], offset[1], offset[2], image->dimensions()[0], image->dimensions()[1], image->dimensions()[2], static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data());
template<class Image> inline static typename std::enable_if<Image::Dimensions == 3, void>::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector3<GLint>& offset, Image* image) {
(texture->*subImage3DImplementation)(target, mipLevel, offset, image->size(), image->components(), image->type(), image->data());
}
template<class Image> inline static typename std::enable_if<Image::Dimensions == 2, void>::type setSub(GLenum target, GLint mipLevel, const Math::Vector<3, GLint>& offset, Image* image) {
glTexSubImage3D(target, mipLevel, offset[0], offset[1], offset[2], image->dimensions()[0], image->dimensions()[1], 1, static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data());
template<class Image> inline static typename std::enable_if<Image::Dimensions == 2, void>::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector3<GLint>& offset, Image* image) {
(texture->*subImage3DImplementation)(target, mipLevel, offset, Math::Vector3<GLint>(image->size(), 1), image->components(), image->type(), image->data());
}
#endif
};
#endif

117
src/Buffer.cpp

@ -0,0 +1,117 @@
/*
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 "Buffer.h"
#include <Utility/Debug.h>
#include "Context.h"
#include "Extensions.h"
#include "Implementation/State.h"
#include "Implementation/BufferState.h"
namespace Magnum {
#ifndef MAGNUM_TARGET_GLES2
Buffer::CopyImplementation Buffer::copyImplementation = &Buffer::copyImplementationDefault;
#endif
Buffer::SetDataImplementation Buffer::setDataImplementation = &Buffer::setDataImplementationDefault;
Buffer::SetSubDataImplementation Buffer::setSubDataImplementation = &Buffer::setSubDataImplementationDefault;
void Buffer::initializeContextBasedFunctionality(Context* context) {
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "Buffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
copyImplementation = &Buffer::copyImplementationDSA;
setDataImplementation = &Buffer::setDataImplementationDSA;
setSubDataImplementation = &Buffer::setSubDataImplementationDSA;
}
#else
static_cast<void>(context);
#endif
}
Buffer::~Buffer() {
GLuint* bindings = Context::current()->state()->buffer->bindings;
/* Remove all current bindings from the state */
for(std::size_t i = 1; i != Implementation::BufferState::TargetCount; ++i)
if(bindings[i] == _id) bindings[i] = 0;
glDeleteBuffers(1, &_id);
}
void Buffer::bind(Target target, GLuint id) {
GLuint& bound = Context::current()->state()->buffer->bindings[Implementation::BufferState::indexForTarget(target)];
/* Already bound, nothing to do */
if(bound == id) return;
/* Bind the buffer otherwise */
bound = id;
glBindBuffer(static_cast<GLenum>(target), id);
}
Buffer::Target Buffer::bindInternal(Target hint) {
GLuint* bindings = Context::current()->state()->buffer->bindings;
GLuint& hintBinding = bindings[Implementation::BufferState::indexForTarget(hint)];
/* Shortcut - if already bound to hint, return */
if(hintBinding == _id) return hint;
/* Return first target in which the buffer is bound */
for(std::size_t i = 1; i != Implementation::BufferState::TargetCount; ++i)
if(bindings[i] == _id) return Implementation::BufferState::targetForIndex[i];
/* Bind the buffer to hint target otherwise */
hintBinding = _id;
glBindBuffer(static_cast<GLenum>(hint), _id);
return hint;
}
#ifndef MAGNUM_TARGET_GLES2
void Buffer::copyImplementationDefault(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
glCopyBufferSubData(static_cast<GLenum>(read->bindInternal(Target::CopyRead)), static_cast<GLenum>(write->bindInternal(Target::CopyWrite)), readOffset, writeOffset, size);
}
#ifndef MAGNUM_TARGET_GLES
void Buffer::copyImplementationDSA(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
glNamedCopyBufferSubDataEXT(read->_id, write->_id, readOffset, writeOffset, size);
}
#endif
#endif
void Buffer::setDataImplementationDefault(GLsizeiptr size, const GLvoid* data, Buffer::Usage usage) {
glBufferData(static_cast<GLenum>(bindInternal(_targetHint)), size, data, static_cast<GLenum>(usage));
}
#ifndef MAGNUM_TARGET_GLES
void Buffer::setDataImplementationDSA(GLsizeiptr size, const GLvoid* data, Buffer::Usage usage) {
glNamedBufferDataEXT(_id, size, data, static_cast<GLenum>(usage));
}
#endif
void Buffer::setSubDataImplementationDefault(GLintptr offset, GLsizeiptr size, const GLvoid* data) {
glBufferSubData(static_cast<GLenum>(bindInternal(_targetHint)), offset, size, data);
}
#ifndef MAGNUM_TARGET_GLES
void Buffer::setSubDataImplementationDSA(GLintptr offset, GLsizeiptr size, const GLvoid* data) {
glNamedBufferSubDataEXT(_id, offset, size, data);
}
#endif
}

400
src/Buffer.h

@ -19,211 +19,327 @@
* @brief Class Magnum::Buffer
*/
#include <cstddef>
#include <array>
#include <vector>
#include "Magnum.h"
#include "magnumVisibility.h"
namespace Magnum {
class Context;
/**
@brief Class for managing buffers
@brief %Buffer
Encapsulates one OpenGL buffer object and provides functions for convenient
data updates.
@section Buffer-data Data updating
Default way to set or update buffer data with setData() or setSubData() is to
explicitly specify data size and pass the pointer to it:
@code
Vector3* data = new Vector3[200];
buffer.setData(200*sizeof(Vector3), data, Buffer::Usage::StaticDraw);
@endcode
Howewer, in some cases, you have the data in fixed-size array with size known
at compile time. There is an convenient overload which detects the size of
passed array, so you don't have to repeat it:
@code
Vector3 data[] = {
// ...
};
buffer.setData(data, Buffer::Usage::StaticDraw);
@endcode
There is also overload for array-like containers from STL, such as `std::vector` or
`std::array`:
@code
std::vector<Vector3> data;
buffer.setData(data, Buffer::Usage::StaticDraw);
@endcode
@section Buffer-performance-optimization Performance optimizations
The engine tracks currently bound buffers to avoid unnecessary calls to
@fn_gl{BindBuffer}. If the buffer is already bound to some target,
functions copy(), setData() and setSubData() use that target in
@fn_gl{CopyBufferSubData}, @fn_gl{BufferData} and @fn_gl{BufferSubData}
functions instead of binding the buffer to some specific target. You can also
use setTargetHint() to possibly reduce unnecessary rebinding.
If extension @extension{EXT,direct_state_access} is available, functions
copy(), setData() and setSubData() use DSA functions to avoid unnecessary
calls to @fn_gl{BindBuffer}. See their respective documentation for more
information.
@todo Support for buffer copying (OpenGL 3.1, @extension{ARB,copy_buffer})
@todo Support for AMD's query buffer (@extension{AMD,query_buffer_object})
@todo BindBufferRange/BindBufferOffset/BindBufferBase for transform feedback (3.0, @extension{EXT,transform_feedback})
*/
class Buffer {
class MAGNUM_EXPORT Buffer {
friend class Context;
Buffer(const Buffer& other) = delete;
Buffer(Buffer&& other) = delete;
Buffer& operator=(const Buffer& other) = delete;
Buffer& operator=(Buffer&& other) = delete;
public:
/** @brief %Buffer target */
/**
* @brief %Buffer target
*
* @see bind(Target), unbind(Target)
*/
enum class Target: GLenum {
/** Used for storing vertex attributes. */
Array = GL_ARRAY_BUFFER,
#ifndef MAGNUM_TARGET_GLES
/**
* Source for copies.
* @requires_gl
* Used for storing atomic counters.
* @requires_gl42 Extension @extension{ARB,shader_atomic_counters}
* @requires_gl Atomic counters are not available in OpenGL ES.
*/
AtomicCounter = GL_ATOMIC_COUNTER_BUFFER,
#endif
/**
* Source for copies. See copy().
* @requires_gl31 Extension @extension{ARB,copy_buffer}
* @requires_gles30 Buffer copying is not available in OpenGL ES
* 2.0.
*/
CopyRead = GL_COPY_READ_BUFFER,
/**
* Target for copies.
* @requires_gl
* Target for copies. See copy().
* @requires_gl31 Extension @extension{ARB,copy_buffer}
* @requires_gles30 Buffer copying is not available in OpenGL ES
* 2.0.
*/
CopyWrite = GL_COPY_WRITE_BUFFER,
#ifndef MAGNUM_TARGET_GLES
/**
* Indirect compute dispatch commands.
* @requires_gl43 Extension @extension{ARB,compute_shader}
* @requires_gl Compute shaders are not available in OpenGL ES.
*/
DispatchIndirect = GL_DISPATCH_INDIRECT_BUFFER,
/**
* Used for supplying arguments for indirect drawing.
* @requires_gl40 Extension @extension{ARB,draw_indirect}
* @requires_gl Indirect drawing not available in OpenGL ES.
*/
DrawIndirect = GL_DRAW_INDIRECT_BUFFER,
#endif
/** Used for storing vertex indices. */
ElementArray = GL_ELEMENT_ARRAY_BUFFER
ElementArray = GL_ELEMENT_ARRAY_BUFFER,
#ifndef MAGNUM_TARGET_GLES
,
/**
* Target for pixel pack operations.
* @requires_gles30 Pixel buffer objects are not available in
* OpenGL ES 2.0.
*/
PixelPack = GL_PIXEL_PACK_BUFFER,
/**
* Source for texture update operations.
* @requires_gl
* @requires_gles30 Pixel buffer objects are not available in
* OpenGL ES 2.0.
*/
PixelUnpack = GL_PIXEL_UNPACK_BUFFER,
#ifndef MAGNUM_TARGET_GLES
/**
* Target for pixel pack operations.
* @requires_gl
* Used for shader storage.
* @requires_gl43 Extension @extension{ARB,shader_storage_buffer_object}
* @requires_gl Shader storage is not available in OpenGL ES.
*/
PixelPack = GL_PIXEL_PACK_BUFFER,
ShaderStorage = GL_SHADER_STORAGE_BUFFER,
/**
* Source for texel fetches.
*
* @see BufferedTexture
* @requires_gl
* Source for texel fetches. See BufferedTexture.
* @requires_gl31 Extension @extension{ARB,texture_buffer_object}
* @requires_gl Texture buffers are not available in OpenGL ES.
*/
Texture = GL_TEXTURE_BUFFER,
#endif
/**
* Target for transform feedback.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,transform_feedback}
* @requires_gles30 Transform feedback is not available in OpenGL
* ES 2.0.
*/
TransformFeedback = GL_TRANSFORM_FEEDBACK_BUFFER,
/**
* Used for storing uniforms.
* @requires_gl
* @requires_gl31 Extension @extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
*/
Uniform = GL_UNIFORM_BUFFER,
/**
* Used for supplying arguments for instanced drawing.
* @requires_gl
* @requires_gl40 Extension @extension{ARB,draw_indirect}
*/
DrawIndirect = GL_DRAW_INDIRECT_BUFFER
#endif
Uniform = GL_UNIFORM_BUFFER
};
/** @brief Buffer usage */
/**
* @brief %Buffer usage
*
* @see setData(GLsizeiptr, const GLvoid*, Usage)
*/
enum class Usage: GLenum {
/**
* Set once by the application and used infrequently for drawing.
*/
StreamDraw = GL_STREAM_DRAW,
#ifndef MAGNUM_TARGET_GLES
/**
* Set once as output from an OpenGL command and used infequently
* for drawing.
* @requires_gl
* @requires_gles30 Only @ref Magnum::Buffer::Usage "Usage::StreamDraw"
* is available in OpenGL ES 2.0.
*/
StreamRead = GL_STREAM_READ,
/**
* Set once as output from an OpenGL command and used infrequently
* for drawing or copying to other buffers.
* @requires_gl
* @requires_gles30 Only @ref Magnum::Buffer::Usage "Usage::StreamDraw"
* is available in OpenGL ES 2.0.
*/
StreamCopy = GL_STREAM_COPY,
#endif
/**
* Set once by the application and used frequently for drawing.
*/
StaticDraw = GL_STATIC_DRAW,
#ifndef MAGNUM_TARGET_GLES
/**
* Set once as output from an OpenGL command and queried many
* times by the application.
* @requires_gl
* @requires_gles30 Only @ref Magnum::Buffer::Usage "Usage::StaticDraw"
* is available in OpenGL ES 2.0.
*/
StaticRead = GL_STATIC_READ,
/**
* Set once as output from an OpenGL command and used frequently
* for drawing or copying to other buffers.
* @requires_gl
* @requires_gles30 Only @ref Magnum::Buffer::Usage "Usage::StaticDraw"
* is available in OpenGL ES 2.0.
*/
StaticCopy = GL_STATIC_COPY,
#endif
/**
* Updated frequently by the application and used frequently
* for drawing or copying to other images.
*/
DynamicDraw = GL_DYNAMIC_DRAW
#ifndef MAGNUM_TARGET_GLES
,
DynamicDraw = GL_DYNAMIC_DRAW,
/**
* Updated frequently as output from OpenGL command and queried
* many times from the application.
* @requires_gl
* @requires_gles30 Only @ref Magnum::Buffer::Usage "Usage::DynamicDraw"
* is available in OpenGL ES 2.0.
*/
DynamicRead = GL_DYNAMIC_READ,
/**
* Updated frequently as output from OpenGL command and used
* frequently for drawing or copying to other images.
* @requires_gl
* @requires_gles30 Only @ref Magnum::Buffer::Usage "Usage::DynamicCopy"
* is available in OpenGL ES 2.0.
*/
DynamicCopy = GL_DYNAMIC_COPY
#endif
};
/**
* @brief Unbind any buffer from given target
* @param target %Target
* @param target %Target
*
* @see @fn_gl{BindBuffer}
*/
inline static void unbind(Target target) { bind(target, 0); }
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Copy one buffer to another
* @param read %Buffer from which to read
* @param write %Buffer to which to copy
* @param readOffset Offset in the read buffer
* @param writeOffset Offset in the write buffer
* @param size Data size
*
* If @extension{EXT,direct_state_access} is not available and the
* buffers aren't already bound somewhere, they are bound to
* `Target::CopyRead` and `Target::CopyWrite` before the copy is
* performed.
* @requires_gl31 Extension @extension{ARB,copy_buffer}
* @requires_gles30 Buffer copying is not available in OpenGL ES 2.0.
* @see @fn_gl{BindBuffer} and @fn_gl{CopyBufferSubData} or
* @fn_gl_extension{NamedCopyBufferSubData,EXT,direct_state_access}
*/
inline static void unbind(Target target) {
glBindBuffer(static_cast<GLenum>(target), 0);
inline static void copy(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
copyImplementation(read, write, readOffset, writeOffset, size);
}
#endif
/**
* @brief Constructor
* @param defaultTarget Default target (used when calling bind()
* without parameter)
*
* Generates new OpenGL buffer.
* @see @fn_gl{GenBuffers}
*/
inline Buffer(Target defaultTarget): _defaultTarget(defaultTarget) {
glGenBuffers(1, &buffer);
inline Buffer(): _targetHint(Target::Array) {
glGenBuffers(1, &_id);
}
/**
* @brief Destructor
*
* Deletes associated OpenGL buffer.
* @see @fn_gl{DeleteBuffers}
*/
inline virtual ~Buffer() {
glDeleteBuffers(1, &buffer);
}
virtual ~Buffer();
/** @brief Default bind type */
inline Target defaultTarget() const { return _defaultTarget; }
/** @brief OpenGL buffer ID */
inline GLuint id() const { return _id; }
/** @brief OpenGL internal buffer ID */
inline GLuint id() const { return buffer; }
/** @brief Target hint */
inline Target targetHint() const { return _targetHint; }
/**
* @brief Bind buffer
* @brief Set target hint
*
* If @extension{EXT,direct_state_access} is not available, the buffer
* must be internally bound to some target before any operation. You
* can specify target which will always be used when binding the
* buffer internally, possibly saving some calls to @fn_gl{BindBuffer}.
*
* Binds buffer with default target.
* Default target hint is `Target::Array`.
* @see setData(), setSubData()
* @todo Target::ElementArray cannot be used when no VAO is bound -
* http://www.opengl.org/wiki/Vertex_Specification#Index_buffers
* ... damned GL state
*/
inline void bind() { bind(_defaultTarget); }
inline void setTargetHint(Target hint) { _targetHint = hint; }
/**
* @brief Bind buffer
* @param target %Target
* @param target %Target
*
* @todo Allow binding to Target::ElementArray only if VAO is bound
* to avoid potential issues?
* @bug Binding to ElementArray if any VAO is active will corrupt the mesh
* @todo Don't allow user to bind buffers?
* @see @fn_gl{BindBuffer}
*/
inline void bind(Target target) {
glBindBuffer(static_cast<GLenum>(target), buffer);
}
inline void bind(Target target) { bind(target, _id); }
/**
* @brief Set buffer data
@ -231,10 +347,14 @@ class Buffer {
* @param data Pointer to data
* @param usage %Buffer usage
*
* Sets buffer data with default target.
* If @extension{EXT,direct_state_access} is not available and the
* buffer is not already bound somewhere, it is bound to hinted target
* before the operation.
* @see setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{BufferData} or
* @fn_gl_extension{NamedBufferData,EXT,direct_state_access}
*/
inline void setData(GLsizeiptr size, const GLvoid* data, Usage usage) {
setData(_defaultTarget, size, data, usage);
(this->*setDataImplementation)(size, data, usage);
}
/**
@ -242,12 +362,10 @@ class Buffer {
* @param data Fixed-size array with data
* @param usage %Buffer usage
*
* Sets buffer data with default target. More convenient for setting
* data from fixed-size arrays than
* setData(GLsizeiptr, const GLvoid*, Usage).
* @see setData(GLsizeiptr, const GLvoid*, Usage).
*/
template<size_t size, class T> inline void setData(const T(&data)[size], Usage usage) {
setData(_defaultTarget, data, usage);
template<std::size_t size, class T> inline void setData(const T(&data)[size], Usage usage) {
setData(size*sizeof(T), data, usage);
}
/**
@ -255,121 +373,91 @@ class Buffer {
* @param data Vector with data
* @param usage %Buffer usage
*
* Sets buffer data with default target.
* @see setData(GLsizeiptr, const GLvoid*, Usage)
*/
template<class T> inline void setData(const std::vector<T>& data, Usage usage) {
setData(_defaultTarget, data, usage);
setData(data.size()*sizeof(T), data.data(), usage);
}
/**
* @brief Set buffer data
* @param target %Target
* @param size Data size
* @param data Pointer to data
* @param usage %Buffer usage
*/
inline void setData(Target target, GLsizeiptr size, const GLvoid* data, Usage usage) {
bind(target);
glBufferData(static_cast<GLenum>(target), size, data, static_cast<GLenum>(usage));
}
/**
* @brief Set buffer data
* @param target %Target
* @param data Fixed-size array with data
* @param usage %Buffer usage
*
* More convenient for setting data from fixed-size arrays than
* setData(Target, GLsizeiptr, const GLvoid*, Usage).
*/
template<size_t size, class T> inline void setData(Target target, const T(&data)[size], Usage usage) {
setData(target, size*sizeof(T), data, usage);
}
/**
* @brief Set buffer data
* @param target %Target
* @param data Vector with data
* @param usage %Buffer usage
*/
template<class T> inline void setData(Target target, const std::vector<T>& data, Usage usage) {
setData(target, data.size()*sizeof(T), data.data(), usage);
/** @overload */
template<std::size_t size, class T> inline void setData(const std::array<T, size>& data, Usage usage) {
setData(data.size()*sizeof(T), data.data(), usage);
}
/**
* @brief Set buffer subdata
* @param offset Offset
* @param offset Offset in the buffer
* @param size Data size
* @param data Pointer to data
*
* Sets buffer subdata with default target.
* If @extension{EXT,direct_state_access} is not available and the
* buffer is not already bound somewhere, it is bound to hinted target
* before the operation.
* @see setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{BufferSubData}
* or @fn_gl_extension{NamedBufferSubData,EXT,direct_state_access}
*/
inline void setSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data) {
setSubData(_defaultTarget, offset, size, data);
(this->*setSubDataImplementation)(offset, size, data);
}
/**
* @brief Set buffer subdata
* @param offset Offset
* @param offset Offset in the buffer
* @param data Fixed-size array with data
*
* Sets buffer subdata with default target. More convenient for
* setting data from fixed-size arrays than
* setSubData(GLintptr, GLsizeiptr, const GLvoid*).
* @see setSubData(GLintptr, GLsizeiptr, const GLvoid*)
*/
template<size_t size, class T> inline void setSubData(GLintptr offset, const T(&data)[size]) {
setSubData(_defaultTarget, offset, data);
template<std::size_t size, class T> inline void setSubData(GLintptr offset, const T(&data)[size]) {
setSubData(offset, size*sizeof(T), data);
}
/**
* @brief Set buffer subdata
* @param offset Offset
* @param offset Offset in the buffer
* @param data Vector with data
*
* Sets buffer subdata with default target.
* @see setSubData(GLintptr, GLsizeiptr, const GLvoid*)
*/
template<class T> inline void setSubData(GLintptr offset, const std::vector<T>& data) {
setSubData(_defaultTarget, offset, data);
setSubData(offset, data.size()*sizeof(T), data.data());
}
/**
* @brief Set buffer subdata
* @param target %Target
* @param offset Offset
* @param size Data size
* @param data Pointer to data
*/
inline void setSubData(Target target, GLintptr offset, GLsizeiptr size, const GLvoid* data) {
bind(target);
glBufferSubData(static_cast<GLenum>(target), offset, size, data);
}
/**
* @brief Set buffer subdata
* @param target %Target
* @param offset Offset
* @param data Fixed-size array with data
*
* More convenient for setting data from fixed-size arrays than
* setSubData(Target, GLintptr, GLsizeiptr, const GLvoid*).
*/
template<size_t size, class T> inline void setSubData(Target target, GLintptr offset, const T(&data)[size]) {
setSubData(target, offset, size*sizeof(T), data);
}
/**
* @brief Set buffer subdata
* @param target %Target
* @param offset Offset
* @param data Vector with data
*/
template<class T> inline void setSubData(Target target, GLintptr offset, const std::vector<T>& data) {
setSubData(target, offset, data.size()*sizeof(T), data.data());
/** @overload */
template<std::size_t size, class T> inline void setSubData(GLintptr offset, const std::array<T, size>& data) {
setSubData(offset, data.size()*sizeof(T), data.data());
}
private:
GLuint buffer;
Target _defaultTarget;
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void bind(Target hint, GLuint id);
Target MAGNUM_LOCAL bindInternal(Target hint);
#ifndef MAGNUM_TARGET_GLES2
typedef void(*CopyImplementation)(Buffer*, Buffer*, GLintptr, GLintptr, GLsizeiptr);
static void MAGNUM_LOCAL copyImplementationDefault(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
#ifndef MAGNUM_TARGET_GLES
static void MAGNUM_LOCAL copyImplementationDSA(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
#endif
static CopyImplementation copyImplementation;
#endif
typedef void(Buffer::*SetDataImplementation)(GLsizeiptr, const GLvoid*, Usage);
void MAGNUM_LOCAL setDataImplementationDefault(GLsizeiptr size, const GLvoid* data, Usage usage);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL setDataImplementationDSA(GLsizeiptr size, const GLvoid* data, Usage usage);
#endif
static SetDataImplementation setDataImplementation;
typedef void(Buffer::*SetSubDataImplementation)(GLintptr, GLsizeiptr, const GLvoid*);
void MAGNUM_LOCAL setSubDataImplementationDefault(GLintptr offset, GLsizeiptr size, const GLvoid* data);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL setSubDataImplementationDSA(GLintptr offset, GLsizeiptr size, const GLvoid* data);
#endif
static SetSubDataImplementation setSubDataImplementation;
GLuint _id;
Target _targetHint;
};
}

31
src/BufferedImage.cpp

@ -0,0 +1,31 @@
/*
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 "BufferedImage.h"
namespace Magnum {
template<std::uint8_t dimensions> void BufferedImage<dimensions>::setData(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, ComponentType type, const GLvoid* data, Buffer::Usage usage) {
_components = components;
_type = type;
_size = size;
_buffer.setData(pixelSize(_components, _type)*size.product(), data, usage);
}
template class BufferedImage<1>;
template class BufferedImage<2>;
template class BufferedImage<3>;
}

46
src/BufferedImage.h

@ -19,24 +19,26 @@
* @brief Class Magnum::BufferedImage, typedef Magnum::BufferedImage1D, Magnum::BufferedImage2D, Magnum::BufferedImage3D
*/
#include "Math/Vector3.h"
#include "AbstractImage.h"
#include "Buffer.h"
#include "DimensionTraits.h"
#include "TypeTraits.h"
namespace Magnum {
#ifndef MAGNUM_TARGET_GLES
/**
@brief %Buffered image
Class for storing image data in GPU memory. Can be replaced with Image, which
stores image data in client memory, ImageWrapper, or for example with
Trade::ImageData.
@requires_gl
@see BufferedImage1D, BufferedImage2D, BufferedImage3D, Buffer
@requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0.
*/
template<size_t imageDimensions> class BufferedImage: public AbstractImage {
template<std::uint8_t dimensions> class MAGNUM_EXPORT BufferedImage: public AbstractImage {
public:
const static size_t Dimensions = imageDimensions; /**< @brief Image dimension count */
const static std::uint8_t Dimensions = dimensions; /**< @brief %Image dimension count */
/**
* @brief Constructor
@ -46,10 +48,12 @@ template<size_t imageDimensions> class BufferedImage: public AbstractImage {
* Dimensions and buffer are empty, call setData() to fill the image
* with data.
*/
BufferedImage(Components components, ComponentType type): AbstractImage(components, type), _buffer(Buffer::Target::PixelPack) {}
inline BufferedImage(Components components, ComponentType type): AbstractImage(components, type) {
_buffer.setTargetHint(Buffer::Target::PixelPack);
}
/** @brief %Image dimensions */
inline constexpr Math::Vector<Dimensions, GLsizei> dimensions() const { return _dimensions; }
/** @brief %Image size */
inline typename DimensionTraits<Dimensions, GLsizei>::VectorType size() const { return _size; }
/**
* @brief Data
@ -57,8 +61,10 @@ template<size_t imageDimensions> class BufferedImage: public AbstractImage {
* Binds the buffer to @ref Buffer::Target "pixel unpack
* target" and returns nullptr, so it can be used for texture updating
* functions the same way as Image::data().
*
* @see Buffer::bind(Target)
*/
void* data() {
inline void* data() {
_buffer.bind(Buffer::Target::PixelUnpack);
return nullptr;
}
@ -68,7 +74,7 @@ template<size_t imageDimensions> class BufferedImage: public AbstractImage {
/**
* @brief Set image data
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components. Data type is detected
* from passed data array.
* @param data %Image data
@ -76,14 +82,16 @@ template<size_t imageDimensions> class BufferedImage: public AbstractImage {
*
* Updates the image buffer with given data. The data are not deleted
* after filling the buffer.
*
* @see setData(const Math::Vector<Dimensions, GLsizei>&, Components, ComponentType, const GLvoid*, Buffer::Usage)
*/
template<class T> inline void setData(const Math::Vector<Dimensions, GLsizei>& dimensions, Components components, const T* data, Buffer::Usage usage) {
setData(dimensions, components, TypeTraits<T>::imageType(), data, usage);
template<class T> inline void setData(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, const T* data, Buffer::Usage usage) {
setData(size, components, TypeTraits<T>::imageType(), data, usage);
}
/**
* @brief Set image data
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components
* @param type Data type
* @param data %Image data
@ -91,17 +99,14 @@ template<size_t imageDimensions> class BufferedImage: public AbstractImage {
*
* Updates the image buffer with given data. The data are not deleted
* after filling the buffer.
*
* @see Buffer::setData()
*/
void setData(const Math::Vector<Dimensions, GLsizei>& dimensions, Components components, ComponentType type, const GLvoid* data, Buffer::Usage usage) {
_components = components;
_type = type;
_dimensions = dimensions;
_buffer.setData(Buffer::Target::PixelPack, pixelSize(_components, _type)*dimensions.product(), data, usage);
}
void setData(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, ComponentType type, const GLvoid* data, Buffer::Usage usage);
protected:
Math::Vector<Dimensions, GLsizei> _dimensions; /**< @brief %Image dimensions */
Buffer _buffer; /**< @brief %Image buffer */
Math::Vector<Dimensions, GLsizei> _size; /**< @brief %Image size */
Buffer _buffer; /**< @brief %Image buffer */
};
/** @brief One-dimensional buffered image */
@ -112,7 +117,6 @@ typedef BufferedImage<2> BufferedImage2D;
/** @brief Three-dimensional buffered image */
typedef BufferedImage<3> BufferedImage3D;
#endif
}

27
src/BufferedTexture.cpp

@ -15,9 +15,32 @@
#include "BufferedTexture.h"
#ifndef MAGNUM_TARGET_GLES
#include "Buffer.h"
#include "Context.h"
#include "Extensions.h"
namespace Magnum {
#ifndef MAGNUM_TARGET_GLES
BufferedTexture::SetBufferImplementation BufferedTexture::setBufferImplementation = &BufferedTexture::setBufferImplementationDefault;
void BufferedTexture::initializeContextBasedFunctionality(Context* context) {
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "BufferedTexture: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
setBufferImplementation = &BufferedTexture::setBufferImplementationDSA;
}
}
void BufferedTexture::setBufferImplementationDefault(BufferedTexture::InternalFormat internalFormat, Buffer* buffer) {
bindInternal();
glTexBuffer(GL_TEXTURE_BUFFER, internalFormat, buffer->id());
}
void BufferedTexture::setBufferImplementationDSA(BufferedTexture::InternalFormat internalFormat, Buffer* buffer) {
glTextureBufferEXT(id(), GL_TEXTURE_BUFFER, internalFormat, buffer->id());
}
BufferedTexture::InternalFormat::InternalFormat(Components components, ComponentType type) {
#define internalFormatSwitch(c) switch(type) { \
case ComponentType::UnsignedByte: \
@ -49,6 +72,6 @@ BufferedTexture::InternalFormat::InternalFormat(Components components, Component
internalFormatSwitch(RGBA)
#undef internalFormatSwitch
}
#endif
}
#endif

63
src/BufferedTexture.h

@ -15,16 +15,20 @@
GNU Lesser General Public License version 3 for more details.
*/
#ifndef MAGNUM_TARGET_GLES
/** @file
* @brief Class Magnum::BufferedTexture
*/
#endif
#include "Renderbuffer.h"
#include "Buffer.h"
#include "AbstractTexture.h"
#ifndef MAGNUM_TARGET_GLES
namespace Magnum {
#ifndef MAGNUM_TARGET_GLES
class Buffer;
class Context;
/**
@brief Buffered texture
@ -37,10 +41,19 @@ using data setting functions in Buffer itself.
When using buffered texture in the shader, use `samplerBuffer` and fetch the
data using integer coordinates in `texelFetch()`.
@requires_gl
@section BufferedTexture-performance-optimization Performance optimizations
If extension @extension{EXT,direct_state_access} is available, setBuffer()
uses DSA function to avoid unnecessary calls to @fn_gl{ActiveTexture} and
@fn_gl{BindTexture}. See @ref AbstractTexture-performance-optimization
"relevant section in AbstractTexture documentation" and respective function
documentation for more information.
@requires_gl31 Extension @extension{ARB,texture_buffer_object}
@requires_gl Texture buffers are not available in OpenGL ES.
*/
class BufferedTexture {
class MAGNUM_EXPORT BufferedTexture: private AbstractTexture {
friend class Context;
BufferedTexture(const BufferedTexture& other) = delete;
BufferedTexture(BufferedTexture&& other) = delete;
BufferedTexture& operator=(const BufferedTexture& other) = delete;
@ -117,25 +130,10 @@ class BufferedTexture {
/*@}*/
/**
* @brief Constructor
*
* Creates one OpenGL texture.
*/
inline BufferedTexture() {
glGenTextures(1, &texture);
}
/** @copydoc AbstractTexture::~AbstractTexture() */
inline virtual ~BufferedTexture() {
glDeleteTextures(1, &texture);
}
inline BufferedTexture(): AbstractTexture(GL_TEXTURE_BUFFER) {}
/** @copydoc AbstractTexture::bind(GLint) */
inline void bind(GLint layer) {
glActiveTexture(GL_TEXTURE0 + layer);
bind();
}
/** @copydoc AbstractTexture::bind() */
inline void bind(GLint layer) { AbstractTexture::bind(layer); }
/**
* @brief Set texture buffer
@ -145,19 +143,20 @@ class BufferedTexture {
* Binds given buffer to this texture. The buffer itself can be then
* filled with data of proper format at any time using Buffer own data
* setting functions.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBuffer}
* or @fn_gl_extension{TextureBuffer,EXT,direct_state_access}
*/
void setBuffer(InternalFormat internalFormat, Buffer* buffer) {
bind();
glTexBuffer(GL_TEXTURE_BUFFER, internalFormat, buffer->id());
inline void setBuffer(InternalFormat internalFormat, Buffer* buffer) {
(this->*setBufferImplementation)(internalFormat, buffer);
}
private:
GLuint texture;
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
/** @copydoc AbstractTexture::bind() */
inline void bind() {
glBindTexture(GL_TEXTURE_BUFFER, texture);
}
typedef void(BufferedTexture::*SetBufferImplementation)(InternalFormat, Buffer*);
void MAGNUM_LOCAL setBufferImplementationDefault(InternalFormat internalFormat, Buffer* buffer);
void MAGNUM_LOCAL setBufferImplementationDSA(InternalFormat internalFormat, Buffer* buffer);
static SetBufferImplementation setBufferImplementation;
};
/** @relates BufferedTexture
@ -172,8 +171,8 @@ inline BufferedTexture::InternalFormat operator|(BufferedTexture::Components com
inline BufferedTexture::InternalFormat operator|(BufferedTexture::ComponentType type, BufferedTexture::Components components) {
return BufferedTexture::InternalFormat(components, type);
}
#endif
}
#endif
#endif

70
src/CMakeLists.txt

@ -1,14 +1,21 @@
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wold-style-cast -pedantic -std=c++0x -fvisibility=hidden")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wold-style-cast -Winit-self -pedantic -std=c++0x -fvisibility=hidden")
# -Wdouble-promotion is supported from GCC 4.6
# TODO: do this with check_c_compiler_flags()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.6.0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
endif()
# If targeting GLES, save it into configuration header
if(TARGET_GLES)
set(MAGNUM_TARGET_GLES 1)
endif()
if(TARGET_GLES2)
set(MAGNUM_TARGET_GLES2 1)
endif()
# -Wdouble-promotion is supported from GCC 4.6
# TODO: do this with check_c_compiler_flags()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.6.0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
if(GCC46_COMPATIBILITY)
set(MAGNUM_GCC46_COMPATIBILITY 1)
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/magnumConfigure.h.cmake
@ -21,8 +28,11 @@ set(Magnum_SRCS
AbstractImage.cpp
AbstractTexture.cpp
AbstractShaderProgram.cpp
BufferedTexture.cpp
Buffer.cpp
BufferedImage.cpp
Context.cpp
Framebuffer.cpp
Image.cpp
IndexedMesh.cpp
Mesh.cpp
Profiler.cpp
@ -30,20 +40,33 @@ set(Magnum_SRCS
Renderbuffer.cpp
Shader.cpp
SizeTraits.cpp
Timeline.cpp
TypeTraits.cpp
Implementation/BufferState.cpp
Implementation/State.cpp
Trade/AbstractImporter.cpp
Trade/MeshData.cpp)
Trade/MeshData2D.cpp
Trade/MeshData3D.cpp)
# Desktop-only code
if(NOT TARGET_GLES)
set(Magnum_SRCS ${Magnum_SRCS}
BufferedTexture.cpp)
endif()
set(Magnum_HEADERS
AbstractImage.h
AbstractShaderProgram.h
AbstractTexture.h
BufferedImage.h
BufferedTexture.h
Buffer.h
Color.h
CubeMapTextureArray.h
Context.h
CubeMapTexture.h
DimensionTraits.h
Extensions.h
Framebuffer.h
Image.h
ImageWrapper.h
@ -53,14 +76,24 @@ set(Magnum_HEADERS
Profiler.h
Query.h
Renderbuffer.h
ResourceManager.h
Shader.h
SizeTraits.h
Swizzle.h
Texture.h
Timeline.h
TypeTraits.h
magnumCompatibility.h
magnumVisibility.h)
# Desktop-only headers
if(NOT TARGET_GLES)
set(Magnum_HEADERS ${Magnum_HEADERS}
BufferedTexture.h
CubeMapTextureArray.h)
endif()
if(NOT CMAKE_NO_OBJECT_TARGET)
add_library(MagnumObjects OBJECT ${Magnum_SRCS})
endif()
@ -88,12 +121,18 @@ else()
${Magnum_SRCS}
${MagnumMath_SRCS})
endif()
target_link_libraries(Magnum ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY})
set(Magnum_LIBS
${CORRADE_UTILITY_LIBRARY}
${CORRADE_PLUGINMANAGER_LIBRARY})
if(NOT TARGET_GLES)
target_link_libraries(Magnum ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARY})
set(Magnum_LIBS ${Magnum_LIBS}
${OPENGL_gl_LIBRARY}
${GLEW_LIBRARY})
else()
target_link_libraries(Magnum ${OPENGLES2_LIBRARY})
set(Magnum_LIBS ${Magnum_LIBS}
${OPENGLES2_LIBRARY})
endif()
target_link_libraries(Magnum ${Magnum_LIBS})
install(TARGETS Magnum DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
install(FILES ${Magnum_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR})
@ -137,12 +176,7 @@ if(BUILD_TESTS)
${Magnum_SRCS})
endif()
set_target_properties(MagnumTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
target_link_libraries(MagnumTestLib ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY})
if(NOT TARGET_GLES)
target_link_libraries(MagnumTestLib ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARY})
else()
target_link_libraries(MagnumTestLib ${OPENGLES2_LIBRARY})
endif()
target_link_libraries(MagnumTestLib ${Magnum_LIBS})
add_subdirectory(Test)
endif()

47
src/Color.h

@ -160,7 +160,7 @@ template<class T> class Color3: public Math::Vector3<T> {
* @brief Create integral color from floating-point color
*
* E.g. `{0.294118, 0.45098, 0.878431}` is converted to
* `{75, 115, 224}`, if resulting type is `unsigned char`.
* `{75, 115, 224}`, if resulting type is `uint8_t`.
*
* @note This function is enabled only if source type is floating-point
* and destination type is integral.
@ -175,7 +175,7 @@ template<class T> class Color3: public Math::Vector3<T> {
* @brief Create floating-point color from integral color
*
* E.g. `{75, 115, 224}` is converted to
* `{0.294118, 0.45098, 0.878431}`, if source type is `unsigned char`.
* `{0.294118, 0.45098, 0.878431}`, if source type is `uint8_t`.
*
* @note This function is enabled only if source type is integral
* and destination type is floating-point.
@ -224,13 +224,12 @@ template<class T> class Color3: public Math::Vector3<T> {
*/
inline constexpr Color3(T r, T g, T b): Math::Vector3<T>(r, g, b) {}
inline constexpr T r() const { return Math::Vector3<T>::x(); } /**< @brief R component */
inline constexpr T g() const { return Math::Vector3<T>::y(); } /**< @brief G component */
inline constexpr T b() const { return Math::Vector3<T>::z(); } /**< @brief B component */
inline void setR(T value) { Math::Vector3<T>::setX(value); } /**< @brief Set R component */
inline void setG(T value) { Math::Vector3<T>::setY(value); } /**< @brief Set G component */
inline void setB(T value) { Math::Vector3<T>::setZ(value); } /**< @brief Set B component */
inline T& r() { return Math::Vector3<T>::x(); } /**< @brief R component */
inline constexpr T r() const { return Math::Vector3<T>::x(); } /**< @overload */
inline T& g() { return Math::Vector3<T>::y(); } /**< @brief G component */
inline constexpr T g() const { return Math::Vector3<T>::y(); } /**< @overload */
inline T& b() { return Math::Vector3<T>::z(); } /**< @brief B component */
inline constexpr T b() const { return Math::Vector3<T>::z(); } /**< @overload */
/**
* @brief Convert to HSV
@ -360,17 +359,16 @@ template<class T> class Color4: public Math::Vector4<T> {
*/
/* Not marked as explicit, because conversion from Color3 to Color4
is fairly common, nearly always with A set to 1 */
inline constexpr Color4(const Math::Vector<3, T>& rgb, T a = Implementation::defaultAlpha<T>()): Math::Vector4<T>(rgb[0], rgb[1], rgb[2], a) {}
inline constexpr T r() const { return Math::Vector4<T>::x(); } /**< @brief R component */
inline constexpr T g() const { return Math::Vector4<T>::y(); } /**< @brief G component */
inline constexpr T b() const { return Math::Vector4<T>::z(); } /**< @brief B component */
inline constexpr T a() const { return Math::Vector4<T>::w(); } /**< @brief A component */
inline constexpr Color4(const Math::Vector3<T>& rgb, T a = Implementation::defaultAlpha<T>()): Math::Vector4<T>(rgb[0], rgb[1], rgb[2], a) {}
inline void setR(T value) { Math::Vector4<T>::setX(value); } /**< @brief Set R component */
inline void setG(T value) { Math::Vector4<T>::setY(value); } /**< @brief Set G component */
inline void setB(T value) { Math::Vector4<T>::setZ(value); } /**< @brief Set B component */
inline void setA(T value) { Math::Vector4<T>::setW(value); } /**< @brief Set A component */
inline T& r() { return Math::Vector4<T>::x(); } /**< @brief R component */
inline constexpr T r() const { return Math::Vector4<T>::x(); } /**< @overload */
inline T& g() { return Math::Vector4<T>::y(); } /**< @brief G component */
inline constexpr T g() const { return Math::Vector4<T>::y(); } /**< @overload */
inline T& b() { return Math::Vector4<T>::z(); } /**< @brief B component */
inline constexpr T b() const { return Math::Vector4<T>::z(); } /**< @overload */
inline T& a() { return Math::Vector4<T>::w(); } /**< @brief A component */
inline constexpr T a() const { return Math::Vector4<T>::w(); } /**< @overload */
/**
* @brief RGB part of the vector
@ -378,7 +376,8 @@ template<class T> class Color4: public Math::Vector4<T> {
*
* @see swizzle()
*/
inline constexpr Color3<T> rgb() const { return Math::Vector4<T>::xyz(); }
inline Color3<T>& rgb() { return Color3<T>::from(Math::Vector4<T>::data()); }
inline constexpr Color3<T> rgb() const { return Color3<T>::from(Math::Vector4<T>::data()); } /**< @overload */
/** @copydoc Color3::toHSV() */
inline constexpr HSV toHSV() const {
@ -407,13 +406,13 @@ template<class T> class Color4: public Math::Vector4<T> {
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color4, 4)
/** @debugoperator{Magnum::Color3} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color3<T>& value) {
return debug << static_cast<const Magnum::Math::Vector3<T>&>(value);
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Color3<T>& value) {
return debug << static_cast<const Math::Vector3<T>&>(value);
}
/** @debugoperator{Magnum::Color4} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color4<T>& value) {
return debug << static_cast<const Magnum::Math::Vector4<T>&>(value);
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Color4<T>& value) {
return debug << static_cast<const Math::Vector4<T>&>(value);
}
}

265
src/Context.cpp

@ -0,0 +1,265 @@
/*
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 "Context.h"
#include <string>
#include <unordered_map>
#include <Utility/Debug.h>
#include "AbstractShaderProgram.h"
#include "AbstractTexture.h"
#include "Buffer.h"
#include "BufferedTexture.h"
#include "Extensions.h"
#include "IndexedMesh.h"
#include "Mesh.h"
#include "Implementation/State.h"
using namespace std;
namespace Magnum {
const std::vector<Extension>& Extension::extensions(Version version) {
#define _extension(prefix, vendor, extension) \
{Extensions::prefix::vendor::extension::Index, Extensions::prefix::vendor::extension::requiredVersion(), Extensions::prefix::vendor::extension::coreVersion(), Extensions::prefix::vendor::extension::string()}
static const std::vector<Extension> empty;
#ifndef MAGNUM_TARGET_GLES
static const std::vector<Extension> extensions{
_extension(GL,EXT,texture_filter_anisotropic)};
static const std::vector<Extension> extensions300{
_extension(GL,APPLE,flush_buffer_range),
_extension(GL,APPLE,vertex_array_object),
_extension(GL,ARB,color_buffer_float),
_extension(GL,ARB,half_float_pixel),
_extension(GL,ARB,texture_float),
_extension(GL,ARB,depth_buffer_float),
_extension(GL,ARB,texture_rg),
_extension(GL,EXT,framebuffer_object),
_extension(GL,EXT,packed_depth_stencil),
_extension(GL,EXT,framebuffer_blit),
_extension(GL,EXT,framebuffer_multisample),
_extension(GL,EXT,gpu_shader4),
_extension(GL,EXT,packed_float),
_extension(GL,EXT,texture_array),
_extension(GL,EXT,texture_compression_rgtc),
_extension(GL,EXT,texture_shared_exponent),
_extension(GL,EXT,framebuffer_sRGB),
_extension(GL,EXT,draw_buffers2),
_extension(GL,EXT,texture_integer),
_extension(GL,EXT,transform_feedback),
_extension(GL,NV,half_float),
_extension(GL,NV,depth_buffer_float),
_extension(GL,NV,conditional_render)};
static const std::vector<Extension> extensions310{
_extension(GL,ARB,texture_rectangle),
_extension(GL,ARB,draw_instanced),
_extension(GL,ARB,texture_buffer_object),
_extension(GL,ARB,uniform_buffer_object),
_extension(GL,ARB,copy_buffer),
_extension(GL,EXT,texture_snorm),
_extension(GL,NV,primitive_restart)};
static const std::vector<Extension> extensions320{
_extension(GL,ARB,geometry_shader4),
_extension(GL,ARB,depth_clamp),
_extension(GL,ARB,draw_elements_base_vertex),
_extension(GL,ARB,fragment_coord_conventions),
_extension(GL,ARB,provoking_vertex),
_extension(GL,ARB,seamless_cube_map),
_extension(GL,ARB,sync),
_extension(GL,ARB,texture_multisample),
_extension(GL,ARB,vertex_array_bgra)};
static const std::vector<Extension> extensions330{
_extension(GL,ARB,instanced_arrays),
_extension(GL,ARB,blend_func_extended),
_extension(GL,ARB,explicit_attrib_location),
_extension(GL,ARB,occlusion_query2),
_extension(GL,ARB,sampler_objects),
_extension(GL,ARB,shader_bit_encoding),
_extension(GL,ARB,texture_rgb10_a2ui),
_extension(GL,ARB,texture_swizzle),
_extension(GL,ARB,timer_query),
_extension(GL,ARB,vertex_type_2_10_10_10_rev)};
static const std::vector<Extension> extensions400{
_extension(GL,ARB,draw_buffers_blend),
_extension(GL,ARB,sample_shading),
_extension(GL,ARB,texture_cube_map_array),
_extension(GL,ARB,texture_gather),
_extension(GL,ARB,texture_query_lod),
_extension(GL,ARB,draw_indirect),
_extension(GL,ARB,gpu_shader5),
_extension(GL,ARB,gpu_shader_fp64),
_extension(GL,ARB,shader_subroutine),
_extension(GL,ARB,tessellation_shader),
_extension(GL,ARB,texture_buffer_object_rgb32),
_extension(GL,ARB,transform_feedback2),
_extension(GL,ARB,transform_feedback3)};
static const std::vector<Extension> extensions410{
_extension(GL,ARB,ES2_compatibility),
_extension(GL,ARB,get_program_binary),
_extension(GL,ARB,separate_shader_objects),
_extension(GL,ARB,shader_precision),
_extension(GL,ARB,vertex_attrib_64bit),
_extension(GL,ARB,viewport_array)};
static const std::vector<Extension> extensions420{
_extension(GL,ARB,texture_compression_bptc),
_extension(GL,ARB,base_instance),
_extension(GL,ARB,shading_language_420pack),
_extension(GL,ARB,transform_feedback_instanced),
_extension(GL,ARB,compressed_texture_pixel_storage),
_extension(GL,ARB,conservative_depth),
_extension(GL,ARB,internalformat_query),
_extension(GL,ARB,map_buffer_alignment),
_extension(GL,ARB,shader_atomic_counters),
_extension(GL,ARB,shader_image_load_store),
_extension(GL,ARB,texture_storage)};
static const std::vector<Extension> extensions430;
#undef _extension
#else
static const std::vector<Extension> extensions;
static const std::vector<Extension> extensionsES200;
static const std::vector<Extension> extensionsES300;
#endif
switch(version) {
case Version::None: return extensions;
#ifndef MAGNUM_TARGET_GLES
case Version::GL210: return empty;
case Version::GL300: return extensions300;
case Version::GL310: return extensions310;
case Version::GL320: return extensions320;
case Version::GL330: return extensions330;
case Version::GL400: return extensions400;
/* case Version::GLES200: */
case Version::GL410: return extensions410;
case Version::GL420: return extensions420;
/* case Version::GLES300: */
case Version::GL430: return extensions430;
#else
case Version::GLES200: return extensionsES200;
case Version::GLES300: return extensionsES300;
#endif
}
return empty;
}
Context* Context::_current = nullptr;
Context::Context() {
/* Version */
glGetIntegerv(GL_MAJOR_VERSION, &_majorVersion);
glGetIntegerv(GL_MINOR_VERSION, &_minorVersion);
_version = static_cast<Version>(_majorVersion*100+_minorVersion*10);
/* Get first future (not supported) version */
vector<Version> versions{
#ifndef MAGNUM_TARGET_GLES
Version::GL300,
Version::GL310,
Version::GL320,
Version::GL330,
Version::GL400,
Version::GL410,
Version::GL420,
Version::GL430,
#else
Version::GLES200,
Version::GLES300,
#endif
Version::None
};
size_t future = 0;
while(versions[future] != Version::None && versions[future] < _version)
++future;
/* List of extensions from future versions (extensions from current and
previous versions should be supported automatically, so we don't need
to check for them) */
unordered_map<string, Extension> futureExtensions;
for(size_t i = future; i != versions.size(); ++i)
for(const Extension& extension: Extension::extensions(versions[i]))
futureExtensions.insert(make_pair(extension._string, extension));
/* Check for presence of extensions in future versions */
#ifndef MAGNUM_TARGET_GLES
if(isVersionSupported(Version::GL300)) {
#else
if(isVersionSupported(Version::GLES300)) {
#endif
#ifndef MAGNUM_TARGET_GLES2
GLuint index = 0;
const char* extension;
while((extension = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, index++)))) {
auto found = futureExtensions.find(extension);
if(found != futureExtensions.end()) {
_supportedExtensions.push_back(found->second);
extensionStatus.set(found->second._index);
}
}
#endif
/* OpenGL 2.1 / OpenGL ES 2.0 doesn't have glGetStringi() */
} else {
/* Don't crash when glGetString() returns nullptr */
const char* e = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if(e) {
vector<string> extensions = Corrade::Utility::split(e, ' ');
for(const string& extension: extensions) {
auto found = futureExtensions.find(extension);
if(found != futureExtensions.end()) {
_supportedExtensions.push_back(found->second);
extensionStatus.set(found->second._index);
}
}
}
}
/* Set this context as current */
CORRADE_ASSERT(!_current, "Context: Another context currently active", );
_current = this;
/* Initialize state tracker */
_state = new Implementation::State;
/* Initialize functionality based on current OpenGL version and extensions */
AbstractShaderProgram::initializeContextBasedFunctionality(this);
AbstractTexture::initializeContextBasedFunctionality(this);
Buffer::initializeContextBasedFunctionality(this);
#ifndef MAGNUM_TARGET_GLES
BufferedTexture::initializeContextBasedFunctionality(this);
#endif
IndexedMesh::initializeContextBasedFunctionality(this);
Mesh::initializeContextBasedFunctionality(this);
}
Context::~Context() {
CORRADE_ASSERT(_current == this, "Context: Cannot destroy context which is not currently active", );
delete _state;
_current = nullptr;
}
Version Context::supportedVersion(initializer_list<Version> versions) const {
for(auto version: versions)
if(isVersionSupported(version)) return version;
#ifndef MAGNUM_TARGET_GLES
return Version::GL210;
#else
return Version::GLES200;
#endif
}
}

273
src/Context.h

@ -0,0 +1,273 @@
#ifndef Magnum_Context_h
#define Magnum_Context_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 Enum Version, class Magnum::Context, Magnum::Extension
*/
#include <bitset>
#include <vector>
#include "Magnum.h"
#include "magnumVisibility.h"
namespace Magnum {
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
class State;
}
#endif
/** @brief OpenGL version */
enum class Version: GLint {
None = 0, /**< @brief Unspecified */
#ifndef MAGNUM_TARGET_GLES
GL210 = 210, /**< @brief OpenGL 2.1 / GLSL 1.20 */
GL300 = 300, /**< @brief OpenGL 3.0 / GLSL 1.30 */
GL310 = 310, /**< @brief OpenGL 3.1 / GLSL 1.40 */
GL320 = 320, /**< @brief OpenGL 3.2 / GLSL 1.50 */
GL330 = 330, /**< @brief OpenGL 3.3, GLSL 3.30 */
GL400 = 400, /**< @brief OpenGL 4.0, GLSL 4.00 */
GL410 = 410, /**< @brief OpenGL 4.1, GLSL 4.10 */
GL420 = 420, /**< @brief OpenGL 4.2, GLSL 4.20 */
GL430 = 430, /**< @brief OpenGL 4.3, GLSL 4.30 */
#endif
/**
* @brief OpenGL ES 2.0, GLSL ES 1.00
*
* All the functionality is present in OpenGL 4.2 (extension
* @extension{ARB,ES2_compatibility}), so on desktop OpenGL this is
* equivalent to @ref Version "Version::GL410".
*/
#ifndef MAGNUM_TARGET_GLES
GLES200 = 410,
#else
GLES200 = 200,
#endif
/**
* @brief OpenGL ES 3.0, GLSL ES 3.00
*
* All the functionality is present in OpenGL 4.3 (extension
* @extension{ARB,ES3_compatibility}), so on desktop OpenGL this is the
* equivalent to @ref Version "Version::GL430".
*/
#ifndef MAGNUM_TARGET_GLES
GLES300 = 430
#else
GLES300 = 300
#endif
};
/**
@brief Run-time information about OpenGL extension
Encapsulates runtime information about OpenGL extension, such as name string,
minimal required OpenGL version and version in which the extension was adopted
to core.
See also Extensions namespace, which contain compile-time information about
OpenGL extensions.
*/
class MAGNUM_EXPORT Extension {
friend class Context;
public:
/** @brief All extensions for given OpenGL version */
static const std::vector<Extension>& extensions(Version version);
/** @brief Minimal version required by this extension */
inline constexpr Version requiredVersion() const { return _requiredVersion; }
/** @brief Version in which this extension was adopted to core */
inline constexpr Version coreVersion() const { return _coreVersion; }
/** @brief %Extension string */
inline constexpr const char* string() const { return _string; }
private:
/* GCC 4.6 doesn't like const members, as std::vector doesn't have
proper move semantic yet */
std::size_t _index;
Version _requiredVersion;
Version _coreVersion;
const char* _string;
inline constexpr Extension(std::size_t index, Version requiredVersion, Version coreVersion, const char* string): _index(index), _requiredVersion(requiredVersion), _coreVersion(coreVersion), _string(string) {}
};
/**
@brief OpenGL context
Provides access to version and extension information.
*/
class MAGNUM_EXPORT Context {
Context(const Context&) = delete;
Context(Context&&) = delete;
Context& operator=(const Context&) = delete;
Context& operator=(Context&&) = delete;
public:
/**
* @brief Constructor
*
* @see @fn_gl{Get} with @def_gl{MAJOR_VERSION}, @def_gl{MINOR_VERSION},
* @fn_gl{GetString} with @def_gl{EXTENSIONS}
*/
Context();
~Context();
/** @brief Current context */
inline static Context* current() { return _current; }
/** @brief OpenGL version */
inline Version version() const { return _version; }
/** @brief Major OpenGL version (e.g. `4`) */
inline GLint majorVersion() const { return _majorVersion; }
/** @brief Minor OpenGL version (e.g. `3`) */
inline GLint minorVersion() const { return _minorVersion; }
/**
* @brief Vendor string
*
* @see @fn_gl{GetString} with @def_gl{VENDOR}
*/
inline std::string vendorString() const {
return reinterpret_cast<const char*>(glGetString(GL_VENDOR));
}
/**
* @brief Renderer string
*
* @see @fn_gl{GetString} with @def_gl{RENDERER}
*/
inline std::string rendererString() const {
return reinterpret_cast<const char*>(glGetString(GL_RENDERER));
}
/**
* @brief Version string
*
* @see @fn_gl{GetString} with @def_gl{VERSION}
*/
inline std::string versionString() const {
return reinterpret_cast<const char*>(glGetString(GL_VERSION));
}
/**
* @brief Shading language version string
*
* @see @fn_gl{GetString} with @def_gl{SHADING_LANGUAGE_VERSION}
*/
inline std::string shadingLanguageVersionString() const {
return reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
}
/**
* @brief Supported extensions
*
* The list contains only extensions from OpenGL versions newer than
* the current.
*
* @see isExtensionSupported(), Extension::extensions()
*/
inline const std::vector<Extension>& supportedExtensions() const {
return _supportedExtensions;
}
/**
* @brief Whether given OpenGL version is supported
*
* @see supportedVersion()
*/
inline bool isVersionSupported(Version version) const {
return _version >= version;
}
/**
* @brief Get supported OpenGL version
*
* Returns first supported OpenGL version from passed list. Convenient
* equivalent to subsequent isVersionSupported() calls, e.g.:
* @code
* Version v = isVersionSupported(Version::GL330) ? Version::GL330 : Version::GL210;
* Version v = supportedVersion({Version::GL330, Version::GL210});
* @endcode
*
* If no version from the list is supported, returns lowest available
* OpenGL version (@ref Version "Version::GL210" for desktop OpenGL,
* @ref Version "Version::GLES200" for OpenGL ES).
*/
Version supportedVersion(std::initializer_list<Version> versions) const;
/**
* @brief Whether given extension is supported
*
* %Extensions usable with this function are listed in Extensions
* namespace in header Extensions.h. Example usage:
* @code
* if(Context::current()->isExtensionSupported<Extensions::GL::ARB::tessellation_shader>()) {
* // draw fancy detailed model
* } else {
* // texture fallback
* }
* @endcode
*
* @see isExtensionSupported(const Extension&) const
*/
template<class T> inline bool isExtensionSupported() const {
return _version >= T::coreVersion() || (_version >= T::requiredVersion() && extensionStatus[T::Index]);
}
/**
* @brief Whether given extension is supported
*
* Can be used e.g. for listing extensions available on current
* hardware, but for general usage prefer isExtensionSupported() const,
* as it does most operations in compile time.
*
* @see supportedExtensions(), Extension::extensions()
*/
inline bool isExtensionSupported(const Extension& extension) const {
return _version >= extension._coreVersion || (_version >= extension._requiredVersion && extensionStatus[extension._index]);
}
#ifndef DOXYGEN_GENERATING_OUTPUT
inline Implementation::State* state() { return _state; }
#endif
private:
static Context* _current;
Version _version;
GLint _majorVersion;
GLint _minorVersion;
std::bitset<128> extensionStatus;
std::vector<Extension> _supportedExtensions;
Implementation::State* _state;
};
}
#endif

16
src/Contexts/AbstractGlInterface.h → src/Contexts/AbstractContextHandler.h

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_AbstractGlInterface_h
#define Magnum_Contexts_AbstractGlInterface_h
#ifndef Magnum_Contexts_AbstractContextHandler_h
#define Magnum_Contexts_AbstractContextHandler_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,29 +16,29 @@
*/
/** @file
* @brief Class Magnum::Contexts::AbstractGlInterface
* @brief Class Magnum::Contexts::AbstractContextHandler
*/
#include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts {
/** @brief Base for OpenGL interfaces */
template<class Display, class VisualId, class Window> class AbstractGlInterface {
/** @brief Base for OpenGL context handlers */
template<class Display, class VisualId, class Window> class AbstractContextHandler {
public:
/**
* @brief Get visual ID
*
* Initializes the interface on given display and returns visual ID.
* Initializes the handler on given display and returns visual ID.
*/
virtual VisualId getVisualId(Display nativeDisplay) = 0;
/**
* @brief Destructor
*
* Finalizes and closes the interface.
* Finalizes and closes the handler.
*/
virtual ~AbstractGlInterface() {}
virtual ~AbstractContextHandler() {}
/** @brief Create context */
virtual void createContext(Window nativeWindow) = 0;

12
src/Contexts/AbstractContext.h → src/Contexts/AbstractWindowContext.h

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_AbstractContext_h
#define Magnum_Contexts_AbstractContext_h
#ifndef Magnum_Contexts_AbstractWindowContext_h
#define Magnum_Contexts_AbstractWindowContext_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,7 +16,7 @@
*/
/** @file
* @brief Class Magnum::Contexts::GlutContext
* @brief Class Magnum::Contexts::AbstractWindowContext
*/
namespace Magnum { namespace Contexts {
@ -27,7 +27,7 @@ namespace Magnum { namespace Contexts {
See subclasses documentation for more information. Context classes subclasses
are meant to be used directly in `main()`, for example:
@code
class MyContext: public Magnum::Contexts::GlutContext {
class MyContext: public Magnum::Contexts::GlutWindowContext {
// implement required methods...
};
int main(int argc, char** argv) {
@ -36,9 +36,9 @@ int main(int argc, char** argv) {
}
@endcode
*/
class AbstractContext {
class AbstractWindowContext {
public:
virtual inline ~AbstractContext() {}
virtual inline ~AbstractWindowContext() {}
/**
* @brief Execute main loop

25
src/Contexts/AbstractXContext.cpp → src/Contexts/AbstractXWindowContext.cpp

@ -13,8 +13,9 @@
GNU Lesser General Public License version 3 for more details.
*/
#include "AbstractXContext.h"
#include "AbstractXWindowContext.h"
#include "Context.h"
#include "ExtensionWrangler.h"
#define None 0L // redef Xlib nonsense
@ -26,12 +27,12 @@ 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) {
AbstractXWindowContext::AbstractXWindowContext(AbstractContextHandler<Display*, VisualID, Window>* contextHandler, int&, char**, const string& title, const Math::Vector2<GLsizei>& size): contextHandler(contextHandler), viewportSize(size), flags(Flag::Redraw) {
/* Get default X display */
display = XOpenDisplay(0);
/* Get visual ID */
VisualID visualId = glInterface->getVisualId(display);
VisualID visualId = contextHandler->getVisualId(display);
/* Get visual info */
XVisualInfo *visInfo, visTemplate;
@ -60,28 +61,32 @@ AbstractXContext::AbstractXContext(AbstractGlInterface<Display*, VisualID, Windo
XSetWMProtocols(display, window, &deleteWindow, 1);
/* Create context */
glInterface->createContext(window);
contextHandler->createContext(window);
/* Capture exposure, keyboard and mouse button events */
XSelectInput(display, window, INPUT_MASK);
/* Set OpenGL context as current */
glInterface->makeCurrent();
contextHandler->makeCurrent();
/* Initialize extension wrangler */
ExtensionWrangler::initialize(glInterface->experimentalExtensionWranglerFeatures());
ExtensionWrangler::initialize(contextHandler->experimentalExtensionWranglerFeatures());
c = new Context;
}
AbstractXContext::~AbstractXContext() {
/* Shut down the interface */
delete glInterface;
AbstractXWindowContext::~AbstractXWindowContext() {
delete c;
/* Shut down context handler */
delete contextHandler;
/* Shut down X */
XDestroyWindow(display, window);
XCloseDisplay(display);
}
int AbstractXContext::exec() {
int AbstractXWindowContext::exec() {
/* Show window */
XMapWindow(display, window);

59
src/Contexts/AbstractXContext.h → src/Contexts/AbstractXWindowContext.h

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_AbstractXContext_h
#define Magnum_Contexts_AbstractXContext_h
#ifndef Magnum_Contexts_AbstractXWindowContext_h
#define Magnum_Contexts_AbstractXWindowContext_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,9 +16,11 @@
*/
/** @file
* @brief Class Magnum::Contexts::AbstractXContext
* @brief Class Magnum::Contexts::AbstractXWindowContext
*/
#include <Containers/EnumSet.h>
#include "Magnum.h"
#include <X11/Xlib.h>
@ -27,12 +29,17 @@
#undef None
#undef Always
#include <Containers/EnumSet.h>
#include "Math/Vector2.h"
#include "AbstractWindowContext.h"
#include "AbstractContextHandler.h"
#include "AbstractContext.h"
#include "AbstractGlInterface.h"
#include "magnumCompatibility.h"
namespace Magnum { namespace Contexts {
namespace Magnum {
class Context;
namespace Contexts {
/** @nosubgrouping
@brief Base for X11-based contexts
@ -41,11 +48,11 @@ Supports keyboard and mouse handling.
@note Not meant to be used directly, see subclasses.
*/
class AbstractXContext: public AbstractContext {
class AbstractXWindowContext: public AbstractWindowContext {
public:
/**
* @brief Constructor
* @param glInterface Interface to OpenGL
* @param contextHandler OpenGL context handler
* @param argc Count of arguments of `main()` function
* @param argv Arguments of `main()` function
* @param title Window title
@ -53,16 +60,16 @@ class AbstractXContext: public AbstractContext {
*
* Creates window with double-buffered OpenGL ES 2 context.
*/
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));
AbstractXWindowContext(AbstractContextHandler<Display*, VisualID, Window>* contextHandler, int& argc, char** argv, const std::string& title = "Magnum X window context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600));
/**
* @brief Destructor
*
* Deletes context and destroys the window.
*/
virtual ~AbstractXContext() = 0;
virtual ~AbstractXWindowContext() = 0;
int exec();
int exec() override;
/** @brief Exit application main loop */
inline void exit() { flags |= Flag::Exit; }
@ -70,16 +77,16 @@ class AbstractXContext: public AbstractContext {
/** @{ @name Drawing functions */
protected:
/** @copydoc GlutContext::viewportEvent() */
/** @copydoc GlutWindowContext::viewportEvent() */
virtual void viewportEvent(const Math::Vector2<GLsizei>& size) = 0;
/** @copydoc GlutContext::drawEvent() */
/** @copydoc GlutWindowContext::drawEvent() */
virtual void drawEvent() = 0;
/** @copydoc GlutContext::swapBuffers() */
inline void swapBuffers() { glInterface->swapBuffers(); }
/** @copydoc GlutWindowContext::swapBuffers() */
inline void swapBuffers() { contextHandler->swapBuffers(); }
/** @copydoc GlutContext::redraw() */
/** @copydoc GlutWindowContext::redraw() */
inline void redraw() { flags |= Flag::Redraw; }
/*@}*/
@ -276,7 +283,9 @@ class AbstractXContext: public AbstractContext {
Window window;
Atom deleteWindow;
AbstractGlInterface<Display*, VisualID, Window>* glInterface;
AbstractContextHandler<Display*, VisualID, Window>* contextHandler;
Context* c;
/** @todo Get this from the created window */
Math::Vector2<GLsizei> viewportSize;
@ -284,15 +293,15 @@ class AbstractXContext: public AbstractContext {
Flags flags;
};
CORRADE_ENUMSET_OPERATORS(AbstractXContext::Modifiers)
CORRADE_ENUMSET_OPERATORS(AbstractXContext::Flags)
CORRADE_ENUMSET_OPERATORS(AbstractXWindowContext::Modifiers)
CORRADE_ENUMSET_OPERATORS(AbstractXWindowContext::Flags)
/* Implementations for inline functions with unused parameters */
inline void AbstractXContext::keyPressEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::keyReleaseEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::mousePressEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::mouseReleaseEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::mouseMotionEvent(Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXWindowContext::keyPressEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXWindowContext::keyReleaseEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXWindowContext::mousePressEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXWindowContext::mouseReleaseEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXWindowContext::mouseMotionEvent(Modifiers, const Math::Vector2<int>&) {}
}}

102
src/Contexts/CMakeLists.txt

@ -2,92 +2,92 @@
add_library(MagnumContextsExtensionWrangler OBJECT ExtensionWrangler.cpp)
set(MagnumContexts_HEADERS
AbstractContext.h
AbstractGlInterface.h
AbstractContextHandler.h
AbstractWindowContext.h
ExtensionWrangler.h)
install(FILES ${MagnumContexts_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
# GLUT context
if(WITH_GLUTCONTEXT)
# GLUT window context
if(WITH_GLUTWINDOWCONTEXT)
find_package(GLUT)
if(GLUT_FOUND)
add_library(MagnumGlutContext STATIC
GlutContext.cpp
add_library(MagnumGlutWindowContext STATIC
GlutWindowContext.cpp
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES GlutContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumGlutContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
install(FILES GlutWindowContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumGlutWindowContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
else()
message(FATAL_ERROR "GLUT library, required by GlutContext, was not found. Set WITH_GLUTCONTEXT to OFF to skip building it.")
message(FATAL_ERROR "GLUT library, required by GlutWindowContext, was not found. Set WITH_GLUTWINDOWCONTEXT to OFF to skip building it.")
endif()
endif()
# SDL2 context
if(WITH_SDL2CONTEXT)
# SDL2 window context
if(WITH_SDL2WINDOWCONTEXT)
find_package(SDL2)
if(SDL2_FOUND)
include_directories(${SDL2_INCLUDE_DIR})
add_library(MagnumSdl2Context STATIC
Sdl2Context.cpp
add_library(MagnumSdl2WindowContext STATIC
Sdl2WindowContext.cpp
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES Sdl2Context.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumSdl2Context DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
install(FILES Sdl2WindowContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumSdl2WindowContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
else()
message(FATAL_ERROR "SDL2 library, required by Sdl2Context, was not found. Set WITH_SDL2CONTEXT to OFF to skip building it.")
message(FATAL_ERROR "SDL2 library, required by Sdl2WindowContext, was not found. Set WITH_SDL2WINDOWCONTEXT to OFF to skip building it.")
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>
# GLX window context
if(WITH_GLXWINDOWCONTEXT)
set(NEED_ABSTRACTXWINDOWCONTEXT 1)
set(NEED_GLXCONTEXT 1)
add_library(MagnumGlxWindowContext STATIC
$<TARGET_OBJECTS:MagnumAbstractXWindowContext>
$<TARGET_OBJECTS:MagnumGlxContextHandler>
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES GlxContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumGlxContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
install(FILES GlxWindowContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumGlxWindowContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
endif()
# X/EGL context
if(WITH_XEGLCONTEXT)
set(NEED_ABSTRACTXCONTEXT 1)
set(NEED_EGLINTERFACE 1)
add_library(MagnumXEglContext STATIC
$<TARGET_OBJECTS:MagnumAbstractXContext>
$<TARGET_OBJECTS:MagnumEglInterface>
# X/EGL window context
if(WITH_XEGLWINDOWCONTEXT)
set(NEED_ABSTRACTXWINDOWCONTEXT 1)
set(NEED_EGLCONTEXT 1)
add_library(MagnumXEglWindowContext STATIC
$<TARGET_OBJECTS:MagnumAbstractXWindowContext>
$<TARGET_OBJECTS:MagnumEglContextHandler>
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES XEglContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumXEglContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
install(FILES XEglWindowContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumXEglWindowContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
endif()
# Abstract X context
if(NEED_ABSTRACTXCONTEXT)
# Abstract X window context
if(NEED_ABSTRACTXWINDOWCONTEXT)
find_package(X11)
if(NOT X11_FOUND)
message(FATAL_ERROR "X11 library, required by some contexts, was not found. Set WITH_*X*CONTEXT to OFF to skip building them.")
message(FATAL_ERROR "X11 library, required by some contexts, was not found. Set WITH_*X*WINDOWCONTEXT to OFF to skip building them.")
endif()
add_library(MagnumAbstractXContext OBJECT AbstractXContext.cpp)
add_library(MagnumAbstractXWindowContext OBJECT AbstractXWindowContext.cpp)
# X11 macros are a mess, disable warnings for C-style casts
set_target_properties(MagnumAbstractXContext PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES AbstractXContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
set_target_properties(MagnumAbstractXWindowContext PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES AbstractXWindowContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
endif()
# GLX interface
if(NEED_GLXINTERFACE)
add_library(MagnumGlxInterface OBJECT GlxInterface.cpp)
# GLX context
if(NEED_GLXCONTEXT)
add_library(MagnumGlxContextHandler OBJECT GlxContextHandler.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)
set_target_properties(MagnumGlxContextHandler PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES GlxContextHandler.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
endif()
# EGL interface
if(NEED_EGLINTERFACE)
# EGL context
if(NEED_EGLCONTEXT)
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.")
message(FATAL_ERROR "EGL library, required by some window contexts, was not found. Set WITH_*EGL*WINDOWCONTEXT to OFF to skip building them.")
endif()
add_library(MagnumEglInterface OBJECT EglInterface.cpp)
add_library(MagnumEglContextHandler OBJECT EglContextHandler.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)
set_target_properties(MagnumEglContextHandler PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES EglContextHandler.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
endif()

125
src/Contexts/EglContextHandler.cpp

@ -0,0 +1,125 @@
/*
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 "EglContextHandler.h"
#include <Utility/Debug.h>
#include "Context.h"
namespace Magnum { namespace Contexts {
EglContextHandler::~EglContextHandler() {
eglDestroyContext(display, context);
eglDestroySurface(display, surface);
eglTerminate(display);
}
VisualId EglContextHandler::getVisualId(EGLNativeDisplayType nativeDisplay) {
/* Initialize */
display = eglGetDisplay(nativeDisplay);
if(!eglInitialize(display, nullptr, nullptr)) {
Error() << "Cannot initialize EGL:" << errorString(eglGetError());
exit(1);
}
#ifndef MAGNUM_TARGET_GLES
EGLenum api = EGL_OPENGL_API;
#else
EGLenum api = EGL_OPENGL_ES_API;
#endif
if(!eglBindAPI(api)) {
Error() << "Cannot bind EGL API:" << errorString(eglGetError());
exit(1);
}
/* 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:" << errorString(eglGetError());
exit(1);
}
if(!configCount) {
Error() << "No matching EGL visual config available";
exit(1);
}
/* Get visual ID */
EGLint visualId;
if(!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualId)) {
Error() << "Cannot get native visual ID:" << errorString(eglGetError());
exit(1);
}
return visualId;
}
void EglContextHandler::createContext(EGLNativeWindowType window) {
static const EGLint contextAttributes[] = {
#ifdef MAGNUM_TARGET_GLES
EGL_CONTEXT_CLIENT_VERSION, 2,
#endif
EGL_NONE
};
if(!eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes)) {
Error() << "Cannot create EGL context:" << errorString(eglGetError());
exit(1);
}
if(!(surface = eglCreateWindowSurface(display, config, window, NULL))) {
Error() << "Cannot create window surface:" << errorString(eglGetError());
exit(1);
}
/** @bug Fixme: On desktop OpenGL and Mesa EGL implementation OpenGL version is 1.0, which is wrong */
}
const char* EglContextHandler::errorString(EGLint error) {
switch(error) {
#define _error(name) case name: return #name;
_error(EGL_SUCCESS)
_error(EGL_NOT_INITIALIZED)
_error(EGL_BAD_ACCESS)
_error(EGL_BAD_ALLOC)
_error(EGL_BAD_ATTRIBUTE)
_error(EGL_BAD_CONTEXT)
_error(EGL_BAD_CONFIG)
_error(EGL_BAD_CURRENT_SURFACE)
_error(EGL_BAD_DISPLAY)
_error(EGL_BAD_SURFACE)
_error(EGL_BAD_MATCH)
_error(EGL_BAD_PARAMETER)
_error(EGL_BAD_NATIVE_PIXMAP)
_error(EGL_BAD_NATIVE_WINDOW)
_error(EGL_CONTEXT_LOST)
#undef _error
}
return "";
}
}}

29
src/Contexts/EglInterface.h → src/Contexts/EglContextHandler.h

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_EglInterface_h
#define Magnum_Contexts_EglInterface_h
#ifndef Magnum_Contexts_EglContextHandler_h
#define Magnum_Contexts_EglContextHandler_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,7 +16,7 @@
*/
/** @file
* @brief Class Magnum::Contexts::EglInterface
* @brief Class Magnum::Contexts::EglContextHandler
*/
#include "Magnum.h"
@ -26,7 +26,12 @@
#endif
#include <EGL/egl.h>
#include "AbstractGlInterface.h"
/* undef Xlib nonsense to avoid conflicts */
#undef None
#include "AbstractContextHandler.h"
#include "magnumCompatibility.h"
namespace Magnum { namespace Contexts {
@ -42,24 +47,26 @@ typedef EGLInt VisualId;
/**
@brief EGL interface
Used in XEglContext.
Used in XEglWindowContext.
*/
class EglInterface: public AbstractGlInterface<EGLNativeDisplayType, VisualId, EGLNativeWindowType> {
class EglContextHandler: public AbstractContextHandler<EGLNativeDisplayType, VisualId, EGLNativeWindowType> {
public:
~EglInterface();
~EglContextHandler();
VisualId getVisualId(EGLNativeDisplayType nativeDisplay);
void createContext(EGLNativeWindowType nativeWindow);
VisualId getVisualId(EGLNativeDisplayType nativeDisplay) override;
void createContext(EGLNativeWindowType nativeWindow) override;
inline void makeCurrent() {
inline void makeCurrent() override {
eglMakeCurrent(display, surface, surface, context);
}
inline void swapBuffers() {
inline void swapBuffers() override {
eglSwapBuffers(display, surface);
}
private:
const char* errorString(EGLint error);
EGLDisplay display;
EGLConfig config;
EGLSurface surface;

86
src/Contexts/EglInterface.cpp

@ -1,86 +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 "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 */
}
}}

2
src/Contexts/ExtensionWrangler.cpp

@ -15,6 +15,8 @@
#include "ExtensionWrangler.h"
#include <Utility/Debug.h>
#include "Magnum.h"
namespace Magnum { namespace Contexts {

13
src/Contexts/GlutContext.cpp → src/Contexts/GlutWindowContext.cpp

@ -13,15 +13,16 @@
GNU Lesser General Public License version 3 for more details.
*/
#include "GlutContext.h"
#include "GlutWindowContext.h"
#include "Context.h"
#include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts {
GlutContext* GlutContext::instance = nullptr;
GlutWindowContext* GlutWindowContext::instance = nullptr;
GlutContext::GlutContext(int& argc, char** argv, const std::string& title, const Math::Vector2<GLsizei>& size): argc(argc), argv(argv) {
GlutWindowContext::GlutWindowContext(int& argc, char** argv, const std::string& title, const Math::Vector2<GLsizei>& size) {
/* Save global instance */
instance = this;
@ -38,6 +39,12 @@ GlutContext::GlutContext(int& argc, char** argv, const std::string& title, const
glutDisplayFunc(staticDrawEvent);
ExtensionWrangler::initialize();
c = new Context;
}
GlutWindowContext::~GlutWindowContext() {
delete c;
}
}}

41
src/Contexts/GlutContext.h → src/Contexts/GlutWindowContext.h

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_GlutContext_h
#define Magnum_Contexts_GlutContext_h
#ifndef Magnum_Contexts_GlutWindowContext_h
#define Magnum_Contexts_GlutWindowContext_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,15 +16,25 @@
*/
/** @file
* @brief Class Magnum::Contexts::GlutContext
* @brief Class Magnum::Contexts::GlutWindowContext
*/
#include <string>
#include "Math/Vector2.h"
#include "Magnum.h"
#include <GL/freeglut.h>
#include "AbstractContext.h"
#include "AbstractWindowContext.h"
#include "magnumCompatibility.h"
namespace Magnum { namespace Contexts {
namespace Magnum {
class Context;
namespace Contexts {
/** @nosubgrouping
@brief GLUT context
@ -35,7 +45,7 @@ support for changing cursor and mouse tracking and warping.
You need to implement at least drawEvent() and viewportEvent() to be able to
draw on the screen.
*/
class GlutContext: public AbstractContext {
class GlutWindowContext: public AbstractWindowContext {
public:
/**
* @brief Constructor
@ -46,9 +56,11 @@ class GlutContext: public AbstractContext {
*
* Creates double-buffered RGBA window with depth and stencil buffers.
*/
GlutContext(int& argc, char** argv, const std::string& title = "Magnum GLUT context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600));
GlutWindowContext(int& argc, char** argv, const std::string& title = "Magnum GLUT window context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600));
~GlutWindowContext();
inline int exec() {
inline int exec() override {
glutMainLoop();
return 0;
}
@ -238,17 +250,16 @@ class GlutContext: public AbstractContext {
instance->drawEvent();
}
static GlutContext* instance;
static GlutWindowContext* instance;
int& argc;
char** argv;
Context* c;
};
/* Implementations for inline functions with unused parameters */
inline void GlutContext::keyPressEvent(Key, const Math::Vector2<int>&) {}
inline void GlutContext::mousePressEvent(MouseButton, const Math::Vector2<int>&) {}
inline void GlutContext::mouseReleaseEvent(MouseButton, const Math::Vector2<int>&) {}
inline void GlutContext::mouseMotionEvent(const Math::Vector2<int>&) {}
inline void GlutWindowContext::keyPressEvent(Key, const Math::Vector2<int>&) {}
inline void GlutWindowContext::mousePressEvent(MouseButton, const Math::Vector2<int>&) {}
inline void GlutWindowContext::mouseReleaseEvent(MouseButton, const Math::Vector2<int>&) {}
inline void GlutWindowContext::mouseMotionEvent(const Math::Vector2<int>&) {}
}}

21
src/Contexts/GlxInterface.cpp → src/Contexts/GlxContextHandler.cpp

@ -13,20 +13,25 @@
GNU Lesser General Public License version 3 for more details.
*/
#include "GlxInterface.h"
#include "GlxContextHandler.h"
#include <GL/glxext.h>
#include <Utility/Debug.h>
#include "Context.h"
#define None 0L // redef Xlib nonsense
namespace Magnum { namespace Contexts {
VisualID GlxInterface::getVisualId(Display* nativeDisplay) {
VisualID GlxContextHandler::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.";
Error() << "GlxContextHandler: GLX version 1.4 or greater is required.";
exit(1);
}
@ -44,7 +49,7 @@ VisualID GlxInterface::getVisualId(Display* nativeDisplay) {
};
configs = glXChooseFBConfig(nativeDisplay, DefaultScreen(nativeDisplay), attributes, &configCount);
if(!configCount) {
Error() << "GlxInterface: no supported framebuffer configuration found.";
Error() << "GlxContextHandler: no supported framebuffer configuration found.";
exit(1);
}
@ -56,13 +61,13 @@ VisualID GlxInterface::getVisualId(Display* nativeDisplay) {
return visualId;
}
void GlxInterface::createContext(Window nativeWindow) {
void GlxContextHandler::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_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
#else
GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
@ -77,12 +82,12 @@ void GlxInterface::createContext(Window nativeWindow) {
context = glXCreateContextAttribsARB(display, configs[0], 0, True, attributes);
XFree(configs);
if(!context) {
Error() << "GlxInterface: cannot create context.";
Error() << "GlxContextHandler: cannot create context.";
exit(1);
}
}
GlxInterface::~GlxInterface() {
GlxContextHandler::~GlxContextHandler() {
glXMakeCurrent(display, None, nullptr);
glXDestroyContext(display, context);
}

31
src/Contexts/GlxInterface.h → src/Contexts/GlxContextHandler.h

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_EglInterface_h
#define Magnum_Contexts_EglInterface_h
#ifndef Magnum_Contexts_GlxContextHandler_h
#define Magnum_Contexts_GlxContextHandler_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,41 +16,46 @@
*/
/** @file
* @brief Class Magnum::Contexts::GlxInterface
* @brief Class Magnum::Contexts::GlxContextHandler
*/
#include "Magnum.h"
#include <GL/glx.h>
/* undef Xlib nonsense to avoid conflicts */
#undef None
#undef Always
#include "AbstractGlInterface.h"
#include "AbstractContextHandler.h"
#include "magnumCompatibility.h"
namespace Magnum { namespace Contexts {
/**
@brief GLX interface
Creates OpenGL 3.3 core context or OpenGL ES 2.0 context, if targetting
Creates OpenGL 3.2 core context or OpenGL ES 2.0 context, if targetting
OpenGL ES.
Used in GlxContext.
Used in GlxWindowContext.
*/
class GlxInterface: public AbstractGlInterface<Display*, VisualID, Window> {
class GlxContextHandler: public AbstractContextHandler<Display*, VisualID, Window> {
public:
~GlxInterface();
~GlxContextHandler();
VisualID getVisualId(Display* nativeDisplay);
void createContext(Window nativeWindow);
VisualID getVisualId(Display* nativeDisplay) override;
void createContext(Window nativeWindow) override;
/* This must be enabled, otherwise (on my NVidia) it crashes when creating VAO. WTF. */
inline ExtensionWrangler::ExperimentalFeatures experimentalExtensionWranglerFeatures() const {
inline ExtensionWrangler::ExperimentalFeatures experimentalExtensionWranglerFeatures() const override {
return ExtensionWrangler::ExperimentalFeatures::Enable;
}
inline void makeCurrent() {
inline void makeCurrent() override {
glXMakeCurrent(display, window, context);
}
inline void swapBuffers() {
inline void swapBuffers() override {
glXSwapBuffers(display, window);
}

18
src/Contexts/GlxContext.h → src/Contexts/GlxWindowContext.h

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_GlxContext_h
#define Magnum_Contexts_GlxContext_h
#ifndef Magnum_Contexts_GlxWindowContext_h
#define Magnum_Contexts_GlxWindowContext_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,20 +16,20 @@
*/
/** @file
* @brief Class Magnum::Contexts::GlxContext
* @brief Class Magnum::Contexts::GlxWindowContext
*/
#include "AbstractXContext.h"
#include "GlxInterface.h"
#include "AbstractXWindowContext.h"
#include "GlxContextHandler.h"
namespace Magnum { namespace Contexts {
/**
@brief GLX context
Uses GlxInterface.
Uses GlxContextHandler.
*/
class GlxContext: public AbstractXContext {
class GlxWindowContext: public AbstractXWindowContext {
public:
/**
* @brief Constructor
@ -38,10 +38,10 @@ class GlxContext: public AbstractXContext {
* @param title Window title
* @param size Window size
*
* Creates window with double-buffered OpenGL 3.3 core context or
* Creates window with double-buffered OpenGL 3.2 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) {}
inline GlxWindowContext(int& argc, char** argv, const std::string& title = "Magnum GLX window context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600)): AbstractXWindowContext(new GlxContextHandler, argc, argv, title, size) {}
};
}}

32
src/Contexts/Sdl2Context.cpp → src/Contexts/Sdl2WindowContext.cpp

@ -13,20 +13,22 @@
GNU Lesser General Public License version 3 for more details.
*/
#include "Sdl2Context.h"
#include "Sdl2WindowContext.h"
#include "Context.h"
#include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts {
Sdl2Context::Sdl2Context(int, char**, const std::string& name, const Math::Vector2<GLsizei>& size): _redraw(true) {
Sdl2WindowContext::Sdl2WindowContext(int, char**, const std::string& name, const Math::Vector2<GLsizei>& size): _redraw(true) {
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
Error() << "Cannot initialize SDL.";
exit(1);
}
/* Request OpenGL 3.3 */
/* Request OpenGL 3.2 */
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
/* Enable double buffering and 24bt depth buffer */
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
@ -52,15 +54,19 @@ Sdl2Context::Sdl2Context(int, char**, const std::string& name, const Math::Vecto
sizeEvent->window.data1 = size.x();
sizeEvent->window.data2 = size.y();
SDL_PushEvent(sizeEvent);
c = new Context;
}
Sdl2Context::~Sdl2Context() {
Sdl2WindowContext::~Sdl2WindowContext() {
delete c;
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
SDL_Quit();
}
int Sdl2Context::exec() {
int Sdl2WindowContext::exec() {
for(;;) {
SDL_Event event;
@ -77,23 +83,23 @@ int Sdl2Context::exec() {
break;
} break;
case SDL_KEYDOWN:
keyPressEvent(static_cast<Key>(event.key.keysym.sym), event.key.repeat);
keyPressEvent(static_cast<Key>(event.key.keysym.sym), Modifiers(), {});
break;
case SDL_KEYUP:
keyReleaseEvent(static_cast<Key>(event.key.keysym.sym));
keyReleaseEvent(static_cast<Key>(event.key.keysym.sym), Modifiers(), {});
break;
case SDL_MOUSEBUTTONDOWN:
mousePressEvent(static_cast<MouseButton>(event.button.button), {event.button.x, event.button.y});
mousePressEvent(static_cast<MouseButton>(event.button.button), Modifiers(), {event.button.x, event.button.y});
break;
case SDL_MOUSEBUTTONUP:
mouseReleaseEvent(static_cast<MouseButton>(event.button.button), {event.button.x, event.button.y});
mouseReleaseEvent(static_cast<MouseButton>(event.button.button), Modifiers(), {event.button.x, event.button.y});
break;
case SDL_MOUSEWHEEL:
mouseWheelEvent({event.wheel.x, event.wheel.y});
if(event.wheel.y != 0)
mousePressEvent(event.wheel.y < 0 ? MouseButton::WheelUp : MouseButton::WheelDown, Modifiers(), {event.wheel.x, event.wheel.y});
break;
case SDL_MOUSEMOTION:
mouseMotionEvent({event.motion.x, event.motion.y},
{event.motion.xrel, event.motion.yrel});
mouseMotionEvent(Modifiers(), {event.motion.x, event.motion.y});
break;
case SDL_QUIT:
return 0;

100
src/Contexts/Sdl2Context.h → src/Contexts/Sdl2WindowContext.h

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_Sdl2Context_h
#define Magnum_Contexts_Sdl2Context_h
#ifndef Magnum_Contexts_Sdl2WindowContext_h
#define Magnum_Contexts_Sdl2WindowContext_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,16 +16,25 @@
*/
/** @file
* @brief Class Magnum::Contexts::Sdl2Context
* @brief Class Magnum::Contexts::Sdl2WindowContext
*/
#include "Math/Vector2.h"
#include "Magnum.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_scancode.h>
#include <Corrade/Containers/EnumSet.h>
#include "AbstractWindowContext.h"
#include "magnumCompatibility.h"
#include "AbstractContext.h"
namespace Magnum {
namespace Magnum { namespace Contexts {
class Context;
namespace Contexts {
/** @nosubgrouping
@brief SDL2 context
@ -35,7 +44,7 @@ Supports keyboard and mouse handling.
You need to implement at least drawEvent() and viewportEvent() to be able to
draw on the screen.
*/
class Sdl2Context: public AbstractContext {
class Sdl2WindowContext: public AbstractWindowContext {
public:
/**
* @brief Constructor
@ -45,38 +54,53 @@ class Sdl2Context: public AbstractContext {
* @param size Window size
*
* Creates centered non-resizable window with double-buffered
* OpenGL 3.3 context with 24bit depth buffer.
* OpenGL 3.2 context with 24bit depth buffer.
*/
Sdl2Context(int argc, char** argv, const std::string& title = "Magnum SDL2 context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600));
Sdl2WindowContext(int argc, char** argv, const std::string& title = "Magnum SDL2 window context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600));
/**
* @brief Destructor
*
* Deletes context and destroys the window.
*/
~Sdl2Context();
~Sdl2WindowContext();
int exec();
int exec() override;
/** @{ @name Drawing functions */
protected:
/** @copydoc GlutContext::viewportEvent() */
/** @copydoc GlutWindowContext::viewportEvent() */
virtual void viewportEvent(const Math::Vector2<GLsizei>& size) = 0;
/** @copydoc GlutContext::drawEvent() */
/** @copydoc GlutWindowContext::drawEvent() */
virtual void drawEvent() = 0;
/** @copydoc GlutContext::swapBuffers() */
/** @copydoc GlutWindowContext::swapBuffers() */
inline void swapBuffers() { SDL_GL_SwapWindow(window); }
/** @copydoc GlutContext::redraw() */
/** @copydoc GlutWindowContext::redraw() */
inline void redraw() { _redraw = true; }
/*@}*/
/** @{ @name Keyboard handling */
public:
/**
* @brief %Modifier
*
* @see Modifiers, keyPressEvent(), keyReleaseEvent(),
* mousePressEvent(), mouseReleaseEvent(), mouseMotionEvent()
*/
enum class Modifier: unsigned int {};
/**
* @brief Set of modifiers
*
* @see keyPressEvent(), keyReleaseEvent()
*/
typedef Corrade::Containers::EnumSet<Modifier, unsigned int> Modifiers;
/**
* @brief Key
*
@ -95,15 +119,18 @@ class Sdl2Context: public AbstractContext {
/**
* @brief Key press event
* @param key Key pressed
* @param repeat Non-zero if this is a key repeat
* @param modifiers Active modifiers (not yet implemented)
* @param position Cursor position (not yet implemented)
*/
virtual void keyPressEvent(Key key, Uint8 repeat);
virtual void keyPressEvent(Key key, Modifiers modifiers, const Math::Vector2<int>& position);
/**
* @brief Key release event
* @param key Key released
* @param modifiers Active modifiers (not yet implemented)
* @param position Cursor position (not yet implemented)
*/
virtual void keyReleaseEvent(Key key);
virtual void keyReleaseEvent(Key key, Modifiers modifiers, const Math::Vector2<int>& position);
/*@}*/
@ -118,7 +145,9 @@ class Sdl2Context: public AbstractContext {
enum class MouseButton: Uint8 {
Left = SDL_BUTTON_LEFT, /**< Left button */
Middle = SDL_BUTTON_MIDDLE, /**< Middle button */
Right = SDL_BUTTON_RIGHT /**< Right button */
Right = SDL_BUTTON_RIGHT, /**< Right button */
WheelUp = 4, /**< Wheel up */
WheelDown = 5 /**< Wheel down */
};
/**
@ -135,41 +164,33 @@ class Sdl2Context: public AbstractContext {
/**
* @brief Mouse press event
* @param button Button pressed
* @param modifiers Active modifiers (not yet implemented)
* @param position Cursor position
*
* Called when mouse button is pressed. Default implementation does
* nothing.
*/
virtual void mousePressEvent(MouseButton button, const Math::Vector2<int>& position);
virtual void mousePressEvent(MouseButton button, Modifiers modifiers, const Math::Vector2<int>& position);
/**
* @brief Mouse release event
* @param button Button released
* @param modifiers Active modifiers (not yet implemented)
* @param position Cursor position
*
* Called when mouse button is released. Default implementation does
* nothing.
*/
virtual void mouseReleaseEvent(MouseButton button, const Math::Vector2<int>& position);
/**
* @brief Mouse wheel event
* @param direction Wheel rotation direction. Negative Y is up and
* positive X is right.
*
* Called when mouse wheel is rotated. Default implementation does
* nothing.
*/
virtual void mouseWheelEvent(const Math::Vector2<int>& direction);
virtual void mouseReleaseEvent(MouseButton button, Modifiers modifiers, const Math::Vector2<int>& position);
/**
* @brief Mouse motion event
* @param modifiers Active modifiers (not yet implemented)
* @param position Mouse position relative to the window
* @param delta Mouse position relative to last motion event
*
* Called when mouse is moved. Default implementation does nothing.
*/
virtual void mouseMotionEvent(const Math::Vector2<int>& position, const Math::Vector2<int>& delta);
virtual void mouseMotionEvent(Modifiers modifiers, const Math::Vector2<int>& position);
/*@}*/
@ -177,16 +198,19 @@ class Sdl2Context: public AbstractContext {
SDL_Window* window;
SDL_GLContext context;
Context* c;
bool _redraw;
};
CORRADE_ENUMSET_OPERATORS(Sdl2WindowContext::Modifiers)
/* Implementations for inline functions with unused parameters */
inline void Sdl2Context::keyPressEvent(Key, Uint8) {}
inline void Sdl2Context::keyReleaseEvent(Key) {}
inline void Sdl2Context::mousePressEvent(MouseButton, const Math::Vector2<int>&) {}
inline void Sdl2Context::mouseReleaseEvent(MouseButton, const Math::Vector2<int>&) {}
inline void Sdl2Context::mouseWheelEvent(const Math::Vector2<int>&) {}
inline void Sdl2Context::mouseMotionEvent(const Math::Vector2<int>&, const Math::Vector2<int>&) {}
inline void Sdl2WindowContext::keyPressEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void Sdl2WindowContext::keyReleaseEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void Sdl2WindowContext::mousePressEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void Sdl2WindowContext::mouseReleaseEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void Sdl2WindowContext::mouseMotionEvent(Modifiers, const Math::Vector2<int>&) {}
}}

16
src/Contexts/XEglContext.h → src/Contexts/XEglWindowContext.h

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_XEglContext_h
#define Magnum_Contexts_XEglContext_h
#ifndef Magnum_Contexts_XEglWindowContext_h
#define Magnum_Contexts_XEglWindowContext_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,20 +16,20 @@
*/
/** @file
* @brief Class Magnum::Contexts::XEglContext
* @brief Class Magnum::Contexts::XEglWindowContext
*/
#include "AbstractXContext.h"
#include "EglInterface.h"
#include "AbstractXWindowContext.h"
#include "EglContextHandler.h"
namespace Magnum { namespace Contexts {
/**
@brief X/EGL context
Uses EglInterface.
Uses EglContextHandler.
*/
class XEglContext: public AbstractXContext {
class XEglWindowContext: public AbstractXWindowContext {
public:
/**
* @brief Constructor
@ -40,7 +40,7 @@ class XEglContext: public AbstractXContext {
*
* 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) {}
inline XEglWindowContext(int& argc, char** argv, const std::string& title = "Magnum X/EGL window context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600)): AbstractXWindowContext(new EglContextHandler, argc, argv, title, size) {}
};
}}

60
src/CubeMapTexture.h

@ -27,9 +27,9 @@ namespace Magnum {
@brief Cube map texture
%Texture used mainly for environemnt maps. See AbstractTexture documentation
for more information about usage. It consists of 6 square textures generating
6 faces of the cube as following. Note that all images must be turned upside
down (+Y is top):
for more information. It consists of 6 square textures generating 6 faces of
the cube as following. Note that all images must be turned upside down (+Y is
top):
+----+
| -Y |
@ -63,8 +63,11 @@ class CubeMapTexture: public AbstractTexture {
/**
* @brief Enable/disable seamless cube map textures
*
* @requires_gl
* Initially disabled on desktop OpenGL.
* @see @fn_gl{Enable}/@fn_gl{Disable} with @def_gl{TEXTURE_CUBE_MAP_SEAMLESS}
* @requires_gl32 Extension @extension{ARB,seamless_cube_map}
* @requires_gl Not available in OpenGL ES 2.0, always enabled in
* OpenGL ES 3.0.
*/
inline static void setSeamless(bool enabled) {
enabled ? glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) : glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
@ -75,34 +78,63 @@ class CubeMapTexture: public AbstractTexture {
* @brief Constructor
*
* Creates one cube map OpenGL texture.
* @see @def_gl{TEXTURE_CUBE_MAP}
*/
inline CubeMapTexture(): AbstractTexture(GL_TEXTURE_CUBE_MAP) {}
/**
* @copydoc Texture::setWrapping()
*/
inline void setWrapping(const Math::Vector<3, Wrapping>& wrapping) {
bind();
DataHelper<3>::setWrapping(GL_TEXTURE_CUBE_MAP, wrapping);
inline CubeMapTexture* setWrapping(const Math::Vector<3, Wrapping>& wrapping) {
DataHelper<3>::setWrapping(this, wrapping);
return this;
}
/**
* @copydoc Texture::setData(GLint, InternalFormat, Image*)
* @param coordinate Coordinate
* @return Pointer to self (for method chaining)
*/
template<class Image> inline void setData(Coordinate coordinate, GLint mipLevel, InternalFormat internalFormat, Image* image) {
bind();
DataHelper<2>::set(static_cast<GLenum>(coordinate), mipLevel, internalFormat, image);
template<class Image> inline CubeMapTexture* setData(Coordinate coordinate, GLint mipLevel, InternalFormat internalFormat, Image* image) {
DataHelper<2>::set(this, static_cast<GLenum>(coordinate), mipLevel, internalFormat, image);
return this;
}
/**
* @copydoc Texture::setSubData(GLint, const Math::Vector<Dimensions, GLint>&, Image*)
* @copydoc Texture::setSubData(GLint, const typename DimensionTraits<Dimensions, GLint>::VectorType&, Image*)
* @param coordinate Coordinate
* @return Pointer to self (for method chaining)
*/
template<class Image> inline void setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector<2, GLint>& offset, const Image* image) {
bind();
DataHelper<2>::setSub(static_cast<GLenum>(coordinate), mipLevel, offset, image);
template<class Image> inline CubeMapTexture* setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector2<GLint>& offset, const Image* image) {
DataHelper<2>::setSub(this, static_cast<GLenum>(coordinate), mipLevel, offset, image);
return this;
}
/* Overloads to remove WTF-factor from method chaining order */
#ifndef DOXYGEN_GENERATING_OUTPUT
inline CubeMapTexture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel) {
AbstractTexture::setMinificationFilter(filter, mipmap);
return this;
}
inline CubeMapTexture* setMagnificationFilter(Filter filter) {
AbstractTexture::setMagnificationFilter(filter);
return this;
}
#ifndef MAGNUM_TARGET_GLES
inline CubeMapTexture* setBorderColor(const Color4<GLfloat>& color) {
AbstractTexture::setBorderColor(color);
return this;
}
#endif
inline CubeMapTexture* setMaxAnisotropy(GLfloat anisotropy) {
AbstractTexture::setMaxAnisotropy(anisotropy);
return this;
}
inline CubeMapTexture* generateMipmap() {
AbstractTexture::generateMipmap();
return this;
}
#endif
};
}

68
src/CubeMapTextureArray.h

@ -15,25 +15,30 @@
GNU Lesser General Public License version 3 for more details.
*/
#ifndef MAGNUM_TARGET_GLES
/** @file
* @brief Class Magnum::CubeMapTextureArray
*/
#endif
#include "Texture.h"
#ifndef MAGNUM_TARGET_GLES
namespace Magnum {
/**
@brief Cube map texture array
For information about usage, see CubeMapTexture documentation.
For information, see CubeMapTexture and AbstractTexture documentation.
When using cube map texture in the shader, use `samplerCubeArray`. Unlike
classic textures, coordinates for cube map textures is signed three-part
vector from the center of the cube, which intersects one of the six sides of
the cube map.
@see CubeMapTexture::setSeamless()
@requires_gl40 Extension @extension{ARB,texture_cube_map_array}
@requires_gl Cube map texture arrays are not available in OpenGL ES.
*/
class CubeMapTextureArray: public AbstractTexture {
public:
@ -47,28 +52,20 @@ class CubeMapTextureArray: public AbstractTexture {
NegativeZ = 5 /**< -Z cube side */
};
/**
* @brief Enable/disable seamless cube map textures
*
* @requires_gl32 Extension @extension{ARB,seamless_cube_map}
*/
inline static void setSeamless(bool enabled) {
enabled ? glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) : glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
}
/**
* @brief Constructor
*
* Creates one cube map OpenGL texture.
* @see @def_gl{TEXTURE_CUBE_MAP_ARRAY}
*/
inline CubeMapTextureArray(): AbstractTexture(GL_TEXTURE_CUBE_MAP_ARRAY) {}
/**
* @copydoc Texture::setWrapping()
*/
inline void setWrapping(const Math::Vector<3, Wrapping>& wrapping) {
bind();
DataHelper<3>::setWrapping(GL_TEXTURE_CUBE_MAP_ARRAY, wrapping);
inline CubeMapTextureArray* setWrapping(const Math::Vector3<Wrapping>& wrapping) {
DataHelper<3>::setWrapping(this, wrapping);
return this;
}
/**
@ -78,9 +75,9 @@ class CubeMapTextureArray: public AbstractTexture {
* for all layers. Each group of 6 2D images is one cube map layer.
* The images are ordered the same way as Coordinate enum.
*/
template<class T> inline void setData(GLint mipLevel, InternalFormat internalFormat, T* image) {
bind();
DataHelper<3>::set(GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, internalFormat, image);
template<class T> inline CubeMapTextureArray* setData(GLint mipLevel, InternalFormat internalFormat, T* image) {
DataHelper<3>::set(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, internalFormat, image);
return this;
}
/**
@ -89,6 +86,7 @@ class CubeMapTextureArray: public AbstractTexture {
* @param offset Offset where to put data in the texture
* @param image Three-dimensional Image, BufferedImage or for
* example Trade::ImageData
* @return Pointer to self (for method chaining)
*
* Sets texture subdata from given image. The image is not deleted
* afterwards.
@ -100,9 +98,9 @@ class CubeMapTextureArray: public AbstractTexture {
*
* @see setSubData(GLsizei, Coordinate, GLint, const Math::Vector<2, GLint>&, const Image*)
*/
template<class Image> inline void setSubData(GLint mipLevel, const Math::Vector<3, GLint>& offset, const Image* image) {
bind();
DataHelper<3>::setSub(GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, offset, image, Math::Vector<3, GLsizei>(Math::Vector<Image::Dimensions, GLsizei>()));
template<class Image> inline CubeMapTextureArray* setSubData(GLint mipLevel, const Math::Vector3<GLint>& offset, const Image* image) {
DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, offset, image, Math::Vector3<GLsizei>(Math::Vector<Image::Dimensions, GLsizei>()));
return this;
}
/**
@ -113,18 +111,44 @@ class CubeMapTextureArray: public AbstractTexture {
* @param offset Offset where to put data in the texture
* @param image Two-dimensional Image, BufferedImage or for
* example Trade::ImageData
* @return Pointer to self (for method chaining)
*
* Sets texture subdata from given image. The image is not deleted
* afterwards.
*
* @see setSubData(GLint, const Math::Vector<3, GLint>&, const Image*)
*/
template<class Image> inline void setSubData(GLsizei layer, Coordinate coordinate, GLint mipLevel, const Math::Vector<2, GLint>& offset, const Image* image) {
bind();
DataHelper<3>::setSub(GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, Math::Vector<3, GLint>(offset, layer*6+static_cast<GLsizei>(coordinate)), image, Math::Vector<2, GLsizei>(Math::Vector<Image::Dimensions, GLsizei>()));
template<class Image> inline CubeMapTextureArray* setSubData(GLsizei layer, Coordinate coordinate, GLint mipLevel, const Math::Vector2<GLint>& offset, const Image* image) {
DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, Math::Vector3<GLint>(offset, layer*6+static_cast<GLsizei>(coordinate)), image, Math::Vector<2, GLsizei>(Math::Vector<Image::Dimensions, GLsizei>()));
return this;
}
/* Overloads to remove WTF-factor from method chaining order */
#ifndef DOXYGEN_GENERATING_OUTPUT
inline CubeMapTextureArray* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel) {
AbstractTexture::setMinificationFilter(filter, mipmap);
return this;
}
inline CubeMapTextureArray* setMagnificationFilter(Filter filter) {
AbstractTexture::setMagnificationFilter(filter);
return this;
}
inline CubeMapTextureArray* setBorderColor(const Color4<GLfloat>& color) {
AbstractTexture::setBorderColor(color);
return this;
}
inline CubeMapTextureArray* setMaxAnisotropy(GLfloat anisotropy) {
AbstractTexture::setMaxAnisotropy(anisotropy);
return this;
}
inline CubeMapTextureArray* generateMipmap() {
AbstractTexture::generateMipmap();
return this;
}
#endif
};
}
#endif
#endif

109
src/DimensionTraits.h

@ -0,0 +1,109 @@
#ifndef Magnum_DimensionTraits_h
#define Magnum_DimensionTraits_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include <cstdint>
/** @file
* @brief Class Magnum::DimensionTraits
*/
namespace Magnum {
namespace Math {
template<std::size_t, class> class Vector;
template<class> class Vector2;
template<class> class Vector3;
template<class> class Point2D;
template<class> class Point3D;
template<class> class Matrix3;
template<class> class Matrix4;
}
/** @brief Matrix, point and vector specializations for given dimension count */
template<std::uint8_t dimensions, class T> struct DimensionTraits {
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Vector type
*
* Math::Vector, Math::Vector2 or Math::Vector3 based on dimension count.
*/
typedef U VectorType;
/**
* @brief Point type
*
* Floating-point Math::Point2D or Math::Point3D for 2D or 3D. No point
* type defined for one dimension and integral types.
*/
typedef U PointType;
/**
* @brief Matrix type
*
* Floating-point Math::Matrix3 or Math::Matrix4 for 2D or 3D. No matrix
* type defined for one dimension and integral types.
*/
typedef U MatrixType;
#endif
};
#ifndef DOXYGEN_GENERATING_OUTPUT
/* One dimension */
template<class T> struct DimensionTraits<1, T> {
typedef Math::Vector<1, T> VectorType;
};
/* Two dimensions - integral */
template<class T> struct DimensionTraits<2, T> {
typedef Math::Vector2<T> VectorType;
};
/* Two dimensions - floating-point */
template<> struct DimensionTraits<2, float> {
typedef Math::Vector2<float> VectorType;
typedef Math::Point2D<float> PointType;
typedef Math::Matrix3<float> MatrixType;
};
template<> struct DimensionTraits<2, double> {
typedef Math::Vector2<double> VectorType;
typedef Math::Point2D<double> PointType;
typedef Math::Matrix3<double> MatrixType;
};
/* Three dimensions - integral */
template<class T> struct DimensionTraits<3, T> {
typedef Math::Vector3<T> VectorType;
};
/* Three dimensions - floating-point */
template<> struct DimensionTraits<3, float> {
typedef Math::Vector3<float> VectorType;
typedef Math::Point3D<float> PointType;
typedef Math::Matrix4<float> MatrixType;
};
template<> struct DimensionTraits<3, double> {
typedef Math::Vector3<double> VectorType;
typedef Math::Point3D<double> PointType;
typedef Math::Matrix4<double> MatrixType;
};
#endif
}
#endif

153
src/Extensions.h

@ -0,0 +1,153 @@
#ifndef Magnum_Extensions_h
#define Magnum_Extensions_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 Namespace Magnum::Extensions
*/
#include "Context.h"
namespace Magnum {
/**
@brief Compile-time information about OpenGL extensions
Each extension is `struct` named hierarchically by prefix, vendor and
extension name, for example `GL::APPLE::vertex_array_object`. Each struct has
the same public methods as Extension class (requiredVersion(), coreVersion()
and string(), but these structs are better suited for compile-time decisions
rather than Extension instances. See Context::isExtensionSupported() for
example usage.
@todo Manual indices for extensions, this has gaps
@todo Unhide ES2_compatibility, ES3_compatibility on ES
@todo Add ES and GL 4.3 extensions
*/
namespace Extensions {
#ifndef MAGNUM_TARGET_GLES
#ifndef DOXYGEN_GENERATING_OUTPUT
#define _extension(prefix, vendor, extension, _requiredVersion, _coreVersion) \
struct extension { \
enum: std::size_t { Index = __LINE__-1 }; \
constexpr static Version requiredVersion() { return Version::_requiredVersion; } \
constexpr static Version coreVersion() { return Version::_coreVersion; } \
constexpr static const char* string() { return #prefix "_" #vendor "_" #extension; } \
};
namespace GL {
#line 1
namespace AMD {
_extension(GL,AMD,shader_trinary_minmax, GL210, None) // #428
} namespace APPLE {
_extension(GL,APPLE,flush_buffer_range, GL210, GL300) // #321
_extension(GL,APPLE,vertex_array_object, GL210, GL300) // #273
} namespace ARB {
_extension(GL,ARB,texture_rectangle, GL210, GL310) // #38
_extension(GL,ARB,color_buffer_float, GL210, GL300) // #39
_extension(GL,ARB,half_float_pixel, GL210, GL300) // #40
_extension(GL,ARB,texture_float, GL210, GL300) // #41
_extension(GL,ARB,depth_buffer_float, GL210, GL300) // #43
_extension(GL,ARB,draw_instanced, GL210, GL310) // #44
_extension(GL,ARB,geometry_shader4, GL210, GL320) // #47
_extension(GL,ARB,instanced_arrays, GL210, GL330) // #49
_extension(GL,ARB,texture_buffer_object, GL210, GL310) // #51
_extension(GL,ARB,texture_rg, GL210, GL300) // #53
_extension(GL,ARB,uniform_buffer_object, GL210, GL310) // #57
_extension(GL,ARB,copy_buffer, /*?*/ GL210, GL310) // #59
_extension(GL,ARB,depth_clamp, /*?*/ GL210, GL320) // #61
_extension(GL,ARB,draw_elements_base_vertex, /*?*/ GL210, GL320) // #62
_extension(GL,ARB,fragment_coord_conventions, /*?*/ GL210, GL320) // #63
_extension(GL,ARB,provoking_vertex, /*?*/ GL210, GL320) // #64
_extension(GL,ARB,seamless_cube_map, GL210, GL320) // #65
_extension(GL,ARB,sync, GL310, GL320) // #66
_extension(GL,ARB,texture_multisample, /*?*/ GL210, GL320) // #67
_extension(GL,ARB,vertex_array_bgra, GL210, GL320) // #68
_extension(GL,ARB,draw_buffers_blend, GL210, GL400) // #69
_extension(GL,ARB,sample_shading, GL210, GL400) // #70
_extension(GL,ARB,texture_cube_map_array, /*?*/ GL210, GL400) // #71
_extension(GL,ARB,texture_gather, GL210, GL400) // #72
_extension(GL,ARB,texture_query_lod, GL210, GL400) // #73
_extension(GL,ARB,texture_compression_bptc, GL310, GL420) // #77
_extension(GL,ARB,blend_func_extended, GL210, GL330) // #78
_extension(GL,ARB,explicit_attrib_location, GL210, GL330) // #79
_extension(GL,ARB,occlusion_query2, GL210, GL330) // #80
_extension(GL,ARB,sampler_objects, GL210, GL330) // #81
_extension(GL,ARB,shader_bit_encoding, /*?*/ GL210, GL330) // #82
_extension(GL,ARB,texture_rgb10_a2ui, GL210, GL330) // #83
_extension(GL,ARB,texture_swizzle, /*?*/ GL210, GL330) // #84
_extension(GL,ARB,timer_query, /*?*/ GL210, GL330) // #85
_extension(GL,ARB,vertex_type_2_10_10_10_rev, GL210, GL330) // #86
_extension(GL,ARB,draw_indirect, GL310, GL400) // #87
_extension(GL,ARB,gpu_shader5, GL320, GL400) // #88
_extension(GL,ARB,gpu_shader_fp64, GL320, GL400) // #89
_extension(GL,ARB,shader_subroutine, GL320, GL400) // #90
_extension(GL,ARB,tessellation_shader, GL320, GL400) // #91
_extension(GL,ARB,texture_buffer_object_rgb32, /*?*/ GL210, GL400) // #92
_extension(GL,ARB,transform_feedback2, GL210, GL400) // #93
_extension(GL,ARB,transform_feedback3, GL210, GL400) // #94
_extension(GL,ARB,ES2_compatibility, /*?*/ GL210, GL410) // #95
_extension(GL,ARB,get_program_binary, GL300, GL410) // #96
_extension(GL,ARB,separate_shader_objects, GL210, GL410) // #97
_extension(GL,ARB,shader_precision, GL400, GL410) // #98
_extension(GL,ARB,vertex_attrib_64bit, GL300, GL410) // #99
_extension(GL,ARB,viewport_array, GL210, GL410) // #100
_extension(GL,ARB,base_instance, GL210, GL420) // #107
_extension(GL,ARB,shading_language_420pack, GL300, GL420) // #108
_extension(GL,ARB,transform_feedback_instanced, GL210, GL420) // #109
_extension(GL,ARB,compressed_texture_pixel_storage, GL210, GL420) // #110
_extension(GL,ARB,conservative_depth, GL300, GL420) // #111
_extension(GL,ARB,internalformat_query, GL210, GL420) // #112
_extension(GL,ARB,map_buffer_alignment, GL210, GL420) // #113
_extension(GL,ARB,shader_atomic_counters, GL300, GL420) // #114
_extension(GL,ARB,shader_image_load_store, GL300, GL420) // #115
_extension(GL,ARB,texture_storage, GL210, GL420) // #117
} namespace EXT {
_extension(GL,EXT,texture_filter_anisotropic, GL210, None) // #187
_extension(GL,EXT,framebuffer_object, GL210, GL300) // #310
_extension(GL,EXT,packed_depth_stencil, GL210, GL300) // #312
_extension(GL,EXT,framebuffer_blit, GL210, GL300) // #316
_extension(GL,EXT,framebuffer_multisample, GL210, GL300) // #317
_extension(GL,EXT,gpu_shader4, GL210, GL300) // #326
_extension(GL,EXT,packed_float, GL210, GL300) // #328
_extension(GL,EXT,texture_array, GL210, GL300) // #329
_extension(GL,EXT,texture_compression_rgtc, GL210, GL300) // #332
_extension(GL,EXT,texture_shared_exponent, GL210, GL300) // #333
_extension(GL,EXT,framebuffer_sRGB, GL210, GL300) // #337
_extension(GL,EXT,draw_buffers2, GL210, GL300) // #340
_extension(GL,EXT,texture_integer, GL210, GL300) // #343
_extension(GL,EXT,transform_feedback, GL210, GL300) // #352
_extension(GL,EXT,direct_state_access, GL210, None) // #353
_extension(GL,EXT,texture_snorm, GL300, GL310) // #365
} namespace INTEL {
/* INTEL_map_texture not supported */ // #429
} namespace NV {
_extension(GL,NV,half_float, GL210, GL300) // #283
_extension(GL,NV,primitive_restart, GL210, GL310) // #285
_extension(GL,NV,depth_buffer_float, GL210, GL300) // #334
_extension(GL,NV,conditional_render, GL210, GL300) // #346
/* NV_draw_texture not supported */ // #430
}
}
#undef _extension
#endif
#endif
}
}
#endif

49
src/Framebuffer.cpp

@ -15,28 +15,12 @@
#include "Framebuffer.h"
namespace Magnum {
Framebuffer::ClearMask Framebuffer::clearMask = Framebuffer::Clear::Color;
void Framebuffer::setFeature(Feature feature, bool enabled) {
/* Enable or disable the feature */
enabled ? glEnable(static_cast<GLenum>(feature)) : glDisable(static_cast<GLenum>(feature));
/* Update clear mask, if needed */
ClearMask clearMaskChange;
if(feature == Feature::DepthTest) clearMaskChange = Clear::Depth;
else if(feature == Feature::StencilTest) clearMaskChange = Clear::Stencil;
else return;
enabled ? clearMask |= clearMaskChange : clearMask &= ~clearMaskChange;
}
#include "BufferedImage.h"
#include "Image.h"
void Framebuffer::setViewport(const Math::Vector2<GLint>& position, const Math::Vector2<GLsizei>& size) {
glViewport(position.x(), position.y(), size.x(), size.y());
}
namespace Magnum {
#ifndef MAGNUM_TARGET_GLES
#ifndef MAGNUM_TARGET_GLES2
void Framebuffer::mapDefaultForDraw(std::initializer_list<DefaultDrawAttachment> attachments) {
GLenum* _attachments = new GLenum[attachments.size()];
for(auto it = attachments.begin(); it != attachments.end(); ++it)
@ -46,34 +30,35 @@ void Framebuffer::mapDefaultForDraw(std::initializer_list<DefaultDrawAttachment>
glDrawBuffers(attachments.size(), _attachments);
delete[] _attachments;
}
#endif
void Framebuffer::mapForDraw(std::initializer_list<int> colorAttachments) {
void Framebuffer::mapForDraw(std::initializer_list<std::int8_t> colorAttachments) {
GLenum* attachments = new GLenum[colorAttachments.size()];
for(auto it = colorAttachments.begin(); it != colorAttachments.end(); ++it)
attachments[it-colorAttachments.begin()] = *it + GL_COLOR_ATTACHMENT0;
bind(Target::Draw);
/** @todo Re-enable when extension wrangler is available for ES2 */
#ifndef MAGNUM_TARGET_GLES2
glDrawBuffers(colorAttachments.size(), attachments);
#endif
delete[] attachments;
}
#endif
void Framebuffer::read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& dimensions, AbstractImage::Components components, AbstractImage::ComponentType type, Image2D* image) {
char* data = new char[AbstractImage::pixelSize(components, type)*dimensions.product()];
glReadPixels(offset.x(), offset.y(), dimensions.x(), dimensions.y(), static_cast<GLenum>(components), static_cast<GLenum>(type), data);
image->setData(dimensions, components, type, data);
void Framebuffer::read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, Image2D* image) {
char* data = new char[AbstractImage::pixelSize(components, type)*size.product()];
glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast<GLenum>(components), static_cast<GLenum>(type), data);
image->setData(size, components, type, data);
}
#ifndef MAGNUM_TARGET_GLES
void Framebuffer::read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& dimensions, AbstractImage::Components components, AbstractImage::ComponentType type, BufferedImage2D* image, Buffer::Usage usage) {
void Framebuffer::read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, BufferedImage2D* image, Buffer::Usage usage) {
/* If the buffer doesn't have sufficient size, resize it */
/** @todo Explicitly reset also when buffer usage changes */
if(image->dimensions() != dimensions || image->components() != components || image->type() != type)
image->setData(dimensions, components, type, nullptr, usage);
if(image->size() != size || image->components() != components || image->type() != type)
image->setData(size, components, type, nullptr, usage);
image->buffer()->bind(Buffer::Target::PixelPack);
glReadPixels(offset.x(), offset.y(), dimensions.x(), dimensions.y(), static_cast<GLenum>(components), static_cast<GLenum>(type), nullptr);
glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast<GLenum>(components), static_cast<GLenum>(type), nullptr);
}
#endif
}

426
src/Framebuffer.h

@ -21,14 +21,24 @@
#include <Containers/EnumSet.h>
#include "BufferedImage.h"
#include "AbstractImage.h"
#include "Buffer.h"
#include "CubeMapTexture.h"
#include "Color.h"
#include "Image.h"
#include "Renderbuffer.h"
namespace Magnum {
template<std::uint8_t> class BufferedImage;
template<std::uint8_t> class Image;
typedef BufferedImage<1> BufferedImage1D;
typedef BufferedImage<2> BufferedImage2D;
typedef BufferedImage<3> BufferedImage3D;
typedef Image<1> Image1D;
typedef Image<2> Image2D;
typedef Image<3> Image3D;
/** @nosubgrouping
@brief %Framebuffer
@ -43,6 +53,20 @@ class MAGNUM_EXPORT Framebuffer {
Framebuffer& operator=(Framebuffer&& other) = delete;
public:
/**
* @brief Affected polygon facing for culling, stencil operations and masks
*
* @see setFaceCullingMode(),
* setStencilFunction(PolygonFacing, StencilFunction, GLint, GLuint),
* setStencilOperation(PolygonFacing, StencilOperation, StencilOperation, StencilOperation),
* setStencilMask(PolygonFacing, GLuint)
*/
enum class PolygonFacing: GLenum {
Front = GL_FRONT, /**< Front-facing polygons */
Back = GL_BACK, /**< Back-facing polygons */
FrontAndBack = GL_FRONT_AND_BACK /**< Front- and back-facing polygons */
};
/** @{ @name Framebuffer features */
/**
@ -62,14 +86,15 @@ class MAGNUM_EXPORT Framebuffer {
/**
* Logical operation
* @see setLogicOperation()
* @requires_gl Logic operations on framebuffer are in desktop OpenGL only.
* @requires_gl Logical operations on framebuffer are not
* available in OpenGL ES.
*/
LogicOperation = GL_COLOR_LOGIC_OP,
/**
* Depth clamping. If enabled, ignores near and far clipping plane.
* @requires_gl
* @requires_gl32 Extension @extension{ARB,depth_clamp}
* @requires_gl Depth clamping is not available in OpenGL ES.
*/
DepthClamp = GL_DEPTH_CLAMP,
#endif
@ -85,16 +110,36 @@ class MAGNUM_EXPORT Framebuffer {
FaceCulling = GL_CULL_FACE /**< Back face culling */
};
/** @brief Set feature */
static void setFeature(Feature feature, bool enabled);
/**
* @brief Set feature
*
* @see @fn_gl{Enable}/@fn_gl{Disable}
*/
inline static void setFeature(Feature feature, bool enabled) {
enabled ? glEnable(static_cast<GLenum>(feature)) : glDisable(static_cast<GLenum>(feature));
}
/**
* @brief Which polygon facing to cull
*
* Initial value is `PolygonFacing::Back`. If set to both front and
* back, only points and lines are drawn.
* @attention You have to also enable face culling with setFeature().
* @see @fn_gl{CullFace}
*/
inline static void setFaceCullingMode(PolygonFacing mode) {
glCullFace(static_cast<GLenum>(mode));
}
/**
* @brief Set viewport size
*
* Call when window size changes.
* @see Camera::setViewport()
* @see @fn_gl{Viewport}
*/
static void setViewport(const Math::Vector2<GLint>& position, const Math::Vector2<GLsizei>& size);
inline static void setViewport(const Math::Vector2<GLint>& position, const Math::Vector2<GLsizei>& size) {
glViewport(position.x(), position.y(), size.x(), size.y());
}
/*@}*/
@ -111,23 +156,15 @@ class MAGNUM_EXPORT Framebuffer {
Stencil = GL_STENCIL_BUFFER_BIT /**< Stencil value */
};
typedef Corrade::Containers::EnumSet<Clear, GLbitfield> ClearMask; /**< @brief Mask for clearing */
/**
* @brief Clear framebuffer
*
* Clears color buffer, depth and stencil buffer in currently active
* framebuffer. If depth or stencil test is not enabled, it doesn't
* clear these buffers.
*
* @see setFeature(), clear(ClearMask)
*/
inline static void clear() { glClear(static_cast<GLbitfield>(clearMask)); }
/** @brief Mask for clearing */
typedef Corrade::Containers::EnumSet<Clear, GLbitfield,
GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT> ClearMask;
/**
* @brief Clear specified buffers in framebuffer
*
* @see clear()
* @see clear(), setClearColor(), setClearDepth(), setClearStencil(),
* @fn_gl{Clear}
* @todo Clearing only given draw buffer
*/
inline static void clear(ClearMask mask) { glClear(static_cast<GLbitfield>(mask)); }
@ -136,6 +173,7 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Set clear color
*
* Initial value is `{0.0f, 0.0f, 0.0f, 1.0f}`.
* @see @fn_gl{ClearColor}
*/
inline static void setClearColor(const Color4<GLfloat>& color) {
glClearColor(color.r(), color.g(), color.b(), color.a());
@ -146,7 +184,8 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Set clear depth
*
* Initial value is `1.0`.
* @requires_gl See setClearDepth(GLfloat), which is supported in OpenGL ES.
* @see @fn_gl{ClearDepth}
* @requires_gl See setClearDepth(GLfloat), which is available in OpenGL ES.
*/
inline static void setClearDepth(GLdouble depth) { glClearDepth(depth); }
#endif
@ -154,7 +193,9 @@ class MAGNUM_EXPORT Framebuffer {
/**
* @overload
*
* @see @fn_gl{ClearDepth}
* @requires_gl41 Extension @extension{ARB,ES2_compatibility}
* @todo Call double version if the extension is not available
*/
inline static void setClearDepth(GLfloat depth) { glClearDepthf(depth); }
@ -162,6 +203,7 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Set clear stencil
*
* Initial value is `0`.
* @see @fn_gl{ClearStencil}
*/
inline static void setClearStencil(GLint stencil) { glClearStencil(stencil); }
@ -175,7 +217,9 @@ class MAGNUM_EXPORT Framebuffer {
* @param size Scissor rectangle size. Initial value is
* size of the window when the context is first attached to a
* window.
*
* @attention You have to enable scissoring with setFeature() first.
* @see @fn_gl{Scissor}
*/
inline static void setScissor(const Math::Vector2<GLint>& bottomLeft, const Math::Vector2<GLsizei>& size) {
glScissor(bottomLeft.x(), bottomLeft.y(), size.x(), size.y());
@ -185,19 +229,6 @@ class MAGNUM_EXPORT Framebuffer {
/** @{ @name Stencil operations */
/**
* @brief Affected polygon facing for stencil operations and masks
*
* @see setStencilFunction(PolygonFacing, StencilFunction, GLint, GLuint),
* setStencilOperation(PolygonFacing, StencilOperation, StencilOperation, StencilOperation),
* setStencilMask(PolygonFacing, GLuint)
*/
enum class PolygonFacing: GLenum {
Front = GL_FRONT, /**< Front-facing polygons */
Back = GL_BACK, /**< Back-facing polygons */
FrontAndBack = GL_FRONT_AND_BACK /**< Front- and back-facing polygons */
};
/**
* @brief Stencil function
*
@ -269,7 +300,8 @@ class MAGNUM_EXPORT Framebuffer {
* Initial value is all `1`s.
*
* @attention You have to enable stencil test with setFeature() first.
* @see setStencilFunction(StencilFunction, GLint, GLuint)
* @see setStencilFunction(StencilFunction, GLint, GLuint),
* @fn_gl{StencilFuncSeparate}
*/
inline static void setStencilFunction(PolygonFacing facing, StencilFunction function, GLint referenceValue, GLuint mask) {
glStencilFuncSeparate(static_cast<GLenum>(facing), static_cast<GLenum>(function), referenceValue, mask);
@ -280,6 +312,7 @@ class MAGNUM_EXPORT Framebuffer {
*
* The same as setStencilFunction(PolygonFacing, StencilFunction, GLint, GLuint)
* with `facing` set to `PolygonFacing::FrontAndBack`.
* @see @fn_gl{StencilFunc}
*/
inline static void setStencilFunction(StencilFunction function, GLint referenceValue, GLuint mask) {
glStencilFunc(static_cast<GLenum>(function), referenceValue, mask);
@ -296,7 +329,8 @@ class MAGNUM_EXPORT Framebuffer {
*
* Initial value for all fields is `StencilOperation::Keep`.
* @attention You have to enable stencil test with setFeature() first.
* @see setStencilOperation(StencilOperation, StencilOperation, StencilOperation)
* @see setStencilOperation(StencilOperation, StencilOperation, StencilOperation),
* @fn_gl{StencilOpSeparate}
*/
inline static void setStencilOperation(PolygonFacing facing, StencilOperation stencilFail, StencilOperation depthFail, StencilOperation depthPass) {
glStencilOpSeparate(static_cast<GLenum>(facing), static_cast<GLenum>(stencilFail), static_cast<GLenum>(depthFail), static_cast<GLenum>(depthPass));
@ -307,6 +341,7 @@ class MAGNUM_EXPORT Framebuffer {
*
* The same as setStencilOperation(PolygonFacing, StencilOperation, StencilOperation, StencilOperation)
* with `facing` set to `PolygonFacing::FrontAndBack`.
* @see @fn_gl{StencilOp}
*/
inline static void setStencilOperation(StencilOperation stencilFail, StencilOperation depthFail, StencilOperation depthPass) {
glStencilOp(static_cast<GLenum>(stencilFail), static_cast<GLenum>(depthFail), static_cast<GLenum>(depthPass));
@ -328,6 +363,7 @@ class MAGNUM_EXPORT Framebuffer {
*
* Initial value is `DepthFunction::Less`.
* @attention You have to enable depth test with setFeature() first.
* @see @fn_gl{DepthFunc}
*/
inline static void setDepthFunction(DepthFunction function) {
glDepthFunc(static_cast<GLenum>(function));
@ -342,6 +378,7 @@ class MAGNUM_EXPORT Framebuffer {
*
* Set to `false` to disallow writing to given color channel. Initial
* values are all `true`.
* @see @fn_gl{ColorMask}
* @todo Masking only given draw buffer
*/
inline static void setColorMask(GLboolean allowRed, GLboolean allowGreen, GLboolean allowBlue, GLboolean allowAlpha) {
@ -353,6 +390,7 @@ class MAGNUM_EXPORT Framebuffer {
*
* Set to `false` to disallow writing to depth buffer. Initial value
* is `true`.
* @see @fn_gl{DepthMask}
*/
inline static void setDepthMask(GLboolean allow) {
glDepthMask(allow);
@ -363,7 +401,7 @@ class MAGNUM_EXPORT Framebuffer {
*
* Set given bit to `0` to disallow writing stencil value for given
* faces to it. Initial value is all `1`s.
* @see setStencilMask(GLuint)
* @see setStencilMask(GLuint), @fn_gl{StencilMaskSeparate}
*/
inline static void setStencilMask(PolygonFacing facing, GLuint allowBits) {
glStencilMaskSeparate(static_cast<GLenum>(facing), allowBits);
@ -374,6 +412,7 @@ class MAGNUM_EXPORT Framebuffer {
*
* The same as setStencilMask(PolygonFacing, GLuint) with `facing` set
* to `PolygonFacing::FrontAndBack`.
* @see @fn_gl{StencilMask}
*/
inline static void setStencilMask(GLuint allowBits) {
glStencilMask(allowBits);
@ -394,24 +433,19 @@ class MAGNUM_EXPORT Framebuffer {
enum class BlendEquation: GLenum {
Add = GL_FUNC_ADD, /**< `source + destination` */
Subtract = GL_FUNC_SUBTRACT, /**< `source - destination` */
ReverseSubtract = GL_FUNC_REVERSE_SUBTRACT /**< `destination - source` */
#ifndef MAGNUM_TARGET_GLES
/** @todo Enable for ES3 when the headers are available */
,
ReverseSubtract = GL_FUNC_REVERSE_SUBTRACT, /**< `destination - source` */
/**
* `min(source, destination)`
* @requires_gles30 Extension @es_extension{EXT,blend_minmax}
* @requires_gles30 %Extension @es_extension2{EXT,blend_minmax,blend_minmax}
*/
Min = GL_MIN,
/**
* `max(source, destination)`
* @requires_gles30 Extension @es_extension{EXT,blend_minmax}
* @requires_gles30 %Extension @es_extension2{EXT,blend_minmax,blend_minmax}
*/
Max = GL_MAX
#endif
};
/**
@ -462,8 +496,9 @@ class MAGNUM_EXPORT Framebuffer {
* Second source color (@f$ RGB = (R_{s1}, G_{s1}, B_{s1}); A = A_{s1} @f$)
*
* @see AbstractShaderProgram::bindFragmentDataLocationIndexed()
* @requires_gl
* @requires_gl33 Extension @extension{ARB,blend_func_extended}
* @requires_gl Multiple blending inputs are not available in
* OpenGL ES.
*/
SecondSourceColor = GL_SRC1_COLOR,
#endif
@ -478,8 +513,9 @@ class MAGNUM_EXPORT Framebuffer {
* One minus second source color (@f$ RGB = (1.0 - R_{s1}, 1.0 - G_{s1}, 1.0 - B_{s1}); A = 1.0 - A_{s1} @f$)
*
* @see AbstractShaderProgram::bindFragmentDataLocationIndexed()
* @requires_gl
* @requires_gl33 Extension @extension{ARB,blend_func_extended}
* @requires_gl Multiple blending inputs are not available in
* OpenGL ES.
*/
OneMinusSecondSourceColor = GL_ONE_MINUS_SRC1_COLOR,
#endif
@ -499,8 +535,9 @@ class MAGNUM_EXPORT Framebuffer {
* Second source alpha (@f$ RGB = (A_{s1}, A_{s1}, A_{s1}); A = A_{s1} @f$)
*
* @see AbstractShaderProgram::bindFragmentDataLocationIndexed()
* @requires_gl
* @requires_gl33 Extension @extension{ARB,blend_func_extended}
* @requires_gl Multiple blending inputs are not available in
* OpenGL ES.
*/
SecondSourceAlpha = GL_SRC1_ALPHA,
#endif
@ -515,8 +552,9 @@ class MAGNUM_EXPORT Framebuffer {
* One minus second source alpha (@f$ RGB = (1.0 - A_{s1}, 1.0 - A_{s1}, 1.0 - A_{s1}); A = 1.0 - A_{s1} @f$)
*
* @see AbstractShaderProgram::bindFragmentDataLocationIndexed()
* @requires_gl
* @requires_gl33 Extension @extension{ARB,blend_func_extended}
* @requires_gl Multiple blending inputs are not available in
* OpenGL ES.
*/
OneMinusSecondSourceAlpha = GL_ONE_MINUS_SRC1_ALPHA,
#endif
@ -544,7 +582,8 @@ class MAGNUM_EXPORT Framebuffer {
* How to combine source color (pixel value) with destination color
* (framebuffer). Initial value is `BlendEquation::Add`.
* @attention You have to enable blending with setFeature() first.
* @see setBlendEquation(BlendEquation, BlendEquation)
* @see setBlendEquation(BlendEquation, BlendEquation),
* @fn_gl{BlendEquation}
*/
inline static void setBlendEquation(BlendEquation equation) {
glBlendEquation(static_cast<GLenum>(equation));
@ -555,6 +594,7 @@ class MAGNUM_EXPORT Framebuffer {
*
* See setBlendEquation(BlendEquation) for more information.
* @attention You have to enable blending with setFeature() first.
* @see @fn_gl{BlendEquationSeparate}
*/
inline static void setBlendEquation(BlendEquation rgb, BlendEquation alpha) {
glBlendEquationSeparate(static_cast<GLenum>(rgb), static_cast<GLenum>(alpha));
@ -569,7 +609,8 @@ class MAGNUM_EXPORT Framebuffer {
* `BlendFunction::Zero`.
*
* @attention You have to enable blending with setFeature() first.
* @see setBlendFunction(BlendFunction, BlendFunction, BlendFunction, BlendFunction)
* @see setBlendFunction(BlendFunction, BlendFunction, BlendFunction, BlendFunction),
* @fn_gl{BlendFunc}
*/
inline static void setBlendFunction(BlendFunction source, BlendFunction destination) {
glBlendFunc(static_cast<GLenum>(source), static_cast<GLenum>(destination));
@ -580,6 +621,7 @@ class MAGNUM_EXPORT Framebuffer {
*
* See setBlendFunction(BlendFunction, BlendFunction) for more information.
* @attention You have to enable blending with setFeature() first.
* @see @fn_gl{BlendFuncSeparate}
*/
inline static void setBlendFunction(BlendFunction sourceRgb, BlendFunction destinationRgb, BlendFunction sourceAlpha, BlendFunction destinationAlpha) {
glBlendFuncSeparate(static_cast<GLenum>(sourceRgb), static_cast<GLenum>(destinationRgb), static_cast<GLenum>(sourceAlpha), static_cast<GLenum>(destinationAlpha));
@ -594,6 +636,7 @@ class MAGNUM_EXPORT Framebuffer {
* `BlendFunction::ConstantAlpha` and
* `BlendFunction::OneMinusConstantAlpha`.
* @attention You have to enable blending with setFeature() first.
* @see @fn_gl{BlendColor}
*/
inline static void setBlendColor(const Color4<GLfloat>& color) {
glBlendColor(color.r(), color.g(), color.b(), color.a());
@ -608,7 +651,8 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Logical operation
*
* @see setLogicOperation()
* @requires_gl
* @requires_gl Logical operations on framebuffer are not available in
* OpenGL ES.
*/
enum class LogicOperation: GLenum {
Clear = GL_CLEAR, /**< `0` */
@ -633,7 +677,9 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Set logical operation
*
* @attention You have to enable logical operation with setFeature() first.
* @requires_gl Logic operations on framebuffer are in desktop OpenGL only.
* @see @fn_gl{LogicOp}
* @requires_gl Logical operations on framebuffer are not available in
* OpenGL ES.
*/
inline static void setLogicOperation(LogicOperation operation) {
glLogicOp(static_cast<GLenum>(operation));
@ -651,81 +697,184 @@ class MAGNUM_EXPORT Framebuffer {
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
enum class Target: GLenum {
#ifndef MAGNUM_TARGET_GLES
/**
* For reading only.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_blit}
* @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample}
* or @es_extension{ANGLE,framebuffer_blit}
*/
Read = GL_READ_FRAMEBUFFER,
/**
* For drawing only.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_blit}
* @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample}
* or @es_extension{ANGLE,framebuffer_blit}
*/
Draw = GL_DRAW_FRAMEBUFFER,
#endif
ReadDraw = GL_FRAMEBUFFER /**< For both reading and drawing. */
};
#ifndef MAGNUM_TARGET_GLES
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Draw attachment for default framebuffer
*
* @see mapDefaultForDraw()
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gles30 Draw attachments for default framebuffer are
* available only in OpenGL ES 3.0.
*/
enum class DefaultDrawAttachment: GLenum {
None = GL_NONE, /**< Don't use the output. */
BackLeft = GL_BACK_LEFT, /**< Write output to back left framebuffer. */
BackRight = GL_BACK_RIGHT, /**< Write output to back right framebuffer. */
FrontLeft = GL_FRONT_LEFT, /**< Write output to front left framebuffer. */
FrontRight = GL_FRONT_RIGHT /**< Write output to front right framebuffer. */
/** Don't use the output. */
None = GL_NONE,
#ifndef MAGNUM_TARGET_GLES
/**
* Write output to back left framebuffer.
* @requires_gl Stereo rendering is not available in OpenGL ES.
*/
BackLeft = GL_BACK_LEFT,
/**
* Write output to back right framebuffer.
* @requires_gl Stereo rendering is not available in OpenGL ES.
*/
BackRight = GL_BACK_RIGHT,
/**
* Write output to front left framebuffer.
* @requires_gl Stereo rendering is not available in OpenGL ES.
*/
FrontLeft = GL_FRONT_LEFT,
/**
* Write output to front right framebuffer.
* @requires_gl Stereo rendering is not available in OpenGL ES.
*/
FrontRight = GL_FRONT_RIGHT,
#endif
/**
* Write output to back framebuffer.
*
* On desktop OpenGL, this is equal to
* @ref Magnum::Framebuffer::DefaultDrawAttachment "DefaultDrawAttachment::BackLeft".
*/
#ifdef MAGNUM_TARGET_GLES
Back = GL_BACK,
#else
Back = GL_BACK_LEFT,
#endif
/**
* Write output to front framebuffer.
*
* On desktop OpenGL, this is equal to
* @ref Magnum::Framebuffer::DefaultDrawAttachment "DefaultDrawAttachment::FrontLeft".
*/
#ifdef MAGNUM_TARGET_GLES
Front = GL_FRONT
#else
Front = GL_FRONT_LEFT
#endif
};
#endif
/**
* @brief Read attachment for default framebuffer
*
* @see mapDefaultForRead()
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gl30 %Extension @extension{EXT,framebuffer_object}
* @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer}
*/
enum class DefaultReadAttachment: GLenum {
FrontLeft = GL_FRONT_LEFT, /**< Read from front left framebuffer. */
FrontRight = GL_FRONT_RIGHT, /**< Read from front right framebuffer. */
BackLeft = GL_BACK_LEFT, /**< Read from back left framebuffer. */
BackRight = GL_BACK_RIGHT, /**< Read from back right framebuffer. */
Left = GL_LEFT, /**< Read from left framebuffers. */
Right = GL_RIGHT, /**< Read from right framebuffers. */
Front = GL_FRONT, /**< Read from front framebuffers. */
Back = GL_BACK, /**< Read from back framebuffers. */
FrontAndBack = GL_FRONT_AND_BACK /**< Read from front and back framebuffers. */
/** Don't read from any framebuffer */
None = GL_NONE,
#ifndef MAGNUM_TARGET_GLES
/**
* Read from back left framebuffer.
* @requires_gl Stereo rendering is not available in OpenGL ES.
*/
BackLeft = GL_BACK_LEFT,
/**
* Read from back right framebuffer.
* @requires_gl Stereo rendering is not available in OpenGL ES.
*/
BackRight = GL_BACK_RIGHT,
/**
* Read from front left framebuffer.
* @requires_gl Stereo rendering is not available in OpenGL ES.
*/
FrontLeft = GL_FRONT_LEFT,
/**
* Read from front right framebuffer.
* @requires_gl Stereo rendering is not available in OpenGL ES.
*/
FrontRight = GL_FRONT_RIGHT,
/**
* Read from left framebuffer.
* @requires_gl Stereo rendering is not available in OpenGL ES.
*/
Left = GL_LEFT,
/**
* Read from right framebuffer.
* @requires_gl Stereo rendering is not available in OpenGL ES.
*/
Right = GL_RIGHT,
#endif
/** Read from back framebuffer. */
Back = GL_BACK,
/**
* Read from front framebuffer.
* @requires_es_extension %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer}
*/
Front = GL_FRONT
#ifndef MAGNUM_TARGET_GLES
,
/**
* Read from front and back framebuffer.
* @requires_gl In OpenGL ES you must specify either
* @ref Magnum::Framebuffer::DefaultReadAttachment "DefaultReadAttachment::Front"
* or @ref Magnum::Framebuffer::DefaultReadAttachment "DefaultReadAttachment::Back".
*/
FrontAndBack = GL_FRONT_AND_BACK
#endif
};
#endif
/**
* @brief Constructor
*
* Generates new OpenGL framebuffer.
* @see @fn_gl{GenFramebuffers}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
inline Framebuffer() { glGenFramebuffers(1, &framebuffer); }
inline Framebuffer() { glGenFramebuffers(1, &_id); }
/**
* @brief Destructor
*
* Deletes associated OpenGL framebuffer.
* @see @fn_gl{DeleteFramebuffers}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
inline ~Framebuffer() { glDeleteFramebuffers(1, &framebuffer); }
inline ~Framebuffer() { glDeleteFramebuffers(1, &_id); }
/**
* @brief Bind default framebuffer to given target
* @param target %Target
*
* @see @fn_gl{BindFramebuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
inline static void bindDefault(Target target) {
@ -735,13 +884,14 @@ class MAGNUM_EXPORT Framebuffer {
/**
* @brief Bind framebuffer
*
* @see @fn_gl{BindFramebuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
inline void bind(Target target) {
glBindFramebuffer(static_cast<GLenum>(target), framebuffer);
glBindFramebuffer(static_cast<GLenum>(target), _id);
}
#ifndef MAGNUM_TARGET_GLES
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Map given attachments of default framebuffer for drawing
* @param attachments Default attachments. If any value is
@ -752,11 +902,13 @@ class MAGNUM_EXPORT Framebuffer {
* If used for blit(), the order is not important. Each used attachment
* should have either renderbuffer or texture attached for writing to
* work properly.
* @see mapForDraw(), mapDefaultForRead()
* @requires_gl
* @see mapForDraw(), mapDefaultForRead(), bindDefault(), @fn_gl{DrawBuffers}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gles30 Draw attachments for default framebuffer are
* available only in OpenGL ES 3.0.
*/
static void mapDefaultForDraw(std::initializer_list<DefaultDrawAttachment> attachments);
#endif
/**
* @brief Map given color attachments of current framebuffer for drawing
@ -768,11 +920,11 @@ class MAGNUM_EXPORT Framebuffer {
* If used for blit(), the order is not important. Each used attachment
* should have either renderbuffer or texture attached for writing to
* work properly.
* @see mapDefaultForDraw(), mapForRead()
* @requires_gl
* @see mapDefaultForDraw(), mapForRead(), bind(), @fn_gl{DrawBuffers}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers}
*/
void mapForDraw(std::initializer_list<int> colorAttachments);
void mapForDraw(std::initializer_list<std::int8_t> colorAttachments);
/**
* @brief Map given attachment of default framebuffer for reading
@ -780,9 +932,9 @@ class MAGNUM_EXPORT Framebuffer {
*
* Each used attachment should have either renderbuffer or texture
* attached to work properly.
* @see mapForRead(), mapDefaultForDraw()
* @requires_gl
* @see mapForRead(), mapDefaultForDraw(), bindDefault(), @fn_gl{ReadBuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer}
*/
inline static void mapDefaultForRead(DefaultReadAttachment attachment) {
bindDefault(Target::Read);
@ -795,15 +947,14 @@ class MAGNUM_EXPORT Framebuffer {
*
* The color attachment should have either renderbuffer or texture
* attached for reading to work properly.
* @see mapDefaultForRead(), mapForDraw()
* @requires_gl
* @see mapDefaultForRead(), mapForDraw(), bind(), @fn_gl{ReadBuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer}
*/
inline void mapForRead(unsigned int colorAttachment) {
inline void mapForRead(std::uint8_t colorAttachment) {
bind(Target::Read);
glReadBuffer(GL_COLOR_ATTACHMENT0 + colorAttachment);
}
#endif
/*@}*/
@ -824,10 +975,12 @@ class MAGNUM_EXPORT Framebuffer {
Stencil = GL_STENCIL_ATTACHMENT /**< Stencil output only. */
#ifndef MAGNUM_TARGET_GLES
#ifndef MAGNUM_TARGET_GLES2
,
/**
* Both depth and stencil output.
* @requires_gles30 Combined depth and stencil attachment is not
* available in OpenGL ES 2.0.
*/
DepthStencil = GL_DEPTH_STENCIL_ATTACHMENT
#endif
@ -837,8 +990,9 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Attach renderbuffer to given framebuffer depth/stencil attachment
* @param target %Target
* @param depthStencilAttachment Depth/stencil attachment
* @param renderbuffer Renderbuffer
* @param renderbuffer %Renderbuffer
*
* @see bind(), @fn_gl{FramebufferRenderbuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
inline void attachRenderbuffer(Target target, DepthStencilAttachment depthStencilAttachment, Renderbuffer* renderbuffer) {
@ -851,11 +1005,12 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Attach renderbuffer to given framebuffer color attachment
* @param target %Target
* @param colorAttachment Color attachment ID (number between 0 and 15)
* @param renderbuffer Renderbuffer
* @param renderbuffer %Renderbuffer
*
* @see bind(), @fn_gl{FramebufferRenderbuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
inline void attachRenderbuffer(Target target, unsigned int colorAttachment, Renderbuffer* renderbuffer) {
inline void attachRenderbuffer(Target target, std::uint8_t colorAttachment, Renderbuffer* renderbuffer) {
/** @todo Check for internal format compatibility */
bind(target);
glFramebufferRenderbuffer(static_cast<GLenum>(target), GL_COLOR_ATTACHMENT0 + colorAttachment, GL_RENDERBUFFER, renderbuffer->id());
@ -869,8 +1024,9 @@ class MAGNUM_EXPORT Framebuffer {
* @param texture 1D texture
* @param mipLevel Mip level
*
* @requires_gl
* @see bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gl Only 2D and 3D textures are available in OpenGL ES.
*/
inline void attachTexture1D(Target target, DepthStencilAttachment depthStencilAttachment, Texture1D* texture, GLint mipLevel) {
/** @todo Check for internal format compatibility */
@ -886,10 +1042,11 @@ class MAGNUM_EXPORT Framebuffer {
* @param texture 1D texture
* @param mipLevel Mip level
*
* @requires_gl
* @see bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gl Only 2D and 3D textures are available in OpenGL ES.
*/
inline void attachTexture1D(Target target, unsigned int colorAttachment, Texture1D* texture, GLint mipLevel) {
inline void attachTexture1D(Target target, std::uint8_t colorAttachment, Texture1D* texture, GLint mipLevel) {
/** @todo Check for internal format compatibility */
/** @todo Check for texture target compatibility */
bind(target);
@ -905,7 +1062,7 @@ class MAGNUM_EXPORT Framebuffer {
* @param mipLevel Mip level. For rectangle textures it
* should be always 0.
*
* @see attachCubeMapTexture()
* @see attachCubeMapTexture(), bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
inline void attachTexture2D(Target target, DepthStencilAttachment depthStencilAttachment, Texture2D* texture, GLint mipLevel) {
@ -923,10 +1080,10 @@ class MAGNUM_EXPORT Framebuffer {
* @param mipLevel Mip level. For rectangle textures it
* should be always 0.
*
* @see attachCubeMapTexture()
* @see attachCubeMapTexture(), bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
inline void attachTexture2D(Target target, unsigned int colorAttachment, Texture2D* texture, GLint mipLevel) {
inline void attachTexture2D(Target target, std::uint8_t colorAttachment, Texture2D* texture, GLint mipLevel) {
/** @todo Check for internal format compatibility */
/** @todo Check for texture target compatibility */
bind(target);
@ -941,7 +1098,7 @@ class MAGNUM_EXPORT Framebuffer {
* @param coordinate Cube map coordinate
* @param mipLevel Mip level
*
* @see attachTexture2D()
* @see attachTexture2D(), bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
inline void attachCubeMapTexture(Target target, DepthStencilAttachment depthStencilAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) {
@ -958,16 +1115,15 @@ class MAGNUM_EXPORT Framebuffer {
* @param coordinate Cube map coordinate
* @param mipLevel Mip level
*
* @see attachTexture2D()
* @see attachTexture2D(), bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
inline void attachCubeMapTexture(Target target, unsigned int colorAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) {
inline void attachCubeMapTexture(Target target, std::uint8_t colorAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) {
/** @todo Check for internal format compatibility */
bind(target);
glFramebufferTexture2D(static_cast<GLenum>(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast<GLenum>(coordinate), texture->id(), mipLevel);
}
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Attach 3D texture to given framebuffer depth/stencil attachment
* @param target %Target
@ -976,14 +1132,23 @@ class MAGNUM_EXPORT Framebuffer {
* @param mipLevel Mip level
* @param layer Layer of 2D image within a 3D texture
*
* @requires_gl
* @see bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_es_extension %Extension @es_extension{OES,texture_3D}
*/
inline void attachTexture3D(Target target, DepthStencilAttachment depthStencilAttachment, Texture3D* texture, GLint mipLevel, GLint layer) {
/** @todo Check for internal format compatibility */
/** @todo Check for texture target compatibility */
bind(target);
/** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */
#ifndef MAGNUM_TARGET_GLES
glFramebufferTexture3D(static_cast<GLenum>(target), static_cast<GLenum>(depthStencilAttachment), static_cast<GLenum>(texture->target()), texture->id(), mipLevel, layer);
#else
static_cast<void>(depthStencilAttachment);
static_cast<void>(texture);
static_cast<void>(mipLevel);
static_cast<void>(layer);
#endif
}
/**
@ -994,30 +1159,37 @@ class MAGNUM_EXPORT Framebuffer {
* @param mipLevel Mip level
* @param layer Layer of 2D image within a 3D texture.
*
* @requires_gl
* @see bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_es_extension %Extension @es_extension{OES,texture_3D}
*/
inline void attachTexture3D(Target target, unsigned int colorAttachment, Texture3D* texture, GLint mipLevel, GLint layer) {
inline void attachTexture3D(Target target, std::uint8_t colorAttachment, Texture3D* texture, GLint mipLevel, GLint layer) {
/** @todo Check for internal format compatibility */
/** @todo Check for texture target compatibility */
bind(target);
/** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */
#ifndef MAGNUM_TARGET_GLES
glFramebufferTexture3D(static_cast<GLenum>(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast<GLenum>(texture->target()), texture->id(), mipLevel, layer);
#else
static_cast<void>(colorAttachment);
static_cast<void>(texture);
static_cast<void>(mipLevel);
static_cast<void>(layer);
#endif
}
#endif
/*@}*/
/** @{ @name Framebuffer blitting and reading */
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Output mask for blitting
*
* Specifies which data are copied when performing blit operation
* using blit().
* @see BlitMask
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit}
*/
enum class Blit: GLbitfield {
Color = GL_COLOR_BUFFER_BIT, /**< Color */
@ -1027,10 +1199,11 @@ class MAGNUM_EXPORT Framebuffer {
/**
* @brief Output mask for blitting
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit}
*/
typedef Corrade::Containers::EnumSet<Blit, GLbitfield> BlitMask;
typedef Corrade::Containers::EnumSet<Blit, GLbitfield,
GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT> BlitMask;
/**
* @brief Copy block of pixels from read to draw framebuffer
@ -1047,8 +1220,9 @@ class MAGNUM_EXPORT Framebuffer {
* mapDefaultForDraw() for binding particular framebuffer for reading
* and drawing. If multiple attachments are specified in mapForDraw()
* / mapDefaultForDraw(), the data are written to each of them.
* @requires_gl
* @see @fn_gl{BlitFramebuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_blit}
* @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit}
*/
inline static void blit(const Math::Vector2<GLint>& bottomLeft, const Math::Vector2<GLint>& topRight, const Math::Vector2<GLint>& destinationBottomLeft, const Math::Vector2<GLint>& destinationTopRight, BlitMask blitMask, AbstractTexture::Filter filter) {
glBlitFramebuffer(bottomLeft.x(), bottomLeft.y(), topRight.x(), topRight.y(), destinationBottomLeft.x(), destinationBottomLeft.y(), destinationTopRight.x(), destinationTopRight.y(), static_cast<GLbitfield>(blitMask), static_cast<GLenum>(filter));
@ -1067,48 +1241,46 @@ class MAGNUM_EXPORT Framebuffer {
* no interpolation is needed and thus
* AbstractTexture::Filter::NearestNeighbor filtering is used by
* default.
* @requires_gl
* @see @fn_gl{BlitFramebuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_blit}
* @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit}
*/
inline static void blit(const Math::Vector2<GLint>& bottomLeft, const Math::Vector2<GLint>& topRight, BlitMask blitMask) {
glBlitFramebuffer(bottomLeft.x(), bottomLeft.y(), topRight.x(), topRight.y(), bottomLeft.x(), bottomLeft.y(), topRight.x(), topRight.y(), static_cast<GLbitfield>(blitMask), static_cast<GLenum>(AbstractTexture::Filter::NearestNeighbor));
}
#endif
/**
* @brief Read block of pixels from framebuffer to image
* @param offset Offset in the framebuffer
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components
* @param type Data type
* @param image %Image where to put the data
*
* @see @fn_gl{ReadPixels}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/
static void read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& dimensions, AbstractImage::Components components, AbstractImage::ComponentType type, Image2D* image);
static void read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, Image2D* image);
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Read block of pixels from framebuffer to buffered image
* @param offset Offset in the framebuffer
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components
* @param type Data type
* @param image Buffered image where to put the data
* @param usage %Buffer usage
*
* @requires_gl
* @see Buffer::bind(Target), @fn_gl{ReadPixels}
* @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0.
*/
static void read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& dimensions, AbstractImage::Components components, AbstractImage::ComponentType type, BufferedImage2D* image, Buffer::Usage usage);
#endif
static void read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, BufferedImage2D* image, Buffer::Usage usage);
/*@}*/
private:
static ClearMask clearMask;
GLuint framebuffer;
GLuint _id;
};
CORRADE_ENUMSET_OPERATORS(Framebuffer::ClearMask)

32
src/Image.cpp

@ -0,0 +1,32 @@
/*
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 "Image.h"
namespace Magnum {
template<std::uint8_t dimensions> void Image<dimensions>::setData(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, ComponentType type, GLvoid* data) {
delete[] _data;
_components = components;
_type = type;
_size = size;
_data = reinterpret_cast<char*>(data);
}
template class Image<1>;
template class Image<2>;
template class Image<3>;
}

47
src/Image.h

@ -19,7 +19,9 @@
* @brief Class Magnum::Image, typedef Magnum::Image1D, Magnum::Image2D, Magnum::Image3D
*/
#include "Math/Vector3.h"
#include "AbstractImage.h"
#include "DimensionTraits.h"
#include "TypeTraits.h"
namespace Magnum {
@ -30,14 +32,15 @@ namespace Magnum {
Class for storing image data on client memory. Can be replaced with
ImageWrapper, BufferedImage, which stores image data in GPU memory, or for
example with Trade::ImageData.
@see Image1D, Image2D, Image3D
*/
template<size_t imageDimensions> class Image: public AbstractImage {
template<std::uint8_t dimensions> class Image: public AbstractImage {
public:
const static size_t Dimensions = imageDimensions; /**< @brief Image dimension count */
const static std::uint8_t Dimensions = dimensions; /**< @brief %Image dimension count */
/**
* @brief Constructor
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components. Data type is detected
* from passed data array.
* @param data %Image data with proper size
@ -45,11 +48,11 @@ template<size_t imageDimensions> class Image: public AbstractImage {
* Note that the image data are not copied on construction, but they
* are deleted on class destruction.
*/
template<class T> inline Image(const Math::Vector<Dimensions, GLsizei>& dimensions, Components components, T* data): AbstractImage(components, TypeTraits<T>::imageType()), _dimensions(dimensions), _data(data) {}
template<class T> inline Image(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, T* data): AbstractImage(components, TypeTraits<T>::imageType()), _size(size), _data(data) {}
/**
* @brief Constructor
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components
* @param type Data type
* @param data %Image data
@ -57,7 +60,7 @@ template<size_t imageDimensions> class Image: public AbstractImage {
* Note that the image data are not copied on construction, but they
* are deleted on class destruction.
*/
inline Image(const Math::Vector<Dimensions, GLsizei>& dimensions, Components components, ComponentType type, GLvoid* data): AbstractImage(components, type), _dimensions(dimensions), _data(reinterpret_cast<char*>(data)) {}
inline Image(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, ComponentType type, GLvoid* data): AbstractImage(components, type), _size(size), _data(reinterpret_cast<char*>(data)) {}
/**
* @brief Constructor
@ -72,16 +75,16 @@ template<size_t imageDimensions> class Image: public AbstractImage {
/** @brief Destructor */
inline ~Image() { delete[] _data; }
/** @brief %Image dimensions */
inline constexpr const Math::Vector<Dimensions, GLsizei>& dimensions() const { return _dimensions; }
/** @brief %Image size */
inline typename DimensionTraits<Dimensions, GLsizei>::VectorType size() const { return _size; }
/** @brief Pointer to raw data */
inline void* data() { return _data; }
inline constexpr const void* data() const { return _data; } /**< @overload */
inline const void* data() const { return _data; } /**< @overload */
/**
* @brief Set image data
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components. Data type is detected
* from passed data array.
* @param data %Image data
@ -89,13 +92,13 @@ template<size_t imageDimensions> class Image: public AbstractImage {
* Deletes previous data and replaces them with new. Note that the
* data are not copied, but they are deleted on destruction.
*/
template<class T> inline void setData(const Math::Vector<Dimensions, GLsizei>& dimensions, Components components, T* data) {
setData(dimensions, components, TypeTraits<T>::imageType(), data);
template<class T> inline void setData(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, T* data) {
setData(size, components, TypeTraits<T>::imageType(), data);
}
/**
* @brief Set image data
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components
* @param type Data type
* @param data %Image data
@ -103,19 +106,19 @@ template<size_t imageDimensions> class Image: public AbstractImage {
* Deletes previous data and replaces them with new. Note that the
* data are not copied, but they are deleted on destruction.
*/
void setData(const Math::Vector<Dimensions, GLsizei>& dimensions, Components components, ComponentType type, GLvoid* data) {
delete[] _data;
_components = components;
_type = type;
_dimensions = dimensions;
_data = reinterpret_cast<char*>(data);
}
void setData(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, ComponentType type, GLvoid* data);
protected:
Math::Vector<Dimensions, GLsizei> _dimensions; /**< @brief %Image dimensions */
char* _data; /**< @brief %Image data */
Math::Vector<Dimensions, GLsizei> _size; /**< @brief %Image size */
char* _data; /**< @brief %Image data */
};
#ifndef DOXYGEN_GENERATING_OUTPUT
extern template class MAGNUM_EXPORT Image<1>;
extern template class MAGNUM_EXPORT Image<2>;
extern template class MAGNUM_EXPORT Image<3>;
#endif
/** @brief One-dimensional image */
typedef Image<1> Image1D;

30
src/ImageWrapper.h

@ -19,7 +19,9 @@
* @brief Class Magnum::ImageWrapper
*/
#include "Math/Vector3.h"
#include "AbstractImage.h"
#include "DimensionTraits.h"
#include "TypeTraits.h"
namespace Magnum {
@ -38,13 +40,13 @@ to change image properties, only data pointer.
See also Image, BufferedImage and Trade::ImageData.
*/
template<size_t imageDimensions> class ImageWrapper: public AbstractImage {
template<std::uint8_t dimensions> class ImageWrapper: public AbstractImage {
public:
const static size_t Dimensions = imageDimensions; /**< @brief Image dimension count */
const static std::uint8_t Dimensions = dimensions; /**< @brief %Image dimension count */
/**
* @brief Constructor
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components. Data type is detected
* from passed data array.
* @param data %Image data with proper size
@ -52,11 +54,11 @@ template<size_t imageDimensions> class ImageWrapper: public AbstractImage {
* Note that the image data are not copied on construction, but they
* are deleted on class destruction.
*/
template<class T> inline ImageWrapper(const Math::Vector<Dimensions, GLsizei>& dimensions, Components components, T* data): AbstractImage(components, TypeTraits<T>::imageType()), _dimensions(dimensions), _data(data) {}
template<class T> inline ImageWrapper(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, T* data): AbstractImage(components, TypeTraits<T>::imageType()), _size(size), _data(data) {}
/**
* @brief Constructor
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components
* @param type Data type
* @param data %Image data
@ -64,25 +66,25 @@ template<size_t imageDimensions> class ImageWrapper: public AbstractImage {
* Note that the image data are not copied on construction, but they
* are deleted on class destruction.
*/
inline ImageWrapper(const Math::Vector<Dimensions, GLsizei>& dimensions, Components components, ComponentType type, GLvoid* data): AbstractImage(components, type), _dimensions(dimensions), _data(reinterpret_cast<char*>(data)) {}
inline ImageWrapper(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, ComponentType type, GLvoid* data): AbstractImage(components, type), _size(size), _data(reinterpret_cast<char*>(data)) {}
/**
* @brief Constructor
* @param dimensions %Image dimensions
* @param size %Image size
* @param components Color components
* @param type Data type
*
* Dimensions and data pointer are set to zero, call setData() to fill
* the image with data.
*/
inline ImageWrapper(const Math::Vector<Dimensions, GLsizei>& dimensions, Components components, ComponentType type): AbstractImage(components, type), _dimensions(dimensions), _data(nullptr) {}
inline ImageWrapper(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, ComponentType type): AbstractImage(components, type), _size(size), _data(nullptr) {}
/** @brief %Image dimensions */
inline constexpr const Math::Vector<Dimensions, GLsizei>& dimensions() const { return _dimensions; }
/** @brief %Image size */
inline typename DimensionTraits<Dimensions, GLsizei>::VectorType size() const { return _size; }
/** @brief Pointer to raw data */
inline void* data() { return _data; }
inline constexpr const void* data() const { return _data; } /**< @overload */
inline const void* data() const { return _data; } /**< @overload */
/**
* @brief Set image data
@ -92,13 +94,13 @@ template<size_t imageDimensions> class ImageWrapper: public AbstractImage {
* passed in constructor. The data are not copied nor deleted on
* destruction.
*/
void setData(GLvoid* data) {
inline void setData(GLvoid* data) {
_data = reinterpret_cast<char*>(data);
}
protected:
Math::Vector<Dimensions, GLsizei> _dimensions; /**< @brief %Image dimensions */
char* _data; /**< @brief %Image data */
Math::Vector<Dimensions, GLsizei> _size; /**< @brief %Image size */
char* _data; /**< @brief %Image data */
};
/** @brief One-dimensional image wrapper */

63
src/Implementation/BufferState.cpp

@ -0,0 +1,63 @@
/*
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 "BufferState.h"
#include <Utility/Debug.h>
namespace Magnum { namespace Implementation {
const Buffer::Target BufferState::targetForIndex[] = {
Buffer::Target::Array,
Buffer::Target::CopyRead,
Buffer::Target::CopyWrite,
Buffer::Target::ElementArray,
Buffer::Target::PixelPack,
Buffer::Target::PixelUnpack,
Buffer::Target::TransformFeedback,
Buffer::Target::Uniform,
#ifndef MAGNUM_TARGET_GLES
Buffer::Target::AtomicCounter,
Buffer::Target::DispatchIndirect,
Buffer::Target::DrawIndirect,
Buffer::Target::ShaderStorage,
Buffer::Target::Texture
#endif
};
std::size_t BufferState::indexForTarget(Buffer::Target target) {
switch(target) {
case Buffer::Target::Array: return 1;
case Buffer::Target::CopyRead: return 2;
case Buffer::Target::CopyWrite: return 3;
case Buffer::Target::ElementArray: return 4;
case Buffer::Target::PixelPack: return 5;
case Buffer::Target::PixelUnpack: return 6;
case Buffer::Target::TransformFeedback: return 7;
case Buffer::Target::Uniform: return 8;
#ifndef MAGNUM_TARGET_GLES
case Buffer::Target::AtomicCounter: return 9;
case Buffer::Target::DispatchIndirect: return 10;
case Buffer::Target::DrawIndirect: return 11;
case Buffer::Target::ShaderStorage: return 12;
case Buffer::Target::Texture: return 13;
#endif
}
CORRADE_ASSERT(false, "Unknown Buffer target", 0);
return 0;
}
}}

43
src/Implementation/BufferState.h

@ -0,0 +1,43 @@
#ifndef Magnum_Implementation_BufferState_h
#define Magnum_Implementation_BufferState_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "Magnum.h"
#include "Buffer.h"
namespace Magnum { namespace Implementation {
struct BufferState {
#ifndef MAGNUM_TARGET_GLES
static const std::size_t TargetCount = 13+1;
#else
static const std::size_t TargetCount = 8+1;
#endif
/* Target <-> index mapping */
static std::size_t indexForTarget(Buffer::Target target);
static const Buffer::Target targetForIndex[TargetCount-1];
inline constexpr BufferState(): bindings() {}
/* Currently bound buffer for all targets */
GLuint bindings[TargetCount];
};
}}
#endif

30
src/Implementation/MeshState.h

@ -0,0 +1,30 @@
#ifndef Magnum_Implementation_MeshState_h
#define Magnum_Implementation_MeshState_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "Magnum.h"
namespace Magnum { namespace Implementation {
struct MeshState {
inline MeshState(): currentVAO(0) {}
GLuint currentVAO;
};
}}
#endif

31
src/Implementation/ShaderProgramState.h

@ -0,0 +1,31 @@
#ifndef Magnum_Implementation_ShaderProgramState_h
#define Magnum_Implementation_ShaderProgramState_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "Magnum.h"
namespace Magnum { namespace Implementation {
struct ShaderProgramState {
inline constexpr ShaderProgramState(): current(0) {}
/* Currently used program */
GLuint current;
};
}}
#endif

34
src/Implementation/State.cpp

@ -0,0 +1,34 @@
/*
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 "State.h"
#include "BufferState.h"
#include "MeshState.h"
#include "ShaderProgramState.h"
#include "TextureState.h"
namespace Magnum { namespace Implementation {
State::State(): buffer(new BufferState), mesh(new MeshState), shaderProgram(new ShaderProgramState), texture(new TextureState) {}
State::~State() {
delete texture;
delete shaderProgram;
delete mesh;
delete buffer;
}
}}

39
src/Implementation/State.h

@ -0,0 +1,39 @@
#ifndef Magnum_Implementation_State_h
#define Magnum_Implementation_State_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "Magnum.h"
namespace Magnum { namespace Implementation {
struct BufferState;
struct MeshState;
struct ShaderProgramState;
struct TextureState;
struct State {
State();
~State();
BufferState* const buffer;
MeshState* const mesh;
ShaderProgramState* const shaderProgram;
TextureState* const texture;
};
}}
#endif

34
src/Implementation/TextureState.h

@ -0,0 +1,34 @@
#ifndef Magnum_Implementation_TextureState_h
#define Magnum_Implementation_TextureState_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "Magnum.h"
namespace Magnum { namespace Implementation {
struct TextureState {
inline TextureState(): maxSupportedLayerCount(0), maxSupportedAnisotropy(0.0f), currentLayer(0) {}
GLint maxSupportedLayerCount;
GLfloat maxSupportedAnisotropy;
GLint currentLayer;
std::vector<GLuint> bindings;
};
}}
#endif

60
src/IndexedMesh.cpp

@ -15,21 +15,25 @@
#include "IndexedMesh.h"
#include <Utility/Debug.h>
#include "Buffer.h"
#include "Context.h"
#include "Extensions.h"
namespace Magnum {
void IndexedMesh::draw() {
/* Vertex array must be bound before finalization */
#ifndef MAGNUM_TARGET_GLES
bind();
#endif
IndexedMesh::BindIndexBufferImplementation IndexedMesh::bindIndexBufferImplementation = &IndexedMesh::bindIndexBufferImplementationDefault;
IndexedMesh::BindIndexedImplementation IndexedMesh::bindIndexedImplementation = &IndexedMesh::bindIndexedImplementationDefault;
finalize();
IndexedMesh* IndexedMesh::setIndexBuffer(Buffer* buffer) {
_indexBuffer = buffer;
(this->*bindIndexBufferImplementation)();
return this;
}
/* Buffers must be bound after initialization */
#ifdef MAGNUM_TARGET_GLES
void IndexedMesh::draw() {
bind();
_indexBuffer.bind();
#endif
/** @todo Start at given index */
glDrawElements(static_cast<GLenum>(primitive()), _indexCount, static_cast<GLenum>(_indexType), nullptr);
@ -37,20 +41,38 @@ void IndexedMesh::draw() {
unbind();
}
#ifndef DOXYGEN_GENERATING_OUTPUT
void IndexedMesh::finalize() {
if(isFinalized()) return;
void IndexedMesh::bind() {
CORRADE_ASSERT(_indexCount, "IndexedMesh: the mesh has zero index count!", );
/* Finalize attribute positions */
Mesh::finalize();
Mesh::bind();
(this->*bindIndexedImplementation)();
}
/* Bind index buffer to VAO too */
void IndexedMesh::initializeContextBasedFunctionality(Context* context) {
/** @todo VAOs are in ES 3.0 and as extension in ES 2.0, enable them when some extension wrangler is available */
#ifndef MAGNUM_TARGET_GLES
_indexBuffer.bind();
if(context->isExtensionSupported<Extensions::GL::APPLE::vertex_array_object>()) {
Debug() << "IndexedMesh: using" << Extensions::GL::APPLE::vertex_array_object::string() << "features";
bindIndexBufferImplementation = &IndexedMesh::bindIndexBufferImplementationVAO;
bindIndexedImplementation = &IndexedMesh::bindIndexedImplementationVAO;
}
#else
static_cast<void>(context);
#endif
}
#endif
void IndexedMesh::bindIndexBufferImplementationDefault() {}
void IndexedMesh::bindIndexBufferImplementationVAO() {
bindVAO(vao);
_indexBuffer->bind(Buffer::Target::ElementArray);
}
void IndexedMesh::bindIndexedImplementationDefault() {
_indexBuffer->bind(Buffer::Target::ElementArray);
}
void IndexedMesh::bindIndexedImplementationVAO() {}
}

113
src/IndexedMesh.h

@ -20,64 +20,117 @@
*/
#include "Mesh.h"
#include "Buffer.h"
namespace Magnum {
/**
* @brief Indexed mesh
*/
@brief Indexed mesh
@section IndexedMesh-configuration Indexed mesh configuration
Next to @ref Mesh-configuration "everything needed for non-indexed mesh" you
have to call also setIndexCount() and setIndexType(). Then create index buffer
and assign it to the mesh using setIndexBuffer() or use
MeshTools::compressIndices() to conveniently fill the index buffer and set
index count and type.
Similarly as in Mesh itself the index buffer is not managed by the mesh, so
you have to manage it on your own. On the other hand it allows you to use
one index buffer for more meshes (with different vertex data in each mesh, for
example) or store more than only index data in one buffer.
@section IndexedMesh-drawing Rendering meshes
From user point-of-view the operation is the same as for
@ref Mesh-drawing "non-indexed meshes".
@section IndexedMesh-performance-optimization Performance optimizations
If @extension{APPLE,vertex_array_object} is supported, next to
@ref Mesh-performance-optimization "optimizations in Mesh itself" the index
buffer is bound on object construction instead of in every draw() call.
*/
class MAGNUM_EXPORT IndexedMesh: public Mesh {
friend class Context;
public:
/**
* @brief Implicit constructor
* @brief Constructor
* @param primitive Primitive type
*
* Allows creating the object without knowing anything about mesh data.
* Note that you have to call setVertexCount(), setIndexCount() and
* setIndexType() manually for mesh to draw properly.
* Creates indexed mesh with no index buffer, zero vertex count and
* zero index count.
* @see setPrimitive(), setVertexCount(), setIndexBuffer(),
* setIndexCount(), setIndexType()
*/
inline IndexedMesh(Primitive primitive = Primitive::Triangles): Mesh(primitive), _indexBuffer(Buffer::Target::ElementArray), _indexCount(0), _indexType(Type::UnsignedShort) {}
inline IndexedMesh(Primitive primitive = Primitive::Triangles): Mesh(primitive), _indexBuffer(nullptr), _indexCount(0), _indexType(Type::UnsignedShort) {}
/**
* @brief Constructor
* @param primitive Primitive type
* @param vertexCount Count of unique vertices
* @param indexCount Count of indices
* @param indexType Type of indices (indexable, see TypeTraits)
* @brief Set index buffer
*
* @see MeshTools::compressIndices(), @fn_gl{BindVertexArray},
* @fn_gl{BindBuffer} (if @extension{APPLE,vertex_array_object}
* is available)
*/
inline IndexedMesh(Primitive primitive, GLsizei vertexCount, GLsizei indexCount, Type indexType = Type::UnsignedShort): Mesh(primitive, vertexCount), _indexBuffer(Buffer::Target::ElementArray), _indexCount(indexCount), _indexType(indexType) {}
IndexedMesh* setIndexBuffer(Buffer* buffer);
/** @brief Index count */
inline GLsizei indexCount() const { return _indexCount; }
/** @brief Set index count */
/** @todo definalize after that? */
inline void setIndexCount(GLsizei count) { _indexCount = count; }
/**
* @brief Set index count
* @return Pointer to self (for method chaining)
*
* @see MeshTools::compressIndices()
*/
inline IndexedMesh* setIndexCount(GLsizei count) {
_indexCount = count;
return this;
}
/** @brief Index type */
inline Type indexType() const { return _indexType; }
/** @brief Set index type */
inline void setIndexType(Type type) { _indexType = type; }
/**
* @brief Index buffer
* @brief Set index type
* @return Pointer to self (for method chaining)
*
* Returns pointer to index buffer, which should be then filled with
* indices (of type specified in constructor).
* @see MeshTools::compressIndices()
*/
inline Buffer* indexBuffer() { return &_indexBuffer; }
inline IndexedMesh* setIndexType(Type type) {
_indexType = type;
return this;
}
/**
* @brief Draw the mesh
*
* Expects an active shader with all uniforms set. See
* @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation"
* for more information.
* @see @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer},
* @fn_gl{VertexAttribPointer}, @fn_gl{DisableVertexAttribArray}
* or @fn_gl{BindVertexArray} (if @extension{APPLE,vertex_array_object}
* is available), @fn_gl{DrawElements}
*/
void draw();
protected:
#ifndef DOXYGEN_GENERATING_OUTPUT
MAGNUM_LOCAL void finalize();
#endif
private:
Buffer _indexBuffer;
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
void MAGNUM_LOCAL bind();
typedef void(IndexedMesh::*BindIndexBufferImplementation)();
void MAGNUM_LOCAL bindIndexBufferImplementationDefault();
void MAGNUM_LOCAL bindIndexBufferImplementationVAO();
static MAGNUM_LOCAL BindIndexBufferImplementation bindIndexBufferImplementation;
typedef void(IndexedMesh::*BindIndexedImplementation)();
void MAGNUM_LOCAL bindIndexedImplementationDefault();
void MAGNUM_LOCAL bindIndexedImplementationVAO();
static MAGNUM_LOCAL BindIndexedImplementation bindIndexedImplementation;
Buffer* _indexBuffer;
GLsizei _indexCount;
Type _indexType;
};

40
src/Magnum.h

@ -23,15 +23,41 @@
#ifndef MAGNUM_TARGET_GLES
#include <GL/glew.h>
#include <GL/glcorearb.h>
#else
#include <GLES2/gl2.h>
#include <GLES3/gl3.h>
#endif
#include "Math/Math.h"
#include "Math/Matrix4.h"
#include "Math/Vector2.h"
/**
* @todo Link to libGL / libGLES based on which windowcontext is used in app
* and whether GLES is enabled or not -- this allows us to use glx with
* ES on nvidia/intel. Using libGL and EGL on nvidia is whole another
* problem, though. How about windows? It won't allow unlinked DLLs, so
* probably always link Magnum itself to GL library there. How about unit
* tests not needing any of GL? -- different testing library?
*/
namespace Corrade {
namespace Utility {
class Debug;
class Warning;
class Error;
}
}
namespace Magnum {
namespace Math {
template<class> class Vector2;
template<class> class Vector3;
template<class> class Vector4;
template<class> class Point2D;
template<class> class Point3D;
template<class> class Matrix3;
template<class> class Matrix4;
template<class T> constexpr T deg(T value);
template<class T> constexpr T rad(T value);
}
/* Bring debugging facility from Corrade::Utility namespace */
using Corrade::Utility::Debug;
@ -47,6 +73,12 @@ typedef Math::Vector3<GLfloat> Vector3;
/** @brief Four-component floating-point vector */
typedef Math::Vector4<GLfloat> Vector4;
/** @brief Two-dimensional floating-point homogeneous coordinates */
typedef Math::Point2D<GLfloat> Point2D;
/** @brief Three-dimensional floating-point homogeneous coordinates */
typedef Math::Point3D<GLfloat> Point3D;
/** @brief 3x3 floating-point matrix */
typedef Math::Matrix3<GLfloat> Matrix3;

20
src/Math/Algorithms/GaussJordan.h

@ -16,7 +16,7 @@
*/
/** @file
* @brief Class GaussJordan
* @brief Class Magnum::Math::Algorithms::GaussJordan
*/
#include "Math/RectangularMatrix.h"
@ -48,7 +48,7 @@ class GaussJordan {
* and the final backsubstitution is done only on @p t, as @p a would
* always end with identity matrix anyway.
*/
template<size_t size, size_t rows, class T> static bool inPlaceTransposed(RectangularMatrix<size, size, T>& a, RectangularMatrix<size, rows, T>& t);
template<std::size_t size, std::size_t rows, class T> static bool inPlaceTransposed(RectangularMatrix<size, size, T>& a, RectangularMatrix<size, rows, T>& t);
/**
* @brief Eliminate in place
@ -56,7 +56,7 @@ class GaussJordan {
* Transposes the matrices, calls inPlaceTransposed() on them and then
* transposes them back.
*/
template<size_t size, size_t cols, class T> static bool inPlace(RectangularMatrix<size, size, T>& a, RectangularMatrix<cols, size, T>& t) {
template<std::size_t size, std::size_t cols, class T> static bool inPlace(RectangularMatrix<size, size, T>& a, RectangularMatrix<cols, size, T>& t) {
a = a.transposed();
RectangularMatrix<size, cols, T> tTransposed = t.transposed();
@ -69,11 +69,11 @@ class GaussJordan {
}
};
template<size_t size, size_t cols, class T> bool GaussJordan::inPlaceTransposed(RectangularMatrix<size, size, T>& a, RectangularMatrix<size, cols, T>& t) {
for(size_t row = 0; row != size; ++row) {
template<std::size_t size, std::size_t cols, class T> bool GaussJordan::inPlaceTransposed(RectangularMatrix<size, size, T>& a, RectangularMatrix<size, cols, T>& t) {
for(std::size_t row = 0; row != size; ++row) {
/* Find max pivot */
size_t rowMax = row;
for(size_t row2 = row+1; row2 != size; ++row2)
std::size_t rowMax = row;
for(std::size_t row2 = row+1; row2 != size; ++row2)
if(std::abs(a(row2, row)) > std::abs(a(rowMax, row)))
rowMax = row2;
@ -86,7 +86,7 @@ template<size_t size, size_t cols, class T> bool GaussJordan::inPlaceTransposed(
return false;
/* Eliminate column */
for(size_t row2 = row+1; row2 != size; ++row2) {
for(std::size_t row2 = row+1; row2 != size; ++row2) {
T c = a(row2, row)/a(row, row);
a[row2] -= a[row]*c;
@ -95,10 +95,10 @@ template<size_t size, size_t cols, class T> bool GaussJordan::inPlaceTransposed(
}
/* Backsubstitute */
for(size_t row = size; row != 0; --row) {
for(std::size_t row = size; row != 0; --row) {
T c = T(1)/a(row-1, row-1);
for(size_t row2 = 0; row2 != row-1; ++row2)
for(std::size_t row2 = 0; row2 != row-1; ++row2)
t[row2] -= t[row-1]*a(row2, row-1)*c;
/* Normalize the row */

3
src/Math/CMakeLists.txt

@ -1,11 +1,14 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
set(MagnumMath_HEADERS
Constants.h
Math.h
MathTypeTraits.h
Matrix.h
Matrix3.h
Matrix4.h
Point2D.h
Point3D.h
RectangularMatrix.h
Vector.h
Vector2.h

79
src/Math/Constants.h

@ -0,0 +1,79 @@
#ifndef Magnum_Math_Constants_h
#define Magnum_Math_Constants_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::Math::Constants, functions Magnum::Math::deg(), Magnum::Math::rad()
*/
namespace Magnum { namespace Math {
/**
@brief Numeric constants
@internal See MathTypeTraits class for implementation notes.
*/
template<class T> struct Constants {
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Pi
*
* @see deg(), rad()
*/
static inline constexpr T pi();
static inline constexpr T sqrt2(); /**< @brief Square root of 2 */
static inline constexpr T sqrt3(); /**< @brief Square root of 3 */
#endif
};
#ifndef DOXYGEN_GENERATING_OUTPUT
template<> struct Constants<double> {
static inline constexpr double pi() { return 3.141592653589793; }
static inline constexpr double sqrt2() { return 1.414213562373095; }
static inline constexpr double sqrt3() { return 1.732050807568877; }
};
template<> struct Constants<float> {
static inline constexpr float pi() { return 3.141592654f; }
static inline constexpr float sqrt2() { return 1.414213562f; }
static inline constexpr float sqrt3() { return 1.732050808f; }
};
#endif
/**
@brief Angle in degrees
Function to make angle entering less error-prone. Converts the value to
radians at compile time. For example `deg(180.0f)` is converted to `3.14f`.
Usable for entering e.g. rotation:
@code
Matrix4::rotation(deg(30.0f), Vector3::yAxis());
@endcode
@see Constants, rad()
*/
template<class T> inline constexpr T deg(T value) { return value*Constants<T>::pi()/180; }
/**
* @brief Angle in radians
*
* See deg() for more information.
*/
template<class T> inline constexpr T rad(T value) { return value; }
}}
#endif

126
src/Math/Geometry/Distance.h

@ -19,6 +19,8 @@
* @brief Class Magnum::Math::Geometry::Distance
*/
#include "Math/Math.h"
#include "Math/Matrix.h"
#include "Math/Vector3.h"
namespace Magnum { namespace Math { namespace Geometry {
@ -27,36 +29,68 @@ namespace Magnum { namespace Math { namespace Geometry {
class Distance {
public:
/**
* @brief %Distance of line and point
* @brief %Distance of line and point in 2D
* @param a First point of the line
* @param b Second point of the line
* @param point Point
*
* The distance *d* is computed from point **p** and line defined by **a**
* and **b** using @ref Vector3::cross() "cross product":
* @f[
* and **b** using @ref Matrix::determinant() "determinant": @f[
* d = \frac{|det(b - a a - point)|} {|b - a|}
* @f]
* Source: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
* @see linePointSquared(const Vector2&, const Vector2&, const Vector2&)
*/
template<class T> inline static T linePoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
return std::abs(Matrix<2, T>::from(b - a, a - point).determinant())/(b - a).length();
}
/**
* @brief %Distance of line and point in 2D, squared
* @param a First point of the line
* @param b Second point of the line
* @param point Point
*
* More efficient than linePoint(const Vector2&, const Vector2&, const Vector2&)
* for comparing distance with other values, because it doesn't
* compute the square root.
*/
template<class T> inline static T linePointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
Vector2<T> bMinusA = b - a;
return Math::pow<2>(Matrix<2, T>::from(bMinusA, a - point).determinant())/bMinusA.dot();
}
/**
* @brief %Distance of line and point in 3D
* @param a First point of the line
* @param b Second point of the line
* @param point Point
*
* The distance *d* is computed from point **p** and line defined by **a**
* and **b** using @ref Vector3::cross() "cross product": @f[
* d = \frac{|(\boldsymbol p - \boldsymbol a) \times (\boldsymbol p - \boldsymbol b)|}
* {|\boldsymbol b - \boldsymbol a|}
* @f]
*
* @see linePointSquared()
* Source: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
* @see linePointSquared(const Vector3&, const Vector3&, const Vector3&)
*/
template<class T> inline static T linePoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return sqrt(linePointSquared(a, b, point));
return std::sqrt(linePointSquared(a, b, point));
}
/**
* @brief %Distance of line and point, squared
* @brief %Distance of line and point in 3D, squared
*
* More efficient than linePoint() for comparing distance with other
* values, because it doesn't compute the square root.
* More efficient than linePoint(const Vector3&, const Vector3&, const Vector3&)
* for comparing distance with other values, because it doesn't
* compute the square root.
*/
template<class T> static T linePointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return Vector3<T>::cross(point - a, point - b).dot()/(b - a).dot();
}
/**
* @brief %Dístance of point from line segment
* @brief %Dístance of point from line segment in 2D
* @param a Starting point of the line
* @param b Ending point of the line
* @param point Point
@ -66,34 +100,88 @@ class Distance {
*
* Determining whether the point lies next to line segment or outside
* is done using Pythagorean theorem. If the following equation
* applies, the point **p** lies outside line segment closer to **a**:
* @f[
* applies, the point **p** lies outside line segment closer to **a**: @f[
* |\boldsymbol p - \boldsymbol b|^2 > |\boldsymbol b - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol a|^2
* @f]
* On the other hand, if the following equation applies, the point
* lies outside line segment closer to **b**:
* @f[
* lies outside line segment closer to **b**: @f[
* |\boldsymbol p - \boldsymbol a|^2 > |\boldsymbol b - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol b|^2
* @f]
* The last alternative is when the following equation applies. The
* point then lies between **a** and **b** and the distance is
* computed the same way as in linePoint().
* @f[
* computed the same way as in linePoint(). @f[
* |\boldsymbol b - \boldsymbol a|^2 > |\boldsymbol p - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol b|^2
* @f]
*
* @see lineSegmentPointSquared()
*/
template<class T> inline static T lineSegmentPoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return sqrt(lineSegmentPointSquared(a, b, point));
template<class T> inline static T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
Vector2<T> pointMinusA = point - a;
Vector2<T> pointMinusB = point - b;
Vector2<T> bMinusA = b - a;
T pointDistanceA = pointMinusA.dot();
T pointDistanceB = pointMinusB.dot();
T bDistanceA = bMinusA.dot();
/* Point is before A */
if(pointDistanceB > bDistanceA + pointDistanceA)
return std::sqrt(pointDistanceA);
/* Point is after B */
if(pointDistanceA > bDistanceA + pointDistanceB)
return std::sqrt(pointDistanceB);
/* Between A and B */
return std::abs(Matrix<2, T>::from(bMinusA, -pointMinusA).determinant())/std::sqrt(bDistanceA);
}
/**
* @brief %Distance of point from line segment, squared
* @brief %Distance of point from line segment in 2D, squared
*
* More efficient than lineSegmentPoint() for comparing distance with
* other values, because it doesn't compute the square root.
*/
template<class T> static T lineSegmentPointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
Vector2<T> pointMinusA = point - a;
Vector2<T> pointMinusB = point - b;
Vector2<T> bMinusA = b - a;
T pointDistanceA = pointMinusA.dot();
T pointDistanceB = pointMinusB.dot();
T bDistanceA = bMinusA.dot();
/* Point is before A */
if(pointDistanceB > bDistanceA + pointDistanceA)
return pointDistanceA;
/* Point is after B */
if(pointDistanceA > bDistanceA + pointDistanceB)
return pointDistanceB;
/* Between A and B */
return Math::pow<2>(Matrix<2, T>::from(bMinusA, -pointMinusA).determinant())/bDistanceA;
}
/**
* @brief %Dístance of point from line segment in 3D
* @param a Starting point of the line
* @param b Ending point of the line
* @param point Point
*
* Similar to 2D implementation
* lineSegmentPoint(const Vector2&, const Vector2&, const Vector2&).
*
* @see lineSegmentPointSquared(const Vector3&, const Vector3&, const Vector3&)
*/
template<class T> inline static T lineSegmentPoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return std::sqrt(lineSegmentPointSquared(a, b, point));
}
/**
* @brief %Distance of point from line segment in 3D, squared
*
* More efficient than lineSegmentPoint(const Vector3&, const Vector3&, const Vector3&) for comparing distance with
* other values, because it doesn't compute the square root.
*/
template<class T> static T lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
Vector3<T> pointMinusA = point - a;
Vector3<T> pointMinusB = point - b;

6
src/Math/Geometry/Intersection.h

@ -39,14 +39,12 @@ class Intersection {
* is inside the line segment defined by `a` and `b`.
*
* First the parameter *f* of parametric equation of the plane
* is computed from plane normal **n** and plane position:
* @f[
* is computed from plane normal **n** and plane position: @f[
* \begin{pmatrix} n_0 \\ n_1 \\ n_2 \end{pmatrix} \cdot
* \begin{pmatrix} x \\ y \\ z \end{pmatrix} - f = 0
* @f]
* Using plane normal **n**, parameter *f* and points **a** and **b**,
* value of *t* is computed and returned.
* @f[
* value of *t* is computed and returned. @f[
* \begin{array}{rcl}
* \Delta \boldsymbol b & = & \boldsymbol b - \boldsymbol a \\
* f & = & \boldsymbol n \cdot (\boldsymbol a + \Delta \boldsymbol b \cdot t) \\

62
src/Math/Geometry/Test/DistanceTest.cpp

@ -17,7 +17,7 @@
#include <limits>
#include "Math.h"
#include "Constants.h"
#include "Distance.h"
CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::DistanceTest)
@ -26,14 +26,35 @@ using namespace std;
namespace Magnum { namespace Math { namespace Geometry { namespace Test {
typedef Magnum::Math::Vector2<float> Vector2;
typedef Magnum::Math::Vector3<float> Vector3;
DistanceTest::DistanceTest() {
addTests(&DistanceTest::linePoint,
&DistanceTest::lineSegmentPoint);
addTests(&DistanceTest::linePoint2D,
&DistanceTest::linePoint3D,
&DistanceTest::lineSegmentPoint2D,
&DistanceTest::lineSegmentPoint3D);
}
void DistanceTest::linePoint() {
void DistanceTest::linePoint2D() {
Vector2 a(0.0f);
Vector2 b(1.0f);
/* Point on the line */
CORRADE_COMPARE((Distance::linePoint(a, b, Vector2(0.25f))), 0.0f);
/* The distance should be the same for all equidistant points */
CORRADE_COMPARE((Distance::linePoint(a, b, Vector2(1.0f, 0.0f))),
1.0f/Constants<float>::sqrt2());
CORRADE_COMPARE((Distance::linePoint(a, b, Vector2(1.0f, 0.0f)+Vector2(100.0f))),
1.0f/Constants<float>::sqrt2());
/* Be sure that *Squared() works the same, as it has slightly different implementation */
CORRADE_COMPARE((Distance::linePointSquared(a, b, Vector2(1.0f, 0.0f))),
0.5f);
}
void DistanceTest::linePoint3D() {
Vector3 a(0.0f);
Vector3 b(1.0f);
@ -47,7 +68,38 @@ void DistanceTest::linePoint() {
Constants<float>::sqrt2()/Constants<float>::sqrt3());
}
void DistanceTest::lineSegmentPoint() {
void DistanceTest::lineSegmentPoint2D() {
Vector2 a(0.0f);
Vector2 b(1.0f);
/* Point on the line segment */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(0.25f))), 0.0f);
/* Point on the line, outside the segment, closer to A */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(-1.0f))), Constants<float>::sqrt2());
/* Be sure that *Squared() works the same, as it has slightly different implementation */
CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(-1.0f))), 2.0f);
/* Point on the line, outside the segment, closer to B */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f+1.0f/Constants<float>::sqrt2()))), 1.0f);
CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f+1.0f/Constants<float>::sqrt2()))), 1.0f);
/* Point next to the line segment */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f))),
1.0f/Constants<float>::sqrt2());
CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f))),
0.5f);
/* Point outside the line segment, closer to A */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f)-Vector2(1.0f, 0.5f))), 0.5f);
CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f)-Vector2(1.0f, 0.5f))), 0.25f);
/* Point outside the line segment, closer to B */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f)+Vector2(0.5f, 1.0f))), 0.5f);
CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f)+Vector2(0.5f, 1.0f))), 0.25f);
}
void DistanceTest::lineSegmentPoint3D() {
Vector3 a(0.0f);
Vector3 b(1.0f);

6
src/Math/Geometry/Test/DistanceTest.h

@ -23,8 +23,10 @@ class DistanceTest: public Corrade::TestSuite::Tester<DistanceTest> {
public:
DistanceTest();
void linePoint();
void lineSegmentPoint();
void linePoint2D();
void linePoint3D();
void lineSegmentPoint2D();
void lineSegmentPoint3D();
};
}}}}

6
src/Math/Math.cpp

@ -15,10 +15,12 @@
#include "Math.h"
using namespace std;
namespace Magnum { namespace Math {
size_t log(size_t base, size_t number) {
size_t log = 0;
std::uint32_t log(std::uint32_t base, std::uint32_t number) {
uint32_t log = 0;
while(number /= base)
++log;
return log;

63
src/Math/Math.h

@ -15,7 +15,6 @@
GNU Lesser General Public License version 3 for more details.
*/
#include <cstddef>
#include <cmath>
#include <type_traits>
#include <limits>
@ -25,7 +24,7 @@
#include "magnumVisibility.h"
/** @file
* @brief Math constants and utilities
* @brief Math utilities
*/
namespace Magnum { namespace Math {
@ -37,33 +36,9 @@ namespace Magnum { namespace Math {
matrices)
*/
/**
@brief Numeric constants
@internal See MathTypeTraits class for implementation notes.
*/
template<class T> struct Constants {
#ifdef DOXYGEN_GENERATING_OUTPUT
static inline constexpr T pi(); /**< @brief Pi */
static inline constexpr T sqrt2(); /**< @brief Square root of 2 */
static inline constexpr T sqrt3(); /**< @brief Square root of 3 */
#endif
};
#ifndef DOXYGEN_GENERATING_OUTPUT
template<> struct Constants<double> {
static inline constexpr double pi() { return 3.141592653589793; }
static inline constexpr double sqrt2() { return 1.414213562373095; }
static inline constexpr double sqrt3() { return 1.732050807568877; }
};
template<> struct Constants<float> {
static inline constexpr float pi() { return 3.141592654f; }
static inline constexpr float sqrt2() { return 1.414213562f; }
static inline constexpr float sqrt3() { return 1.732050808f; }
};
namespace Implementation {
template<size_t exponent> struct Pow {
template<std::uint32_t exponent> struct Pow {
template<class T> inline constexpr T operator()(T base) const {
return base*Pow<exponent-1>()(base);
}
@ -79,7 +54,7 @@ namespace Implementation {
*
* Returns integral power of base to the exponent.
*/
template<size_t exponent, class T> inline constexpr T pow(T base) {
template<std::uint32_t exponent, class T> inline constexpr T pow(T base) {
return Implementation::Pow<exponent>()(base);
}
@ -88,7 +63,7 @@ template<size_t exponent, class T> inline constexpr T pow(T base) {
*
* Returns integral logarithm of given number with given base.
*/
size_t MAGNUM_EXPORT log(size_t base, size_t number);
std::uint32_t MAGNUM_EXPORT log(std::uint32_t base, std::uint32_t number);
/**
@brief Normalize floating-point value
@ -100,11 +75,11 @@ type to value in range @f$ [0, 1] @f$.
literals, this function should be called with both template parameters
explicit, e.g.:
@code
// Even if this is char literal, integral type is `int`, thus a = 0.1f
// Even if this is character literal, integral type is 32bit, thus a != 1.0f
float a = normalize<float>('\127');
// b = 1.0f
float b = normalize<float, char>('\127');
float b = normalize<float, int8_t>('\127');
@endcode
@todo Signed normalization to [-1.0, 1.0] like in OpenGL?
@ -121,9 +96,12 @@ Converts floating-point value in range @f$ [0, 1] @f$ to full range of given
integral type.
@note For best precision, `FloatingPoint` type should be always larger that
resulting `Integral` type (e.g. `double` to `int`, `long double` to `long long`).
resulting `Integral` type (e.g. `double` to `std::int32_t`, `long double` to
`std::int64_t`).
@todo Signed normalization to [-1.0, 1.0] like in OpenGL?
@todo Stable behavior (working/broken) for long double and long long
(currently fails in Debug builds, but passes in Release on GCC 4.7)
*/
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() +
@ -136,27 +114,6 @@ template<class T> inline T clamp(T value, T min, T max) {
return std::min(std::max(value, min), max);
}
/**
@brief Angle in degrees
Function to make angle entering less error-prone. Converts the value to
radians at compile time. For example `deg(180.0f)` is converted to `3.14f`.
Usable for entering e.g. rotation:
@code
Matrix4::rotation(deg(30.0f), Vector3::yAxis());
@endcode
@see rad()
*/
template<class T> inline constexpr T deg(T value) { return value*Constants<T>::pi()/180; }
/**
* @brief Angle in radians
*
* See deg() for more information.
*/
template<class T> inline constexpr T rad(T value) { return value; }
}}
#endif

58
src/Math/MathTypeTraits.h

@ -19,7 +19,7 @@
* @brief Class Magnum::Math::MathTypeTraits
*/
#include <cstddef>
#include <cstdint>
#include <cmath>
#include "magnumCompatibility.h"
@ -55,7 +55,7 @@ support given feature, thus forcing the compilation stop with an error.
template<class T> struct MathTypeTraits {
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Corresponding numeric type large at least as `int`
* @brief Corresponding numeric type large at least as 32bit integer
*
* Usable e.g. to prevent conversion of `char` to characters when printing
* numeric types to output.
@ -114,67 +114,63 @@ template<class T> struct MathTypeTraitsFloatingPoint {
}
};
template<size_t> struct MathTypeTraitsLong {};
template<std::size_t> struct MathTypeTraitsLong {};
template<> struct MathTypeTraitsLong<sizeof(int)> {
typedef unsigned int UnsignedType;
typedef int Type;
template<> struct MathTypeTraitsLong<4> {
typedef std::uint32_t UnsignedType;
typedef std::int32_t Type;
};
template<> struct MathTypeTraitsLong<sizeof(long long)> {
typedef unsigned long long UnsignedType;
typedef long long Type;
template<> struct MathTypeTraitsLong<8> {
typedef std::uint64_t UnsignedType;
typedef std::int64_t Type;
};
}
template<> struct MathTypeTraits<unsigned char>: public Implementation::MathTypeTraitsIntegral<unsigned char> {
typedef unsigned int NumericType;
template<> struct MathTypeTraits<std::uint8_t>: Implementation::MathTypeTraitsIntegral<std::uint8_t> {
typedef std::uint32_t NumericType;
typedef float FloatingPointType;
};
template<> struct MathTypeTraits<char>: public Implementation::MathTypeTraitsIntegral<char> {
typedef int NumericType;
template<> struct MathTypeTraits<std::int8_t>: Implementation::MathTypeTraitsIntegral<std::int8_t> {
typedef std::int32_t NumericType;
typedef float FloatingPointType;
};
template<> struct MathTypeTraits<unsigned short>: public Implementation::MathTypeTraitsIntegral<unsigned short> {
typedef unsigned int NumericType;
template<> struct MathTypeTraits<std::uint16_t>: Implementation::MathTypeTraitsIntegral<std::uint16_t> {
typedef std::uint32_t NumericType;
typedef float FloatingPointType;
};
template<> struct MathTypeTraits<short>: public Implementation::MathTypeTraitsIntegral<short> {
typedef int NumericType;
template<> struct MathTypeTraits<std::int16_t>: Implementation::MathTypeTraitsIntegral<std::int16_t> {
typedef std::int32_t NumericType;
typedef float FloatingPointType;
};
template<> struct MathTypeTraits<unsigned int>: public Implementation::MathTypeTraitsIntegral<unsigned int> {
typedef unsigned int NumericType;
template<> struct MathTypeTraits<std::uint32_t>: Implementation::MathTypeTraitsIntegral<std::uint32_t> {
typedef std::uint32_t NumericType;
typedef double FloatingPointType;
};
template<> struct MathTypeTraits<int>: public Implementation::MathTypeTraitsIntegral<int> {
typedef int NumericType;
template<> struct MathTypeTraits<std::int32_t>: Implementation::MathTypeTraitsIntegral<std::int32_t> {
typedef std::int32_t NumericType;
typedef double FloatingPointType;
};
template<> struct MathTypeTraits<unsigned long long>: public Implementation::MathTypeTraitsIntegral<unsigned long long> {
typedef unsigned long long NumericType;
template<> struct MathTypeTraits<std::uint64_t>: Implementation::MathTypeTraitsIntegral<std::uint64_t> {
typedef std::uint64_t NumericType;
typedef long double FloatingPointType;
};
template<> struct MathTypeTraits<long long>: public Implementation::MathTypeTraitsIntegral<long long> {
typedef long long NumericType;
template<> struct MathTypeTraits<std::int64_t>: Implementation::MathTypeTraitsIntegral<std::int64_t> {
typedef std::int64_t NumericType;
typedef long double FloatingPointType;
};
/* long is 32 bits somewhere and 64 bits elsewhere */
template<> struct MathTypeTraits<long unsigned int>: public Implementation::MathTypeTraitsIntegral<typename Implementation::MathTypeTraitsLong<sizeof(long unsigned int)>::Type> {};
template<> struct MathTypeTraits<long int>: public Implementation::MathTypeTraitsIntegral<typename Implementation::MathTypeTraitsLong<sizeof(long int)>::Type> {};
template<> struct MathTypeTraits<float>: public Implementation::MathTypeTraitsFloatingPoint<float> {
template<> struct MathTypeTraits<float>: Implementation::MathTypeTraitsFloatingPoint<float> {
typedef float NumericType;
typedef float FloatingPointType;
inline constexpr static float epsilon() { return FLOAT_EQUALITY_PRECISION; }
};
template<> struct MathTypeTraits<double>: public Implementation::MathTypeTraitsFloatingPoint<double> {
template<> struct MathTypeTraits<double>: Implementation::MathTypeTraitsFloatingPoint<double> {
typedef float NumericType;
typedef double FloatingPointType;

74
src/Math/Matrix.h

@ -25,21 +25,22 @@ namespace Magnum { namespace Math {
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<size_t size, class T> class MatrixDeterminant;
template<std::size_t size, class T> class MatrixDeterminant;
}
#endif
/**
@brief Square matrix
@tparam s %Matrix size
@tparam size %Matrix size
@tparam T Data type
See @ref matrix-vector for brief introduction.
@configurationvalueref{Magnum::Math::Matrix}
@todo @c PERFORMANCE - loop unrolling for Matrix<3, T> and Matrix<4, T>
@todo first col, then row (cache adjacency)
*/
template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
template<std::size_t size, class T> class Matrix: public RectangularMatrix<size, size, T> {
public:
const static size_t size = s; /**< @brief %Matrix size */
const static std::size_t Size = size; /**< @brief %Matrix size */
/** @brief Pass to constructor to create zero-filled matrix */
enum ZeroType { Zero };
@ -61,12 +62,12 @@ template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
* `Matrix m(Matrix::Identity);`. Optional parameter @p value allows
* you to specify value on diagonal.
*/
inline explicit Matrix(IdentityType = Identity, T value = T(1)) {
for(size_t i = 0; i != size; ++i)
inline Matrix(IdentityType = Identity, T value = T(1)) {
for(std::size_t i = 0; i != size; ++i)
(*this)(i, i) = value;
}
/** @copydoc RectangularMatrix::RectangularMatrix(T, U...) */
/** @copydoc RectangularMatrix::RectangularMatrix */
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class ...U> inline constexpr Matrix(T first, U... next): RectangularMatrix<size, size, T>(first, next...) {}
#else
@ -91,18 +92,18 @@ template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
T trace() const {
T out(0);
for(size_t i = 0; i != size; ++i)
for(std::size_t i = 0; i != size; ++i)
out += (*this)(i, i);
return out;
}
/** @brief %Matrix without given column and row */
Matrix<size-1, T> ij(size_t skipCol, size_t skipRow) const {
Matrix<size-1, T> ij(std::size_t skipCol, std::size_t skipRow) const {
Matrix<size-1, T> out(Matrix<size-1, T>::Zero);
for(size_t row = 0; row != size-1; ++row)
for(size_t col = 0; col != size-1; ++col)
for(std::size_t col = 0; col != size-1; ++col)
for(std::size_t row = 0; row != size-1; ++row)
out(col, row) = (*this)(col + (col >= skipCol),
row + (row >= skipRow));
@ -112,15 +113,12 @@ template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
/**
* @brief Determinant
*
* Computed recursively using Laplace's formula:
* @f[
* \det(A) = \sum_{j=1}^n (-1)^{i+j} a_{i,j} \det(A^{i,j})
* @f]
* @f$ A^{i, j} @f$ is matrix without i-th row and j-th column, see
* Computed recursively using Laplace's formula: @f[
* \det(A) = \sum_{j=1}^n (-1)^{i+j} a_{i,j} \det(A^{i,j})
* @f] @f$ A^{i, j} @f$ is matrix without i-th row and j-th column, see
* ij(). The formula is expanded down to 2x2 matrix, where the
* determinant is computed directly:
* @f[
* \det(A) = a_{0, 0} a_{1, 1} - a_{1, 0} a_{0, 1}
* determinant is computed directly: @f[
* \det(A) = a_{0, 0} a_{1, 1} - a_{1, 0} a_{0, 1}
* @f]
*/
inline T determinant() const { return Implementation::MatrixDeterminant<size, T>()(*this); }
@ -128,9 +126,8 @@ template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
/**
* @brief Inverted matrix
*
* Computed using Cramer's rule:
* @f[
* A^{-1} = \frac{1}{\det(A)} Adj(A)
* Computed using Cramer's rule: @f[
* A^{-1} = \frac{1}{\det(A)} Adj(A)
* @f]
*/
Matrix<size, T> inverted() const {
@ -138,8 +135,8 @@ template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
T _determinant = determinant();
for(size_t row = 0; row != size; ++row)
for(size_t col = 0; col != size; ++col)
for(std::size_t col = 0; col != size; ++col)
for(std::size_t row = 0; row != size; ++row)
out(col, row) = (((row+col) & 1) ? -1 : 1)*ij(row, col).determinant()/_determinant;
return out;
@ -150,7 +147,7 @@ template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
inline Matrix<size, T> operator*(const Matrix<size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
template<size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const {
template<std::size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
inline Vector<size, T> operator*(const Vector<size, T>& other) const {
@ -162,17 +159,17 @@ template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
};
#ifndef DOXYGEN_GENERATING_OUTPUT
template<size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Matrix<size, T>>::type operator*(U number, const Matrix<size, T>& matrix) {
template<std::size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Matrix<size, T>>::type operator*(U number, const Matrix<size, T>& matrix) {
return number*RectangularMatrix<size, size, T>(matrix);
}
template<size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Matrix<size, T>>::type operator/(U number, const Matrix<size, T>& matrix) {
template<std::size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Matrix<size, T>>::type operator/(U number, const Matrix<size, T>& matrix) {
return number/RectangularMatrix<size, size, T>(matrix);
}
#endif
/** @debugoperator{Magnum::Math::Matrix} */
template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix<size, T>& value) {
return debug << static_cast<const Magnum::Math::RectangularMatrix<size, size, T>&>(value);
template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix<size, T>& value) {
return debug << static_cast<const RectangularMatrix<size, size, T>&>(value);
}
#ifndef DOXYGEN_GENERATING_OUTPUT
@ -192,10 +189,10 @@ template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utili
return *this; \
} \
\
inline VectorType<T>& operator[](size_t col) { \
inline VectorType<T>& operator[](std::size_t col) { \
return VectorType<T>::from(Matrix<size, T>::data()+col*size); \
} \
inline constexpr const VectorType<T>& operator[](size_t col) const { \
inline constexpr const VectorType<T>& operator[](std::size_t col) const { \
return VectorType<T>::from(Matrix<size, T>::data()+col*size); \
} \
\
@ -206,7 +203,7 @@ template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utili
Matrix<size, T>::operator*=(other); \
return *this; \
} \
template<size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const { \
template<std::size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
inline VectorType<T> operator*(const Vector<size, T>& other) const { \
@ -226,13 +223,12 @@ template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utili
namespace Implementation {
template<size_t size, class T> class MatrixDeterminant {
template<std::size_t size, class T> class MatrixDeterminant {
public:
/** @brief Functor */
T operator()(const Matrix<size, T>& m) {
T out(0);
for(size_t col = 0; col != size; ++col)
for(std::size_t col = 0; col != size; ++col)
out += ((col & 1) ? -1 : 1)*m(col, 0)*m.ij(col, 0).determinant();
return out;
@ -241,7 +237,6 @@ template<size_t size, class T> class MatrixDeterminant {
template<class T> class MatrixDeterminant<2, T> {
public:
/** @brief Functor */
inline constexpr T operator()(const Matrix<2, T>& m) {
return m(0, 0)*m(1, 1) - m(1, 0)*m(0, 1);
}
@ -249,7 +244,6 @@ template<class T> class MatrixDeterminant<2, T> {
template<class T> class MatrixDeterminant<1, T> {
public:
/** @brief Functor */
inline constexpr T operator()(const Matrix<1, T>& m) {
return m(0, 0);
}
@ -262,7 +256,7 @@ 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>>: public ConfigurationValue<Magnum::Math::RectangularMatrix<size, size, T>> {};
template<std::size_t size, class T> struct ConfigurationValue<Magnum::Math::Matrix<size, T>>: public ConfigurationValue<Magnum::Math::RectangularMatrix<size, size, T>> {};
}}
#endif

98
src/Math/Matrix3.h

@ -20,57 +20,64 @@
*/
#include "Matrix.h"
#include "Vector3.h"
#include "Point2D.h"
namespace Magnum { namespace Math {
/**
@brief 3x3 matrix
@brief 3x3 matrix for affine transformations in 2D
@tparam T Data type
Provides functions for transformations in 2D. See also Matrix4 for 3D
transformations.
Provides functions for transformations in 2D. See Matrix4 for 3D
transformations. See also @ref matrix-vector for brief introduction.
@configurationvalueref{Magnum::Math::Matrix3}
*/
template<class T> class Matrix3: public Matrix<3, T> {
public:
/**
* @brief 2D translation matrix
* @param vec Translation vector
* @param vector Translation vector
*
* @see Matrix4::translation(), Vector2::xAxis(), Vector2::yAxis()
* @see translation(), Matrix4::translation(const Vector3&),
* Vector2::xAxis(), Vector2::yAxis()
*/
inline constexpr static Matrix3<T> translation(const Vector2<T>& vec) {
inline constexpr static Matrix3<T> translation(const Vector2<T>& vector) {
return Matrix3<T>( /* Column-major! */
T(1), T(0), T(0),
T(0), T(1), T(0),
vec.x(), vec.y(), T(1)
vector.x(), vector.y(), T(1)
);
}
/**
* @brief 2D scaling matrix
* @param vec Scaling vector
* @param vector Scaling vector
*
* @see Matrix4::scaling(), Vector2::xScale(), Vector2::yScale()
* @see rotationScaling() const, Matrix4::scaling(const Vector3&),
* Vector2::xScale(), Vector2::yScale()
*/
inline constexpr static Matrix3<T> scaling(const Vector2<T>& vec) {
inline constexpr static Matrix3<T> scaling(const Vector2<T>& vector) {
return Matrix3<T>( /* Column-major! */
vec.x(), T(0), T(0),
T(0), vec.y(), T(0),
vector.x(), T(0), T(0),
T(0), vector.y(), T(0),
T(0), T(0), T(1)
);
}
/**
* @brief 3D rotation matrix
* @param angle Rotation angle (counterclockwise, in radians)
* @brief 2D rotation matrix
* @param angle Rotation angle (counterclockwise, in radians)
*
* @see Matrix4::rotation(), deg(), rad()
* @see rotation() const, Matrix4::rotation(T, const Vector3&), deg(),
* rad()
*/
static Matrix3<T> rotation(T angle) {
T sine = std::sin(angle);
T cosine = std::cos(angle);
return Matrix3<T>( /* Column-major! */
T(cos(angle)), T(sin(angle)), T(0),
-T(sin(angle)), T(cos(angle)), T(0),
cosine, sine, T(0),
-sine, cosine, T(0),
T(0), T(0), T(1)
);
}
@ -79,13 +86,13 @@ template<class T> class Matrix3: public Matrix<3, T> {
inline constexpr explicit Matrix3(typename Matrix<3, T>::ZeroType): Matrix<3, T>(Matrix<3, T>::Zero) {}
/** @copydoc Matrix::Matrix(IdentityType, T) */
inline constexpr explicit Matrix3(typename Matrix<3, T>::IdentityType = (Matrix<3, T>::Identity), T value = T(1)): Matrix<3, T>(
inline constexpr Matrix3(typename Matrix<3, T>::IdentityType = (Matrix<3, T>::Identity), T value = T(1)): Matrix<3, T>(
value, T(0), T(0),
T(0), value, T(0),
T(0), T(0), value
) {}
/** @copydoc Matrix::Matrix(T, U...) */
/** @copydoc Matrix::Matrix */
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class ...U> inline constexpr Matrix3(T first, U... next): Matrix<3, T>(first, next...) {}
#else
@ -95,13 +102,60 @@ template<class T> class Matrix3: public Matrix<3, T> {
/** @brief Copy constructor */
inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {}
/**
* @brief 2D rotation and scaling part of the matrix
*
* Upper-left 2x2 part of the matrix.
* @see rotation() const, rotation(T), Matrix4::rotationScaling() const
*/
inline Matrix<2, T> rotationScaling() const {
return Matrix<2, T>::from(
(*this)[0].xy(),
(*this)[1].xy());
}
/**
* @brief 2D rotation part of the matrix
*
* Normalized upper-left 2x2 part of the matrix.
* @see rotationScaling() const, rotation(T), Matrix4::rotation() const
*/
inline Matrix<2, T> rotation() const {
return Matrix<2, T>::from(
(*this)[0].xy().normalized(),
(*this)[1].xy().normalized());
}
/**
* @brief 2D translation part of the matrix
*
* First two elements of last column.
* @see translation(const Vector2&), Matrix4::translation()
*/
inline Vector2<T>& translation() {
return (*this)[2].xy();
}
/** @overload */
inline constexpr Vector2<T> translation() const {
return (*this)[2].xy();
}
/** @todo up(), right() */
#ifndef DOXYGEN_GENERATING_OUTPUT
inline Point2D<T> operator*(const Point2D<T>& other) const {
return Matrix<3, T>::operator*(other);
}
#endif
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(3, 3, Matrix3<T>)
};
/** @debugoperator{Magnum::Math::Matrix3} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix3<T>& value) {
return debug << static_cast<const Magnum::Math::Matrix<3, T>&>(value);
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix3<T>& value) {
return debug << static_cast<const Matrix<3, T>&>(value);
}
}}

202
src/Math/Matrix4.h

@ -19,16 +19,17 @@
* @brief Class Magnum::Math::Matrix4
*/
#include "Matrix3.h"
#include "Vector4.h"
#include "Matrix.h"
#include "Point3D.h"
namespace Magnum { namespace Math {
/**
@brief 4x4 matrix
@brief 4x4 matrix for affine transformations in 3D
@tparam T Data type
Provides functions for transformations in 3D. See also Matrix3 for 2D
transformations.
Provides functions for transformations in 3D. See Matrix3 for 2D
transformations. See also @ref matrix-vector for brief introduction.
@configurationvalueref{Magnum::Math::Matrix4}
@todo Shearing
@todo Reflection
@ -36,86 +37,153 @@ transformations.
template<class T> class Matrix4: public Matrix<4, T> {
public:
/**
* @brief 3D translation matrix
* @param vec Translation vector
* @brief 3D translation
* @param vector Translation vector
*
* @see Matrix3::translation(), Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis()
* @see translation(), Matrix3::translation(const Vector2&),
* 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>& vector) {
return Matrix4<T>( /* Column-major! */
T(1), T(0), T(0), T(0),
T(0), T(1), T(0), T(0),
T(0), T(0), T(1), T(0),
vec.x(), vec.y(), vec.z(), T(1)
vector.x(), vector.y(), vector.z(), T(1)
);
}
/**
* @brief 3D scaling matrix
* @param vec Scaling vector
* @brief 3D scaling
* @param vector Scaling vector
*
* @see Matrix3::scaling(), Vector3::xScale(), Vector3::yScale(), Vector3::zScale()
* @see rotationScaling() const, Matrix3::scaling(const Vector2&),
* 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>& vector) {
return Matrix4<T>( /* Column-major! */
vec.x(), T(0), T(0), T(0),
T(0), vec.y(), T(0), T(0),
T(0), T(0), vec.z(), T(0),
vector.x(), T(0), T(0), T(0),
T(0), vector.y(), T(0), T(0),
T(0), T(0), vector.z(), T(0),
T(0), T(0), T(0), T(1)
);
}
/**
* @brief 3D rotation matrix
* @param angle Rotation angle (counterclockwise, in radians)
* @param vec Rotation vector
* @brief 3D rotation around arbitrary axis
* @param angle Rotation angle (counterclockwise, in radians)
* @param normalizedAxis Normalized rotation axis
*
* @see Matrix3::rotation(), Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis(), deg(), rad()
* @todo optimize - Assume the vectors are normalized?
* If possible, use faster alternatives like rotationX(), rotationY()
* and rotationZ().
* @see rotation() const, Matrix3::rotation(T), Vector3::xAxis(),
* Vector3::yAxis(), Vector3::zAxis(), deg(), rad()
* @attention Assertion fails on non-normalized rotation vector and
* identity matrix is returned.
*/
static Matrix4<T> rotation(T angle, const Vector3<T>& vec) {
Vector3<T> vn = vec.normalized();
static Matrix4<T> rotation(T angle, const Vector3<T>& normalizedAxis) {
CORRADE_ASSERT(MathTypeTraits<T>::equals(normalizedAxis.dot(), T(1)),
"Math::Matrix4::rotation(): axis must be normalized", {});
T sine = std::sin(angle);
T cosine = std::cos(angle);
T oneMinusCosine = T(1) - cosine;
T xx = vn.x()*vn.x();
T xy = vn.x()*vn.y();
T xz = vn.x()*vn.z();
T yy = vn.y()*vn.y();
T yz = vn.y()*vn.z();
T zz = vn.z()*vn.z();
T xx = normalizedAxis.x()*normalizedAxis.x();
T xy = normalizedAxis.x()*normalizedAxis.y();
T xz = normalizedAxis.x()*normalizedAxis.z();
T yy = normalizedAxis.y()*normalizedAxis.y();
T yz = normalizedAxis.y()*normalizedAxis.z();
T zz = normalizedAxis.z()*normalizedAxis.z();
return Matrix4<T>( /* Column-major! */
cosine + xx*oneMinusCosine,
xy*oneMinusCosine + vn.z()*sine,
xz*oneMinusCosine - vn.y()*sine,
xy*oneMinusCosine + normalizedAxis.z()*sine,
xz*oneMinusCosine - normalizedAxis.y()*sine,
T(0),
xy*oneMinusCosine - vn.z()*sine,
xy*oneMinusCosine - normalizedAxis.z()*sine,
cosine + yy*oneMinusCosine,
yz*oneMinusCosine + vn.x()*sine,
yz*oneMinusCosine + normalizedAxis.x()*sine,
T(0),
xz*oneMinusCosine + vn.y()*sine,
yz*oneMinusCosine - vn.x()*sine,
xz*oneMinusCosine + normalizedAxis.y()*sine,
yz*oneMinusCosine - normalizedAxis.x()*sine,
cosine + zz*oneMinusCosine,
T(0),
T(0), T(0), T(0), T(1)
);
}
/**
* @brief 3D rotation around X axis
* @param angle Rotation angle (counterclockwise, in radians)
*
* Faster than calling `Matrix4::rotation(angle, Vector3::xAxis())`.
* @see rotation(T, const Vector3&), rotationY(), rotationZ(),
* rotation() const, Matrix3::rotation(T), deg(), rad()
*/
static Matrix4<T> rotationX(T angle) {
T sine = std::sin(angle);
T cosine = std::cos(angle);
return Matrix4<T>( /* Column-major! */
T(1), T(0), T(0), T(0),
T(0), cosine, sine, T(0),
T(0), -sine, cosine, T(0),
T(0), T(0), T(0), T(1)
);
}
/**
* @brief 3D rotation around Y axis
* @param angle Rotation angle (counterclockwise, in radians)
*
* Faster than calling `Matrix4::rotation(angle, Vector3::yAxis())`.
* @see rotation(T, const Vector3&), rotationX(), rotationZ(),
* rotation() const, Matrix3::rotation(T), deg(), rad()
*/
static Matrix4<T> rotationY(T angle) {
T sine = std::sin(angle);
T cosine = std::cos(angle);
return Matrix4<T>( /* Column-major! */
cosine, T(0), -sine, T(0),
T(0), T(1), T(0), T(0),
sine, T(0), cosine, T(0),
T(0), T(0), T(0), T(1)
);
}
/**
* @brief 3D rotation matrix around Z axis
* @param angle Rotation angle (counterclockwise, in radians)
*
* Faster than calling `Matrix4::rotation(angle, Vector3::zAxis())`.
* @see rotation(T, const Vector3&), rotationX(), rotationY(),
* rotation() const, Matrix3::rotation(T), deg(), rad()
*/
static Matrix4<T> rotationZ(T angle) {
T sine = std::sin(angle);
T cosine = std::cos(angle);
return Matrix4<T>( /* Column-major! */
cosine, sine, T(0), T(0),
-sine, cosine, T(0), T(0),
T(0), T(0), T(1), T(0),
T(0), T(0), T(0), T(1)
);
}
/** @copydoc Matrix::Matrix(ZeroType) */
inline constexpr explicit Matrix4(typename Matrix<4, T>::ZeroType): Matrix<4, T>(Matrix<4, T>::Zero) {}
/** @copydoc Matrix::Matrix(IdentityType, T) */
inline constexpr explicit Matrix4(typename Matrix<4, T>::IdentityType = (Matrix<4, T>::Identity), T value = T(1)): Matrix<4, T>(
inline constexpr Matrix4(typename Matrix<4, T>::IdentityType = (Matrix<4, T>::Identity), T value = T(1)): Matrix<4, T>(
value, T(0), T(0), T(0),
T(0), value, T(0), T(0),
T(0), T(0), value, T(0),
T(0), T(0), T(0), value
) {}
/** @copydoc Matrix::Matrix(T, U...) */
/** @copydoc Matrix::Matrix */
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class ...U> inline constexpr Matrix4(T first, U... next): Matrix<4, T>(first, next...) {}
#else
@ -125,27 +193,38 @@ template<class T> class Matrix4: public Matrix<4, T> {
/** @brief Copy constructor */
inline constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {}
/** @copydoc Matrix::ij() */
inline Matrix3<T> ij(size_t skipRow, size_t skipCol) const { return Matrix<4, T>::ij(skipRow, skipCol); }
/** @brief Rotation and scaling part of the matrix */
inline Matrix3<T> rotationScaling() const {
/**
* @brief 3D rotation and scaling part of the matrix
*
* Upper-left 3x3 part of the matrix.
* @see rotation() const, rotation(T, const Vector3&),
* Matrix3::rotationScaling() const
*/
inline Matrix<3, T> rotationScaling() const {
/* Not Matrix3, because it is for affine 2D transformations */
#ifndef CORRADE_GCC45_COMPATIBILITY /* GCC 4.5 badly optimizes this */
return Matrix3<T>::from(
return Matrix<3, T>::from(
(*this)[0].xyz(),
(*this)[1].xyz(),
(*this)[2].xyz());
#else
return Matrix3<T>(
return Matrix<3, T>(
(*this)(0, 0), (*this)(0, 1), (*this)(0, 2),
(*this)(1, 0), (*this)(1, 1), (*this)(1, 2),
(*this)(2, 0), (*this)(2, 1), (*this)(2, 2));
#endif
}
/** @brief Rotation part of the matrix */
inline Matrix3<T> rotation() const {
return Matrix3<T>::from(
/**
* @brief 3D rotation part of the matrix
*
* Normalized upper-left 3x3 part of the matrix.
* @see rotationScaling() const, rotation(T, const Vector3&),
* Matrix3::rotation() const
*/
inline Matrix<3, T> rotation() const {
/* Not Matrix3, because it is for affine 2D transformations */
return Matrix<3, T>::from(
#ifndef CORRADE_GCC45_COMPATIBILITY /* GCC 4.5 badly optimizes this */
(*this)[0].xyz().normalized(),
(*this)[1].xyz().normalized(),
@ -157,13 +236,36 @@ template<class T> class Matrix4: public Matrix<4, T> {
#endif
}
/**
* @brief 3D translation part of the matrix
*
* First three elements of last column.
* @see translation(const Vector3&), Matrix3::translation()
*/
inline Vector3<T>& translation() {
return (*this)[3].xyz();
}
/** @overload */
inline constexpr Vector3<T> translation() const {
return (*this)[3].xyz();
}
/** @todo up(), forward(), right() */
#ifndef DOXYGEN_GENERATING_OUTPUT
inline Point3D<T> operator*(const Point3D<T>& other) const {
return Matrix<4, T>::operator*(other);
}
#endif
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix4, Vector4, 4)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(4, 4, Matrix4<T>)
};
/** @debugoperator{Magnum::Math::Matrix4} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix4<T>& value) {
return debug << static_cast<const Magnum::Math::Matrix<4, T>&>(value);
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix4<T>& value) {
return debug << static_cast<const Matrix<4, T>&>(value);
}
}}

89
src/Math/Point2D.h

@ -0,0 +1,89 @@
#ifndef Magnum_Math_Point2D_h
#define Magnum_Math_Point2D_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::Math::Point2D
*/
#include "Vector3.h"
namespace Magnum { namespace Math {
/**
@brief Two-dimensional homogeneous coordinates
@tparam T Data type
Same as Vector3, except that constructors have default value for Z component
set to one. See also @ref matrix-vector for brief introduction.
@see Point3D
@configurationvalueref{Magnum::Math::Point2D}
*/
template<class T> class Point2D: public Vector3<T> {
public:
/**
* @brief Default constructor
*
* X and Y components are set to zero, Z is set to one.
*/
inline constexpr Point2D(): Vector3<T>(T(0), T(0), T(1)) {}
/** @brief Copy constructor */
inline constexpr Point2D(const RectangularMatrix<1, 3, T>& other): Vector3<T>(other) {}
/**
* @brief Constructor
* @param x X component
* @param y Y component
* @param z Z component
*/
inline constexpr Point2D(T x, T y, T z = T(1)): Vector3<T>(x, y, z) {}
/**
* @brief Constructor
* @param xy Two-component vector
* @param z Z component
*/
inline constexpr Point2D(const Vector2<T>& xy, T z = T(1)): Vector3<T>(xy, z) {}
/**
* @brief Vector part of the point
*
* Equivalent to calling xy(). Useful for seamless 2D/3D integration.
* @see Point3D::vector()
*/
inline Vector2<T>& vector() { return Vector3<T>::xy(); }
inline constexpr Vector2<T> vector() const { return Vector3<T>::xy(); } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Point2D, 3)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Point2D<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Point2D, 3)
/** @debugoperator{Magnum::Math::Point2D} */
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Point2D<T>& value) {
return debug << static_cast<const Vector<3, T>&>(value);
}
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Point2D} */
template<class T> struct ConfigurationValue<Magnum::Math::Point2D<T>>: public ConfigurationValue<Magnum::Math::Vector<3, T>> {};
}}
#endif

90
src/Math/Point3D.h

@ -0,0 +1,90 @@
#ifndef Magnum_Math_Point3D_h
#define Magnum_Math_Point3D_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::Math::Point3D
*/
#include "Vector4.h"
namespace Magnum { namespace Math {
/**
@brief Three-dimensional homogeneous coordinates
@tparam T Data type
Same as Vector4, except that constructors have default value for W component
set to one. See also @ref matrix-vector for brief introduction.
@see Point2D
@configurationvalueref{Magnum::Math::Point3D}
*/
template<class T> class Point3D: public Vector4<T> {
public:
/**
* @brief Default constructor
*
* X, Y and Z components are set to zero, W is set to one.
*/
inline constexpr Point3D(): Vector4<T>(T(0), T(0), T(0), T(1)) {}
/** @brief Copy constructor */
inline constexpr Point3D(const RectangularMatrix<1, 4, T>& other): Vector4<T>(other) {}
/**
* @brief Constructor
* @param x X component
* @param y Y component
* @param z Z component
* @param w W component
*/
inline constexpr Point3D(T x, T y, T z, T w = T(1)): Vector4<T>(x, y, z, w) {}
/**
* @brief Constructor
* @param xyz Three-component vector
* @param w W component
*/
inline constexpr Point3D(const Vector3<T>& xyz, T w = T(1)): Vector4<T>(xyz, w) {}
/**
* @brief Vector part of the point
*
* Equivalent to calling xyz(). Useful for seamless 2D/3D integration.
* @see Point2D::vector()
*/
inline Vector3<T>& vector() { return Vector4<T>::xyz(); }
inline constexpr Vector3<T> vector() const { return Vector4<T>::xyz(); } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Point3D, 4)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Point3D<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Point3D, 4)
/** @debugoperator{Magnum::Math::Point3D} */
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Point3D<T>& value) {
return debug << static_cast<const Vector<4, T>&>(value);
}
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Point3D} */
template<class T> struct ConfigurationValue<Magnum::Math::Point3D<T>>: public ConfigurationValue<Magnum::Math::Vector<4, T>> {};
}}
#endif

130
src/Math/RectangularMatrix.h

@ -28,38 +28,47 @@
namespace Magnum { namespace Math {
/** @todo Properly test all constexpr */
template<std::size_t, std::size_t, class> class RectangularMatrix;
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<size_t ...> struct Sequence {};
template<std::size_t ...> struct Sequence {};
/* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */
template<size_t N, size_t ...sequence> struct GenerateSequence:
template<std::size_t N, std::size_t ...sequence> struct GenerateSequence:
GenerateSequence<N-1, N-1, sequence...> {};
template<size_t ...sequence> struct GenerateSequence<0, sequence...> {
template<std::size_t ...sequence> struct GenerateSequence<0, sequence...> {
typedef Sequence<sequence...> Type;
};
/* Implementation for RectangularMatrix<cols, rows, T>::from(const RectangularMatrix<cols, rows, U>&) */
template<class T, class U, std::size_t c, std::size_t ...sequence> inline constexpr Math::RectangularMatrix<c, sizeof...(sequence)/c, T> rectangularMatrixFrom(Sequence<sequence...>, const Math::RectangularMatrix<c, sizeof...(sequence)/c, U>& matrix) {
return {T(matrix.data()[sequence])...};
}
}
#endif
template<size_t size, class T> class Vector;
template<std::size_t size, class T> class Vector;
/**
@brief Rectangular matrix
@tparam c Column count
@tparam r Row count
@tparam cols Column count
@tparam rows Row count
@tparam T Data type
See also Matrix (square) and Vector.
See @ref matrix-vector for brief introduction. See also Matrix (square) and
Vector.
*/
template<size_t c, size_t r, class T> class RectangularMatrix {
static_assert(c != 0 && r != 0, "Matrix cannot have zero elements");
friend class Vector<r, T>;
template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
static_assert(cols != 0 && rows != 0, "Matrix cannot have zero elements");
public:
typedef T Type; /**< @brief Data type */
const static size_t cols = c; /**< @brief %Matrix column count */
const static size_t rows = r; /**< @brief %Matrix row count */
typedef T Type; /**< @brief Data type */
const static std::size_t Cols = cols; /**< @brief %Matrix column count */
const static std::size_t Rows = rows; /**< @brief %Matrix row count */
/**
* @brief %Matrix from array
@ -81,12 +90,29 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
* @brief %Matrix from column vectors
* @param first First column vector
* @param next Next column vectors
*
* @todo Creating matrix from arbitrary combination of matrices with n rows
*/
template<class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(const Vector<rows, T>& first, const U&... next) {
static_assert(sizeof...(next)+1 == cols, "Improper number of arguments passed to Matrix from Vector constructor");
return from(typename Implementation::GenerateSequence<rows>::Type(), first, next...);
}
/**
* @brief %Matrix from another of different type
*
* Performs only default casting on the values, no rounding or
* anything else. Example usage:
* @code
* RectangularMatrix<4, 1, float> floatingPoint(1.3f, 2.7f, -15.0f, 7.0f);
* RectangularMatrix<4, 1, std::int8_t> integral(RectangularMatrix<4, 1, std::int8_t>::from(floatingPoint));
* // integral == {1, 2, -15, 7}
* @endcode
*/
template<class U> inline constexpr static RectangularMatrix<cols, rows, T> from(const RectangularMatrix<cols, rows, U>& other) {
return Implementation::rectangularMatrixFrom<T, U>(typename Implementation::GenerateSequence<cols*rows>::Type(), other);
}
/** @brief Zero-filled matrix constructor */
inline constexpr RectangularMatrix(): _data() {}
@ -107,10 +133,10 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
#endif
/** @brief Copy constructor */
inline constexpr RectangularMatrix(const RectangularMatrix<c, r, T>&) = default;
inline constexpr RectangularMatrix(const RectangularMatrix<cols, rows, T>&) = default;
/** @brief Assignment operator */
inline RectangularMatrix<c, r, T>& operator=(const RectangularMatrix<c, r, T>&) = default;
inline RectangularMatrix<cols, rows, T>& operator=(const RectangularMatrix<cols, rows, T>&) = default;
/**
* @brief Raw data
@ -126,11 +152,11 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
* For accessing individual elements prefer to use operator(), as it
* is guaranteed to not involve unnecessary conversions.
*/
inline Vector<rows, T>& operator[](size_t col) {
inline Vector<rows, T>& operator[](std::size_t col) {
return Vector<rows, T>::from(_data+col*rows);
}
/** @overload */
inline constexpr const Vector<rows, T>& operator[](size_t col) const {
inline constexpr const Vector<rows, T>& operator[](std::size_t col) const {
return Vector<rows, T>::from(_data+col*rows);
}
@ -140,17 +166,17 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
* Prefer this instead of using `[][]`.
* @see operator[]
*/
inline T& operator()(size_t col, size_t row) {
inline T& operator()(std::size_t col, std::size_t row) {
return _data[col*rows+row];
}
/** @overload */
inline constexpr const T& operator()(size_t col, size_t row) const {
inline constexpr const T& operator()(std::size_t col, std::size_t row) const {
return _data[col*rows+row];
}
/** @brief Equality operator */
inline bool operator==(const RectangularMatrix<cols, rows, T>& other) const {
for(size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols*rows; ++i)
if(!MathTypeTraits<T>::equals(_data[i], other._data[i])) return false;
return true;
@ -177,7 +203,7 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
* in-place.
*/
RectangularMatrix<cols, rows, T>& operator+=(const RectangularMatrix<cols, rows, T>& other) {
for(size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols*rows; ++i)
_data[i] += other._data[i];
return *this;
@ -187,7 +213,7 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
RectangularMatrix<cols, rows, T> operator-() const {
RectangularMatrix<cols, rows, T> out;
for(size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols*rows; ++i)
out._data[i] = -_data[i];
return out;
@ -209,7 +235,7 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
* in-place.
*/
RectangularMatrix<cols, rows, T>& operator-=(const RectangularMatrix<cols, rows, T>& other) {
for(size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols*rows; ++i)
_data[i] -= other._data[i];
return *this;
@ -239,7 +265,7 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
#else
template<class U> RectangularMatrix<cols, rows, T>& operator*=(U number) {
#endif
for(size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols*rows; ++i)
_data[i] *= number;
return *this;
@ -269,19 +295,19 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
#else
template<class U> RectangularMatrix<cols, rows, T>& operator/=(U number) {
#endif
for(size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols*rows; ++i)
_data[i] /= number;
return *this;
}
/** @brief Multiply matrix */
template<size_t size> RectangularMatrix<size, rows, T> operator*(const RectangularMatrix<size, cols, T>& other) const {
template<std::size_t size> RectangularMatrix<size, rows, T> operator*(const RectangularMatrix<size, cols, T>& other) const {
RectangularMatrix<size, rows, T> out;
for(size_t row = 0; row != rows; ++row)
for(size_t col = 0; col != size; ++col) /** @todo swap */
for(size_t pos = 0; pos != cols; ++pos)
for(std::size_t col = 0; col != size; ++col)
for(std::size_t row = 0; row != rows; ++row)
for(std::size_t pos = 0; pos != cols; ++pos)
out(col, row) += (*this)(pos, row)*other(col, pos);
return out;
@ -301,22 +327,25 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
RectangularMatrix<rows, cols, T> transposed() const {
RectangularMatrix<rows, cols, T> out;
for(size_t col = 0; col != cols; ++col)
for(size_t row = 0; row != rows; ++row)
for(std::size_t col = 0; col != cols; ++col)
for(std::size_t row = 0; row != rows; ++row)
out(row, col) = (*this)(col, row);
return out;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
protected:
T _data[rows*cols];
#endif
private:
template<size_t ...sequence, class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(Implementation::Sequence<sequence...> s, const Vector<rows, T>& first, U... next) {
template<std::size_t ...sequence, class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(Implementation::Sequence<sequence...> s, const Vector<rows, T>& first, U... next) {
return from(s, next..., first[sequence]...);
}
template<size_t ...sequence, class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(Implementation::Sequence<sequence...>, T first, U... next) {
template<std::size_t ...sequence, class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(Implementation::Sequence<sequence...>, T first, U... next) {
return RectangularMatrix<cols, rows, T>(first, next...);
}
T _data[rows*cols];
};
/** @relates RectangularMatrix
@ -325,9 +354,9 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
@see RectangularMatrix::operator*(U) const
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<size_t cols, size_t rows, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator*(U number, const RectangularMatrix<cols, rows, T>& matrix) {
template<std::size_t cols, std::size_t rows, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator*(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#else
template<size_t cols, size_t rows, class T, class U> inline RectangularMatrix<cols, rows, T> operator*(U number, const RectangularMatrix<cols, rows, T>& matrix) {
template<std::size_t cols, std::size_t rows, class T, class U> inline RectangularMatrix<cols, rows, T> operator*(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#endif
return matrix*number;
}
@ -343,25 +372,25 @@ RectangularMatrix<2, 3, float> another = 1.0f/mat; // {1.0f, 0.5f, -0.25f, 0.128
@see RectangularMatrix::operator/()
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<size_t cols, size_t rows, class T, class U> typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) {
template<std::size_t cols, std::size_t rows, class T, class U> typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#else
template<size_t cols, size_t rows, class T, class U> RectangularMatrix<cols, rows, T> operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) {
template<std::size_t cols, std::size_t rows, class T, class U> RectangularMatrix<cols, rows, T> operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#endif
RectangularMatrix<cols, rows, T> out;
for(size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols*rows; ++i)
out.data()[i] = number/matrix.data()[i];
return out;
}
/** @debugoperator{Magnum::Math::RectangularMatrix} */
template<size_t cols, size_t rows, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::RectangularMatrix<cols, rows, T>& value) {
template<std::size_t cols, std::size_t rows, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::RectangularMatrix<cols, rows, T>& value) {
debug << "Matrix(";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
for(size_t row = 0; row != rows; ++row) {
for(std::size_t row = 0; row != rows; ++row) {
if(row != 0) debug << ",\n ";
for(size_t col = 0; col != cols; ++col) {
for(std::size_t col = 0; col != cols; ++col) {
if(col != 0) debug << ", ";
debug << typename MathTypeTraits<T>::NumericType(value[col][row]);
}
@ -381,6 +410,9 @@ template<size_t cols, size_t rows, class T> Corrade::Utility::Debug operator<<(C
} \
template<class ...U> inline constexpr static __VA_ARGS__ from(const Math::Vector<rows, T>& first, const U&... next) { \
return Math::RectangularMatrix<cols, rows, T>::from(first, next...); \
} \
template<class U> inline constexpr static RectangularMatrix<cols, rows, T> from(const Math::RectangularMatrix<cols, rows, U>& other) { \
return Math::RectangularMatrix<cols, rows, T>::from(other); \
} \
\
inline __VA_ARGS__& operator=(const Math::RectangularMatrix<cols, rows, T>& other) { \
@ -427,13 +459,13 @@ template<size_t cols, size_t rows, class T> Corrade::Utility::Debug operator<<(C
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::RectangularMatrix} */
template<size_t cols, size_t rows, class T> struct ConfigurationValue<Magnum::Math::RectangularMatrix<cols, rows, T>> {
template<std::size_t cols, std::size_t rows, class T> struct ConfigurationValue<Magnum::Math::RectangularMatrix<cols, rows, T>> {
/** @brief Writes elements separated with spaces */
static std::string toString(const Magnum::Math::RectangularMatrix<cols, rows, T>& value, int flags = 0) {
std::string output;
for(size_t row = 0; row != rows; ++row) {
for(size_t col = 0; col != cols; ++col) {
for(std::size_t row = 0; row != rows; ++row) {
for(std::size_t col = 0; col != cols; ++col) {
if(!output.empty()) output += ' ';
output += ConfigurationValue<T>::toString(value(col, row), flags);
}
@ -447,8 +479,8 @@ template<size_t cols, size_t rows, class T> struct ConfigurationValue<Magnum::Ma
Magnum::Math::RectangularMatrix<cols, rows, T> result;
std::istringstream in(stringValue);
for(size_t row = 0; row != rows; ++row) {
for(size_t col = 0; col != cols; ++col) {
for(std::size_t row = 0; row != rows; ++row) {
for(std::size_t col = 0; col != cols; ++col) {
std::string num;
in >> num;
result(col, row) = ConfigurationValue<T>::fromString(num, flags);

18
src/Math/Test/CMakeLists.txt

@ -1,20 +1,24 @@
corrade_add_test2(MathConstantsTest ConstantsTest.cpp)
if(NOT CMAKE_NO_OBJECT_TARGET)
set(MathTest_SRCS MathTest.cpp $<TARGET_OBJECTS:MagnumMathObjects>)
else()
set(MathTest_SRCS MathTest.cpp ${MagnumMath_SRCS})
endif()
corrade_add_test2(MathTest ${MathTest_SRCS})
corrade_add_test2(MathMathTypeTraitsTest MathTypeTraitsTest.cpp)
corrade_add_test2(MathRectangularMatrixTest RectangularMatrixTest.cpp)
corrade_add_test2(MathVectorTest VectorTest.cpp)
set_target_properties(MathVectorTest PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
corrade_add_test2(MathVector2Test Vector2Test.cpp)
corrade_add_test2(MathVector3Test Vector3Test.cpp)
corrade_add_test2(MathVector4Test Vector4Test.cpp)
corrade_add_test2(MathPoint2DTest Point2DTest.cpp)
corrade_add_test2(MathPoint3DTest Point3DTest.cpp)
corrade_add_test2(MathMatrixTest MatrixTest.cpp)
corrade_add_test2(MathMatrix3Test Matrix3Test.cpp)
corrade_add_test2(MathMatrix4Test Matrix4Test.cpp)
if(NOT CMAKE_NO_OBJECT_TARGET)
set(MathTest_SRCS MathTest.cpp $<TARGET_OBJECTS:MagnumMathObjects>)
else()
set(MathTest_SRCS MathTest.cpp ${MagnumMath_SRCS})
endif()
corrade_add_test2(MathTest ${MathTest_SRCS})
set_target_properties(MathVectorTest MathMatrix4Test PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)

44
src/Math/Test/ConstantsTest.cpp

@ -0,0 +1,44 @@
/*
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 "ConstantsTest.h"
#include "Constants.h"
#include "Math.h"
CORRADE_TEST_MAIN(Magnum::Math::Test::ConstantsTest)
namespace Magnum { namespace Math { namespace Test {
ConstantsTest::ConstantsTest() {
addTests(&ConstantsTest::constants,
&ConstantsTest::degrad);
}
void ConstantsTest::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 ConstantsTest::degrad() {
CORRADE_COMPARE(deg(90.0), Constants<double>::pi()/2);
CORRADE_COMPARE(deg(90.0f), Constants<float>::pi()/2);
CORRADE_COMPARE(rad(Constants<double>::pi()/2), Constants<double>::pi()/2);
}
}}}

32
src/Math/Test/ConstantsTest.h

@ -0,0 +1,32 @@
#ifndef Magnum_Math_Test_ConstantsTest_h
#define Magnum_Math_Test_ConstantsTest_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include <TestSuite/Tester.h>
namespace Magnum { namespace Math { namespace Test {
class ConstantsTest: public Corrade::TestSuite::Tester<ConstantsTest> {
public:
ConstantsTest();
void constants();
void degrad();
};
}}}
#endif

86
src/Math/Test/MathTest.cpp

@ -24,77 +24,61 @@ CORRADE_TEST_MAIN(Magnum::Math::Test::MathTest)
namespace Magnum { namespace Math { namespace Test {
MathTest::MathTest() {
addTests(&MathTest::constants,
&MathTest::degrad,
&MathTest::normalize,
addTests(&MathTest::normalize,
&MathTest::denormalize,
&MathTest::clamp,
&MathTest::pow,
&MathTest::log);
}
void MathTest::constants() {
CORRADE_COMPARE(Math::pow<2>(Constants<float>::sqrt2()), 2.0f);
CORRADE_COMPARE(Math::pow<2>(Constants<float>::sqrt3()), 3.0f);
CORRADE_COMPARE(Math::pow<2>(Constants<double>::sqrt2()), 2.0);
CORRADE_COMPARE(Math::pow<2>(Constants<double>::sqrt3()), 3.0);
}
void MathTest::degrad() {
CORRADE_COMPARE(deg(90.0), Constants<double>::pi()/2);
CORRADE_COMPARE(deg(90.0f), Constants<float>::pi()/2);
CORRADE_COMPARE(rad(Constants<double>::pi()/2), Constants<double>::pi()/2);
}
void MathTest::normalize() {
/* Range for signed and unsigned */
CORRADE_COMPARE((Math::normalize<float, char>(-128)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, char>(127)), 1.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned char>(0)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned char>(255)), 1.0f);
CORRADE_COMPARE((Math::normalize<float, int8_t>(-128)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, int8_t>(127)), 1.0f);
CORRADE_COMPARE((Math::normalize<float, uint8_t>(0)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, uint8_t>(255)), 1.0f);
/* Between */
CORRADE_COMPARE((Math::normalize<float, short>(16384)), 0.750011f);
CORRADE_COMPARE((Math::normalize<float, short>(-16384)), 0.250004f);
CORRADE_COMPARE((Math::normalize<float, int16_t>(16384)), 0.750011f);
CORRADE_COMPARE((Math::normalize<float, int16_t>(-16384)), 0.250004f);
/* Test overflow for large types */
CORRADE_COMPARE((Math::normalize<float, int>(numeric_limits<int>::min())), 0.0f);
CORRADE_COMPARE((Math::normalize<float, int>(numeric_limits<int>::max())), 1.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned int>(0)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned int>(numeric_limits<unsigned int>::max())), 1.0f);
CORRADE_COMPARE((Math::normalize<double, long long>(numeric_limits<long long>::min())), 0.0);
CORRADE_COMPARE((Math::normalize<double, long long>(numeric_limits<long long>::max())), 1.0);
CORRADE_COMPARE((Math::normalize<double, unsigned long long>(0)), 0.0);
CORRADE_COMPARE((Math::normalize<double, unsigned long long>(numeric_limits<unsigned long long>::max())), 1.0);
CORRADE_COMPARE((Math::normalize<float, int32_t>(numeric_limits<int32_t>::min())), 0.0f);
CORRADE_COMPARE((Math::normalize<float, int32_t>(numeric_limits<int32_t>::max())), 1.0f);
CORRADE_COMPARE((Math::normalize<float, uint32_t>(0)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, uint32_t>(numeric_limits<uint32_t>::max())), 1.0f);
CORRADE_COMPARE((Math::normalize<double, int64_t>(numeric_limits<int64_t>::min())), 0.0);
CORRADE_COMPARE((Math::normalize<double, int64_t>(numeric_limits<int64_t>::max())), 1.0);
CORRADE_COMPARE((Math::normalize<double, uint64_t>(0)), 0.0);
CORRADE_COMPARE((Math::normalize<double, uint64_t>(numeric_limits<uint64_t>::max())), 1.0);
}
void MathTest::denormalize() {
/* Range for signed and unsigned */
CORRADE_COMPARE(Math::denormalize<char>(0.0f), -128);
CORRADE_COMPARE(Math::denormalize<char>(1.0f), 127);
CORRADE_COMPARE(Math::denormalize<unsigned char>(0.0f), 0);
CORRADE_COMPARE(Math::denormalize<unsigned char>(1.0f), 255);
CORRADE_COMPARE(Math::denormalize<int8_t>(0.0f), -128);
CORRADE_COMPARE(Math::denormalize<int8_t>(1.0f), 127);
CORRADE_COMPARE(Math::denormalize<uint8_t>(0.0f), 0);
CORRADE_COMPARE(Math::denormalize<uint8_t>(1.0f), 255);
/* Between */
CORRADE_COMPARE(Math::denormalize<short>(0.33f), -11141);
CORRADE_COMPARE(Math::denormalize<short>(0.66f), 10485);
CORRADE_COMPARE(Math::denormalize<int16_t>(0.33f), -11141);
CORRADE_COMPARE(Math::denormalize<int16_t>(0.66f), 10485);
/* Test overflow for large types */
CORRADE_COMPARE(Math::denormalize<int>(0.0f), numeric_limits<int>::min());
CORRADE_COMPARE(Math::denormalize<unsigned int>(0.0f), 0);
CORRADE_COMPARE(Math::denormalize<long long>(0.0), numeric_limits<long long>::min());
CORRADE_COMPARE(Math::denormalize<unsigned long long>(0.0), 0);
CORRADE_COMPARE(Math::denormalize<int>(1.0), numeric_limits<int>::max());
CORRADE_COMPARE(Math::denormalize<unsigned int>(1.0), numeric_limits<unsigned int>::max());
{
CORRADE_EXPECT_FAIL("Denormalize doesn't work for large types well");
CORRADE_COMPARE((Math::denormalize<long long, long double>(1.0)), numeric_limits<long long>::max());
CORRADE_COMPARE((Math::denormalize<unsigned long long, long double>(1.0)), numeric_limits<unsigned long long>::max());
}
CORRADE_COMPARE(Math::denormalize<int32_t>(0.0f), numeric_limits<int32_t>::min());
CORRADE_COMPARE(Math::denormalize<uint32_t>(0.0f), 0);
CORRADE_COMPARE(Math::denormalize<int64_t>(0.0), numeric_limits<int64_t>::min());
CORRADE_COMPARE(Math::denormalize<uint64_t>(0.0), 0);
CORRADE_COMPARE(Math::denormalize<int32_t>(1.0), numeric_limits<int32_t>::max());
CORRADE_COMPARE(Math::denormalize<uint32_t>(1.0), numeric_limits<uint32_t>::max());
// {
// CORRADE_EXPECT_FAIL("Denormalize doesn't work for large types well");
// CORRADE_COMPARE((Math::denormalize<long long, long double>(1.0)), numeric_limits<long long>::max());
// CORRADE_COMPARE((Math::denormalize<unsigned long long, long double>(1.0)), numeric_limits<unsigned long long>::max());
// }
}
void MathTest::clamp() {

2
src/Math/Test/MathTest.h

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

20
src/Math/Test/MathTypeTraitsTest.cpp

@ -21,6 +21,8 @@
CORRADE_TEST_MAIN(Magnum::Math::Test::MathTypeTraitsTest)
using namespace std;
namespace Magnum { namespace Math { namespace Test {
MathTypeTraitsTest::MathTypeTraitsTest() {
@ -29,16 +31,14 @@ MathTypeTraitsTest::MathTypeTraitsTest() {
}
void MathTypeTraitsTest::equalsIntegral() {
_equalsIntegral<unsigned char>();
_equalsIntegral<char>();
_equalsIntegral<unsigned short>();
_equalsIntegral<short>();
_equalsIntegral<unsigned int>();
_equalsIntegral<int>();
_equalsIntegral<unsigned long int>();
_equalsIntegral<long int>();
_equalsIntegral<unsigned long long>();
_equalsIntegral<long long>();
_equalsIntegral<uint8_t>();
_equalsIntegral<int8_t>();
_equalsIntegral<uint16_t>();
_equalsIntegral<int16_t>();
_equalsIntegral<uint32_t>();
_equalsIntegral<int32_t>();
_equalsIntegral<uint64_t>();
_equalsIntegral<int64_t>();
}
void MathTypeTraitsTest::equalsFloatingPoint() {

43
src/Math/Test/Matrix3Test.cpp

@ -17,8 +17,8 @@
#include <sstream>
#include "Constants.h"
#include "Matrix3.h"
#include "Math.h"
CORRADE_TEST_MAIN(Magnum::Math::Test::Matrix3Test)
@ -28,12 +28,17 @@ using namespace Corrade::Utility;
namespace Magnum { namespace Math { namespace Test {
typedef Math::Matrix3<float> Matrix3;
typedef Math::Matrix<2, float> Matrix2;
typedef Math::Vector2<float> Vector2;
Matrix3Test::Matrix3Test() {
addTests(&Matrix3Test::constructIdentity,
&Matrix3Test::translation,
&Matrix3Test::scaling,
&Matrix3Test::rotation,
&Matrix3Test::rotationScalingPart,
&Matrix3Test::rotationPart,
&Matrix3Test::translationPart,
&Matrix3Test::debug,
&Matrix3Test::configuration);
}
@ -90,6 +95,42 @@ void Matrix3Test::rotation() {
CORRADE_COMPARE(Matrix3::rotation(deg(15.0f)), matrix);
}
void Matrix3Test::rotationScalingPart() {
Matrix3 m(
3.0f, 5.0f, 8.0f,
4.0f, 4.0f, 7.0f,
7.0f, -1.0f, 8.0f
);
Matrix2 expected(
3.0f, 5.0f,
4.0f, 4.0f
);
CORRADE_COMPARE(m.rotationScaling(), expected);
}
void Matrix3Test::rotationPart() {
Matrix2 expectedRotationPart(
0.965926f, 0.258819f,
-0.258819f, 0.965926f
);
Matrix3 rotation = Matrix3::rotation(deg(15.0f));
CORRADE_COMPARE(rotation.rotation(), expectedRotationPart);
Matrix3 rotationTransformed = Matrix3::translation({2.0f, 5.0f})*rotation*Matrix3::scaling(Vector2(9.0f));
CORRADE_COMPARE(rotationTransformed.rotation(), expectedRotationPart);
}
void Matrix3Test::translationPart() {
Matrix3 m(1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
-5.0f, 12.0f, 1.0f);
Vector2 expected(-5.0f, 12.0f);
CORRADE_COMPARE(m.translation(), expected);
}
void Matrix3Test::debug() {
Matrix3 m(
3.0f, 5.0f, 8.0f,

3
src/Math/Test/Matrix3Test.h

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

64
src/Math/Test/Matrix4Test.cpp

@ -17,8 +17,8 @@
#include <sstream>
#include "Constants.h"
#include "Matrix4.h"
#include "Math.h"
CORRADE_TEST_MAIN(Magnum::Math::Test::Matrix4Test)
@ -28,15 +28,20 @@ using namespace Corrade::Utility;
namespace Magnum { namespace Math { namespace Test {
typedef Math::Matrix4<float> Matrix4;
typedef Math::Matrix3<float> Matrix3;
typedef Math::Matrix<3, float> Matrix3;
typedef Math::Vector3<float> Vector3;
Matrix4Test::Matrix4Test() {
addTests(&Matrix4Test::constructIdentity,
&Matrix4Test::translation,
&Matrix4Test::scaling,
&Matrix4Test::rotation,
&Matrix4Test::rotationX,
&Matrix4Test::rotationY,
&Matrix4Test::rotationZ,
&Matrix4Test::rotationScalingPart,
&Matrix4Test::rotationPart,
&Matrix4Test::translationPart,
&Matrix4Test::debug,
&Matrix4Test::configuration);
}
@ -88,14 +93,46 @@ void Matrix4Test::scaling() {
}
void Matrix4Test::rotation() {
ostringstream o;
Error::setOutput(&o);
CORRADE_COMPARE(Matrix4::rotation(deg(-74.0f), {-1.0f, 2.0f, 2.0f}), Matrix4());
CORRADE_COMPARE(o.str(), "Math::Matrix4::rotation(): axis must be normalized\n");
Matrix4 matrix(
0.35612214f, -0.80181062f, 0.47987163f, 0.0f,
0.47987163f, 0.59757638f, 0.6423595f, 0.0f,
-0.80181062f, 0.0015183985f, 0.59757638f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
0.35612214f, -0.80181062f, 0.47987163f, 0.0f,
0.47987163f, 0.59757638f, 0.6423595f, 0.0f,
-0.80181062f, 0.0015183985f, 0.59757638f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
CORRADE_COMPARE(Matrix4::rotation(deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized()), matrix);
}
void Matrix4Test::rotationX() {
Matrix4 matrix(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.90096887f, 0.43388374f, 0.0f,
0.0f, -0.43388374f, 0.90096887f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants<float>::pi()/7), Vector3::xAxis()), matrix);
CORRADE_COMPARE(Matrix4::rotationX(rad(Math::Constants<float>::pi()/7)), matrix);
}
void Matrix4Test::rotationY() {
Matrix4 matrix(0.90096887f, 0.0f, -0.43388374f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.43388374f, 0.0f, 0.90096887f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants<float>::pi()/7), Vector3::yAxis()), matrix);
CORRADE_COMPARE(Matrix4::rotationY(rad(Math::Constants<float>::pi()/7)), matrix);
}
CORRADE_COMPARE(Matrix4::rotation(deg(-74.0f), {-1.0f, 2.0f, 2.0f}), matrix);
void Matrix4Test::rotationZ() {
Matrix4 matrix( 0.90096887f, 0.43388374f, 0.0f, 0.0f,
-0.43388374f, 0.90096887f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants<float>::pi()/7), Vector3::zAxis()), matrix);
CORRADE_COMPARE(Matrix4::rotationZ(rad(Math::Constants<float>::pi()/7)), matrix);
}
void Matrix4Test::rotationScalingPart() {
@ -122,13 +159,22 @@ void Matrix4Test::rotationPart() {
-0.80181062f, 0.0015183985f, 0.59757638f
);
Matrix4 rotation = Matrix4::rotation(deg(-74.0f), {-1.0f, 2.0f, 2.0f});
Matrix4 rotation = Matrix4::rotation(deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized());
CORRADE_COMPARE(rotation.rotation(), expectedRotationPart);
Matrix4 rotationTransformed = Matrix4::translation({2.0f, 5.0f, -3.0f})*rotation*Matrix4::scaling(Vector3<float>(9.0f));
Matrix4 rotationTransformed = Matrix4::translation({2.0f, 5.0f, -3.0f})*rotation*Matrix4::scaling(Vector3(9.0f));
CORRADE_COMPARE(rotationTransformed.rotation(), expectedRotationPart);
}
void Matrix4Test::translationPart() {
Matrix4 m(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
-5.0f, 12.0f, 0.5f, 1.0f);
Vector3 expected(-5.0f, 12.0f, 0.5f);
CORRADE_COMPARE(m.translation(), expected);
}
void Matrix4Test::debug() {
Matrix4 m(
3.0f, 5.0f, 8.0f, 4.0f,

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

Loading…
Cancel
Save