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) 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 # Parts of the library
option(WITH_EVERYTHING "Build everything (doesn't include contexts)" ON) option(WITH_EVERYTHING "Build everything (doesn't include contexts)" ON)
option(WITH_MESHTOOLS "Build MeshTools library" OFF) cmake_dependent_option(WITH_MESHTOOLS "Build MeshTools library" OFF "NOT WITH_EVERYTHING" ON)
option(WITH_PHYSICS "Build Physics library" OFF) cmake_dependent_option(WITH_PHYSICS "Build Physics library" OFF "NOT WITH_EVERYTHING" ON)
option(WITH_PRIMITIVES "Builf Primitives library" OFF) cmake_dependent_option(WITH_PRIMITIVES "Builf Primitives library" OFF "NOT WITH_EVERYTHING" ON)
option(WITH_SCENEGRAPH "Build SceneGraph library" OFF) cmake_dependent_option(WITH_SCENEGRAPH "Build SceneGraph library" OFF "NOT WITH_EVERYTHING;NOT WITH_PHYSICS" ON)
option(WITH_SHADERS "Build Shaders library" OFF) cmake_dependent_option(WITH_SHADERS "Build Shaders library" OFF "NOT WITH_EVERYTHING;NOT WITH_PHYSICS" ON)
option(WITH_GLXCONTEXT "Build GlxContext library" OFF) option(WITH_GLXWINDOWCONTEXT "Build GlxWindowContext library" OFF)
cmake_dependent_option(WITH_XEGLCONTEXT "Build XEglContext library" OFF "TARGET_GLES" OFF) cmake_dependent_option(WITH_XEGLWINDOWCONTEXT "Build XEglWindowContext library" OFF "TARGET_GLES" OFF)
cmake_dependent_option(WITH_GLUTCONTEXT "Build GlutContext library" OFF "NOT TARGET_GLES" OFF) cmake_dependent_option(WITH_GLUTWINDOWCONTEXT "Build GlutWindowContext library" OFF "NOT TARGET_GLES" OFF)
option(WITH_SDL2CONTEXT "Build Sdl2Context library" OFF) option(WITH_SDL2WINDOWCONTEXT "Build Sdl2WindowContext library" OFF)
option(BUILD_TESTS "Build unit tests." 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) if(BUILD_TESTS)
enable_testing() enable_testing()
endif() 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_CMAKE_MODULE_INSTALL_DIR ${CMAKE_ROOT}/Modules)
set(MAGNUM_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/Magnum) set(MAGNUM_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/Magnum)
include_directories(${CMAKE_SOURCE_DIR}/external)
add_subdirectory(external)
add_subdirectory(modules) add_subdirectory(modules)
add_subdirectory(src) 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." \ "configurationvalue{1}=@brief %Configuration value parser and writer @xrefitem configurationvalues \"Configuration value parser and writer\" \"Configuration value parsers and writers for custom types\" Allows parsing and writing \1 from and to Corrade::Utility::Configuration." \
"collisionoperator{2}=@relates \1\n@brief Collision of %\1 and %\2\n@see \2::operator%(const \1&) const" \ "collisionoperator{2}=@relates \1\n@brief Collision of %\1 and %\2\n@see \2::operator%(const \1&) const" \
"todoc=@xrefitem todoc \"Documentation todo\" \"Documentation-related todo list\"" \ "todoc=@xrefitem todoc \"Documentation todo\" \"Documentation-related todo list\"" \
"requires_gl=@xrefitem requires-gl \"Requires desktop OpenGL\" \"Functionality requiring desktop OpenGL (not available on OpenGL ES)\" Not available on OpenGL ES." \ "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_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_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\"" \ "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\"" \ "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>" \ "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_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\"" \ "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). # This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding # A mapping has the form "name=value". For example adding
@ -396,7 +400,7 @@ EXTRACT_STATIC = NO
# defined locally in source files will be included in the documentation. # defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included. # 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 # 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 # methods, which are defined in the implementation section but not in
@ -700,6 +704,7 @@ INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.cpp \ FILE_PATTERNS = *.cpp \
*.h \ *.h \
*.hpp \
*.dox *.dox
# The RECURSIVE tag can be used to turn specify whether or not subdirectories # 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/* # for example use the pattern */test/*
EXCLUDE_PATTERNS = */Test/* \ EXCLUDE_PATTERNS = */Test/* \
*/Implementation/* \
*Visibility.h *Visibility.h
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # 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 # will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this. # 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 # 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 * Easy-to-use templated mathematical library for matrix/vector calculations
and geometry. 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 * Hierarchical scene graph which supports transformation caching for better
performance, classes for convenient usage of shaders, buffers and textures. performance, physics library for collision detection and rigid body
Access to framebuffer and occlusion queries. dynamics.
* Physics library for collision detection and rigid body dynamics. Mesh tools
for cleaning, optimizing and generating meshes.
* Plugin-based data exchange framework for importing image, mesh, material * Plugin-based data exchange framework for importing image, mesh, material
and scene data in various formats. and scene data in various formats.
* Collection of pre-made graphic primitives and shaders for testing purposes. * 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 * Comprehensive use of C++11 features for safety, performance and ease of
development. All code which doesn't directly interact with OpenGL is development. All code which doesn't directly interact with OpenGL is
covered with unit tests. covered with unit tests.
* Actively maintained Doxygen documentation. Occasionally updated snapshot is * 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 INSTALLATION
============ ============
@ -37,18 +40,18 @@ Minimal dependencies
**OpenGL ES 2** headers, if targeting OpenGL ES. **OpenGL ES 2** headers, if targeting OpenGL ES.
* **GLEW** - OpenGL extension wrangler * **GLEW** - OpenGL extension wrangler
* **Corrade** - Plugin management and utility library. You can get it at * **Corrade** - Plugin management and utility library. You can get it at
http://mosra.cz/blog/corrade.php http://github.com/mosra/corrade or at http://mosra.cz/blog/corrade.php.
Compilation, installation Compilation, installation
------------------------- -------------------------
The library (for example with GLUT context) can be built and installed using The library (for example with GLUT window context) can be built and installed
these four commands: using these four commands:
mkdir -p build && cd build mkdir -p build && cd build
cmake .. \ cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_INSTALL_PREFIX=/usr \
-DWITH_GLUTCONTEXT=ON -DWITH_GLUTWINDOWCONTEXT=ON
make make
make install 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 `-DBUILD_TESTS=True` to CMake. Unit tests use Corrade's TestSuite framework
and can be run using and can be run using
ctest -V ctest --output-on-failure
in build directory. Everything should pass ;-) in build directory. Everything should pass ;-)

29
doc/building.dox

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

42
doc/coding-style.dox

@ -57,7 +57,39 @@ with @c \@extension command:
@extension{ARB,timer_query} @extension{ARB,timer_query}
@endcode @endcode
It produces link to the specification of the extension in OpenGL registry, 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 @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 for some functionality (not related to any member function), it should be
noted in the description. 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 All classes and functions using those commands are cross-referenced in page
@ref required-extensions. @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 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 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 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 @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 - @ref Physics::Point "Physics::Point*D" - @copybrief Physics::Point
- Physics::Line - @copybrief Physics::Line - @ref Physics::Line "Physics::Line*D" - @copybrief Physics::Line
- Physics::LineSegment - @copybrief Physics::LineSegment - @ref Physics::LineSegment "Physics::LineSegment*D" - @copybrief Physics::LineSegment
One-dimensional shapes don't provide collision detection with each other Because of numerical instability it's not possible to detect collisions of
because of numerical instability. 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 - Physics::Plane - @copybrief Physics::Plane
@subsection CollisionDetectionShapes3D Three-dimensional shapes @subsection collision-detection-shapes3D Three-dimensional shapes
- Physics::Sphere - @copybrief Physics::Sphere - @ref Physics::Sphere "Physics::Sphere*D" - @copybrief Physics::Sphere
- Physics::Capsule - @copybrief Physics::Capsule - @ref Physics::Capsule "Physics::Capsule*D" - @copybrief Physics::Capsule
- Physics::AxisAlignedBox - @copybrief Physics::AxisAlignedBox - @ref Physics::AxisAlignedBox "Physics::AxisAlignedBox*D" - @copybrief Physics::AxisAlignedBox
- Physics::Box - @copybrief Physics::Box - @ref Physics::Box "Physics::Box*D" - @copybrief Physics::Box
The easiest (and most efficient) shape combination for detecting collisions The easiest (and most efficient) shape combination for detecting collisions
is point and sphere, followed by two spheres. Computing collision of two boxes is point and sphere, followed by two spheres. Computing collision of two boxes
is least efficient. 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, Shapes can be grouped together using one of three available logical
union, intersection, difference and XOR. These operations are mapped to operations: AND, OR and NOT. These operations are mapped to operator&&(),
operator~(), operator|(), operator&(), operator-() and operator^(), so for operator||() and operator!(), so for example creating negation of logical OR
example creating complement of union of sphere and box is simple as this: of line segment and point is simple as this:
@code @code
Physics::Sphere sphere; Physics::LineSegment3D segment;
Physics::Box box; Physics::Point3D point;
Physics::ShapeGroup group = ~(sphere|box); Physics::ShapeGroup3D group = !(segment || point);
@endcode @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 The resulting object internally stores copies of both shapes, so the original
instances can be destroyed. For simple combinations appropriate resulting instances can be destroyed. For simple combinations appropriate resulting
shape is generated (e.g. intersection of line and three-dimensional object shape is generated (e.g. logical OR of point and sphere can be only the sphere,
can be a line segment) and stored inside ShapeGroup instead of two original if the point lies inside) and stored inside ShapeGroup instead of two original
objects. 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 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 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 recreating the group again. You can, however, explicitly pass a reference to
original object, so you can change it later: original object, so you can change it later:
@code @code
Physics::Sphere sphere; Physics::LineSegment3D segment;
Physics::Box box; 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 @endcode
Note that passing a reference implies that you must not destroy the original 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. 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 If there are many shapes grouped together, it might hurt performance of
collision detection, because it might be testing collision with more shapes collision detection, because it might be testing collision with more shapes
than necessary. It's then good to specify simplified version of such shape, 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 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 - was detected with the simplified shape. It is in fact logical AND using
the collision is initially detected on first (simplified) shape and then on operator&&() - the collision is initially detected on first (simplified) shape
the other: and then on the other:
@code @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 @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 Shape pairs which have collision detection implemented can be tested for
collision using operator%(), for example: collision using operator%(), for example:
@code @code
Physics::Point point; Physics::Point3D point;
Physics::Sphere sphere; Physics::Sphere3D sphere;
bool collide = point % sphere; bool collide = point % sphere;
@endcode @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. %Magnum is 3D graphics engine written in C++11 and OpenGL 3 Core Profile.
Features: Features:
- Easy-to-use templated @ref Math "mathematical library" for matrix/vector - Easy-to-use templated @ref Math "mathematical library" for
calculations and @ref Math::Geometry "geometry". @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 - Hierarchical @ref SceneGraph "scene graph" which supports transformation
caching for better performance, classes for convenient usage of caching for better performance, @ref Physics "physics library" for collision
@ref AbstractShaderProgram "shaders", @ref Buffer "buffers" and detection and rigid body dynamics.
@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.
- Plugin-based @ref Trade "data exchange framework" for importing image, mesh, - Plugin-based @ref Trade "data exchange framework" for importing image, mesh,
material and scene data in various formats. material and scene data in various formats.
- Collection of pre-made @ref Primitives "graphic primitives" and - Collection of pre-made @ref Primitives "graphic primitives" and
@ref Shaders "shaders" for testing purposes. @ref Shaders "shaders" for testing purposes.
- Classes for easy creation of OpenGL context with @ref Contexts - 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 - Comprehensive use of C++11 features for safety, performance and ease of
development. All code which doesn't directly interact with OpenGL is development. All code which doesn't directly interact with OpenGL is
covered with unit tests. 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 @section getting-started Getting started
Applications using %Magnum have at least two parts. One part manages OpenGL To get up and running, you must first subclass one of the provided window
context using some toolkit and takes care of window resizing, mouse and context classes and implement required functions. %Magnum provides
keyboard input, while the other manages the scene and does the rendering. implementations for the most common toolkits (such as GLUT, Xlib, or SDL2) in
While it is possible for you to manage the OpenGL context and events on your Contexts namespace.
own, %Magnum provides implementations for the most common toolkits (such as
GLUT, SDL or Qt) in Contexts namespace. %Scene in %Magnum is composed of Then you can either draw your meshes directly or use SceneGraph which will
hierarchically connected object instances. To build the scene you need Scene help you with object hierarchy, transformations and resource management.
object with assigned camera and at least one Object instance.
@subsection getting-started-examples Tutorials and examples @subsection getting-started-examples Tutorials and examples
The best way to get started is to @ref examples-triangle "render your first triangle" The best way to get started is to render your first triangle in
in step-by-step tutorial. Then you can dig deeper and try @ref example-index @ref example-index "step-by-step tutorial". Then you can dig deeper and try
"other examples", read about fundamental principles in the documentation or other examples, read about @ref features "fundamental principles" in the
start experimenting on your own! documentation or start experimenting on your own!
@subsection getting-started-hacking Hacking Magnum @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 /** @namespace Magnum::Math
@brief %Math library @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 /** @dir Math/Algorithms
@ -89,7 +90,7 @@ Collection of shaders for testing purposes.
/** @namespace Magnum::Physics /** @namespace Magnum::Physics
@brief %Physics library @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. 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 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). supported on Intel GPUs even if they are capable of OpenGL 2.1 only).
- @subpage requires-gl
- @subpage requires-gl30 - @subpage requires-gl30
- @subpage requires-gl31 - @subpage requires-gl31
- @subpage requires-gl32 - @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-gl42
- @subpage requires-gl43 - @subpage requires-gl43
- @subpage requires-extension - @subpage requires-extension
- @subpage requires-gl
- @subpage requires-gles30 - @subpage requires-gles30
- @subpage requires-es-extension - @subpage requires-es-extension
- @subpage unsupported
@page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES) @page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES)
@page requires-gl30 Functionality requiring OpenGL 3.0 @page requires-gl30 Functionality requiring OpenGL 3.0

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

18
src/AbstractImage.cpp

@ -14,8 +14,13 @@
*/ */
#include "AbstractImage.h" #include "AbstractImage.h"
#include <Utility/Debug.h>
#include "TypeTraits.h" #include "TypeTraits.h"
using namespace std;
namespace Magnum { namespace Magnum {
size_t AbstractImage::pixelSize(Components format, ComponentType type) { size_t AbstractImage::pixelSize(Components format, ComponentType type) {
@ -69,6 +74,8 @@ size_t AbstractImage::pixelSize(Components format, ComponentType type) {
switch(format) { switch(format) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
case Components::Red: case Components::Red:
case Components::Green:
case Components::Blue:
return 1*size; return 1*size;
case Components::RedGreen: case Components::RedGreen:
return 2*size; return 2*size;
@ -83,9 +90,16 @@ size_t AbstractImage::pixelSize(Components format, ComponentType type) {
case Components::BGRA: case Components::BGRA:
#endif #endif
return 4*size; 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 * @brief Class Magnum::AbstractImage
*/ */
#include <cstddef>
#include "Magnum.h" #include "Magnum.h"
#include "magnumVisibility.h"
namespace Magnum { namespace Magnum {
/** /**
@ -264,7 +268,7 @@ class MAGNUM_EXPORT AbstractImage {
* @param components Color components * @param components Color components
* @param type Data type * @param type Data type
*/ */
static size_t pixelSize(Components components, ComponentType type); static std::size_t pixelSize(Components components, ComponentType type);
/** /**
* @brief Constructor * @brief Constructor

482
src/AbstractShaderProgram.cpp

@ -17,16 +17,76 @@
#include <fstream> #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 #define LINKER_MESSAGE_MAX_LENGTH 1024
using namespace std; using namespace std;
namespace Magnum { 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() { bool AbstractShaderProgram::use() {
if(state != Linked) return false; 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; return true;
} }
@ -34,26 +94,26 @@ bool AbstractShaderProgram::attachShader(Shader& shader) {
GLuint _shader = shader.compile(); GLuint _shader = shader.compile();
if(!_shader) return false; if(!_shader) return false;
glAttachShader(program, _shader); glAttachShader(_id, _shader);
return true; return true;
} }
void AbstractShaderProgram::bindAttributeLocation(GLuint location, const string& name) { void AbstractShaderProgram::bindAttributeLocation(GLuint location, const string& name) {
CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: attribute cannot be bound after linking.", ); CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: attribute cannot be bound after linking.", );
glBindAttribLocation(program, location, name.c_str()); glBindAttribLocation(_id, location, name.c_str());
} }
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::bindFragmentDataLocation(GLuint location, const std::string& name) { void AbstractShaderProgram::bindFragmentDataLocation(GLuint location, const std::string& name) {
CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", ); CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", );
glBindFragDataLocation(program, location, name.c_str()); glBindFragDataLocation(_id, location, name.c_str());
} }
void AbstractShaderProgram::bindFragmentDataLocationIndexed(GLuint location, GLuint index, const std::string& name) { void AbstractShaderProgram::bindFragmentDataLocationIndexed(GLuint location, GLuint index, const std::string& name) {
CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", ); CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", );
glBindFragDataLocationIndexed(program, location, index, name.c_str()); glBindFragDataLocationIndexed(_id, location, index, name.c_str());
} }
#endif #endif
@ -62,15 +122,15 @@ void AbstractShaderProgram::link() {
if(state != Initialized) return; if(state != Initialized) return;
/* Link shader program */ /* Link shader program */
glLinkProgram(program); glLinkProgram(_id);
/* Check link status */ /* Check link status */
GLint status; GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status); glGetProgramiv(_id, GL_LINK_STATUS, &status);
/* Display errors or warnings */ /* Display errors or warnings */
char message[LINKER_MESSAGE_MAX_LENGTH]; 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 */ /* Show error log and delete shader */
if(status == GL_FALSE) { if(status == GL_FALSE) {
@ -90,10 +150,414 @@ GLint AbstractShaderProgram::uniformLocation(const std::string& name) {
/** @todo What if linking just failed (not programmer error?) */ /** @todo What if linking just failed (not programmer error?) */
CORRADE_ASSERT(state == Linked, "AbstractShaderProgram: uniform location cannot be retrieved before linking.", -1); CORRADE_ASSERT(state == Linked, "AbstractShaderProgram: uniform location cannot be retrieved before linking.", -1);
GLint location = glGetUniformLocation(program, name.c_str()); GLint location = glGetUniformLocation(_id, name.c_str());
if(location == -1) if(location == -1)
Warning() << "AbstractShaderProgram: location of uniform \'" + name + "\' cannot be retrieved!"; Warning() << "AbstractShaderProgram: location of uniform \'" + name + "\' cannot be retrieved!";
return location; 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 "AbstractTexture.h"
#include "Context.h"
#include "Extensions.h"
#include "Implementation/State.h"
#include "Implementation/TextureState.h"
namespace Magnum { 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 #ifndef DOXYGEN_GENERATING_OUTPUT
/* Check correctness of binary OR in setMinificationFilter(). If nobody fucks /* Check correctness of binary OR in setMinificationFilter(). If nobody fucks
@ -35,40 +67,253 @@ static_assert((filter_or(NearestNeighbor, BaseLevel) == GL_NEAREST) &&
#endif #endif
GLint AbstractTexture::maxSupportedLayerCount() { GLint AbstractTexture::maxSupportedLayerCount() {
GLint value; return Context::current()->state()->texture->maxSupportedLayerCount;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &value);
return value;
} }
#ifndef MAGNUM_TARGET_GLES
GLfloat AbstractTexture::maxSupportedAnisotropy() { GLfloat AbstractTexture::maxSupportedAnisotropy() {
GLfloat value; GLfloat& value = Context::current()->state()->texture->maxSupportedAnisotropy;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &value);
/** @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; 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 #endif
void AbstractTexture::setMinificationFilter(Filter filter, Mipmap mipmap) { AbstractTexture* AbstractTexture::setMinificationFilter(Filter filter, Mipmap mipmap) {
#ifndef MAGNUM_TARGET_GLES #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 #endif
bind(); (this->*parameteriImplementation)(GL_TEXTURE_MIN_FILTER,
glTexParameteri(_target, GL_TEXTURE_MIN_FILTER,
static_cast<GLint>(filter)|static_cast<GLint>(mipmap)); static_cast<GLint>(filter)|static_cast<GLint>(mipmap));
return this;
} }
void AbstractTexture::generateMipmap() { AbstractTexture* AbstractTexture::generateMipmap() {
#ifndef MAGNUM_TARGET_GLES #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 #endif
bind(); (this->*mipmapImplementation)();
return this;
}
void AbstractTexture::mipmapImplementationDefault() {
bindInternal();
glGenerateMipmap(_target); glGenerateMipmap(_target);
} }
#ifndef MAGNUM_TARGET_GLES #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) { AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components components, AbstractTexture::ComponentType type) {
#ifndef MAGNUM_TARGET_GLES
#define internalFormatSwitch(c) switch(type) { \ #define internalFormatSwitch(c) switch(type) { \
case ComponentType::UnsignedByte: \ case ComponentType::UnsignedByte: \
internalFormat = GL_##c##8UI; break; \ internalFormat = GL_##c##8UI; break; \
@ -95,6 +340,30 @@ AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components comp
case ComponentType::NormalizedShort: \ case ComponentType::NormalizedShort: \
internalFormat = GL_##c##16_SNORM; break; \ 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) if(components == Components::Red)
internalFormatSwitch(R) internalFormatSwitch(R)
else if(components == Components::RedGreen) else if(components == Components::RedGreen)
@ -105,23 +374,22 @@ AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components comp
internalFormatSwitch(RGBA) internalFormatSwitch(RGBA)
#undef internalFormatSwitch #undef internalFormatSwitch
} }
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT #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 #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 #endif
glTexParameteri(target, GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping[0])); (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping.x()));
glTexParameteri(target, GL_TEXTURE_WRAP_T, static_cast<GLint>(wrapping[1])); (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_T, static_cast<GLint>(wrapping.y()));
} }
void AbstractTexture::DataHelper<3>::setWrapping(GLenum target, const Math::Vector<3, Wrapping>& wrapping) { void AbstractTexture::DataHelper<3>::setWrapping(AbstractTexture* texture, const Math::Vector3<Wrapping>& wrapping) {
glTexParameteri(target, GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping[0])); (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping.x()));
glTexParameteri(target, GL_TEXTURE_WRAP_T, static_cast<GLint>(wrapping[1])); (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_T, static_cast<GLint>(wrapping.y()));
#ifndef MAGNUM_TARGET_GLES #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
} }
#endif #endif

365
src/AbstractTexture.h

@ -19,11 +19,16 @@
* @brief Class Magnum::AbstractTexture * @brief Class Magnum::AbstractTexture
*/ */
#include <cstdint>
#include "Magnum.h" #include "Magnum.h"
#include "Color.h" #include "Color.h"
#include "AbstractImage.h"
namespace Magnum { namespace Magnum {
class Context;
/** /**
@brief Base for textures @brief Base for textures
@ -40,10 +45,33 @@ AbstractShaderProgram::setUniform(GLint, GLint).
See Texture, CubeMapTexture and CubeMapTextureArray documentation for more See Texture, CubeMapTexture and CubeMapTextureArray documentation for more
information. 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 Add glPixelStore encapsulation
@todo Texture copying @todo Texture copying
*/ */
class MAGNUM_EXPORT AbstractTexture { class MAGNUM_EXPORT AbstractTexture {
friend class Context;
AbstractTexture(const AbstractTexture& other) = delete; AbstractTexture(const AbstractTexture& other) = delete;
AbstractTexture(AbstractTexture&& other) = delete; AbstractTexture(AbstractTexture&& other) = delete;
AbstractTexture& operator=(const 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 * Clamp to border color. Coordinates out of range will be clamped
* to border color (set with setBorderColor()). * to border color (set with setBorderColor()).
* @requires_gl * @requires_gl Texture border is not available in OpenGL ES.
*/ */
ClampToBorder = GL_CLAMP_TO_BORDER ClampToBorder = GL_CLAMP_TO_BORDER
#endif #endif
@ -113,10 +141,10 @@ class MAGNUM_EXPORT AbstractTexture {
/** @{ @name Internal texture formats */ /** @{ @name Internal texture formats */
#ifndef MAGNUM_TARGET_GLES
/** /**
* @brief Color components * @brief Color components
* @requires_gl *
* @requires_gles30 (no extension providing this functionality)
*/ */
enum class Components { enum class Components {
/** /**
@ -142,7 +170,7 @@ class MAGNUM_EXPORT AbstractTexture {
* *
* `NormalizedUnsignedByte` and `NormalizedUnsignedShort` are the * `NormalizedUnsignedByte` and `NormalizedUnsignedShort` are the
* main ones for general usage. * main ones for general usage.
* @requires_gl * @requires_gles30 (no extension providing this functionality)
*/ */
enum class ComponentType { enum class ComponentType {
/** /**
@ -206,20 +234,23 @@ class MAGNUM_EXPORT AbstractTexture {
*/ */
NormalizedByte, NormalizedByte,
#ifndef MAGNUM_TARGET_GLES
/** /**
* Normalized unsigned short, i.e. values from range @f$ [0; 65536] @f$ * Normalized unsigned short, i.e. values from range @f$ [0; 65536] @f$
* are converted to range @f$ [0.0; 1.0] @f$. * are converted to range @f$ [0.0; 1.0] @f$.
* @requires_gl
*/ */
NormalizedUnsignedShort, NormalizedUnsignedShort,
/** /**
* Normalized signed short, i.e. values from range @f$ [-32768; 32767] @f$ * Normalized signed short, i.e. values from range @f$ [-32768; 32767] @f$
* are converted to range @f$ [-1.0; 1.0] @f$. * are converted to range @f$ [-1.0; 1.0] @f$.
* @requires_gl
* @requires_gl31 Extension @extension{EXT,texture_snorm} * @requires_gl31 Extension @extension{EXT,texture_snorm}
*/ */
NormalizedShort NormalizedShort
#endif
}; };
#endif
/** /**
* @brief Internal format * @brief Internal format
@ -228,23 +259,21 @@ class MAGNUM_EXPORT AbstractTexture {
* normalization see enums Components and ComponentType. * normalization see enums Components and ComponentType.
*/ */
enum class Format: GLenum { enum class Format: GLenum {
#ifndef MAGNUM_TARGET_GLES
/** /**
* One-component (red channel), unsigned normalized, probably * One-component (red channel), unsigned normalized, probably
* 8bit. * 8bit.
* @requires_gl
* @requires_gl30 Extension @extension{ARB,texture_rg} * @requires_gl30 Extension @extension{ARB,texture_rg}
* @requires_gles30 (no extension providing this functionality)
*/ */
Red = GL_RED, Red = GL_RED,
/** /**
* Two-component (red and green channel), unsigned normalized, * Two-component (red and green channel), unsigned normalized,
* each component probably 8bit, 16bit total. * each component probably 8bit, 16bit total.
* @requires_gl
* @requires_gl30 Extension @extension{ARB,texture_rg} * @requires_gl30 Extension @extension{ARB,texture_rg}
* @requires_gles30 (no extension providing this functionality)
*/ */
RedGreen = GL_RG, RedGreen = GL_RG,
#endif
/** /**
* Three-component RGB, unsigned normalized, each component * Three-component RGB, unsigned normalized, each component
@ -278,36 +307,36 @@ class MAGNUM_EXPORT AbstractTexture {
* @requires_gl * @requires_gl
*/ */
BGRA = GL_BGRA, BGRA = GL_BGRA,
#endif
/** /**
* Four-component sRGBA, unsigned normalized, each component * Four-component sRGBA, unsigned normalized, each component
* 8bit, 32bit total. * 8bit, 32bit total.
* @requires_gl * @requires_gles30 (no extension providing this functionality)
*/ */
SRGBA8 = GL_SRGB8_ALPHA8, SRGBA8 = GL_SRGB8_ALPHA8,
/** /**
* Three-component sRGB, unsigned normalized, each component * Three-component sRGB, unsigned normalized, each component
* 8bit, 24bit total. * 8bit, 24bit total.
* @requires_gl * @requires_gles30 (no extension providing this functionality)
*/ */
SRGB8 = GL_SRGB8, SRGB8 = GL_SRGB8,
/** /**
* Four-component RGBA, unsigned normalized, each RGB component * Four-component RGBA, unsigned normalized, each RGB component
* 10bit, alpha 2bit, 32bit total. * 10bit, alpha 2bit, 32bit total.
* @requires_gl * @requires_gles30 (no extension providing this functionality)
*/ */
RGB10Alpha2 = GL_RGB10_A2, RGB10Alpha2 = GL_RGB10_A2,
/** /**
* Four-component RGBA, unsigned non-normalized, each RGB * Four-component RGBA, unsigned non-normalized, each RGB
* component 10bit, alpha channel 2bit, 32bit total. * component 10bit, alpha channel 2bit, 32bit total.
* @requires_gl
* @requires_gl33 Extension @extension{ARB,texture_rgb10_a2ui} * @requires_gl33 Extension @extension{ARB,texture_rgb10_a2ui}
* @requires_gles30 (no extension providing this functionality)
*/ */
RGB10Alpha2Unsigned = GL_RGB10_A2UI, RGB10Alpha2Unsigned = GL_RGB10_A2UI,
#endif
/** /**
* Four-component RGBA, unsigned normalized, each RGB component * Four-component RGBA, unsigned normalized, each RGB component
@ -319,41 +348,35 @@ class MAGNUM_EXPORT AbstractTexture {
* Four-component RGBA, unsigned normalized, each component 4bit, * Four-component RGBA, unsigned normalized, each component 4bit,
* 16bit total. * 16bit total.
*/ */
RGBA4 = GL_RGBA4 RGBA4 = GL_RGBA4,
#ifndef MAGNUM_TARGET_GLES
,
/** /**
* Three-component RGB, float, red and green 11bit, blue 10bit, * Three-component RGB, float, red and green 11bit, blue 10bit,
* 32bit total. * 32bit total.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,packed_float} * @requires_gl30 Extension @extension{EXT,packed_float}
* @requires_gles30 (no extension providing this functionality)
*/ */
RG11B10Float = GL_R11F_G11F_B10F RG11B10Float = GL_R11F_G11F_B10F,
#endif
/* 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) #if defined(GL_RGB565) || defined(DOXYGEN_GENERATING_OUTPUT)
,
/** /**
* Three-component RGB, unsigned normalized, red and blue 5bit, * Three-component RGB, unsigned normalized, red and blue 5bit,
* green 6bit, 16bit total. * green 6bit, 16bit total.
*/ */
RGB565 = GL_RGB565 RGB565 = GL_RGB565,
#endif #endif
#ifndef MAGNUM_TARGET_GLES
,
/** /**
* Three-component RGB, unsigned with exponent, each component * Three-component RGB, unsigned with exponent, each component
* 9bit, exponent 5bit, 32bit total. * 9bit, exponent 5bit, 32bit total.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,texture_shared_exponent} * @requires_gl30 Extension @extension{EXT,texture_shared_exponent}
* @requires_gles30 (no extension providing this functionality)
*/ */
RGB9Exponent5 = GL_RGB9_E5, RGB9Exponent5 = GL_RGB9_E5,
#ifndef MAGNUM_TARGET_GLES
/** /**
* Compressed red channel, unsigned normalized. * Compressed red channel, unsigned normalized.
* @requires_gl * @requires_gl
@ -408,35 +431,39 @@ class MAGNUM_EXPORT AbstractTexture {
*/ */
CompressedRtgcSignedRedGreen = GL_COMPRESSED_SIGNED_RG_RGTC2, 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. * BPTC compressed RGBA, unsigned normalized.
* @requires_gl * @requires_gl
* @requires_gl42 Extension @extension{ARB,texture_compression_bptc} * @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. * BPTC compressed sRGBA, unsigned normalized.
* @requires_gl * @requires_gl
* @requires_gl42 Extension @extension{ARB,texture_compression_bptc} * @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. * BPTC compressed RGB, signed float.
* @requires_gl * @requires_gl
* @requires_gl42 Extension @extension{ARB,texture_compression_bptc} * @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. * BPTC compressed RGB, unsigned float.
* @requires_gl * @requires_gl
* @requires_gl42 Extension @extension{ARB,texture_compression_bptc} * @requires_gl42 Extension @extension{ARB,texture_compression_bptc}
*/ */
CompressedBptcRGBUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, CompressedBptcRGBUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB,
#endif
/*}*/
/** /**
* Depth component, at least 16bit. * Depth component, at least 16bit.
@ -456,40 +483,40 @@ class MAGNUM_EXPORT AbstractTexture {
* @requires_gl * @requires_gl
*/ */
DepthStencil = GL_DEPTH_STENCIL, DepthStencil = GL_DEPTH_STENCIL,
#endif
/** /**
* 16bit depth component. * 16bit depth component.
* @requires_gl * @requires_gles30 (no extension providing this functionality)
*/ */
Depth16 = GL_DEPTH_COMPONENT16, Depth16 = GL_DEPTH_COMPONENT16,
/** /**
* 24bit depth component. * 24bit depth component.
* @requires_gl * @requires_gles30 (no extension providing this functionality)
*/ */
Depth24 = GL_DEPTH_COMPONENT24, Depth24 = GL_DEPTH_COMPONENT24,
/** /**
* 32bit float depth component. * 32bit float depth component.
* @requires_gl
* @requires_gl30 Extension @extension{ARB,depth_buffer_float} * @requires_gl30 Extension @extension{ARB,depth_buffer_float}
* @requires_gles30 (no extension providing this functionality)
*/ */
Depth32Float = GL_DEPTH_COMPONENT32F, Depth32Float = GL_DEPTH_COMPONENT32F,
/** /**
* 24bit depth and 8bit stencil component. * 24bit depth and 8bit stencil component.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,packed_depth_stencil} * @requires_gl30 Extension @extension{EXT,packed_depth_stencil}
* @requires_gles30 (no extension providing this functionality)
*/ */
Depth24Stencil8 = GL_DEPTH24_STENCIL8, Depth24Stencil8 = GL_DEPTH24_STENCIL8,
/** /**
* 32bit float depth component and 8bit stencil component. * 32bit float depth component and 8bit stencil component.
* @requires_gl
* @requires_gl30 Extension @extension{ARB,depth_buffer_float} * @requires_gl30 Extension @extension{ARB,depth_buffer_float}
* @requires_gles30 (no extension providing this functionality)
*/ */
Depth32FloatStencil8 = GL_DEPTH32F_STENCIL8 Depth32FloatStencil8 = GL_DEPTH32F_STENCIL8
#endif
}; };
/** /**
@ -510,14 +537,12 @@ class MAGNUM_EXPORT AbstractTexture {
*/ */
class MAGNUM_EXPORT InternalFormat { class MAGNUM_EXPORT InternalFormat {
public: public:
#ifndef MAGNUM_TARGET_GLES
/** /**
* @brief Constructor from component count and data type per component * @brief Constructor from component count and data type per component
* *
* @requires_gl * @requires_gles30 (no extension providing this functionality)
*/ */
InternalFormat(Components components, ComponentType type); InternalFormat(Components components, ComponentType type);
#endif
/** @brief Constructor from named internal format */ /** @brief Constructor from named internal format */
inline constexpr InternalFormat(Format format): internalFormat(static_cast<GLint>(format)) {} inline constexpr InternalFormat(Format format): internalFormat(static_cast<GLint>(format)) {}
@ -534,52 +559,54 @@ class MAGNUM_EXPORT AbstractTexture {
/** /**
* @brief Max supported layer count * @brief Max supported layer count
* *
* At least 48. * @see bind(GLint), @fn_gl{Get} with @def_gl{MAX_COMBINED_TEXTURE_IMAGE_UNITS},
* @see bind(GLint) * @fn_gl{ActiveTexture}
*/ */
static GLint maxSupportedLayerCount(); static GLint maxSupportedLayerCount();
#ifndef MAGNUM_TARGET_GLES
/** /**
* @brief Max supported anisotropy * @brief Max supported anisotropy
* *
* @see setMaxAnisotropy() * @see setMaxAnisotropy(), @fn_gl{Get} with @def_gl{MAX_TEXTURE_MAX_ANISOTROPY_EXT}
* @requires_extension @extension{EXT,texture_filter_anisotropic} * @requires_extension %Extension @extension{EXT,texture_filter_anisotropic}
* @requires_es_extension %Extension @es_extension2{EXT,texture_filter_anisotropic,texture_filter_anisotropic}
*/ */
static GLfloat maxSupportedAnisotropy(); static GLfloat maxSupportedAnisotropy();
#endif
/** /**
* @brief Constructor * @brief Constructor
* @param target Target, e.g. `GL_TEXTURE_2D`. * @param target Target, e.g. `GL_TEXTURE_2D`.
* *
* Creates one OpenGL texture. * Creates one OpenGL texture.
* @see @fn_gl{GenTextures}
*/ */
inline AbstractTexture(GLenum target): _target(target) { inline AbstractTexture(GLenum target): _target(target) {
glGenTextures(1, &texture); glGenTextures(1, &_id);
} }
/** /**
* @brief Destructor * @brief Destructor
* *
* Deletes assigned OpenGL texture. * Deletes assigned OpenGL texture.
* @see @fn_gl{DeleteTextures}
*/ */
virtual ~AbstractTexture() = 0; virtual ~AbstractTexture() = 0;
/** @brief OpenGL internal texture ID */ /** @brief OpenGL texture ID */
inline GLuint id() const { return texture; } inline GLuint id() const { return _id; }
/** /**
* @brief Bind texture for rendering * @brief Bind texture for rendering
* *
* Sets current texture as active in given layer. The layer must be * Sets current texture as active in given layer. The layer must be
* between 0 and maxSupportedLayerCount(). Note that only one texture * 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) { void bind(GLint layer);
glActiveTexture(GL_TEXTURE0 + layer);
bind();
}
/** /**
* @brief Set minification filter * @brief Set minification filter
@ -587,92 +614,185 @@ class MAGNUM_EXPORT AbstractTexture {
* @param mipmap Mipmap filtering. If set to anything else than * @param mipmap Mipmap filtering. If set to anything else than
* BaseMipLevel, make sure textures for all mip levels are set or * BaseMipLevel, make sure textures for all mip levels are set or
* call generateMipmap(). * call generateMipmap().
* @return Pointer to self (for method chaining)
* *
* Sets filter used when the object pixel size is smaller than the * 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, * @attention For rectangle textures only some modes are supported,
* see @ref AbstractTexture::Filter "Filter" and * see @ref AbstractTexture::Filter "Filter" and
* @ref AbstractTexture::Mipmap "Mipmap" documentation for more * @ref AbstractTexture::Mipmap "Mipmap" documentation for more
* information. * 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 * @brief Set magnification filter
* @param filter Filter * @param filter Filter
* @return Pointer to self (for method chaining)
* *
* Sets filter used when the object pixel size is larger than largest * 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) { inline AbstractTexture* setMagnificationFilter(Filter filter) {
bind(); (this->*parameteriImplementation)(GL_TEXTURE_MAG_FILTER, static_cast<GLint>(filter));
glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(filter)); return this;
} }
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
/** /**
* @brief Set border color * @brief Set border color
* @return Pointer to self (for method chaining)
* *
* Border color when @ref AbstractTexture::Wrapping "wrapping" is set * Border color when @ref AbstractTexture::Wrapping "wrapping" is set
* to `ClampToBorder`. * to `ClampToBorder`. If @extension{EXT,direct_state_access} is not
* @requires_gl * 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) { inline AbstractTexture* setBorderColor(const Color4<GLfloat>& color) {
bind(); (this->*parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR, color.data());
glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, color.data()); return this;
} }
#endif
/** /**
* @brief Set max anisotropy * @brief Set max anisotropy
* @return Pointer to self (for method chaining)
* *
* Default value is `1.0`, which means no anisotropy. Set to value * Default value is `1.0f`, which means no anisotropy. Set to value
* greater than `1.0` for anisotropic filtering. * greater than `1.0f` for anisotropic filtering. If
* @see maxSupportedAnisotropy() * @extension{EXT,direct_state_access} is not available, the texture
* @requires_extension @extension{EXT,texture_filter_anisotropic} * 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) { inline AbstractTexture* setMaxAnisotropy(GLfloat anisotropy) {
bind(); /** @todo Remove `ifndef` when extension header is available */
glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); #ifndef MAGNUM_TARGET_GLES
(this->*parameterfImplementation)(GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
#else
static_cast<void>(anisotropy);
#endif
return this;
} }
#endif
/** /**
* @brief Generate mipmap * @brief Generate mipmap
* @return Pointer to self (for method chaining)
* *
* Can not be used for rectangle textures. * Can not be used for rectangle textures. If
* @see setMinificationFilter() * @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} * @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/ */
void generateMipmap(); AbstractTexture* generateMipmap();
protected: protected:
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
template<size_t textureDimensions> struct DataHelper {}; template<std::uint8_t textureDimensions> struct DataHelper {};
#endif
const GLenum _target; /**< @brief Target */ /* Unlike bind() this also sets the binding layer as active */
void MAGNUM_LOCAL bindInternal();
/** const GLenum _target;
* @brief Bind texture for parameter modification #endif
*
* Unlike bind(GLint) doesn't bind the texture to any particular
* layer, thus unusable for binding for rendering.
*/
inline void bind() {
glBindTexture(_target, texture);
}
private: 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 /** @relates AbstractTexture
@brief Convertor of component count and data type to InternalFormat @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) { inline AbstractTexture::InternalFormat operator|(AbstractTexture::Components components, AbstractTexture::ComponentType type) {
return AbstractTexture::InternalFormat(components, 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) { inline AbstractTexture::InternalFormat operator|(AbstractTexture::ComponentType type, AbstractTexture::Components components) {
return AbstractTexture::InternalFormat(components, type); return AbstractTexture::InternalFormat(components, type);
} }
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
@ -695,16 +814,16 @@ template<> struct AbstractTexture::DataHelper<1> {
inline constexpr static Target target() { return Target::Texture1D; } inline constexpr static Target target() { return Target::Texture1D; }
inline static void setWrapping(GLenum target, const Math::Vector<1, Wrapping>& wrapping) { inline static void setWrapping(AbstractTexture* texture, const Math::Vector<1, Wrapping>& wrapping) {
glTexParameteri(target, GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping[0])); (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) { 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) {
glTexImage1D(target, mipLevel, internalFormat, image->dimensions()[0], 0, static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data()); (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) { 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) {
glTexSubImage1D(target, mipLevel, offset[0], image->dimensions()[0], static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data()); (texture->*subImage1DImplementation)(target, mipLevel, offset, image->size(), image->components(), image->type(), image->data());
} }
}; };
#endif #endif
@ -720,47 +839,41 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> {
inline constexpr static Target target() { return Target::Texture2D; } 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) { 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) {
glTexImage2D(target, mipLevel, internalFormat, image->dimensions()[0], image->dimensions()[1], 0, static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data()); (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) { 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) {
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()); (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) { 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) {
glTexSubImage2D(target, mipLevel, offset[0], offset[1], image->dimensions()[0], 1, static_cast<GLenum>(image->components()), static_cast<GLenum>(image->type()), image->data()); (texture->*subImage2DImplementation)(target, mipLevel, offset, Math::Vector2<GLint>(image->size(), 1), image->components(), image->type(), image->data());
} }
}; };
template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> {
enum class Target: GLenum { enum class Target: GLenum {
#ifndef MAGNUM_TARGET_GLES
Texture3D = GL_TEXTURE_3D, Texture3D = GL_TEXTURE_3D,
Texture2DArray = GL_TEXTURE_2D_ARRAY Texture2DArray = GL_TEXTURE_2D_ARRAY
#endif
}; };
#ifndef MAGNUM_TARGET_GLES
inline constexpr static Target target() { return Target::Texture3D; } 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(AbstractTexture* texture, GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) {
template<class Image> inline static typename std::enable_if<Image::Dimensions == 3, void>::type set(GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) { (texture->*image3DImplementation)(target, mipLevel, internalFormat, image->size(), image->components(), image->type(), image->data());
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 setSub(GLenum target, GLint mipLevel, const Math::Vector<3, GLint>& offset, Image* image) { 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) {
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()); (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) { 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) {
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()); (texture->*subImage3DImplementation)(target, mipLevel, offset, Math::Vector3<GLint>(image->size(), 1), image->components(), image->type(), image->data());
} }
#endif
}; };
#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 * @brief Class Magnum::Buffer
*/ */
#include <cstddef>
#include <array>
#include <vector>
#include "Magnum.h" #include "Magnum.h"
#include "magnumVisibility.h"
namespace Magnum { 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 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(const Buffer& other) = delete;
Buffer(Buffer&& other) = delete; Buffer(Buffer&& other) = delete;
Buffer& operator=(const Buffer& other) = delete; Buffer& operator=(const Buffer& other) = delete;
Buffer& operator=(Buffer&& other) = delete; Buffer& operator=(Buffer&& other) = delete;
public: public:
/** @brief %Buffer target */ /**
* @brief %Buffer target
*
* @see bind(Target), unbind(Target)
*/
enum class Target: GLenum { enum class Target: GLenum {
/** Used for storing vertex attributes. */ /** Used for storing vertex attributes. */
Array = GL_ARRAY_BUFFER, Array = GL_ARRAY_BUFFER,
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
/** /**
* Source for copies. * Used for storing atomic counters.
* @requires_gl * @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_gl31 Extension @extension{ARB,copy_buffer}
* @requires_gles30 Buffer copying is not available in OpenGL ES
* 2.0.
*/ */
CopyRead = GL_COPY_READ_BUFFER, CopyRead = GL_COPY_READ_BUFFER,
/** /**
* Target for copies. * Target for copies. See copy().
* @requires_gl
* @requires_gl31 Extension @extension{ARB,copy_buffer} * @requires_gl31 Extension @extension{ARB,copy_buffer}
* @requires_gles30 Buffer copying is not available in OpenGL ES
* 2.0.
*/ */
CopyWrite = GL_COPY_WRITE_BUFFER, 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 #endif
/** Used for storing vertex indices. */ /** 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. * 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, PixelUnpack = GL_PIXEL_UNPACK_BUFFER,
#ifndef MAGNUM_TARGET_GLES
/** /**
* Target for pixel pack operations. * Used for shader storage.
* @requires_gl * @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. * Source for texel fetches. See BufferedTexture.
*
* @see BufferedTexture
* @requires_gl
* @requires_gl31 Extension @extension{ARB,texture_buffer_object} * @requires_gl31 Extension @extension{ARB,texture_buffer_object}
* @requires_gl Texture buffers are not available in OpenGL ES.
*/ */
Texture = GL_TEXTURE_BUFFER, Texture = GL_TEXTURE_BUFFER,
#endif
/** /**
* Target for transform feedback. * Target for transform feedback.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,transform_feedback} * @requires_gl30 Extension @extension{EXT,transform_feedback}
* @requires_gles30 Transform feedback is not available in OpenGL
* ES 2.0.
*/ */
TransformFeedback = GL_TRANSFORM_FEEDBACK_BUFFER, TransformFeedback = GL_TRANSFORM_FEEDBACK_BUFFER,
/** /**
* Used for storing uniforms. * Used for storing uniforms.
* @requires_gl
* @requires_gl31 Extension @extension{ARB,uniform_buffer_object} * @requires_gl31 Extension @extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
*/ */
Uniform = GL_UNIFORM_BUFFER, 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
}; };
/** @brief Buffer usage */ /**
* @brief %Buffer usage
*
* @see setData(GLsizeiptr, const GLvoid*, Usage)
*/
enum class Usage: GLenum { enum class Usage: GLenum {
/** /**
* Set once by the application and used infrequently for drawing. * Set once by the application and used infrequently for drawing.
*/ */
StreamDraw = GL_STREAM_DRAW, StreamDraw = GL_STREAM_DRAW,
#ifndef MAGNUM_TARGET_GLES
/** /**
* Set once as output from an OpenGL command and used infequently * Set once as output from an OpenGL command and used infequently
* for drawing. * for drawing.
* @requires_gl * @requires_gles30 Only @ref Magnum::Buffer::Usage "Usage::StreamDraw"
* is available in OpenGL ES 2.0.
*/ */
StreamRead = GL_STREAM_READ, StreamRead = GL_STREAM_READ,
/** /**
* Set once as output from an OpenGL command and used infrequently * Set once as output from an OpenGL command and used infrequently
* for drawing or copying to other buffers. * 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, StreamCopy = GL_STREAM_COPY,
#endif
/** /**
* Set once by the application and used frequently for drawing. * Set once by the application and used frequently for drawing.
*/ */
StaticDraw = GL_STATIC_DRAW, StaticDraw = GL_STATIC_DRAW,
#ifndef MAGNUM_TARGET_GLES
/** /**
* Set once as output from an OpenGL command and queried many * Set once as output from an OpenGL command and queried many
* times by the application. * 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, StaticRead = GL_STATIC_READ,
/** /**
* Set once as output from an OpenGL command and used frequently * Set once as output from an OpenGL command and used frequently
* for drawing or copying to other buffers. * 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, StaticCopy = GL_STATIC_COPY,
#endif
/** /**
* Updated frequently by the application and used frequently * Updated frequently by the application and used frequently
* for drawing or copying to other images. * for drawing or copying to other images.
*/ */
DynamicDraw = GL_DYNAMIC_DRAW DynamicDraw = GL_DYNAMIC_DRAW,
#ifndef MAGNUM_TARGET_GLES
,
/** /**
* Updated frequently as output from OpenGL command and queried * Updated frequently as output from OpenGL command and queried
* many times from the application. * 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, DynamicRead = GL_DYNAMIC_READ,
/** /**
* Updated frequently as output from OpenGL command and used * Updated frequently as output from OpenGL command and used
* frequently for drawing or copying to other images. * 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 DynamicCopy = GL_DYNAMIC_COPY
#endif
}; };
/** /**
* @brief Unbind any buffer from given target * @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) { inline static void copy(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
glBindBuffer(static_cast<GLenum>(target), 0); copyImplementation(read, write, readOffset, writeOffset, size);
} }
#endif
/** /**
* @brief Constructor * @brief Constructor
* @param defaultTarget Default target (used when calling bind()
* without parameter)
* *
* Generates new OpenGL buffer. * Generates new OpenGL buffer.
* @see @fn_gl{GenBuffers}
*/ */
inline Buffer(Target defaultTarget): _defaultTarget(defaultTarget) { inline Buffer(): _targetHint(Target::Array) {
glGenBuffers(1, &buffer); glGenBuffers(1, &_id);
} }
/** /**
* @brief Destructor * @brief Destructor
* *
* Deletes associated OpenGL buffer. * Deletes associated OpenGL buffer.
* @see @fn_gl{DeleteBuffers}
*/ */
inline virtual ~Buffer() { virtual ~Buffer();
glDeleteBuffers(1, &buffer);
}
/** @brief Default bind type */ /** @brief OpenGL buffer ID */
inline Target defaultTarget() const { return _defaultTarget; } inline GLuint id() const { return _id; }
/** @brief OpenGL internal buffer ID */ /** @brief Target hint */
inline GLuint id() const { return buffer; } 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 * @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) { inline void bind(Target target) { bind(target, _id); }
glBindBuffer(static_cast<GLenum>(target), buffer);
}
/** /**
* @brief Set buffer data * @brief Set buffer data
@ -231,10 +347,14 @@ class Buffer {
* @param data Pointer to data * @param data Pointer to data
* @param usage %Buffer usage * @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) { 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 data Fixed-size array with data
* @param usage %Buffer usage * @param usage %Buffer usage
* *
* Sets buffer data with default target. More convenient for setting * @see setData(GLsizeiptr, const GLvoid*, Usage).
* data from fixed-size arrays than
* setData(GLsizeiptr, const GLvoid*, Usage).
*/ */
template<size_t size, class T> inline void setData(const T(&data)[size], Usage usage) { template<std::size_t size, class T> inline void setData(const T(&data)[size], Usage usage) {
setData(_defaultTarget, data, usage); setData(size*sizeof(T), data, usage);
} }
/** /**
@ -255,121 +373,91 @@ class Buffer {
* @param data Vector with data * @param data Vector with data
* @param usage %Buffer usage * @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) { 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);
} }
/** /** @overload */
* @brief Set buffer data template<std::size_t size, class T> inline void setData(const std::array<T, size>& data, Usage usage) {
* @param target %Target setData(data.size()*sizeof(T), data.data(), usage);
* @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);
} }
/** /**
* @brief Set buffer subdata * @brief Set buffer subdata
* @param offset Offset * @param offset Offset in the buffer
* @param size Data size * @param size Data size
* @param data Pointer to data * @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) { inline void setSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data) {
setSubData(_defaultTarget, offset, size, data); (this->*setSubDataImplementation)(offset, size, data);
} }
/** /**
* @brief Set buffer subdata * @brief Set buffer subdata
* @param offset Offset * @param offset Offset in the buffer
* @param data Fixed-size array with data * @param data Fixed-size array with data
* *
* Sets buffer subdata with default target. More convenient for * @see setSubData(GLintptr, GLsizeiptr, const GLvoid*)
* setting data from fixed-size arrays than
* setSubData(GLintptr, GLsizeiptr, const GLvoid*).
*/ */
template<size_t size, class T> inline void setSubData(GLintptr offset, const T(&data)[size]) { template<std::size_t size, class T> inline void setSubData(GLintptr offset, const T(&data)[size]) {
setSubData(_defaultTarget, offset, data); setSubData(offset, size*sizeof(T), data);
} }
/** /**
* @brief Set buffer subdata * @brief Set buffer subdata
* @param offset Offset * @param offset Offset in the buffer
* @param data Vector with data * @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) { 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());
} }
/** /** @overload */
* @brief Set buffer subdata template<std::size_t size, class T> inline void setSubData(GLintptr offset, const std::array<T, size>& data) {
* @param target %Target setSubData(offset, data.size()*sizeof(T), data.data());
* @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());
} }
private: private:
GLuint buffer; static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
Target _defaultTarget;
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 * @brief Class Magnum::BufferedImage, typedef Magnum::BufferedImage1D, Magnum::BufferedImage2D, Magnum::BufferedImage3D
*/ */
#include "Math/Vector3.h"
#include "AbstractImage.h" #include "AbstractImage.h"
#include "Buffer.h" #include "Buffer.h"
#include "DimensionTraits.h"
#include "TypeTraits.h" #include "TypeTraits.h"
namespace Magnum { namespace Magnum {
#ifndef MAGNUM_TARGET_GLES
/** /**
@brief %Buffered image @brief %Buffered image
Class for storing image data in GPU memory. Can be replaced with Image, which 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 stores image data in client memory, ImageWrapper, or for example with
Trade::ImageData. 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: public:
const static size_t Dimensions = imageDimensions; /**< @brief Image dimension count */ const static std::uint8_t Dimensions = dimensions; /**< @brief %Image dimension count */
/** /**
* @brief Constructor * @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 * Dimensions and buffer are empty, call setData() to fill the image
* with data. * 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 */ /** @brief %Image size */
inline constexpr Math::Vector<Dimensions, GLsizei> dimensions() const { return _dimensions; } inline typename DimensionTraits<Dimensions, GLsizei>::VectorType size() const { return _size; }
/** /**
* @brief Data * @brief Data
@ -57,8 +61,10 @@ template<size_t imageDimensions> class BufferedImage: public AbstractImage {
* Binds the buffer to @ref Buffer::Target "pixel unpack * Binds the buffer to @ref Buffer::Target "pixel unpack
* target" and returns nullptr, so it can be used for texture updating * target" and returns nullptr, so it can be used for texture updating
* functions the same way as Image::data(). * functions the same way as Image::data().
*
* @see Buffer::bind(Target)
*/ */
void* data() { inline void* data() {
_buffer.bind(Buffer::Target::PixelUnpack); _buffer.bind(Buffer::Target::PixelUnpack);
return nullptr; return nullptr;
} }
@ -68,7 +74,7 @@ template<size_t imageDimensions> class BufferedImage: public AbstractImage {
/** /**
* @brief Set image data * @brief Set image data
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components. Data type is detected * @param components Color components. Data type is detected
* from passed data array. * from passed data array.
* @param data %Image data * @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 * Updates the image buffer with given data. The data are not deleted
* after filling the buffer. * 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) { template<class T> inline void setData(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, const T* data, Buffer::Usage usage) {
setData(dimensions, components, TypeTraits<T>::imageType(), data, usage); setData(size, components, TypeTraits<T>::imageType(), data, usage);
} }
/** /**
* @brief Set image data * @brief Set image data
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components * @param components Color components
* @param type Data type * @param type Data type
* @param data %Image data * @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 * Updates the image buffer with given data. The data are not deleted
* after filling the buffer. * 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) { void setData(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, 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);
}
protected: protected:
Math::Vector<Dimensions, GLsizei> _dimensions; /**< @brief %Image dimensions */ Math::Vector<Dimensions, GLsizei> _size; /**< @brief %Image size */
Buffer _buffer; /**< @brief %Image buffer */ Buffer _buffer; /**< @brief %Image buffer */
}; };
/** @brief One-dimensional buffered image */ /** @brief One-dimensional buffered image */
@ -112,7 +117,6 @@ typedef BufferedImage<2> BufferedImage2D;
/** @brief Three-dimensional buffered image */ /** @brief Three-dimensional buffered image */
typedef BufferedImage<3> BufferedImage3D; typedef BufferedImage<3> BufferedImage3D;
#endif
} }

27
src/BufferedTexture.cpp

@ -15,9 +15,32 @@
#include "BufferedTexture.h" #include "BufferedTexture.h"
#ifndef MAGNUM_TARGET_GLES
#include "Buffer.h"
#include "Context.h"
#include "Extensions.h"
namespace Magnum { 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) { BufferedTexture::InternalFormat::InternalFormat(Components components, ComponentType type) {
#define internalFormatSwitch(c) switch(type) { \ #define internalFormatSwitch(c) switch(type) { \
case ComponentType::UnsignedByte: \ case ComponentType::UnsignedByte: \
@ -49,6 +72,6 @@ BufferedTexture::InternalFormat::InternalFormat(Components components, Component
internalFormatSwitch(RGBA) internalFormatSwitch(RGBA)
#undef internalFormatSwitch #undef internalFormatSwitch
} }
#endif
} }
#endif

63
src/BufferedTexture.h

@ -15,16 +15,20 @@
GNU Lesser General Public License version 3 for more details. GNU Lesser General Public License version 3 for more details.
*/ */
#ifndef MAGNUM_TARGET_GLES
/** @file /** @file
* @brief Class Magnum::BufferedTexture * @brief Class Magnum::BufferedTexture
*/ */
#endif
#include "Renderbuffer.h" #include "AbstractTexture.h"
#include "Buffer.h"
#ifndef MAGNUM_TARGET_GLES
namespace Magnum { namespace Magnum {
#ifndef MAGNUM_TARGET_GLES class Buffer;
class Context;
/** /**
@brief Buffered texture @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 When using buffered texture in the shader, use `samplerBuffer` and fetch the
data using integer coordinates in `texelFetch()`. 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_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(const BufferedTexture& other) = delete;
BufferedTexture(BufferedTexture&& other) = delete; BufferedTexture(BufferedTexture&& other) = delete;
BufferedTexture& operator=(const BufferedTexture& other) = delete; BufferedTexture& operator=(const BufferedTexture& other) = delete;
@ -117,25 +130,10 @@ class BufferedTexture {
/*@}*/ /*@}*/
/** inline BufferedTexture(): AbstractTexture(GL_TEXTURE_BUFFER) {}
* @brief Constructor
*
* Creates one OpenGL texture.
*/
inline BufferedTexture() {
glGenTextures(1, &texture);
}
/** @copydoc AbstractTexture::~AbstractTexture() */
inline virtual ~BufferedTexture() {
glDeleteTextures(1, &texture);
}
/** @copydoc AbstractTexture::bind(GLint) */ /** @copydoc AbstractTexture::bind() */
inline void bind(GLint layer) { inline void bind(GLint layer) { AbstractTexture::bind(layer); }
glActiveTexture(GL_TEXTURE0 + layer);
bind();
}
/** /**
* @brief Set texture buffer * @brief Set texture buffer
@ -145,19 +143,20 @@ class BufferedTexture {
* Binds given buffer to this texture. The buffer itself can be then * 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 * filled with data of proper format at any time using Buffer own data
* setting functions. * 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) { inline void setBuffer(InternalFormat internalFormat, Buffer* buffer) {
bind(); (this->*setBufferImplementation)(internalFormat, buffer);
glTexBuffer(GL_TEXTURE_BUFFER, internalFormat, buffer->id());
} }
private: private:
GLuint texture; static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
/** @copydoc AbstractTexture::bind() */ typedef void(BufferedTexture::*SetBufferImplementation)(InternalFormat, Buffer*);
inline void bind() { void MAGNUM_LOCAL setBufferImplementationDefault(InternalFormat internalFormat, Buffer* buffer);
glBindTexture(GL_TEXTURE_BUFFER, texture); void MAGNUM_LOCAL setBufferImplementationDSA(InternalFormat internalFormat, Buffer* buffer);
} static SetBufferImplementation setBufferImplementation;
}; };
/** @relates BufferedTexture /** @relates BufferedTexture
@ -172,8 +171,8 @@ inline BufferedTexture::InternalFormat operator|(BufferedTexture::Components com
inline BufferedTexture::InternalFormat operator|(BufferedTexture::ComponentType type, BufferedTexture::Components components) { inline BufferedTexture::InternalFormat operator|(BufferedTexture::ComponentType type, BufferedTexture::Components components) {
return BufferedTexture::InternalFormat(components, type); return BufferedTexture::InternalFormat(components, type);
} }
#endif
} }
#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 targeting GLES, save it into configuration header
if(TARGET_GLES) if(TARGET_GLES)
set(MAGNUM_TARGET_GLES 1) set(MAGNUM_TARGET_GLES 1)
endif() endif()
if(TARGET_GLES2)
set(MAGNUM_TARGET_GLES2 1)
endif()
# -Wdouble-promotion is supported from GCC 4.6 if(GCC46_COMPATIBILITY)
# TODO: do this with check_c_compiler_flags() set(MAGNUM_GCC46_COMPATIBILITY 1)
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() endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/magnumConfigure.h.cmake configure_file(${CMAKE_CURRENT_SOURCE_DIR}/magnumConfigure.h.cmake
@ -21,8 +28,11 @@ set(Magnum_SRCS
AbstractImage.cpp AbstractImage.cpp
AbstractTexture.cpp AbstractTexture.cpp
AbstractShaderProgram.cpp AbstractShaderProgram.cpp
BufferedTexture.cpp Buffer.cpp
BufferedImage.cpp
Context.cpp
Framebuffer.cpp Framebuffer.cpp
Image.cpp
IndexedMesh.cpp IndexedMesh.cpp
Mesh.cpp Mesh.cpp
Profiler.cpp Profiler.cpp
@ -30,20 +40,33 @@ set(Magnum_SRCS
Renderbuffer.cpp Renderbuffer.cpp
Shader.cpp Shader.cpp
SizeTraits.cpp SizeTraits.cpp
Timeline.cpp
TypeTraits.cpp TypeTraits.cpp
Implementation/BufferState.cpp
Implementation/State.cpp
Trade/AbstractImporter.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 set(Magnum_HEADERS
AbstractImage.h AbstractImage.h
AbstractShaderProgram.h AbstractShaderProgram.h
AbstractTexture.h AbstractTexture.h
BufferedImage.h BufferedImage.h
BufferedTexture.h
Buffer.h Buffer.h
Color.h Color.h
CubeMapTextureArray.h Context.h
CubeMapTexture.h CubeMapTexture.h
DimensionTraits.h
Extensions.h
Framebuffer.h Framebuffer.h
Image.h Image.h
ImageWrapper.h ImageWrapper.h
@ -53,14 +76,24 @@ set(Magnum_HEADERS
Profiler.h Profiler.h
Query.h Query.h
Renderbuffer.h Renderbuffer.h
ResourceManager.h
Shader.h Shader.h
SizeTraits.h SizeTraits.h
Swizzle.h Swizzle.h
Texture.h Texture.h
Timeline.h
TypeTraits.h TypeTraits.h
magnumCompatibility.h magnumCompatibility.h
magnumVisibility.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) if(NOT CMAKE_NO_OBJECT_TARGET)
add_library(MagnumObjects OBJECT ${Magnum_SRCS}) add_library(MagnumObjects OBJECT ${Magnum_SRCS})
endif() endif()
@ -88,12 +121,18 @@ else()
${Magnum_SRCS} ${Magnum_SRCS}
${MagnumMath_SRCS}) ${MagnumMath_SRCS})
endif() endif()
target_link_libraries(Magnum ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY}) set(Magnum_LIBS
${CORRADE_UTILITY_LIBRARY}
${CORRADE_PLUGINMANAGER_LIBRARY})
if(NOT TARGET_GLES) if(NOT TARGET_GLES)
target_link_libraries(Magnum ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARY}) set(Magnum_LIBS ${Magnum_LIBS}
${OPENGL_gl_LIBRARY}
${GLEW_LIBRARY})
else() else()
target_link_libraries(Magnum ${OPENGLES2_LIBRARY}) set(Magnum_LIBS ${Magnum_LIBS}
${OPENGLES2_LIBRARY})
endif() endif()
target_link_libraries(Magnum ${Magnum_LIBS})
install(TARGETS Magnum DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(TARGETS Magnum DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
install(FILES ${Magnum_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}) install(FILES ${Magnum_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR})
@ -137,12 +176,7 @@ if(BUILD_TESTS)
${Magnum_SRCS}) ${Magnum_SRCS})
endif() endif()
set_target_properties(MagnumTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) set_target_properties(MagnumTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
target_link_libraries(MagnumTestLib ${CORRADE_UTILITY_LIBRARY} ${CORRADE_PLUGINMANAGER_LIBRARY}) target_link_libraries(MagnumTestLib ${Magnum_LIBS})
if(NOT TARGET_GLES)
target_link_libraries(MagnumTestLib ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARY})
else()
target_link_libraries(MagnumTestLib ${OPENGLES2_LIBRARY})
endif()
add_subdirectory(Test) add_subdirectory(Test)
endif() 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 * @brief Create integral color from floating-point color
* *
* E.g. `{0.294118, 0.45098, 0.878431}` is converted to * 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 * @note This function is enabled only if source type is floating-point
* and destination type is integral. * 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 * @brief Create floating-point color from integral color
* *
* E.g. `{75, 115, 224}` is converted to * 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 * @note This function is enabled only if source type is integral
* and destination type is floating-point. * 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 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 T& r() { return Math::Vector3<T>::x(); } /**< @brief R component */
inline constexpr T g() const { return Math::Vector3<T>::y(); } /**< @brief G component */ inline constexpr T r() const { return Math::Vector3<T>::x(); } /**< @overload */
inline constexpr T b() const { return Math::Vector3<T>::z(); } /**< @brief B component */ inline T& g() { return Math::Vector3<T>::y(); } /**< @brief G component */
inline constexpr T g() const { return Math::Vector3<T>::y(); } /**< @overload */
inline void setR(T value) { Math::Vector3<T>::setX(value); } /**< @brief Set R component */ inline T& b() { return Math::Vector3<T>::z(); } /**< @brief B component */
inline void setG(T value) { Math::Vector3<T>::setY(value); } /**< @brief Set G component */ inline constexpr T b() const { return Math::Vector3<T>::z(); } /**< @overload */
inline void setB(T value) { Math::Vector3<T>::setZ(value); } /**< @brief Set B component */
/** /**
* @brief Convert to HSV * @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 /* Not marked as explicit, because conversion from Color3 to Color4
is fairly common, nearly always with A set to 1 */ 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 Color4(const Math::Vector3<T>& rgb, T a = Implementation::defaultAlpha<T>()): Math::Vector4<T>(rgb[0], rgb[1], rgb[2], a) {}
inline constexpr T r() const { return Math::Vector4<T>::x(); } /**< @brief R component */
inline constexpr T g() const { return Math::Vector4<T>::y(); } /**< @brief G component */
inline constexpr T b() const { return Math::Vector4<T>::z(); } /**< @brief B component */
inline constexpr T a() const { return Math::Vector4<T>::w(); } /**< @brief A component */
inline void setR(T value) { Math::Vector4<T>::setX(value); } /**< @brief Set R component */ inline T& r() { return Math::Vector4<T>::x(); } /**< @brief R component */
inline void setG(T value) { Math::Vector4<T>::setY(value); } /**< @brief Set G component */ inline constexpr T r() const { return Math::Vector4<T>::x(); } /**< @overload */
inline void setB(T value) { Math::Vector4<T>::setZ(value); } /**< @brief Set B component */ inline T& g() { return Math::Vector4<T>::y(); } /**< @brief G component */
inline void setA(T value) { Math::Vector4<T>::setW(value); } /**< @brief Set A 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 * @brief RGB part of the vector
@ -378,7 +376,8 @@ template<class T> class Color4: public Math::Vector4<T> {
* *
* @see swizzle() * @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() */ /** @copydoc Color3::toHSV() */
inline constexpr HSV toHSV() const { 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) MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color4, 4)
/** @debugoperator{Magnum::Color3} */ /** @debugoperator{Magnum::Color3} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color3<T>& value) { template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Color3<T>& value) {
return debug << static_cast<const Magnum::Math::Vector3<T>&>(value); return debug << static_cast<const Math::Vector3<T>&>(value);
} }
/** @debugoperator{Magnum::Color4} */ /** @debugoperator{Magnum::Color4} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color4<T>& value) { template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Color4<T>& value) {
return debug << static_cast<const Magnum::Math::Vector4<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 #ifndef Magnum_Contexts_AbstractContextHandler_h
#define Magnum_Contexts_AbstractGlInterface_h #define Magnum_Contexts_AbstractContextHandler_h
/* /*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,29 +16,29 @@
*/ */
/** @file /** @file
* @brief Class Magnum::Contexts::AbstractGlInterface * @brief Class Magnum::Contexts::AbstractContextHandler
*/ */
#include "ExtensionWrangler.h" #include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts { namespace Magnum { namespace Contexts {
/** @brief Base for OpenGL interfaces */ /** @brief Base for OpenGL context handlers */
template<class Display, class VisualId, class Window> class AbstractGlInterface { template<class Display, class VisualId, class Window> class AbstractContextHandler {
public: public:
/** /**
* @brief Get visual ID * @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; virtual VisualId getVisualId(Display nativeDisplay) = 0;
/** /**
* @brief Destructor * @brief Destructor
* *
* Finalizes and closes the interface. * Finalizes and closes the handler.
*/ */
virtual ~AbstractGlInterface() {} virtual ~AbstractContextHandler() {}
/** @brief Create context */ /** @brief Create context */
virtual void createContext(Window nativeWindow) = 0; virtual void createContext(Window nativeWindow) = 0;

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

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_AbstractContext_h #ifndef Magnum_Contexts_AbstractWindowContext_h
#define Magnum_Contexts_AbstractContext_h #define Magnum_Contexts_AbstractWindowContext_h
/* /*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,7 +16,7 @@
*/ */
/** @file /** @file
* @brief Class Magnum::Contexts::GlutContext * @brief Class Magnum::Contexts::AbstractWindowContext
*/ */
namespace Magnum { namespace Contexts { namespace Magnum { namespace Contexts {
@ -27,7 +27,7 @@ namespace Magnum { namespace Contexts {
See subclasses documentation for more information. Context classes subclasses See subclasses documentation for more information. Context classes subclasses
are meant to be used directly in `main()`, for example: are meant to be used directly in `main()`, for example:
@code @code
class MyContext: public Magnum::Contexts::GlutContext { class MyContext: public Magnum::Contexts::GlutWindowContext {
// implement required methods... // implement required methods...
}; };
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -36,9 +36,9 @@ int main(int argc, char** argv) {
} }
@endcode @endcode
*/ */
class AbstractContext { class AbstractWindowContext {
public: public:
virtual inline ~AbstractContext() {} virtual inline ~AbstractWindowContext() {}
/** /**
* @brief Execute main loop * @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. GNU Lesser General Public License version 3 for more details.
*/ */
#include "AbstractXContext.h" #include "AbstractXWindowContext.h"
#include "Context.h"
#include "ExtensionWrangler.h" #include "ExtensionWrangler.h"
#define None 0L // redef Xlib nonsense #define None 0L // redef Xlib nonsense
@ -26,12 +27,12 @@ using namespace std;
namespace Magnum { namespace Contexts { 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 */ /* Get default X display */
display = XOpenDisplay(0); display = XOpenDisplay(0);
/* Get visual ID */ /* Get visual ID */
VisualID visualId = glInterface->getVisualId(display); VisualID visualId = contextHandler->getVisualId(display);
/* Get visual info */ /* Get visual info */
XVisualInfo *visInfo, visTemplate; XVisualInfo *visInfo, visTemplate;
@ -60,28 +61,32 @@ AbstractXContext::AbstractXContext(AbstractGlInterface<Display*, VisualID, Windo
XSetWMProtocols(display, window, &deleteWindow, 1); XSetWMProtocols(display, window, &deleteWindow, 1);
/* Create context */ /* Create context */
glInterface->createContext(window); contextHandler->createContext(window);
/* Capture exposure, keyboard and mouse button events */ /* Capture exposure, keyboard and mouse button events */
XSelectInput(display, window, INPUT_MASK); XSelectInput(display, window, INPUT_MASK);
/* Set OpenGL context as current */ /* Set OpenGL context as current */
glInterface->makeCurrent(); contextHandler->makeCurrent();
/* Initialize extension wrangler */ /* Initialize extension wrangler */
ExtensionWrangler::initialize(glInterface->experimentalExtensionWranglerFeatures()); ExtensionWrangler::initialize(contextHandler->experimentalExtensionWranglerFeatures());
c = new Context;
} }
AbstractXContext::~AbstractXContext() { AbstractXWindowContext::~AbstractXWindowContext() {
/* Shut down the interface */ delete c;
delete glInterface;
/* Shut down context handler */
delete contextHandler;
/* Shut down X */ /* Shut down X */
XDestroyWindow(display, window); XDestroyWindow(display, window);
XCloseDisplay(display); XCloseDisplay(display);
} }
int AbstractXContext::exec() { int AbstractXWindowContext::exec() {
/* Show window */ /* Show window */
XMapWindow(display, window); XMapWindow(display, window);

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

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_AbstractXContext_h #ifndef Magnum_Contexts_AbstractXWindowContext_h
#define Magnum_Contexts_AbstractXContext_h #define Magnum_Contexts_AbstractXWindowContext_h
/* /*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,9 +16,11 @@
*/ */
/** @file /** @file
* @brief Class Magnum::Contexts::AbstractXContext * @brief Class Magnum::Contexts::AbstractXWindowContext
*/ */
#include <Containers/EnumSet.h>
#include "Magnum.h" #include "Magnum.h"
#include <X11/Xlib.h> #include <X11/Xlib.h>
@ -27,12 +29,17 @@
#undef None #undef None
#undef Always #undef Always
#include <Containers/EnumSet.h> #include "Math/Vector2.h"
#include "AbstractWindowContext.h"
#include "AbstractContextHandler.h"
#include "AbstractContext.h" #include "magnumCompatibility.h"
#include "AbstractGlInterface.h"
namespace Magnum { namespace Contexts { namespace Magnum {
class Context;
namespace Contexts {
/** @nosubgrouping /** @nosubgrouping
@brief Base for X11-based contexts @brief Base for X11-based contexts
@ -41,11 +48,11 @@ Supports keyboard and mouse handling.
@note Not meant to be used directly, see subclasses. @note Not meant to be used directly, see subclasses.
*/ */
class AbstractXContext: public AbstractContext { class AbstractXWindowContext: public AbstractWindowContext {
public: public:
/** /**
* @brief Constructor * @brief Constructor
* @param glInterface Interface to OpenGL * @param contextHandler OpenGL context handler
* @param argc Count of arguments of `main()` function * @param argc Count of arguments of `main()` function
* @param argv Arguments of `main()` function * @param argv Arguments of `main()` function
* @param title Window title * @param title Window title
@ -53,16 +60,16 @@ class AbstractXContext: public AbstractContext {
* *
* Creates window with double-buffered OpenGL ES 2 context. * 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 * @brief Destructor
* *
* Deletes context and destroys the window. * Deletes context and destroys the window.
*/ */
virtual ~AbstractXContext() = 0; virtual ~AbstractXWindowContext() = 0;
int exec(); int exec() override;
/** @brief Exit application main loop */ /** @brief Exit application main loop */
inline void exit() { flags |= Flag::Exit; } inline void exit() { flags |= Flag::Exit; }
@ -70,16 +77,16 @@ class AbstractXContext: public AbstractContext {
/** @{ @name Drawing functions */ /** @{ @name Drawing functions */
protected: protected:
/** @copydoc GlutContext::viewportEvent() */ /** @copydoc GlutWindowContext::viewportEvent() */
virtual void viewportEvent(const Math::Vector2<GLsizei>& size) = 0; virtual void viewportEvent(const Math::Vector2<GLsizei>& size) = 0;
/** @copydoc GlutContext::drawEvent() */ /** @copydoc GlutWindowContext::drawEvent() */
virtual void drawEvent() = 0; virtual void drawEvent() = 0;
/** @copydoc GlutContext::swapBuffers() */ /** @copydoc GlutWindowContext::swapBuffers() */
inline void swapBuffers() { glInterface->swapBuffers(); } inline void swapBuffers() { contextHandler->swapBuffers(); }
/** @copydoc GlutContext::redraw() */ /** @copydoc GlutWindowContext::redraw() */
inline void redraw() { flags |= Flag::Redraw; } inline void redraw() { flags |= Flag::Redraw; }
/*@}*/ /*@}*/
@ -276,7 +283,9 @@ class AbstractXContext: public AbstractContext {
Window window; Window window;
Atom deleteWindow; Atom deleteWindow;
AbstractGlInterface<Display*, VisualID, Window>* glInterface; AbstractContextHandler<Display*, VisualID, Window>* contextHandler;
Context* c;
/** @todo Get this from the created window */ /** @todo Get this from the created window */
Math::Vector2<GLsizei> viewportSize; Math::Vector2<GLsizei> viewportSize;
@ -284,15 +293,15 @@ class AbstractXContext: public AbstractContext {
Flags flags; Flags flags;
}; };
CORRADE_ENUMSET_OPERATORS(AbstractXContext::Modifiers) CORRADE_ENUMSET_OPERATORS(AbstractXWindowContext::Modifiers)
CORRADE_ENUMSET_OPERATORS(AbstractXContext::Flags) CORRADE_ENUMSET_OPERATORS(AbstractXWindowContext::Flags)
/* Implementations for inline functions with unused parameters */ /* Implementations for inline functions with unused parameters */
inline void AbstractXContext::keyPressEvent(Key, Modifiers, const Math::Vector2<int>&) {} inline void AbstractXWindowContext::keyPressEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::keyReleaseEvent(Key, Modifiers, const Math::Vector2<int>&) {} inline void AbstractXWindowContext::keyReleaseEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::mousePressEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {} inline void AbstractXWindowContext::mousePressEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::mouseReleaseEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {} inline void AbstractXWindowContext::mouseReleaseEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void AbstractXContext::mouseMotionEvent(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) add_library(MagnumContextsExtensionWrangler OBJECT ExtensionWrangler.cpp)
set(MagnumContexts_HEADERS set(MagnumContexts_HEADERS
AbstractContext.h AbstractContextHandler.h
AbstractGlInterface.h AbstractWindowContext.h
ExtensionWrangler.h) ExtensionWrangler.h)
install(FILES ${MagnumContexts_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) install(FILES ${MagnumContexts_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
# GLUT context # GLUT window context
if(WITH_GLUTCONTEXT) if(WITH_GLUTWINDOWCONTEXT)
find_package(GLUT) find_package(GLUT)
if(GLUT_FOUND) if(GLUT_FOUND)
add_library(MagnumGlutContext STATIC add_library(MagnumGlutWindowContext STATIC
GlutContext.cpp GlutWindowContext.cpp
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>) $<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES GlutContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) install(FILES GlutWindowContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumGlutContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(TARGETS MagnumGlutWindowContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
else() 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()
endif() endif()
# SDL2 context # SDL2 window context
if(WITH_SDL2CONTEXT) if(WITH_SDL2WINDOWCONTEXT)
find_package(SDL2) find_package(SDL2)
if(SDL2_FOUND) if(SDL2_FOUND)
include_directories(${SDL2_INCLUDE_DIR}) include_directories(${SDL2_INCLUDE_DIR})
add_library(MagnumSdl2Context STATIC add_library(MagnumSdl2WindowContext STATIC
Sdl2Context.cpp Sdl2WindowContext.cpp
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>) $<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES Sdl2Context.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) install(FILES Sdl2WindowContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumSdl2Context DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(TARGETS MagnumSdl2WindowContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
else() 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()
endif() endif()
# GLX context # GLX window context
if(WITH_GLXCONTEXT) if(WITH_GLXWINDOWCONTEXT)
set(NEED_ABSTRACTXCONTEXT 1) set(NEED_ABSTRACTXWINDOWCONTEXT 1)
set(NEED_GLXINTERFACE 1) set(NEED_GLXCONTEXT 1)
add_library(MagnumGlxContext STATIC add_library(MagnumGlxWindowContext STATIC
$<TARGET_OBJECTS:MagnumAbstractXContext> $<TARGET_OBJECTS:MagnumAbstractXWindowContext>
$<TARGET_OBJECTS:MagnumGlxInterface> $<TARGET_OBJECTS:MagnumGlxContextHandler>
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>) $<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES GlxContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) install(FILES GlxWindowContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumGlxContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(TARGETS MagnumGlxWindowContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
endif() endif()
# X/EGL context # X/EGL window context
if(WITH_XEGLCONTEXT) if(WITH_XEGLWINDOWCONTEXT)
set(NEED_ABSTRACTXCONTEXT 1) set(NEED_ABSTRACTXWINDOWCONTEXT 1)
set(NEED_EGLINTERFACE 1) set(NEED_EGLCONTEXT 1)
add_library(MagnumXEglContext STATIC add_library(MagnumXEglWindowContext STATIC
$<TARGET_OBJECTS:MagnumAbstractXContext> $<TARGET_OBJECTS:MagnumAbstractXWindowContext>
$<TARGET_OBJECTS:MagnumEglInterface> $<TARGET_OBJECTS:MagnumEglContextHandler>
$<TARGET_OBJECTS:MagnumContextsExtensionWrangler>) $<TARGET_OBJECTS:MagnumContextsExtensionWrangler>)
install(FILES XEglContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) install(FILES XEglWindowContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
install(TARGETS MagnumXEglContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) install(TARGETS MagnumXEglWindowContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
endif() endif()
# Abstract X context # Abstract X window context
if(NEED_ABSTRACTXCONTEXT) if(NEED_ABSTRACTXWINDOWCONTEXT)
find_package(X11) find_package(X11)
if(NOT X11_FOUND) 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() endif()
add_library(MagnumAbstractXContext OBJECT AbstractXContext.cpp) add_library(MagnumAbstractXWindowContext OBJECT AbstractXWindowContext.cpp)
# X11 macros are a mess, disable warnings for C-style casts # X11 macros are a mess, disable warnings for C-style casts
set_target_properties(MagnumAbstractXContext PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast") set_target_properties(MagnumAbstractXWindowContext PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES AbstractXContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) install(FILES AbstractXWindowContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
endif() endif()
# GLX interface # GLX context
if(NEED_GLXINTERFACE) if(NEED_GLXCONTEXT)
add_library(MagnumGlxInterface OBJECT GlxInterface.cpp) add_library(MagnumGlxContextHandler OBJECT GlxContextHandler.cpp)
# X11 macros are a mess, disable warnings for C-style casts # X11 macros are a mess, disable warnings for C-style casts
set_target_properties(MagnumGlxInterface PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast") set_target_properties(MagnumGlxContextHandler PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES GlxInterface.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) install(FILES GlxContextHandler.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
endif() endif()
# EGL interface # EGL context
if(NEED_EGLINTERFACE) if(NEED_EGLCONTEXT)
find_package(EGL) find_package(EGL)
if(NOT EGL_FOUND) 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() endif()
add_library(MagnumEglInterface OBJECT EglInterface.cpp) add_library(MagnumEglContextHandler OBJECT EglContextHandler.cpp)
# X11 macros are a mess, disable warnings for C-style casts # X11 macros are a mess, disable warnings for C-style casts
set_target_properties(MagnumEglInterface PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast") set_target_properties(MagnumEglContextHandler PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
install(FILES EglInterface.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) install(FILES EglContextHandler.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts)
endif() 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 #ifndef Magnum_Contexts_EglContextHandler_h
#define Magnum_Contexts_EglInterface_h #define Magnum_Contexts_EglContextHandler_h
/* /*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,7 +16,7 @@
*/ */
/** @file /** @file
* @brief Class Magnum::Contexts::EglInterface * @brief Class Magnum::Contexts::EglContextHandler
*/ */
#include "Magnum.h" #include "Magnum.h"
@ -26,7 +26,12 @@
#endif #endif
#include <EGL/egl.h> #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 { namespace Magnum { namespace Contexts {
@ -42,24 +47,26 @@ typedef EGLInt VisualId;
/** /**
@brief EGL interface @brief EGL interface
Used in XEglContext. Used in XEglWindowContext.
*/ */
class EglInterface: public AbstractGlInterface<EGLNativeDisplayType, VisualId, EGLNativeWindowType> { class EglContextHandler: public AbstractContextHandler<EGLNativeDisplayType, VisualId, EGLNativeWindowType> {
public: public:
~EglInterface(); ~EglContextHandler();
VisualId getVisualId(EGLNativeDisplayType nativeDisplay); VisualId getVisualId(EGLNativeDisplayType nativeDisplay) override;
void createContext(EGLNativeWindowType nativeWindow); void createContext(EGLNativeWindowType nativeWindow) override;
inline void makeCurrent() { inline void makeCurrent() override {
eglMakeCurrent(display, surface, surface, context); eglMakeCurrent(display, surface, surface, context);
} }
inline void swapBuffers() { inline void swapBuffers() override {
eglSwapBuffers(display, surface); eglSwapBuffers(display, surface);
} }
private: private:
const char* errorString(EGLint error);
EGLDisplay display; EGLDisplay display;
EGLConfig config; EGLConfig config;
EGLSurface surface; 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 "ExtensionWrangler.h"
#include <Utility/Debug.h>
#include "Magnum.h" #include "Magnum.h"
namespace Magnum { namespace Contexts { 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. GNU Lesser General Public License version 3 for more details.
*/ */
#include "GlutContext.h" #include "GlutWindowContext.h"
#include "Context.h"
#include "ExtensionWrangler.h" #include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts { 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 */ /* Save global instance */
instance = this; instance = this;
@ -38,6 +39,12 @@ GlutContext::GlutContext(int& argc, char** argv, const std::string& title, const
glutDisplayFunc(staticDrawEvent); glutDisplayFunc(staticDrawEvent);
ExtensionWrangler::initialize(); 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 #ifndef Magnum_Contexts_GlutWindowContext_h
#define Magnum_Contexts_GlutContext_h #define Magnum_Contexts_GlutWindowContext_h
/* /*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,15 +16,25 @@
*/ */
/** @file /** @file
* @brief Class Magnum::Contexts::GlutContext * @brief Class Magnum::Contexts::GlutWindowContext
*/ */
#include <string>
#include "Math/Vector2.h"
#include "Magnum.h" #include "Magnum.h"
#include <GL/freeglut.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 /** @nosubgrouping
@brief GLUT context @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 You need to implement at least drawEvent() and viewportEvent() to be able to
draw on the screen. draw on the screen.
*/ */
class GlutContext: public AbstractContext { class GlutWindowContext: public AbstractWindowContext {
public: public:
/** /**
* @brief Constructor * @brief Constructor
@ -46,9 +56,11 @@ class GlutContext: public AbstractContext {
* *
* Creates double-buffered RGBA window with depth and stencil buffers. * 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(); glutMainLoop();
return 0; return 0;
} }
@ -238,17 +250,16 @@ class GlutContext: public AbstractContext {
instance->drawEvent(); instance->drawEvent();
} }
static GlutContext* instance; static GlutWindowContext* instance;
int& argc; Context* c;
char** argv;
}; };
/* Implementations for inline functions with unused parameters */ /* Implementations for inline functions with unused parameters */
inline void GlutContext::keyPressEvent(Key, const Math::Vector2<int>&) {} inline void GlutWindowContext::keyPressEvent(Key, const Math::Vector2<int>&) {}
inline void GlutContext::mousePressEvent(MouseButton, const Math::Vector2<int>&) {} inline void GlutWindowContext::mousePressEvent(MouseButton, const Math::Vector2<int>&) {}
inline void GlutContext::mouseReleaseEvent(MouseButton, const Math::Vector2<int>&) {} inline void GlutWindowContext::mouseReleaseEvent(MouseButton, const Math::Vector2<int>&) {}
inline void GlutContext::mouseMotionEvent(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. GNU Lesser General Public License version 3 for more details.
*/ */
#include "GlxInterface.h" #include "GlxContextHandler.h"
#include <GL/glxext.h> #include <GL/glxext.h>
#include <Utility/Debug.h>
#include "Context.h"
#define None 0L // redef Xlib nonsense
namespace Magnum { namespace Contexts { namespace Magnum { namespace Contexts {
VisualID GlxInterface::getVisualId(Display* nativeDisplay) { VisualID GlxContextHandler::getVisualId(Display* nativeDisplay) {
display = nativeDisplay; display = nativeDisplay;
/* Check version */ /* Check version */
int major, minor; int major, minor;
glXQueryVersion(nativeDisplay, &major, &minor); glXQueryVersion(nativeDisplay, &major, &minor);
if(major == 1 && minor < 4) { 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); exit(1);
} }
@ -44,7 +49,7 @@ VisualID GlxInterface::getVisualId(Display* nativeDisplay) {
}; };
configs = glXChooseFBConfig(nativeDisplay, DefaultScreen(nativeDisplay), attributes, &configCount); configs = glXChooseFBConfig(nativeDisplay, DefaultScreen(nativeDisplay), attributes, &configCount);
if(!configCount) { if(!configCount) {
Error() << "GlxInterface: no supported framebuffer configuration found."; Error() << "GlxContextHandler: no supported framebuffer configuration found.";
exit(1); exit(1);
} }
@ -56,13 +61,13 @@ VisualID GlxInterface::getVisualId(Display* nativeDisplay) {
return visualId; return visualId;
} }
void GlxInterface::createContext(Window nativeWindow) { void GlxContextHandler::createContext(Window nativeWindow) {
window = nativeWindow; window = nativeWindow;
GLint attributes[] = { GLint attributes[] = {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
GLX_CONTEXT_MAJOR_VERSION_ARB, 3, 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, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
#else #else
GLX_CONTEXT_MAJOR_VERSION_ARB, 2, GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
@ -77,12 +82,12 @@ void GlxInterface::createContext(Window nativeWindow) {
context = glXCreateContextAttribsARB(display, configs[0], 0, True, attributes); context = glXCreateContextAttribsARB(display, configs[0], 0, True, attributes);
XFree(configs); XFree(configs);
if(!context) { if(!context) {
Error() << "GlxInterface: cannot create context."; Error() << "GlxContextHandler: cannot create context.";
exit(1); exit(1);
} }
} }
GlxInterface::~GlxInterface() { GlxContextHandler::~GlxContextHandler() {
glXMakeCurrent(display, None, nullptr); glXMakeCurrent(display, None, nullptr);
glXDestroyContext(display, context); glXDestroyContext(display, context);
} }

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

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

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

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_GlxContext_h #ifndef Magnum_Contexts_GlxWindowContext_h
#define Magnum_Contexts_GlxContext_h #define Magnum_Contexts_GlxWindowContext_h
/* /*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,20 +16,20 @@
*/ */
/** @file /** @file
* @brief Class Magnum::Contexts::GlxContext * @brief Class Magnum::Contexts::GlxWindowContext
*/ */
#include "AbstractXContext.h" #include "AbstractXWindowContext.h"
#include "GlxInterface.h" #include "GlxContextHandler.h"
namespace Magnum { namespace Contexts { namespace Magnum { namespace Contexts {
/** /**
@brief GLX context @brief GLX context
Uses GlxInterface. Uses GlxContextHandler.
*/ */
class GlxContext: public AbstractXContext { class GlxWindowContext: public AbstractXWindowContext {
public: public:
/** /**
* @brief Constructor * @brief Constructor
@ -38,10 +38,10 @@ class GlxContext: public AbstractXContext {
* @param title Window title * @param title Window title
* @param size Window size * @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. * 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. GNU Lesser General Public License version 3 for more details.
*/ */
#include "Sdl2Context.h" #include "Sdl2WindowContext.h"
#include "Context.h"
#include "ExtensionWrangler.h" #include "ExtensionWrangler.h"
namespace Magnum { namespace Contexts { 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) { if(SDL_Init(SDL_INIT_VIDEO) < 0) {
Error() << "Cannot initialize SDL."; Error() << "Cannot initialize SDL.";
exit(1); 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_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 */ /* Enable double buffering and 24bt depth buffer */
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 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.data1 = size.x();
sizeEvent->window.data2 = size.y(); sizeEvent->window.data2 = size.y();
SDL_PushEvent(sizeEvent); SDL_PushEvent(sizeEvent);
c = new Context;
} }
Sdl2Context::~Sdl2Context() { Sdl2WindowContext::~Sdl2WindowContext() {
delete c;
SDL_GL_DeleteContext(context); SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
SDL_Quit(); SDL_Quit();
} }
int Sdl2Context::exec() { int Sdl2WindowContext::exec() {
for(;;) { for(;;) {
SDL_Event event; SDL_Event event;
@ -77,23 +83,23 @@ int Sdl2Context::exec() {
break; break;
} break; } break;
case SDL_KEYDOWN: case SDL_KEYDOWN:
keyPressEvent(static_cast<Key>(event.key.keysym.sym), event.key.repeat); keyPressEvent(static_cast<Key>(event.key.keysym.sym), Modifiers(), {});
break; break;
case SDL_KEYUP: case SDL_KEYUP:
keyReleaseEvent(static_cast<Key>(event.key.keysym.sym)); keyReleaseEvent(static_cast<Key>(event.key.keysym.sym), Modifiers(), {});
break; break;
case SDL_MOUSEBUTTONDOWN: 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; break;
case SDL_MOUSEBUTTONUP: 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; break;
case SDL_MOUSEWHEEL: 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; break;
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
mouseMotionEvent({event.motion.x, event.motion.y}, mouseMotionEvent(Modifiers(), {event.motion.x, event.motion.y});
{event.motion.xrel, event.motion.yrel});
break; break;
case SDL_QUIT: case SDL_QUIT:
return 0; return 0;

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

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_Sdl2Context_h #ifndef Magnum_Contexts_Sdl2WindowContext_h
#define Magnum_Contexts_Sdl2Context_h #define Magnum_Contexts_Sdl2WindowContext_h
/* /*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,16 +16,25 @@
*/ */
/** @file /** @file
* @brief Class Magnum::Contexts::Sdl2Context * @brief Class Magnum::Contexts::Sdl2WindowContext
*/ */
#include "Math/Vector2.h"
#include "Magnum.h" #include "Magnum.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_scancode.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 /** @nosubgrouping
@brief SDL2 context @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 You need to implement at least drawEvent() and viewportEvent() to be able to
draw on the screen. draw on the screen.
*/ */
class Sdl2Context: public AbstractContext { class Sdl2WindowContext: public AbstractWindowContext {
public: public:
/** /**
* @brief Constructor * @brief Constructor
@ -45,38 +54,53 @@ class Sdl2Context: public AbstractContext {
* @param size Window size * @param size Window size
* *
* Creates centered non-resizable window with double-buffered * 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 * @brief Destructor
* *
* Deletes context and destroys the window. * Deletes context and destroys the window.
*/ */
~Sdl2Context(); ~Sdl2WindowContext();
int exec(); int exec() override;
/** @{ @name Drawing functions */ /** @{ @name Drawing functions */
protected: protected:
/** @copydoc GlutContext::viewportEvent() */ /** @copydoc GlutWindowContext::viewportEvent() */
virtual void viewportEvent(const Math::Vector2<GLsizei>& size) = 0; virtual void viewportEvent(const Math::Vector2<GLsizei>& size) = 0;
/** @copydoc GlutContext::drawEvent() */ /** @copydoc GlutWindowContext::drawEvent() */
virtual void drawEvent() = 0; virtual void drawEvent() = 0;
/** @copydoc GlutContext::swapBuffers() */ /** @copydoc GlutWindowContext::swapBuffers() */
inline void swapBuffers() { SDL_GL_SwapWindow(window); } inline void swapBuffers() { SDL_GL_SwapWindow(window); }
/** @copydoc GlutContext::redraw() */ /** @copydoc GlutWindowContext::redraw() */
inline void redraw() { _redraw = true; } inline void redraw() { _redraw = true; }
/*@}*/ /*@}*/
/** @{ @name Keyboard handling */ /** @{ @name Keyboard handling */
public: 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 * @brief Key
* *
@ -95,15 +119,18 @@ class Sdl2Context: public AbstractContext {
/** /**
* @brief Key press event * @brief Key press event
* @param key Key pressed * @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 * @brief Key release event
* @param key Key released * @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 { enum class MouseButton: Uint8 {
Left = SDL_BUTTON_LEFT, /**< Left button */ Left = SDL_BUTTON_LEFT, /**< Left button */
Middle = SDL_BUTTON_MIDDLE, /**< Middle 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 * @brief Mouse press event
* @param button Button pressed * @param button Button pressed
* @param modifiers Active modifiers (not yet implemented)
* @param position Cursor position * @param position Cursor position
* *
* Called when mouse button is pressed. Default implementation does * Called when mouse button is pressed. Default implementation does
* nothing. * nothing.
*/ */
virtual void mousePressEvent(MouseButton button, const Math::Vector2<int>& position); virtual void mousePressEvent(MouseButton button, Modifiers modifiers, const Math::Vector2<int>& position);
/** /**
* @brief Mouse release event * @brief Mouse release event
* @param button Button released * @param button Button released
* @param modifiers Active modifiers (not yet implemented)
* @param position Cursor position * @param position Cursor position
* *
* Called when mouse button is released. Default implementation does * Called when mouse button is released. Default implementation does
* nothing. * nothing.
*/ */
virtual void mouseReleaseEvent(MouseButton button, const Math::Vector2<int>& position); virtual void mouseReleaseEvent(MouseButton button, Modifiers modifiers, const Math::Vector2<int>& position);
/**
* @brief Mouse 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);
/** /**
* @brief Mouse motion event * @brief Mouse motion event
* @param modifiers Active modifiers (not yet implemented)
* @param position Mouse position relative to the window * @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. * 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_Window* window;
SDL_GLContext context; SDL_GLContext context;
Context* c;
bool _redraw; bool _redraw;
}; };
CORRADE_ENUMSET_OPERATORS(Sdl2WindowContext::Modifiers)
/* Implementations for inline functions with unused parameters */ /* Implementations for inline functions with unused parameters */
inline void Sdl2Context::keyPressEvent(Key, Uint8) {} inline void Sdl2WindowContext::keyPressEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void Sdl2Context::keyReleaseEvent(Key) {} inline void Sdl2WindowContext::keyReleaseEvent(Key, Modifiers, const Math::Vector2<int>&) {}
inline void Sdl2Context::mousePressEvent(MouseButton, const Math::Vector2<int>&) {} inline void Sdl2WindowContext::mousePressEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void Sdl2Context::mouseReleaseEvent(MouseButton, const Math::Vector2<int>&) {} inline void Sdl2WindowContext::mouseReleaseEvent(MouseButton, Modifiers, const Math::Vector2<int>&) {}
inline void Sdl2Context::mouseWheelEvent(const Math::Vector2<int>&) {} inline void Sdl2WindowContext::mouseMotionEvent(Modifiers, const Math::Vector2<int>&) {}
inline void Sdl2Context::mouseMotionEvent(const Math::Vector2<int>&, const Math::Vector2<int>&) {}
}} }}

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

@ -1,5 +1,5 @@
#ifndef Magnum_Contexts_XEglContext_h #ifndef Magnum_Contexts_XEglWindowContext_h
#define Magnum_Contexts_XEglContext_h #define Magnum_Contexts_XEglWindowContext_h
/* /*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -16,20 +16,20 @@
*/ */
/** @file /** @file
* @brief Class Magnum::Contexts::XEglContext * @brief Class Magnum::Contexts::XEglWindowContext
*/ */
#include "AbstractXContext.h" #include "AbstractXWindowContext.h"
#include "EglInterface.h" #include "EglContextHandler.h"
namespace Magnum { namespace Contexts { namespace Magnum { namespace Contexts {
/** /**
@brief X/EGL context @brief X/EGL context
Uses EglInterface. Uses EglContextHandler.
*/ */
class XEglContext: public AbstractXContext { class XEglWindowContext: public AbstractXWindowContext {
public: public:
/** /**
* @brief Constructor * @brief Constructor
@ -40,7 +40,7 @@ class XEglContext: public AbstractXContext {
* *
* Creates window with double-buffered OpenGL ES 2 context. * 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 @brief Cube map texture
%Texture used mainly for environemnt maps. See AbstractTexture documentation %Texture used mainly for environemnt maps. See AbstractTexture documentation
for more information about usage. It consists of 6 square textures generating for more information. It consists of 6 square textures generating 6 faces of
6 faces of the cube as following. Note that all images must be turned upside the cube as following. Note that all images must be turned upside down (+Y is
down (+Y is top): top):
+----+ +----+
| -Y | | -Y |
@ -63,8 +63,11 @@ class CubeMapTexture: public AbstractTexture {
/** /**
* @brief Enable/disable seamless cube map textures * @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_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) { inline static void setSeamless(bool enabled) {
enabled ? glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) : glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); enabled ? glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS) : glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
@ -75,34 +78,63 @@ class CubeMapTexture: public AbstractTexture {
* @brief Constructor * @brief Constructor
* *
* Creates one cube map OpenGL texture. * Creates one cube map OpenGL texture.
* @see @def_gl{TEXTURE_CUBE_MAP}
*/ */
inline CubeMapTexture(): AbstractTexture(GL_TEXTURE_CUBE_MAP) {} inline CubeMapTexture(): AbstractTexture(GL_TEXTURE_CUBE_MAP) {}
/** /**
* @copydoc Texture::setWrapping() * @copydoc Texture::setWrapping()
*/ */
inline void setWrapping(const Math::Vector<3, Wrapping>& wrapping) { inline CubeMapTexture* setWrapping(const Math::Vector<3, Wrapping>& wrapping) {
bind(); DataHelper<3>::setWrapping(this, wrapping);
DataHelper<3>::setWrapping(GL_TEXTURE_CUBE_MAP, wrapping); return this;
} }
/** /**
* @copydoc Texture::setData(GLint, InternalFormat, Image*) * @copydoc Texture::setData(GLint, InternalFormat, Image*)
* @param coordinate Coordinate * @param coordinate Coordinate
* @return Pointer to self (for method chaining)
*/ */
template<class Image> inline void setData(Coordinate coordinate, GLint mipLevel, InternalFormat internalFormat, Image* image) { template<class Image> inline CubeMapTexture* setData(Coordinate coordinate, GLint mipLevel, InternalFormat internalFormat, Image* image) {
bind(); DataHelper<2>::set(this, static_cast<GLenum>(coordinate), mipLevel, internalFormat, image);
DataHelper<2>::set(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 * @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) { template<class Image> inline CubeMapTexture* setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector2<GLint>& offset, const Image* image) {
bind(); DataHelper<2>::setSub(this, static_cast<GLenum>(coordinate), mipLevel, offset, image);
DataHelper<2>::setSub(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. GNU Lesser General Public License version 3 for more details.
*/ */
#ifndef MAGNUM_TARGET_GLES
/** @file /** @file
* @brief Class Magnum::CubeMapTextureArray * @brief Class Magnum::CubeMapTextureArray
*/ */
#endif
#include "Texture.h" #include "Texture.h"
#ifndef MAGNUM_TARGET_GLES
namespace Magnum { namespace Magnum {
/** /**
@brief Cube map texture array @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 When using cube map texture in the shader, use `samplerCubeArray`. Unlike
classic textures, coordinates for cube map textures is signed three-part 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 vector from the center of the cube, which intersects one of the six sides of
the cube map. the cube map.
@see CubeMapTexture::setSeamless()
@requires_gl40 Extension @extension{ARB,texture_cube_map_array} @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 { class CubeMapTextureArray: public AbstractTexture {
public: public:
@ -47,28 +52,20 @@ class CubeMapTextureArray: public AbstractTexture {
NegativeZ = 5 /**< -Z cube side */ 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 * @brief Constructor
* *
* Creates one cube map OpenGL texture. * Creates one cube map OpenGL texture.
* @see @def_gl{TEXTURE_CUBE_MAP_ARRAY}
*/ */
inline CubeMapTextureArray(): AbstractTexture(GL_TEXTURE_CUBE_MAP_ARRAY) {} inline CubeMapTextureArray(): AbstractTexture(GL_TEXTURE_CUBE_MAP_ARRAY) {}
/** /**
* @copydoc Texture::setWrapping() * @copydoc Texture::setWrapping()
*/ */
inline void setWrapping(const Math::Vector<3, Wrapping>& wrapping) { inline CubeMapTextureArray* setWrapping(const Math::Vector3<Wrapping>& wrapping) {
bind(); DataHelper<3>::setWrapping(this, wrapping);
DataHelper<3>::setWrapping(GL_TEXTURE_CUBE_MAP_ARRAY, 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. * for all layers. Each group of 6 2D images is one cube map layer.
* The images are ordered the same way as Coordinate enum. * The images are ordered the same way as Coordinate enum.
*/ */
template<class T> inline void setData(GLint mipLevel, InternalFormat internalFormat, T* image) { template<class T> inline CubeMapTextureArray* setData(GLint mipLevel, InternalFormat internalFormat, T* image) {
bind(); DataHelper<3>::set(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, internalFormat, image);
DataHelper<3>::set(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 offset Offset where to put data in the texture
* @param image Three-dimensional Image, BufferedImage or for * @param image Three-dimensional Image, BufferedImage or for
* example Trade::ImageData * example Trade::ImageData
* @return Pointer to self (for method chaining)
* *
* Sets texture subdata from given image. The image is not deleted * Sets texture subdata from given image. The image is not deleted
* afterwards. * afterwards.
@ -100,9 +98,9 @@ class CubeMapTextureArray: public AbstractTexture {
* *
* @see setSubData(GLsizei, Coordinate, GLint, const Math::Vector<2, GLint>&, const Image*) * @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) { template<class Image> inline CubeMapTextureArray* setSubData(GLint mipLevel, const Math::Vector3<GLint>& offset, const Image* image) {
bind(); DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, offset, image, Math::Vector3<GLsizei>(Math::Vector<Image::Dimensions, GLsizei>()));
DataHelper<3>::setSub(GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, offset, image, Math::Vector<3, 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 offset Offset where to put data in the texture
* @param image Two-dimensional Image, BufferedImage or for * @param image Two-dimensional Image, BufferedImage or for
* example Trade::ImageData * example Trade::ImageData
* @return Pointer to self (for method chaining)
* *
* Sets texture subdata from given image. The image is not deleted * Sets texture subdata from given image. The image is not deleted
* afterwards. * afterwards.
* *
* @see setSubData(GLint, const Math::Vector<3, GLint>&, const Image*) * @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) { template<class Image> inline CubeMapTextureArray* setSubData(GLsizei layer, Coordinate coordinate, GLint mipLevel, const Math::Vector2<GLint>& offset, const Image* image) {
bind(); 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>()));
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>())); 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 #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" #include "Framebuffer.h"
namespace Magnum { #include "BufferedImage.h"
#include "Image.h"
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;
}
void Framebuffer::setViewport(const Math::Vector2<GLint>& position, const Math::Vector2<GLsizei>& size) { namespace Magnum {
glViewport(position.x(), position.y(), size.x(), size.y());
}
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES2
void Framebuffer::mapDefaultForDraw(std::initializer_list<DefaultDrawAttachment> attachments) { void Framebuffer::mapDefaultForDraw(std::initializer_list<DefaultDrawAttachment> attachments) {
GLenum* _attachments = new GLenum[attachments.size()]; GLenum* _attachments = new GLenum[attachments.size()];
for(auto it = attachments.begin(); it != attachments.end(); ++it) for(auto it = attachments.begin(); it != attachments.end(); ++it)
@ -46,34 +30,35 @@ void Framebuffer::mapDefaultForDraw(std::initializer_list<DefaultDrawAttachment>
glDrawBuffers(attachments.size(), _attachments); glDrawBuffers(attachments.size(), _attachments);
delete[] _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()]; GLenum* attachments = new GLenum[colorAttachments.size()];
for(auto it = colorAttachments.begin(); it != colorAttachments.end(); ++it) for(auto it = colorAttachments.begin(); it != colorAttachments.end(); ++it)
attachments[it-colorAttachments.begin()] = *it + GL_COLOR_ATTACHMENT0; attachments[it-colorAttachments.begin()] = *it + GL_COLOR_ATTACHMENT0;
bind(Target::Draw); bind(Target::Draw);
/** @todo Re-enable when extension wrangler is available for ES2 */
#ifndef MAGNUM_TARGET_GLES2
glDrawBuffers(colorAttachments.size(), attachments); glDrawBuffers(colorAttachments.size(), attachments);
#endif
delete[] attachments; delete[] attachments;
} }
#endif
void Framebuffer::read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& dimensions, AbstractImage::Components components, AbstractImage::ComponentType type, Image2D* image) { 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)*dimensions.product()]; char* data = new char[AbstractImage::pixelSize(components, type)*size.product()];
glReadPixels(offset.x(), offset.y(), dimensions.x(), dimensions.y(), static_cast<GLenum>(components), static_cast<GLenum>(type), data); glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast<GLenum>(components), static_cast<GLenum>(type), data);
image->setData(dimensions, components, type, data); image->setData(size, components, type, data);
} }
#ifndef MAGNUM_TARGET_GLES void Framebuffer::read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, BufferedImage2D* image, Buffer::Usage usage) {
void Framebuffer::read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& dimensions, AbstractImage::Components components, AbstractImage::ComponentType type, BufferedImage2D* image, Buffer::Usage usage) {
/* If the buffer doesn't have sufficient size, resize it */ /* If the buffer doesn't have sufficient size, resize it */
/** @todo Explicitly reset also when buffer usage changes */ /** @todo Explicitly reset also when buffer usage changes */
if(image->dimensions() != dimensions || image->components() != components || image->type() != type) if(image->size() != size || image->components() != components || image->type() != type)
image->setData(dimensions, components, type, nullptr, usage); image->setData(size, components, type, nullptr, usage);
image->buffer()->bind(Buffer::Target::PixelPack); 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 <Containers/EnumSet.h>
#include "BufferedImage.h" #include "AbstractImage.h"
#include "Buffer.h"
#include "CubeMapTexture.h" #include "CubeMapTexture.h"
#include "Color.h" #include "Color.h"
#include "Image.h"
#include "Renderbuffer.h" #include "Renderbuffer.h"
namespace Magnum { 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 /** @nosubgrouping
@brief %Framebuffer @brief %Framebuffer
@ -43,6 +53,20 @@ class MAGNUM_EXPORT Framebuffer {
Framebuffer& operator=(Framebuffer&& other) = delete; Framebuffer& operator=(Framebuffer&& other) = delete;
public: 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 */ /** @{ @name Framebuffer features */
/** /**
@ -62,14 +86,15 @@ class MAGNUM_EXPORT Framebuffer {
/** /**
* Logical operation * Logical operation
* @see setLogicOperation() * @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, LogicOperation = GL_COLOR_LOGIC_OP,
/** /**
* Depth clamping. If enabled, ignores near and far clipping plane. * Depth clamping. If enabled, ignores near and far clipping plane.
* @requires_gl
* @requires_gl32 Extension @extension{ARB,depth_clamp} * @requires_gl32 Extension @extension{ARB,depth_clamp}
* @requires_gl Depth clamping is not available in OpenGL ES.
*/ */
DepthClamp = GL_DEPTH_CLAMP, DepthClamp = GL_DEPTH_CLAMP,
#endif #endif
@ -85,16 +110,36 @@ class MAGNUM_EXPORT Framebuffer {
FaceCulling = GL_CULL_FACE /**< Back face culling */ 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 * @brief Set viewport size
* *
* Call when window size changes. * 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 */ Stencil = GL_STENCIL_BUFFER_BIT /**< Stencil value */
}; };
typedef Corrade::Containers::EnumSet<Clear, GLbitfield> ClearMask; /**< @brief Mask for clearing */ /** @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 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 Clear specified buffers in framebuffer * @brief Clear specified buffers in framebuffer
* *
* @see clear() * @see clear(), setClearColor(), setClearDepth(), setClearStencil(),
* @fn_gl{Clear}
* @todo Clearing only given draw buffer * @todo Clearing only given draw buffer
*/ */
inline static void clear(ClearMask mask) { glClear(static_cast<GLbitfield>(mask)); } inline static void clear(ClearMask mask) { glClear(static_cast<GLbitfield>(mask)); }
@ -136,6 +173,7 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Set clear color * @brief Set clear color
* *
* Initial value is `{0.0f, 0.0f, 0.0f, 1.0f}`. * Initial value is `{0.0f, 0.0f, 0.0f, 1.0f}`.
* @see @fn_gl{ClearColor}
*/ */
inline static void setClearColor(const Color4<GLfloat>& color) { inline static void setClearColor(const Color4<GLfloat>& color) {
glClearColor(color.r(), color.g(), color.b(), color.a()); glClearColor(color.r(), color.g(), color.b(), color.a());
@ -146,7 +184,8 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Set clear depth * @brief Set clear depth
* *
* Initial value is `1.0`. * 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); } inline static void setClearDepth(GLdouble depth) { glClearDepth(depth); }
#endif #endif
@ -154,7 +193,9 @@ class MAGNUM_EXPORT Framebuffer {
/** /**
* @overload * @overload
* *
* @see @fn_gl{ClearDepth}
* @requires_gl41 Extension @extension{ARB,ES2_compatibility} * @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); } inline static void setClearDepth(GLfloat depth) { glClearDepthf(depth); }
@ -162,6 +203,7 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Set clear stencil * @brief Set clear stencil
* *
* Initial value is `0`. * Initial value is `0`.
* @see @fn_gl{ClearStencil}
*/ */
inline static void setClearStencil(GLint stencil) { glClearStencil(stencil); } inline static void setClearStencil(GLint stencil) { glClearStencil(stencil); }
@ -175,7 +217,9 @@ class MAGNUM_EXPORT Framebuffer {
* @param size Scissor rectangle size. Initial value is * @param size Scissor rectangle size. Initial value is
* size of the window when the context is first attached to a * size of the window when the context is first attached to a
* window. * window.
*
* @attention You have to enable scissoring with setFeature() first. * @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) { inline static void setScissor(const Math::Vector2<GLint>& bottomLeft, const Math::Vector2<GLsizei>& size) {
glScissor(bottomLeft.x(), bottomLeft.y(), size.x(), size.y()); glScissor(bottomLeft.x(), bottomLeft.y(), size.x(), size.y());
@ -185,19 +229,6 @@ class MAGNUM_EXPORT Framebuffer {
/** @{ @name Stencil operations */ /** @{ @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 * @brief Stencil function
* *
@ -269,7 +300,8 @@ class MAGNUM_EXPORT Framebuffer {
* Initial value is all `1`s. * Initial value is all `1`s.
* *
* @attention You have to enable stencil test with setFeature() first. * @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) { inline static void setStencilFunction(PolygonFacing facing, StencilFunction function, GLint referenceValue, GLuint mask) {
glStencilFuncSeparate(static_cast<GLenum>(facing), static_cast<GLenum>(function), referenceValue, 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) * The same as setStencilFunction(PolygonFacing, StencilFunction, GLint, GLuint)
* with `facing` set to `PolygonFacing::FrontAndBack`. * with `facing` set to `PolygonFacing::FrontAndBack`.
* @see @fn_gl{StencilFunc}
*/ */
inline static void setStencilFunction(StencilFunction function, GLint referenceValue, GLuint mask) { inline static void setStencilFunction(StencilFunction function, GLint referenceValue, GLuint mask) {
glStencilFunc(static_cast<GLenum>(function), referenceValue, mask); glStencilFunc(static_cast<GLenum>(function), referenceValue, mask);
@ -296,7 +329,8 @@ class MAGNUM_EXPORT Framebuffer {
* *
* Initial value for all fields is `StencilOperation::Keep`. * Initial value for all fields is `StencilOperation::Keep`.
* @attention You have to enable stencil test with setFeature() first. * @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) { 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)); 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) * The same as setStencilOperation(PolygonFacing, StencilOperation, StencilOperation, StencilOperation)
* with `facing` set to `PolygonFacing::FrontAndBack`. * with `facing` set to `PolygonFacing::FrontAndBack`.
* @see @fn_gl{StencilOp}
*/ */
inline static void setStencilOperation(StencilOperation stencilFail, StencilOperation depthFail, StencilOperation depthPass) { inline static void setStencilOperation(StencilOperation stencilFail, StencilOperation depthFail, StencilOperation depthPass) {
glStencilOp(static_cast<GLenum>(stencilFail), static_cast<GLenum>(depthFail), static_cast<GLenum>(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`. * Initial value is `DepthFunction::Less`.
* @attention You have to enable depth test with setFeature() first. * @attention You have to enable depth test with setFeature() first.
* @see @fn_gl{DepthFunc}
*/ */
inline static void setDepthFunction(DepthFunction function) { inline static void setDepthFunction(DepthFunction function) {
glDepthFunc(static_cast<GLenum>(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 * Set to `false` to disallow writing to given color channel. Initial
* values are all `true`. * values are all `true`.
* @see @fn_gl{ColorMask}
* @todo Masking only given draw buffer * @todo Masking only given draw buffer
*/ */
inline static void setColorMask(GLboolean allowRed, GLboolean allowGreen, GLboolean allowBlue, GLboolean allowAlpha) { 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 * Set to `false` to disallow writing to depth buffer. Initial value
* is `true`. * is `true`.
* @see @fn_gl{DepthMask}
*/ */
inline static void setDepthMask(GLboolean allow) { inline static void setDepthMask(GLboolean allow) {
glDepthMask(allow); glDepthMask(allow);
@ -363,7 +401,7 @@ class MAGNUM_EXPORT Framebuffer {
* *
* Set given bit to `0` to disallow writing stencil value for given * Set given bit to `0` to disallow writing stencil value for given
* faces to it. Initial value is all `1`s. * 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) { inline static void setStencilMask(PolygonFacing facing, GLuint allowBits) {
glStencilMaskSeparate(static_cast<GLenum>(facing), allowBits); glStencilMaskSeparate(static_cast<GLenum>(facing), allowBits);
@ -374,6 +412,7 @@ class MAGNUM_EXPORT Framebuffer {
* *
* The same as setStencilMask(PolygonFacing, GLuint) with `facing` set * The same as setStencilMask(PolygonFacing, GLuint) with `facing` set
* to `PolygonFacing::FrontAndBack`. * to `PolygonFacing::FrontAndBack`.
* @see @fn_gl{StencilMask}
*/ */
inline static void setStencilMask(GLuint allowBits) { inline static void setStencilMask(GLuint allowBits) {
glStencilMask(allowBits); glStencilMask(allowBits);
@ -394,24 +433,19 @@ class MAGNUM_EXPORT Framebuffer {
enum class BlendEquation: GLenum { enum class BlendEquation: GLenum {
Add = GL_FUNC_ADD, /**< `source + destination` */ Add = GL_FUNC_ADD, /**< `source + destination` */
Subtract = GL_FUNC_SUBTRACT, /**< `source - destination` */ Subtract = GL_FUNC_SUBTRACT, /**< `source - destination` */
ReverseSubtract = GL_FUNC_REVERSE_SUBTRACT /**< `destination - source` */ ReverseSubtract = GL_FUNC_REVERSE_SUBTRACT, /**< `destination - source` */
#ifndef MAGNUM_TARGET_GLES
/** @todo Enable for ES3 when the headers are available */
,
/** /**
* `min(source, destination)` * `min(source, destination)`
* @requires_gles30 Extension @es_extension{EXT,blend_minmax} * @requires_gles30 %Extension @es_extension2{EXT,blend_minmax,blend_minmax}
*/ */
Min = GL_MIN, Min = GL_MIN,
/** /**
* `max(source, destination)` * `max(source, destination)`
* @requires_gles30 Extension @es_extension{EXT,blend_minmax} * @requires_gles30 %Extension @es_extension2{EXT,blend_minmax,blend_minmax}
*/ */
Max = GL_MAX 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$) * Second source color (@f$ RGB = (R_{s1}, G_{s1}, B_{s1}); A = A_{s1} @f$)
* *
* @see AbstractShaderProgram::bindFragmentDataLocationIndexed() * @see AbstractShaderProgram::bindFragmentDataLocationIndexed()
* @requires_gl
* @requires_gl33 Extension @extension{ARB,blend_func_extended} * @requires_gl33 Extension @extension{ARB,blend_func_extended}
* @requires_gl Multiple blending inputs are not available in
* OpenGL ES.
*/ */
SecondSourceColor = GL_SRC1_COLOR, SecondSourceColor = GL_SRC1_COLOR,
#endif #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$) * 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() * @see AbstractShaderProgram::bindFragmentDataLocationIndexed()
* @requires_gl
* @requires_gl33 Extension @extension{ARB,blend_func_extended} * @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, OneMinusSecondSourceColor = GL_ONE_MINUS_SRC1_COLOR,
#endif #endif
@ -499,8 +535,9 @@ class MAGNUM_EXPORT Framebuffer {
* Second source alpha (@f$ RGB = (A_{s1}, A_{s1}, A_{s1}); A = A_{s1} @f$) * Second source alpha (@f$ RGB = (A_{s1}, A_{s1}, A_{s1}); A = A_{s1} @f$)
* *
* @see AbstractShaderProgram::bindFragmentDataLocationIndexed() * @see AbstractShaderProgram::bindFragmentDataLocationIndexed()
* @requires_gl
* @requires_gl33 Extension @extension{ARB,blend_func_extended} * @requires_gl33 Extension @extension{ARB,blend_func_extended}
* @requires_gl Multiple blending inputs are not available in
* OpenGL ES.
*/ */
SecondSourceAlpha = GL_SRC1_ALPHA, SecondSourceAlpha = GL_SRC1_ALPHA,
#endif #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$) * 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() * @see AbstractShaderProgram::bindFragmentDataLocationIndexed()
* @requires_gl
* @requires_gl33 Extension @extension{ARB,blend_func_extended} * @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, OneMinusSecondSourceAlpha = GL_ONE_MINUS_SRC1_ALPHA,
#endif #endif
@ -544,7 +582,8 @@ class MAGNUM_EXPORT Framebuffer {
* How to combine source color (pixel value) with destination color * How to combine source color (pixel value) with destination color
* (framebuffer). Initial value is `BlendEquation::Add`. * (framebuffer). Initial value is `BlendEquation::Add`.
* @attention You have to enable blending with setFeature() first. * @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) { inline static void setBlendEquation(BlendEquation equation) {
glBlendEquation(static_cast<GLenum>(equation)); glBlendEquation(static_cast<GLenum>(equation));
@ -555,6 +594,7 @@ class MAGNUM_EXPORT Framebuffer {
* *
* See setBlendEquation(BlendEquation) for more information. * See setBlendEquation(BlendEquation) for more information.
* @attention You have to enable blending with setFeature() first. * @attention You have to enable blending with setFeature() first.
* @see @fn_gl{BlendEquationSeparate}
*/ */
inline static void setBlendEquation(BlendEquation rgb, BlendEquation alpha) { inline static void setBlendEquation(BlendEquation rgb, BlendEquation alpha) {
glBlendEquationSeparate(static_cast<GLenum>(rgb), static_cast<GLenum>(alpha)); glBlendEquationSeparate(static_cast<GLenum>(rgb), static_cast<GLenum>(alpha));
@ -569,7 +609,8 @@ class MAGNUM_EXPORT Framebuffer {
* `BlendFunction::Zero`. * `BlendFunction::Zero`.
* *
* @attention You have to enable blending with setFeature() first. * @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) { inline static void setBlendFunction(BlendFunction source, BlendFunction destination) {
glBlendFunc(static_cast<GLenum>(source), static_cast<GLenum>(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. * See setBlendFunction(BlendFunction, BlendFunction) for more information.
* @attention You have to enable blending with setFeature() first. * @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) { 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)); 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::ConstantAlpha` and
* `BlendFunction::OneMinusConstantAlpha`. * `BlendFunction::OneMinusConstantAlpha`.
* @attention You have to enable blending with setFeature() first. * @attention You have to enable blending with setFeature() first.
* @see @fn_gl{BlendColor}
*/ */
inline static void setBlendColor(const Color4<GLfloat>& color) { inline static void setBlendColor(const Color4<GLfloat>& color) {
glBlendColor(color.r(), color.g(), color.b(), color.a()); glBlendColor(color.r(), color.g(), color.b(), color.a());
@ -608,7 +651,8 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Logical operation * @brief Logical operation
* *
* @see setLogicOperation() * @see setLogicOperation()
* @requires_gl * @requires_gl Logical operations on framebuffer are not available in
* OpenGL ES.
*/ */
enum class LogicOperation: GLenum { enum class LogicOperation: GLenum {
Clear = GL_CLEAR, /**< `0` */ Clear = GL_CLEAR, /**< `0` */
@ -633,7 +677,9 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Set logical operation * @brief Set logical operation
* *
* @attention You have to enable logical operation with setFeature() first. * @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) { inline static void setLogicOperation(LogicOperation operation) {
glLogicOp(static_cast<GLenum>(operation)); glLogicOp(static_cast<GLenum>(operation));
@ -651,81 +697,184 @@ class MAGNUM_EXPORT Framebuffer {
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/ */
enum class Target: GLenum { enum class Target: GLenum {
#ifndef MAGNUM_TARGET_GLES
/** /**
* For reading only. * For reading only.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_blit} * @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, Read = GL_READ_FRAMEBUFFER,
/** /**
* For drawing only. * For drawing only.
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_blit} * @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, Draw = GL_DRAW_FRAMEBUFFER,
#endif
ReadDraw = GL_FRAMEBUFFER /**< For both reading and drawing. */ ReadDraw = GL_FRAMEBUFFER /**< For both reading and drawing. */
}; };
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES2
/** /**
* @brief Draw attachment for default framebuffer * @brief Draw attachment for default framebuffer
* *
* @see mapDefaultForDraw() * @see mapDefaultForDraw()
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @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 { enum class DefaultDrawAttachment: GLenum {
None = GL_NONE, /**< Don't use the output. */ /** Don't use the output. */
BackLeft = GL_BACK_LEFT, /**< Write output to back left framebuffer. */ None = GL_NONE,
BackRight = GL_BACK_RIGHT, /**< Write output to back right framebuffer. */
FrontLeft = GL_FRONT_LEFT, /**< Write output to front left framebuffer. */ #ifndef MAGNUM_TARGET_GLES
FrontRight = GL_FRONT_RIGHT /**< Write output to front right framebuffer. */ /**
* 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 * @brief Read attachment for default framebuffer
* *
* @see mapDefaultForRead() * @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 { enum class DefaultReadAttachment: GLenum {
FrontLeft = GL_FRONT_LEFT, /**< Read from front left framebuffer. */ /** Don't read from any framebuffer */
FrontRight = GL_FRONT_RIGHT, /**< Read from front right framebuffer. */ None = GL_NONE,
BackLeft = GL_BACK_LEFT, /**< Read from back left framebuffer. */
BackRight = GL_BACK_RIGHT, /**< Read from back right framebuffer. */ #ifndef MAGNUM_TARGET_GLES
Left = GL_LEFT, /**< Read from left framebuffers. */ /**
Right = GL_RIGHT, /**< Read from right framebuffers. */ * Read from back left framebuffer.
Front = GL_FRONT, /**< Read from front framebuffers. */ * @requires_gl Stereo rendering is not available in OpenGL ES.
Back = GL_BACK, /**< Read from back framebuffers. */ */
FrontAndBack = GL_FRONT_AND_BACK /**< Read from front and back framebuffers. */ 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 * @brief Constructor
* *
* Generates new OpenGL framebuffer. * Generates new OpenGL framebuffer.
* @see @fn_gl{GenFramebuffers}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/ */
inline Framebuffer() { glGenFramebuffers(1, &framebuffer); } inline Framebuffer() { glGenFramebuffers(1, &_id); }
/** /**
* @brief Destructor * @brief Destructor
* *
* Deletes associated OpenGL framebuffer. * Deletes associated OpenGL framebuffer.
* @see @fn_gl{DeleteFramebuffers}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/ */
inline ~Framebuffer() { glDeleteFramebuffers(1, &framebuffer); } inline ~Framebuffer() { glDeleteFramebuffers(1, &_id); }
/** /**
* @brief Bind default framebuffer to given target * @brief Bind default framebuffer to given target
* @param target %Target * @param target %Target
* *
* @see @fn_gl{BindFramebuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/ */
inline static void bindDefault(Target target) { inline static void bindDefault(Target target) {
@ -735,13 +884,14 @@ class MAGNUM_EXPORT Framebuffer {
/** /**
* @brief Bind framebuffer * @brief Bind framebuffer
* *
* @see @fn_gl{BindFramebuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/ */
inline void bind(Target target) { 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 * @brief Map given attachments of default framebuffer for drawing
* @param attachments Default attachments. If any value is * @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 * If used for blit(), the order is not important. Each used attachment
* should have either renderbuffer or texture attached for writing to * should have either renderbuffer or texture attached for writing to
* work properly. * work properly.
* @see mapForDraw(), mapDefaultForRead() * @see mapForDraw(), mapDefaultForRead(), bindDefault(), @fn_gl{DrawBuffers}
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @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); static void mapDefaultForDraw(std::initializer_list<DefaultDrawAttachment> attachments);
#endif
/** /**
* @brief Map given color attachments of current framebuffer for drawing * @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 * If used for blit(), the order is not important. Each used attachment
* should have either renderbuffer or texture attached for writing to * should have either renderbuffer or texture attached for writing to
* work properly. * work properly.
* @see mapDefaultForDraw(), mapForRead() * @see mapDefaultForDraw(), mapForRead(), bind(), @fn_gl{DrawBuffers}
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @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 * @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 * Each used attachment should have either renderbuffer or texture
* attached to work properly. * attached to work properly.
* @see mapForRead(), mapDefaultForDraw() * @see mapForRead(), mapDefaultForDraw(), bindDefault(), @fn_gl{ReadBuffer}
* @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}
*/ */
inline static void mapDefaultForRead(DefaultReadAttachment attachment) { inline static void mapDefaultForRead(DefaultReadAttachment attachment) {
bindDefault(Target::Read); bindDefault(Target::Read);
@ -795,15 +947,14 @@ class MAGNUM_EXPORT Framebuffer {
* *
* The color attachment should have either renderbuffer or texture * The color attachment should have either renderbuffer or texture
* attached for reading to work properly. * attached for reading to work properly.
* @see mapDefaultForRead(), mapForDraw() * @see mapDefaultForRead(), mapForDraw(), bind(), @fn_gl{ReadBuffer}
* @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}
*/ */
inline void mapForRead(unsigned int colorAttachment) { inline void mapForRead(std::uint8_t colorAttachment) {
bind(Target::Read); bind(Target::Read);
glReadBuffer(GL_COLOR_ATTACHMENT0 + colorAttachment); glReadBuffer(GL_COLOR_ATTACHMENT0 + colorAttachment);
} }
#endif
/*@}*/ /*@}*/
@ -824,10 +975,12 @@ class MAGNUM_EXPORT Framebuffer {
Stencil = GL_STENCIL_ATTACHMENT /**< Stencil output only. */ Stencil = GL_STENCIL_ATTACHMENT /**< Stencil output only. */
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES2
, ,
/** /**
* Both depth and stencil output. * 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 DepthStencil = GL_DEPTH_STENCIL_ATTACHMENT
#endif #endif
@ -837,8 +990,9 @@ class MAGNUM_EXPORT Framebuffer {
* @brief Attach renderbuffer to given framebuffer depth/stencil attachment * @brief Attach renderbuffer to given framebuffer depth/stencil attachment
* @param target %Target * @param target %Target
* @param depthStencilAttachment Depth/stencil attachment * @param depthStencilAttachment Depth/stencil attachment
* @param renderbuffer Renderbuffer * @param renderbuffer %Renderbuffer
* *
* @see bind(), @fn_gl{FramebufferRenderbuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/ */
inline void attachRenderbuffer(Target target, DepthStencilAttachment depthStencilAttachment, Renderbuffer* renderbuffer) { 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 * @brief Attach renderbuffer to given framebuffer color attachment
* @param target %Target * @param target %Target
* @param colorAttachment Color attachment ID (number between 0 and 15) * @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} * @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 */ /** @todo Check for internal format compatibility */
bind(target); bind(target);
glFramebufferRenderbuffer(static_cast<GLenum>(target), GL_COLOR_ATTACHMENT0 + colorAttachment, GL_RENDERBUFFER, renderbuffer->id()); 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 texture 1D texture
* @param mipLevel Mip level * @param mipLevel Mip level
* *
* @requires_gl * @see bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @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) { inline void attachTexture1D(Target target, DepthStencilAttachment depthStencilAttachment, Texture1D* texture, GLint mipLevel) {
/** @todo Check for internal format compatibility */ /** @todo Check for internal format compatibility */
@ -886,10 +1042,11 @@ class MAGNUM_EXPORT Framebuffer {
* @param texture 1D texture * @param texture 1D texture
* @param mipLevel Mip level * @param mipLevel Mip level
* *
* @requires_gl * @see bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @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 internal format compatibility */
/** @todo Check for texture target compatibility */ /** @todo Check for texture target compatibility */
bind(target); bind(target);
@ -905,7 +1062,7 @@ class MAGNUM_EXPORT Framebuffer {
* @param mipLevel Mip level. For rectangle textures it * @param mipLevel Mip level. For rectangle textures it
* should be always 0. * should be always 0.
* *
* @see attachCubeMapTexture() * @see attachCubeMapTexture(), bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/ */
inline void attachTexture2D(Target target, DepthStencilAttachment depthStencilAttachment, Texture2D* texture, GLint mipLevel) { 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 * @param mipLevel Mip level. For rectangle textures it
* should be always 0. * should be always 0.
* *
* @see attachCubeMapTexture() * @see attachCubeMapTexture(), bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @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 internal format compatibility */
/** @todo Check for texture target compatibility */ /** @todo Check for texture target compatibility */
bind(target); bind(target);
@ -941,7 +1098,7 @@ class MAGNUM_EXPORT Framebuffer {
* @param coordinate Cube map coordinate * @param coordinate Cube map coordinate
* @param mipLevel Mip level * @param mipLevel Mip level
* *
* @see attachTexture2D() * @see attachTexture2D(), bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl30 Extension @extension{EXT,framebuffer_object}
*/ */
inline void attachCubeMapTexture(Target target, DepthStencilAttachment depthStencilAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { 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 coordinate Cube map coordinate
* @param mipLevel Mip level * @param mipLevel Mip level
* *
* @see attachTexture2D() * @see attachTexture2D(), bind(), @fn_gl{FramebufferTexture}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @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 */ /** @todo Check for internal format compatibility */
bind(target); bind(target);
glFramebufferTexture2D(static_cast<GLenum>(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast<GLenum>(coordinate), texture->id(), mipLevel); 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 * @brief Attach 3D texture to given framebuffer depth/stencil attachment
* @param target %Target * @param target %Target
@ -976,14 +1132,23 @@ class MAGNUM_EXPORT Framebuffer {
* @param mipLevel Mip level * @param mipLevel Mip level
* @param layer Layer of 2D image within a 3D texture * @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_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) { inline void attachTexture3D(Target target, DepthStencilAttachment depthStencilAttachment, Texture3D* texture, GLint mipLevel, GLint layer) {
/** @todo Check for internal format compatibility */ /** @todo Check for internal format compatibility */
/** @todo Check for texture target compatibility */ /** @todo Check for texture target compatibility */
bind(target); 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); 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 mipLevel Mip level
* @param layer Layer of 2D image within a 3D texture. * @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_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 internal format compatibility */
/** @todo Check for texture target compatibility */ /** @todo Check for texture target compatibility */
bind(target); 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); 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 */ /** @{ @name Framebuffer blitting and reading */
#ifndef MAGNUM_TARGET_GLES
/** /**
* @brief Output mask for blitting * @brief Output mask for blitting
* *
* Specifies which data are copied when performing blit operation * Specifies which data are copied when performing blit operation
* using blit(). * using blit().
* @see BlitMask * @see BlitMask
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl30 Extension @extension{EXT,framebuffer_object}
* @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit}
*/ */
enum class Blit: GLbitfield { enum class Blit: GLbitfield {
Color = GL_COLOR_BUFFER_BIT, /**< Color */ Color = GL_COLOR_BUFFER_BIT, /**< Color */
@ -1027,10 +1199,11 @@ class MAGNUM_EXPORT Framebuffer {
/** /**
* @brief Output mask for blitting * @brief Output mask for blitting
* @requires_gl
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @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 * @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 * mapDefaultForDraw() for binding particular framebuffer for reading
* and drawing. If multiple attachments are specified in mapForDraw() * and drawing. If multiple attachments are specified in mapForDraw()
* / mapDefaultForDraw(), the data are written to each of them. * / mapDefaultForDraw(), the data are written to each of them.
* @requires_gl * @see @fn_gl{BlitFramebuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_blit} * @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) { 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)); 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 * no interpolation is needed and thus
* AbstractTexture::Filter::NearestNeighbor filtering is used by * AbstractTexture::Filter::NearestNeighbor filtering is used by
* default. * default.
* @requires_gl * @see @fn_gl{BlitFramebuffer}
* @requires_gl30 Extension @extension{EXT,framebuffer_blit} * @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) { 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)); 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 * @brief Read block of pixels from framebuffer to image
* @param offset Offset in the framebuffer * @param offset Offset in the framebuffer
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components * @param components Color components
* @param type Data type * @param type Data type
* @param image %Image where to put the data * @param image %Image where to put the data
* *
* @see @fn_gl{ReadPixels}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @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 * @brief Read block of pixels from framebuffer to buffered image
* @param offset Offset in the framebuffer * @param offset Offset in the framebuffer
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components * @param components Color components
* @param type Data type * @param type Data type
* @param image Buffered image where to put the data * @param image Buffered image where to put the data
* @param usage %Buffer usage * @param usage %Buffer usage
* *
* @requires_gl * @see Buffer::bind(Target), @fn_gl{ReadPixels}
* @requires_gl30 Extension @extension{EXT,framebuffer_object} * @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); static void read(const Math::Vector2<GLint>& offset, const Math::Vector2<GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, BufferedImage2D* image, Buffer::Usage usage);
#endif
/*@}*/ /*@}*/
private: private:
static ClearMask clearMask; GLuint _id;
GLuint framebuffer;
}; };
CORRADE_ENUMSET_OPERATORS(Framebuffer::ClearMask) 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 * @brief Class Magnum::Image, typedef Magnum::Image1D, Magnum::Image2D, Magnum::Image3D
*/ */
#include "Math/Vector3.h"
#include "AbstractImage.h" #include "AbstractImage.h"
#include "DimensionTraits.h"
#include "TypeTraits.h" #include "TypeTraits.h"
namespace Magnum { namespace Magnum {
@ -30,14 +32,15 @@ namespace Magnum {
Class for storing image data on client memory. Can be replaced with Class for storing image data on client memory. Can be replaced with
ImageWrapper, BufferedImage, which stores image data in GPU memory, or for ImageWrapper, BufferedImage, which stores image data in GPU memory, or for
example with Trade::ImageData. 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: public:
const static size_t Dimensions = imageDimensions; /**< @brief Image dimension count */ const static std::uint8_t Dimensions = dimensions; /**< @brief %Image dimension count */
/** /**
* @brief Constructor * @brief Constructor
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components. Data type is detected * @param components Color components. Data type is detected
* from passed data array. * from passed data array.
* @param data %Image data with proper size * @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 * Note that the image data are not copied on construction, but they
* are deleted on class destruction. * 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 * @brief Constructor
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components * @param components Color components
* @param type Data type * @param type Data type
* @param data %Image data * @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 * Note that the image data are not copied on construction, but they
* are deleted on class destruction. * 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 * @brief Constructor
@ -72,16 +75,16 @@ template<size_t imageDimensions> class Image: public AbstractImage {
/** @brief Destructor */ /** @brief Destructor */
inline ~Image() { delete[] _data; } inline ~Image() { delete[] _data; }
/** @brief %Image dimensions */ /** @brief %Image size */
inline constexpr const Math::Vector<Dimensions, GLsizei>& dimensions() const { return _dimensions; } inline typename DimensionTraits<Dimensions, GLsizei>::VectorType size() const { return _size; }
/** @brief Pointer to raw data */ /** @brief Pointer to raw data */
inline void* data() { return _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 * @brief Set image data
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components. Data type is detected * @param components Color components. Data type is detected
* from passed data array. * from passed data array.
* @param data %Image data * @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 * Deletes previous data and replaces them with new. Note that the
* data are not copied, but they are deleted on destruction. * 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) { template<class T> inline void setData(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, T* data) {
setData(dimensions, components, TypeTraits<T>::imageType(), data); setData(size, components, TypeTraits<T>::imageType(), data);
} }
/** /**
* @brief Set image data * @brief Set image data
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components * @param components Color components
* @param type Data type * @param type Data type
* @param data %Image data * @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 * Deletes previous data and replaces them with new. Note that the
* data are not copied, but they are deleted on destruction. * data are not copied, but they are deleted on destruction.
*/ */
void setData(const Math::Vector<Dimensions, GLsizei>& dimensions, Components components, ComponentType type, GLvoid* data) { void setData(const typename DimensionTraits<Dimensions, GLsizei>::VectorType& size, Components components, ComponentType type, GLvoid* data);
delete[] _data;
_components = components;
_type = type;
_dimensions = dimensions;
_data = reinterpret_cast<char*>(data);
}
protected: protected:
Math::Vector<Dimensions, GLsizei> _dimensions; /**< @brief %Image dimensions */ Math::Vector<Dimensions, GLsizei> _size; /**< @brief %Image size */
char* _data; /**< @brief %Image data */ 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 */ /** @brief One-dimensional image */
typedef Image<1> Image1D; typedef Image<1> Image1D;

30
src/ImageWrapper.h

@ -19,7 +19,9 @@
* @brief Class Magnum::ImageWrapper * @brief Class Magnum::ImageWrapper
*/ */
#include "Math/Vector3.h"
#include "AbstractImage.h" #include "AbstractImage.h"
#include "DimensionTraits.h"
#include "TypeTraits.h" #include "TypeTraits.h"
namespace Magnum { namespace Magnum {
@ -38,13 +40,13 @@ to change image properties, only data pointer.
See also Image, BufferedImage and Trade::ImageData. 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: public:
const static size_t Dimensions = imageDimensions; /**< @brief Image dimension count */ const static std::uint8_t Dimensions = dimensions; /**< @brief %Image dimension count */
/** /**
* @brief Constructor * @brief Constructor
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components. Data type is detected * @param components Color components. Data type is detected
* from passed data array. * from passed data array.
* @param data %Image data with proper size * @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 * Note that the image data are not copied on construction, but they
* are deleted on class destruction. * 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 * @brief Constructor
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components * @param components Color components
* @param type Data type * @param type Data type
* @param data %Image data * @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 * Note that the image data are not copied on construction, but they
* are deleted on class destruction. * 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 * @brief Constructor
* @param dimensions %Image dimensions * @param size %Image size
* @param components Color components * @param components Color components
* @param type Data type * @param type Data type
* *
* Dimensions and data pointer are set to zero, call setData() to fill * Dimensions and data pointer are set to zero, call setData() to fill
* the image with data. * 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 */ /** @brief %Image size */
inline constexpr const Math::Vector<Dimensions, GLsizei>& dimensions() const { return _dimensions; } inline typename DimensionTraits<Dimensions, GLsizei>::VectorType size() const { return _size; }
/** @brief Pointer to raw data */ /** @brief Pointer to raw data */
inline void* data() { return _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 * @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 * passed in constructor. The data are not copied nor deleted on
* destruction. * destruction.
*/ */
void setData(GLvoid* data) { inline void setData(GLvoid* data) {
_data = reinterpret_cast<char*>(data); _data = reinterpret_cast<char*>(data);
} }
protected: protected:
Math::Vector<Dimensions, GLsizei> _dimensions; /**< @brief %Image dimensions */ Math::Vector<Dimensions, GLsizei> _size; /**< @brief %Image size */
char* _data; /**< @brief %Image data */ char* _data; /**< @brief %Image data */
}; };
/** @brief One-dimensional image wrapper */ /** @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 "IndexedMesh.h"
#include <Utility/Debug.h>
#include "Buffer.h"
#include "Context.h"
#include "Extensions.h"
namespace Magnum { namespace Magnum {
void IndexedMesh::draw() { IndexedMesh::BindIndexBufferImplementation IndexedMesh::bindIndexBufferImplementation = &IndexedMesh::bindIndexBufferImplementationDefault;
/* Vertex array must be bound before finalization */ IndexedMesh::BindIndexedImplementation IndexedMesh::bindIndexedImplementation = &IndexedMesh::bindIndexedImplementationDefault;
#ifndef MAGNUM_TARGET_GLES
bind();
#endif
finalize(); IndexedMesh* IndexedMesh::setIndexBuffer(Buffer* buffer) {
_indexBuffer = buffer;
(this->*bindIndexBufferImplementation)();
return this;
}
/* Buffers must be bound after initialization */ void IndexedMesh::draw() {
#ifdef MAGNUM_TARGET_GLES
bind(); bind();
_indexBuffer.bind();
#endif
/** @todo Start at given index */ /** @todo Start at given index */
glDrawElements(static_cast<GLenum>(primitive()), _indexCount, static_cast<GLenum>(_indexType), nullptr); glDrawElements(static_cast<GLenum>(primitive()), _indexCount, static_cast<GLenum>(_indexType), nullptr);
@ -37,20 +41,38 @@ void IndexedMesh::draw() {
unbind(); unbind();
} }
#ifndef DOXYGEN_GENERATING_OUTPUT void IndexedMesh::bind() {
void IndexedMesh::finalize() {
if(isFinalized()) return;
CORRADE_ASSERT(_indexCount, "IndexedMesh: the mesh has zero index count!", ); CORRADE_ASSERT(_indexCount, "IndexedMesh: the mesh has zero index count!", );
/* Finalize attribute positions */ Mesh::bind();
Mesh::finalize(); (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 #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
} }
#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 "Mesh.h"
#include "Buffer.h"
namespace Magnum { 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 { class MAGNUM_EXPORT IndexedMesh: public Mesh {
friend class Context;
public: public:
/** /**
* @brief Implicit constructor * @brief Constructor
* @param primitive Primitive type * @param primitive Primitive type
* *
* Allows creating the object without knowing anything about mesh data. * Creates indexed mesh with no index buffer, zero vertex count and
* Note that you have to call setVertexCount(), setIndexCount() and * zero index count.
* setIndexType() manually for mesh to draw properly. * @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 * @brief Set index buffer
* @param primitive Primitive type *
* @param vertexCount Count of unique vertices * @see MeshTools::compressIndices(), @fn_gl{BindVertexArray},
* @param indexCount Count of indices * @fn_gl{BindBuffer} (if @extension{APPLE,vertex_array_object}
* @param indexType Type of indices (indexable, see TypeTraits) * 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 */ /** @brief Index count */
inline GLsizei indexCount() const { return _indexCount; } inline GLsizei indexCount() const { return _indexCount; }
/** @brief Set index count */ /**
/** @todo definalize after that? */ * @brief Set index count
inline void setIndexCount(GLsizei count) { _indexCount = count; } * @return Pointer to self (for method chaining)
*
* @see MeshTools::compressIndices()
*/
inline IndexedMesh* setIndexCount(GLsizei count) {
_indexCount = count;
return this;
}
/** @brief Index type */ /** @brief Index type */
inline Type indexType() const { return _indexType; } 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 * @see MeshTools::compressIndices()
* indices (of type specified in constructor).
*/ */
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(); void draw();
protected:
#ifndef DOXYGEN_GENERATING_OUTPUT
MAGNUM_LOCAL void finalize();
#endif
private: 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; GLsizei _indexCount;
Type _indexType; Type _indexType;
}; };

40
src/Magnum.h

@ -23,15 +23,41 @@
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
#include <GL/glew.h> #include <GL/glew.h>
#include <GL/glcorearb.h>
#else #else
#include <GLES2/gl2.h> #include <GLES3/gl3.h>
#endif #endif
#include "Math/Math.h" /**
#include "Math/Matrix4.h" * @todo Link to libGL / libGLES based on which windowcontext is used in app
#include "Math/Vector2.h" * 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 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 */ /* Bring debugging facility from Corrade::Utility namespace */
using Corrade::Utility::Debug; using Corrade::Utility::Debug;
@ -47,6 +73,12 @@ typedef Math::Vector3<GLfloat> Vector3;
/** @brief Four-component floating-point vector */ /** @brief Four-component floating-point vector */
typedef Math::Vector4<GLfloat> Vector4; 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 */ /** @brief 3x3 floating-point matrix */
typedef Math::Matrix3<GLfloat> Matrix3; typedef Math::Matrix3<GLfloat> Matrix3;

20
src/Math/Algorithms/GaussJordan.h

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

3
src/Math/CMakeLists.txt

@ -1,11 +1,14 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR})
set(MagnumMath_HEADERS set(MagnumMath_HEADERS
Constants.h
Math.h Math.h
MathTypeTraits.h MathTypeTraits.h
Matrix.h Matrix.h
Matrix3.h Matrix3.h
Matrix4.h Matrix4.h
Point2D.h
Point3D.h
RectangularMatrix.h RectangularMatrix.h
Vector.h Vector.h
Vector2.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 * @brief Class Magnum::Math::Geometry::Distance
*/ */
#include "Math/Math.h"
#include "Math/Matrix.h"
#include "Math/Vector3.h" #include "Math/Vector3.h"
namespace Magnum { namespace Math { namespace Geometry { namespace Magnum { namespace Math { namespace Geometry {
@ -27,36 +29,68 @@ namespace Magnum { namespace Math { namespace Geometry {
class Distance { class Distance {
public: public:
/** /**
* @brief %Distance of line and point * @brief %Distance of line and point in 2D
* @param a First point of the line * @param a First point of the line
* @param b Second point of the line * @param b Second point of the line
* @param point Point * @param point Point
* *
* The distance *d* is computed from point **p** and line defined by **a** * The distance *d* is computed from point **p** and line defined by **a**
* and **b** using @ref Vector3::cross() "cross product": * and **b** using @ref Matrix::determinant() "determinant": @f[
* @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)|} * d = \frac{|(\boldsymbol p - \boldsymbol a) \times (\boldsymbol p - \boldsymbol b)|}
* {|\boldsymbol b - \boldsymbol a|} * {|\boldsymbol b - \boldsymbol a|}
* @f] * @f]
* * Source: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
* @see linePointSquared() * @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) { 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 * More efficient than linePoint(const Vector3&, const Vector3&, const Vector3&)
* values, because it doesn't compute the square root. * 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) { 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(); 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 a Starting point of the line
* @param b Ending point of the line * @param b Ending point of the line
* @param point Point * @param point Point
@ -66,34 +100,88 @@ class Distance {
* *
* Determining whether the point lies next to line segment or outside * Determining whether the point lies next to line segment or outside
* is done using Pythagorean theorem. If the following equation * is done using Pythagorean theorem. If the following equation
* applies, the point **p** lies outside line segment closer to **a**: * applies, the point **p** lies outside line segment closer to **a**: @f[
* @f[
* |\boldsymbol p - \boldsymbol b|^2 > |\boldsymbol b - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol a|^2 * |\boldsymbol p - \boldsymbol b|^2 > |\boldsymbol b - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol a|^2
* @f] * @f]
* On the other hand, if the following equation applies, the point * On the other hand, if the following equation applies, the point
* lies outside line segment closer to **b**: * lies outside line segment closer to **b**: @f[
* @f[
* |\boldsymbol p - \boldsymbol a|^2 > |\boldsymbol b - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol b|^2 * |\boldsymbol p - \boldsymbol a|^2 > |\boldsymbol b - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol b|^2
* @f] * @f]
* The last alternative is when the following equation applies. The * The last alternative is when the following equation applies. The
* point then lies between **a** and **b** and the distance is * point then lies between **a** and **b** and the distance is
* computed the same way as in linePoint(). * computed the same way as in linePoint(). @f[
* @f[
* |\boldsymbol b - \boldsymbol a|^2 > |\boldsymbol p - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol b|^2 * |\boldsymbol b - \boldsymbol a|^2 > |\boldsymbol p - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol b|^2
* @f] * @f]
* *
* @see lineSegmentPointSquared() * @see lineSegmentPointSquared()
*/ */
template<class T> inline static T lineSegmentPoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) { template<class T> inline static T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
return sqrt(lineSegmentPointSquared(a, b, 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 * More efficient than lineSegmentPoint() for comparing distance with
* other values, because it doesn't compute the square root. * 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) { 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> pointMinusA = point - a;
Vector3<T> pointMinusB = point - b; 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`. * is inside the line segment defined by `a` and `b`.
* *
* First the parameter *f* of parametric equation of the plane * First the parameter *f* of parametric equation of the plane
* is computed from plane normal **n** and plane position: * is computed from plane normal **n** and plane position: @f[
* @f[
* \begin{pmatrix} n_0 \\ n_1 \\ n_2 \end{pmatrix} \cdot * \begin{pmatrix} n_0 \\ n_1 \\ n_2 \end{pmatrix} \cdot
* \begin{pmatrix} x \\ y \\ z \end{pmatrix} - f = 0 * \begin{pmatrix} x \\ y \\ z \end{pmatrix} - f = 0
* @f] * @f]
* Using plane normal **n**, parameter *f* and points **a** and **b**, * Using plane normal **n**, parameter *f* and points **a** and **b**,
* value of *t* is computed and returned. * value of *t* is computed and returned. @f[
* @f[
* \begin{array}{rcl} * \begin{array}{rcl}
* \Delta \boldsymbol b & = & \boldsymbol b - \boldsymbol a \\ * \Delta \boldsymbol b & = & \boldsymbol b - \boldsymbol a \\
* f & = & \boldsymbol n \cdot (\boldsymbol a + \Delta \boldsymbol b \cdot t) \\ * 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 <limits>
#include "Math.h" #include "Constants.h"
#include "Distance.h" #include "Distance.h"
CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::DistanceTest) CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::DistanceTest)
@ -26,14 +26,35 @@ using namespace std;
namespace Magnum { namespace Math { namespace Geometry { namespace Test { namespace Magnum { namespace Math { namespace Geometry { namespace Test {
typedef Magnum::Math::Vector2<float> Vector2;
typedef Magnum::Math::Vector3<float> Vector3; typedef Magnum::Math::Vector3<float> Vector3;
DistanceTest::DistanceTest() { DistanceTest::DistanceTest() {
addTests(&DistanceTest::linePoint, addTests(&DistanceTest::linePoint2D,
&DistanceTest::lineSegmentPoint); &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 a(0.0f);
Vector3 b(1.0f); Vector3 b(1.0f);
@ -47,7 +68,38 @@ void DistanceTest::linePoint() {
Constants<float>::sqrt2()/Constants<float>::sqrt3()); 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 a(0.0f);
Vector3 b(1.0f); Vector3 b(1.0f);

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

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

6
src/Math/Math.cpp

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

63
src/Math/Math.h

@ -15,7 +15,6 @@
GNU Lesser General Public License version 3 for more details. GNU Lesser General Public License version 3 for more details.
*/ */
#include <cstddef>
#include <cmath> #include <cmath>
#include <type_traits> #include <type_traits>
#include <limits> #include <limits>
@ -25,7 +24,7 @@
#include "magnumVisibility.h" #include "magnumVisibility.h"
/** @file /** @file
* @brief Math constants and utilities * @brief Math utilities
*/ */
namespace Magnum { namespace Math { namespace Magnum { namespace Math {
@ -37,33 +36,9 @@ namespace Magnum { namespace Math {
matrices) 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 #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 { 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 { template<class T> inline constexpr T operator()(T base) const {
return base*Pow<exponent-1>()(base); return base*Pow<exponent-1>()(base);
} }
@ -79,7 +54,7 @@ namespace Implementation {
* *
* Returns integral power of base to the exponent. * 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); 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. * 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 @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 literals, this function should be called with both template parameters
explicit, e.g.: explicit, e.g.:
@code @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'); float a = normalize<float>('\127');
// b = 1.0f // b = 1.0f
float b = normalize<float, char>('\127'); float b = normalize<float, int8_t>('\127');
@endcode @endcode
@todo Signed normalization to [-1.0, 1.0] like in OpenGL? @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. integral type.
@note For best precision, `FloatingPoint` type should be always larger that @note For best precision, `FloatingPoint` type should be always larger that
resulting `Integral` type (e.g. `double` to `int`, `long double` to `long long`). resulting `Integral` type (e.g. `double` to `std::int32_t`, `long double` to
`std::int64_t`).
@todo Signed normalization to [-1.0, 1.0] like in OpenGL? @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) { template<class Integral, class FloatingPoint> inline constexpr typename std::enable_if<std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value, Integral>::type denormalize(FloatingPoint value) {
return std::numeric_limits<Integral>::min() + return std::numeric_limits<Integral>::min() +
@ -136,27 +114,6 @@ template<class T> inline T clamp(T value, T min, T max) {
return std::min(std::max(value, min), 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 #endif

58
src/Math/MathTypeTraits.h

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

74
src/Math/Matrix.h

@ -25,21 +25,22 @@ namespace Magnum { namespace Math {
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation { namespace Implementation {
template<size_t size, class T> class MatrixDeterminant; template<std::size_t size, class T> class MatrixDeterminant;
} }
#endif #endif
/** /**
@brief Square matrix @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} @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: 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 */ /** @brief Pass to constructor to create zero-filled matrix */
enum ZeroType { Zero }; 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 * `Matrix m(Matrix::Identity);`. Optional parameter @p value allows
* you to specify value on diagonal. * you to specify value on diagonal.
*/ */
inline explicit Matrix(IdentityType = Identity, T value = T(1)) { inline Matrix(IdentityType = Identity, T value = T(1)) {
for(size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
(*this)(i, i) = value; (*this)(i, i) = value;
} }
/** @copydoc RectangularMatrix::RectangularMatrix(T, U...) */ /** @copydoc RectangularMatrix::RectangularMatrix */
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
template<class ...U> inline constexpr Matrix(T first, U... next): RectangularMatrix<size, size, T>(first, next...) {} template<class ...U> inline constexpr Matrix(T first, U... next): RectangularMatrix<size, size, T>(first, next...) {}
#else #else
@ -91,18 +92,18 @@ template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
T trace() const { T trace() const {
T out(0); T out(0);
for(size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
out += (*this)(i, i); out += (*this)(i, i);
return out; return out;
} }
/** @brief %Matrix without given column and row */ /** @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); Matrix<size-1, T> out(Matrix<size-1, T>::Zero);
for(size_t row = 0; row != size-1; ++row) for(std::size_t col = 0; col != size-1; ++col)
for(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), out(col, row) = (*this)(col + (col >= skipCol),
row + (row >= skipRow)); row + (row >= skipRow));
@ -112,15 +113,12 @@ template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
/** /**
* @brief Determinant * @brief Determinant
* *
* Computed recursively using Laplace's formula: * Computed recursively using Laplace's formula: @f[
* @f[ * \det(A) = \sum_{j=1}^n (-1)^{i+j} a_{i,j} \det(A^{i,j})
* \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
* @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 * ij(). The formula is expanded down to 2x2 matrix, where the
* determinant is computed directly: * determinant is computed directly: @f[
* @f[ * \det(A) = a_{0, 0} a_{1, 1} - a_{1, 0} a_{0, 1}
* \det(A) = a_{0, 0} a_{1, 1} - a_{1, 0} a_{0, 1}
* @f] * @f]
*/ */
inline T determinant() const { return Implementation::MatrixDeterminant<size, T>()(*this); } 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 * @brief Inverted matrix
* *
* Computed using Cramer's rule: * Computed using Cramer's rule: @f[
* @f[ * A^{-1} = \frac{1}{\det(A)} Adj(A)
* A^{-1} = \frac{1}{\det(A)} Adj(A)
* @f] * @f]
*/ */
Matrix<size, T> inverted() const { 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(); T _determinant = determinant();
for(size_t row = 0; row != size; ++row) for(std::size_t col = 0; col != size; ++col)
for(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; out(col, row) = (((row+col) & 1) ? -1 : 1)*ij(row, col).determinant()/_determinant;
return out; 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 { inline Matrix<size, T> operator*(const Matrix<size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other); 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); return RectangularMatrix<size, size, T>::operator*(other);
} }
inline Vector<size, T> operator*(const Vector<size, T>& other) const { 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 #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); 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); return number/RectangularMatrix<size, size, T>(matrix);
} }
#endif #endif
/** @debugoperator{Magnum::Math::Matrix} */ /** @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) { 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 Magnum::Math::RectangularMatrix<size, size, T>&>(value); return debug << static_cast<const RectangularMatrix<size, size, T>&>(value);
} }
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
@ -192,10 +189,10 @@ template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utili
return *this; \ 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); \ 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); \ 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); \ Matrix<size, T>::operator*=(other); \
return *this; \ 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); \ return Matrix<size, T>::operator*(other); \
} \ } \
inline VectorType<T> operator*(const Vector<size, T>& other) const { \ 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 { namespace Implementation {
template<size_t size, class T> class MatrixDeterminant { template<std::size_t size, class T> class MatrixDeterminant {
public: public:
/** @brief Functor */
T operator()(const Matrix<size, T>& m) { T operator()(const Matrix<size, T>& m) {
T out(0); 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(); out += ((col & 1) ? -1 : 1)*m(col, 0)*m.ij(col, 0).determinant();
return out; return out;
@ -241,7 +237,6 @@ template<size_t size, class T> class MatrixDeterminant {
template<class T> class MatrixDeterminant<2, T> { template<class T> class MatrixDeterminant<2, T> {
public: public:
/** @brief Functor */
inline constexpr T operator()(const Matrix<2, T>& m) { inline constexpr T operator()(const Matrix<2, T>& m) {
return m(0, 0)*m(1, 1) - m(1, 0)*m(0, 1); return m(0, 0)*m(1, 1) - m(1, 0)*m(0, 1);
} }
@ -249,7 +244,6 @@ template<class T> class MatrixDeterminant<2, T> {
template<class T> class MatrixDeterminant<1, T> { template<class T> class MatrixDeterminant<1, T> {
public: public:
/** @brief Functor */
inline constexpr T operator()(const Matrix<1, T>& m) { inline constexpr T operator()(const Matrix<1, T>& m) {
return m(0, 0); return m(0, 0);
} }
@ -262,7 +256,7 @@ template<class T> class MatrixDeterminant<1, T> {
namespace Corrade { namespace Utility { namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Matrix} */ /** @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 #endif

98
src/Math/Matrix3.h

@ -20,57 +20,64 @@
*/ */
#include "Matrix.h" #include "Matrix.h"
#include "Vector3.h" #include "Point2D.h"
namespace Magnum { namespace Math { 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 Provides functions for transformations in 2D. See Matrix4 for 3D
transformations. transformations. See also @ref matrix-vector for brief introduction.
@configurationvalueref{Magnum::Math::Matrix3} @configurationvalueref{Magnum::Math::Matrix3}
*/ */
template<class T> class Matrix3: public Matrix<3, T> { template<class T> class Matrix3: public Matrix<3, T> {
public: public:
/** /**
* @brief 2D translation matrix * @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! */ return Matrix3<T>( /* Column-major! */
T(1), T(0), T(0), T(1), T(0), T(0),
T(0), T(1), T(0), T(0), T(1), T(0),
vec.x(), vec.y(), T(1) vector.x(), vector.y(), T(1)
); );
} }
/** /**
* @brief 2D scaling matrix * @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! */ return Matrix3<T>( /* Column-major! */
vec.x(), T(0), T(0), vector.x(), T(0), T(0),
T(0), vec.y(), T(0), T(0), vector.y(), T(0),
T(0), T(0), T(1) T(0), T(0), T(1)
); );
} }
/** /**
* @brief 3D rotation matrix * @brief 2D rotation matrix
* @param angle Rotation angle (counterclockwise, in radians) * @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) { static Matrix3<T> rotation(T angle) {
T sine = std::sin(angle);
T cosine = std::cos(angle);
return Matrix3<T>( /* Column-major! */ return Matrix3<T>( /* Column-major! */
T(cos(angle)), T(sin(angle)), T(0), cosine, sine, T(0),
-T(sin(angle)), T(cos(angle)), T(0), -sine, cosine, T(0),
T(0), T(0), T(1) 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) {} inline constexpr explicit Matrix3(typename Matrix<3, T>::ZeroType): Matrix<3, T>(Matrix<3, T>::Zero) {}
/** @copydoc Matrix::Matrix(IdentityType, T) */ /** @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), value, T(0), T(0),
T(0), value, T(0), T(0), value, T(0),
T(0), T(0), value T(0), T(0), value
) {} ) {}
/** @copydoc Matrix::Matrix(T, U...) */ /** @copydoc Matrix::Matrix */
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
template<class ...U> inline constexpr Matrix3(T first, U... next): Matrix<3, T>(first, next...) {} template<class ...U> inline constexpr Matrix3(T first, U... next): Matrix<3, T>(first, next...) {}
#else #else
@ -95,13 +102,60 @@ template<class T> class Matrix3: public Matrix<3, T> {
/** @brief Copy constructor */ /** @brief Copy constructor */
inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {} 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_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(3, 3, Matrix3<T>) MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(3, 3, Matrix3<T>)
}; };
/** @debugoperator{Magnum::Math::Matrix3} */ /** @debugoperator{Magnum::Math::Matrix3} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix3<T>& value) { template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix3<T>& value) {
return debug << static_cast<const Magnum::Math::Matrix<3, 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 * @brief Class Magnum::Math::Matrix4
*/ */
#include "Matrix3.h" #include "Matrix.h"
#include "Vector4.h" #include "Point3D.h"
namespace Magnum { namespace Math { 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 Provides functions for transformations in 3D. See Matrix3 for 2D
transformations. transformations. See also @ref matrix-vector for brief introduction.
@configurationvalueref{Magnum::Math::Matrix4} @configurationvalueref{Magnum::Math::Matrix4}
@todo Shearing @todo Shearing
@todo Reflection @todo Reflection
@ -36,86 +37,153 @@ transformations.
template<class T> class Matrix4: public Matrix<4, T> { template<class T> class Matrix4: public Matrix<4, T> {
public: public:
/** /**
* @brief 3D translation matrix * @brief 3D translation
* @param vec Translation vector * @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! */ return Matrix4<T>( /* Column-major! */
T(1), T(0), T(0), T(0), T(1), T(0), T(0), T(0),
T(0), T(1), T(0), T(0), T(0), T(1), T(0), T(0),
T(0), T(0), T(1), 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 * @brief 3D scaling
* @param vec Scaling vector * @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! */ return Matrix4<T>( /* Column-major! */
vec.x(), T(0), T(0), T(0), vector.x(), T(0), T(0), T(0),
T(0), vec.y(), T(0), T(0), T(0), vector.y(), T(0), T(0),
T(0), T(0), vec.z(), T(0), T(0), T(0), vector.z(), T(0),
T(0), T(0), T(0), T(1) T(0), T(0), T(0), T(1)
); );
} }
/** /**
* @brief 3D rotation matrix * @brief 3D rotation around arbitrary axis
* @param angle Rotation angle (counterclockwise, in radians) * @param angle Rotation angle (counterclockwise, in radians)
* @param vec Rotation vector * @param normalizedAxis Normalized rotation axis
* *
* @see Matrix3::rotation(), Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis(), deg(), rad() * If possible, use faster alternatives like rotationX(), rotationY()
* @todo optimize - Assume the vectors are normalized? * 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) { static Matrix4<T> rotation(T angle, const Vector3<T>& normalizedAxis) {
Vector3<T> vn = vec.normalized(); CORRADE_ASSERT(MathTypeTraits<T>::equals(normalizedAxis.dot(), T(1)),
"Math::Matrix4::rotation(): axis must be normalized", {});
T sine = std::sin(angle); T sine = std::sin(angle);
T cosine = std::cos(angle); T cosine = std::cos(angle);
T oneMinusCosine = T(1) - cosine; T oneMinusCosine = T(1) - cosine;
T xx = vn.x()*vn.x(); T xx = normalizedAxis.x()*normalizedAxis.x();
T xy = vn.x()*vn.y(); T xy = normalizedAxis.x()*normalizedAxis.y();
T xz = vn.x()*vn.z(); T xz = normalizedAxis.x()*normalizedAxis.z();
T yy = vn.y()*vn.y(); T yy = normalizedAxis.y()*normalizedAxis.y();
T yz = vn.y()*vn.z(); T yz = normalizedAxis.y()*normalizedAxis.z();
T zz = vn.z()*vn.z(); T zz = normalizedAxis.z()*normalizedAxis.z();
return Matrix4<T>( /* Column-major! */ return Matrix4<T>( /* Column-major! */
cosine + xx*oneMinusCosine, cosine + xx*oneMinusCosine,
xy*oneMinusCosine + vn.z()*sine, xy*oneMinusCosine + normalizedAxis.z()*sine,
xz*oneMinusCosine - vn.y()*sine, xz*oneMinusCosine - normalizedAxis.y()*sine,
T(0), T(0),
xy*oneMinusCosine - vn.z()*sine, xy*oneMinusCosine - normalizedAxis.z()*sine,
cosine + yy*oneMinusCosine, cosine + yy*oneMinusCosine,
yz*oneMinusCosine + vn.x()*sine, yz*oneMinusCosine + normalizedAxis.x()*sine,
T(0), T(0),
xz*oneMinusCosine + vn.y()*sine, xz*oneMinusCosine + normalizedAxis.y()*sine,
yz*oneMinusCosine - vn.x()*sine, yz*oneMinusCosine - normalizedAxis.x()*sine,
cosine + zz*oneMinusCosine, cosine + zz*oneMinusCosine,
T(0), T(0),
T(0), T(0), T(0), T(1) 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) */ /** @copydoc Matrix::Matrix(ZeroType) */
inline constexpr explicit Matrix4(typename Matrix<4, T>::ZeroType): Matrix<4, T>(Matrix<4, T>::Zero) {} inline constexpr explicit Matrix4(typename Matrix<4, T>::ZeroType): Matrix<4, T>(Matrix<4, T>::Zero) {}
/** @copydoc Matrix::Matrix(IdentityType, T) */ /** @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), value, T(0), T(0), T(0),
T(0), value, T(0), T(0), T(0), value, T(0), T(0),
T(0), T(0), value, T(0), T(0), T(0), value, T(0),
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 #ifndef DOXYGEN_GENERATING_OUTPUT
template<class ...U> inline constexpr Matrix4(T first, U... next): Matrix<4, T>(first, next...) {} template<class ...U> inline constexpr Matrix4(T first, U... next): Matrix<4, T>(first, next...) {}
#else #else
@ -125,27 +193,38 @@ template<class T> class Matrix4: public Matrix<4, T> {
/** @brief Copy constructor */ /** @brief Copy constructor */
inline constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {} 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 3D rotation and scaling part of the matrix
*
/** @brief Rotation and scaling part of the matrix */ * Upper-left 3x3 part of the matrix.
inline Matrix3<T> rotationScaling() const { * @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 */ #ifndef CORRADE_GCC45_COMPATIBILITY /* GCC 4.5 badly optimizes this */
return Matrix3<T>::from( return Matrix<3, T>::from(
(*this)[0].xyz(), (*this)[0].xyz(),
(*this)[1].xyz(), (*this)[1].xyz(),
(*this)[2].xyz()); (*this)[2].xyz());
#else #else
return Matrix3<T>( return Matrix<3, T>(
(*this)(0, 0), (*this)(0, 1), (*this)(0, 2), (*this)(0, 0), (*this)(0, 1), (*this)(0, 2),
(*this)(1, 0), (*this)(1, 1), (*this)(1, 2), (*this)(1, 0), (*this)(1, 1), (*this)(1, 2),
(*this)(2, 0), (*this)(2, 1), (*this)(2, 2)); (*this)(2, 0), (*this)(2, 1), (*this)(2, 2));
#endif #endif
} }
/** @brief Rotation part of the matrix */ /**
inline Matrix3<T> rotation() const { * @brief 3D rotation part of the matrix
return Matrix3<T>::from( *
* 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 */ #ifndef CORRADE_GCC45_COMPATIBILITY /* GCC 4.5 badly optimizes this */
(*this)[0].xyz().normalized(), (*this)[0].xyz().normalized(),
(*this)[1].xyz().normalized(), (*this)[1].xyz().normalized(),
@ -157,13 +236,36 @@ template<class T> class Matrix4: public Matrix<4, T> {
#endif #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_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix4, Vector4, 4)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(4, 4, Matrix4<T>) MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(4, 4, Matrix4<T>)
}; };
/** @debugoperator{Magnum::Math::Matrix4} */ /** @debugoperator{Magnum::Math::Matrix4} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix4<T>& value) { template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix4<T>& value) {
return debug << static_cast<const Magnum::Math::Matrix<4, 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 { namespace Magnum { namespace Math {
/** @todo Properly test all constexpr */
template<std::size_t, std::size_t, class> class RectangularMatrix;
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation { namespace Implementation {
template<size_t ...> struct Sequence {}; template<std::size_t ...> struct Sequence {};
/* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ /* 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...> {}; 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; 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 #endif
template<size_t size, class T> class Vector; template<std::size_t size, class T> class Vector;
/** /**
@brief Rectangular matrix @brief Rectangular matrix
@tparam c Column count @tparam cols Column count
@tparam r Row 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 { template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
static_assert(c != 0 && r != 0, "Matrix cannot have zero elements"); static_assert(cols != 0 && rows != 0, "Matrix cannot have zero elements");
friend class Vector<r, T>;
public: public:
typedef T Type; /**< @brief Data type */ typedef T Type; /**< @brief Data type */
const static size_t cols = c; /**< @brief %Matrix column count */ const static std::size_t Cols = cols; /**< @brief %Matrix column count */
const static size_t rows = r; /**< @brief %Matrix row count */ const static std::size_t Rows = rows; /**< @brief %Matrix row count */
/** /**
* @brief %Matrix from array * @brief %Matrix from array
@ -81,12 +90,29 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
* @brief %Matrix from column vectors * @brief %Matrix from column vectors
* @param first First column vector * @param first First column vector
* @param next Next column vectors * @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) { 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"); 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...); 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 */ /** @brief Zero-filled matrix constructor */
inline constexpr RectangularMatrix(): _data() {} inline constexpr RectangularMatrix(): _data() {}
@ -107,10 +133,10 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
#endif #endif
/** @brief Copy constructor */ /** @brief Copy constructor */
inline constexpr RectangularMatrix(const RectangularMatrix<c, r, T>&) = default; inline constexpr RectangularMatrix(const RectangularMatrix<cols, rows, T>&) = default;
/** @brief Assignment operator */ /** @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 * @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 * For accessing individual elements prefer to use operator(), as it
* is guaranteed to not involve unnecessary conversions. * 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); return Vector<rows, T>::from(_data+col*rows);
} }
/** @overload */ /** @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); 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 `[][]`. * Prefer this instead of using `[][]`.
* @see operator[] * @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]; return _data[col*rows+row];
} }
/** @overload */ /** @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]; return _data[col*rows+row];
} }
/** @brief Equality operator */ /** @brief Equality operator */
inline bool operator==(const RectangularMatrix<cols, rows, T>& other) const { 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; if(!MathTypeTraits<T>::equals(_data[i], other._data[i])) return false;
return true; return true;
@ -177,7 +203,7 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
* in-place. * in-place.
*/ */
RectangularMatrix<cols, rows, T>& operator+=(const RectangularMatrix<cols, rows, T>& other) { 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]; _data[i] += other._data[i];
return *this; 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> operator-() const {
RectangularMatrix<cols, rows, T> out; 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]; out._data[i] = -_data[i];
return out; return out;
@ -209,7 +235,7 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
* in-place. * in-place.
*/ */
RectangularMatrix<cols, rows, T>& operator-=(const RectangularMatrix<cols, rows, T>& other) { 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]; _data[i] -= other._data[i];
return *this; return *this;
@ -239,7 +265,7 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
#else #else
template<class U> RectangularMatrix<cols, rows, T>& operator*=(U number) { template<class U> RectangularMatrix<cols, rows, T>& operator*=(U number) {
#endif #endif
for(size_t i = 0; i != cols*rows; ++i) for(std::size_t i = 0; i != cols*rows; ++i)
_data[i] *= number; _data[i] *= number;
return *this; return *this;
@ -269,19 +295,19 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
#else #else
template<class U> RectangularMatrix<cols, rows, T>& operator/=(U number) { template<class U> RectangularMatrix<cols, rows, T>& operator/=(U number) {
#endif #endif
for(size_t i = 0; i != cols*rows; ++i) for(std::size_t i = 0; i != cols*rows; ++i)
_data[i] /= number; _data[i] /= number;
return *this; return *this;
} }
/** @brief Multiply matrix */ /** @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; RectangularMatrix<size, rows, T> out;
for(size_t row = 0; row != rows; ++row) for(std::size_t col = 0; col != size; ++col)
for(size_t col = 0; col != size; ++col) /** @todo swap */ for(std::size_t row = 0; row != rows; ++row)
for(size_t pos = 0; pos != cols; ++pos) for(std::size_t pos = 0; pos != cols; ++pos)
out(col, row) += (*this)(pos, row)*other(col, pos); out(col, row) += (*this)(pos, row)*other(col, pos);
return out; 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> transposed() const {
RectangularMatrix<rows, cols, T> out; RectangularMatrix<rows, cols, T> out;
for(size_t col = 0; col != cols; ++col) for(std::size_t col = 0; col != cols; ++col)
for(size_t row = 0; row != rows; ++row) for(std::size_t row = 0; row != rows; ++row)
out(row, col) = (*this)(col, row); out(row, col) = (*this)(col, row);
return out; return out;
} }
#ifndef DOXYGEN_GENERATING_OUTPUT
protected:
T _data[rows*cols];
#endif
private: 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]...); 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...); return RectangularMatrix<cols, rows, T>(first, next...);
} }
T _data[rows*cols];
}; };
/** @relates RectangularMatrix /** @relates RectangularMatrix
@ -325,9 +354,9 @@ template<size_t c, size_t r, class T> class RectangularMatrix {
@see RectangularMatrix::operator*(U) const @see RectangularMatrix::operator*(U) const
*/ */
#ifndef DOXYGEN_GENERATING_OUTPUT #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 #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 #endif
return matrix*number; 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/() @see RectangularMatrix::operator/()
*/ */
#ifndef DOXYGEN_GENERATING_OUTPUT #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 #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 #endif
RectangularMatrix<cols, rows, T> out; 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]; out.data()[i] = number/matrix.data()[i];
return out; return out;
} }
/** @debugoperator{Magnum::Math::RectangularMatrix} */ /** @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 << "Matrix(";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); 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 "; 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 << ", "; if(col != 0) debug << ", ";
debug << typename MathTypeTraits<T>::NumericType(value[col][row]); 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) { \ 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...); \ 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) { \ 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 { namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::RectangularMatrix} */ /** @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 */ /** @brief Writes elements separated with spaces */
static std::string toString(const Magnum::Math::RectangularMatrix<cols, rows, T>& value, int flags = 0) { static std::string toString(const Magnum::Math::RectangularMatrix<cols, rows, T>& value, int flags = 0) {
std::string output; std::string output;
for(size_t row = 0; row != rows; ++row) { for(std::size_t row = 0; row != rows; ++row) {
for(size_t col = 0; col != cols; ++col) { for(std::size_t col = 0; col != cols; ++col) {
if(!output.empty()) output += ' '; if(!output.empty()) output += ' ';
output += ConfigurationValue<T>::toString(value(col, row), flags); 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; Magnum::Math::RectangularMatrix<cols, rows, T> result;
std::istringstream in(stringValue); std::istringstream in(stringValue);
for(size_t row = 0; row != rows; ++row) { for(std::size_t row = 0; row != rows; ++row) {
for(size_t col = 0; col != cols; ++col) { for(std::size_t col = 0; col != cols; ++col) {
std::string num; std::string num;
in >> num; in >> num;
result(col, row) = ConfigurationValue<T>::fromString(num, flags); 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(MathMathTypeTraitsTest MathTypeTraitsTest.cpp)
corrade_add_test2(MathRectangularMatrixTest RectangularMatrixTest.cpp) corrade_add_test2(MathRectangularMatrixTest RectangularMatrixTest.cpp)
corrade_add_test2(MathVectorTest VectorTest.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(MathVector2Test Vector2Test.cpp)
corrade_add_test2(MathVector3Test Vector3Test.cpp) corrade_add_test2(MathVector3Test Vector3Test.cpp)
corrade_add_test2(MathVector4Test Vector4Test.cpp) corrade_add_test2(MathVector4Test Vector4Test.cpp)
corrade_add_test2(MathPoint2DTest Point2DTest.cpp)
corrade_add_test2(MathPoint3DTest Point3DTest.cpp)
corrade_add_test2(MathMatrixTest MatrixTest.cpp) corrade_add_test2(MathMatrixTest MatrixTest.cpp)
corrade_add_test2(MathMatrix3Test Matrix3Test.cpp) corrade_add_test2(MathMatrix3Test Matrix3Test.cpp)
corrade_add_test2(MathMatrix4Test Matrix4Test.cpp) corrade_add_test2(MathMatrix4Test Matrix4Test.cpp)
if(NOT CMAKE_NO_OBJECT_TARGET) set_target_properties(MathVectorTest MathMatrix4Test PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
set(MathTest_SRCS MathTest.cpp $<TARGET_OBJECTS:MagnumMathObjects>)
else()
set(MathTest_SRCS MathTest.cpp ${MagnumMath_SRCS})
endif()
corrade_add_test2(MathTest ${MathTest_SRCS})

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 { namespace Magnum { namespace Math { namespace Test {
MathTest::MathTest() { MathTest::MathTest() {
addTests(&MathTest::constants, addTests(&MathTest::normalize,
&MathTest::degrad,
&MathTest::normalize,
&MathTest::denormalize, &MathTest::denormalize,
&MathTest::clamp, &MathTest::clamp,
&MathTest::pow, &MathTest::pow,
&MathTest::log); &MathTest::log);
} }
void MathTest::constants() {
CORRADE_COMPARE(Math::pow<2>(Constants<float>::sqrt2()), 2.0f);
CORRADE_COMPARE(Math::pow<2>(Constants<float>::sqrt3()), 3.0f);
CORRADE_COMPARE(Math::pow<2>(Constants<double>::sqrt2()), 2.0);
CORRADE_COMPARE(Math::pow<2>(Constants<double>::sqrt3()), 3.0);
}
void MathTest::degrad() {
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() { void MathTest::normalize() {
/* Range for signed and unsigned */ /* Range for signed and unsigned */
CORRADE_COMPARE((Math::normalize<float, char>(-128)), 0.0f); CORRADE_COMPARE((Math::normalize<float, int8_t>(-128)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, char>(127)), 1.0f); CORRADE_COMPARE((Math::normalize<float, int8_t>(127)), 1.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned char>(0)), 0.0f); CORRADE_COMPARE((Math::normalize<float, uint8_t>(0)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned char>(255)), 1.0f); CORRADE_COMPARE((Math::normalize<float, uint8_t>(255)), 1.0f);
/* Between */ /* Between */
CORRADE_COMPARE((Math::normalize<float, short>(16384)), 0.750011f); CORRADE_COMPARE((Math::normalize<float, int16_t>(16384)), 0.750011f);
CORRADE_COMPARE((Math::normalize<float, short>(-16384)), 0.250004f); CORRADE_COMPARE((Math::normalize<float, int16_t>(-16384)), 0.250004f);
/* Test overflow for large types */ /* Test overflow for large types */
CORRADE_COMPARE((Math::normalize<float, int>(numeric_limits<int>::min())), 0.0f); CORRADE_COMPARE((Math::normalize<float, int32_t>(numeric_limits<int32_t>::min())), 0.0f);
CORRADE_COMPARE((Math::normalize<float, int>(numeric_limits<int>::max())), 1.0f); CORRADE_COMPARE((Math::normalize<float, int32_t>(numeric_limits<int32_t>::max())), 1.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned int>(0)), 0.0f); CORRADE_COMPARE((Math::normalize<float, uint32_t>(0)), 0.0f);
CORRADE_COMPARE((Math::normalize<float, unsigned int>(numeric_limits<unsigned int>::max())), 1.0f); CORRADE_COMPARE((Math::normalize<float, uint32_t>(numeric_limits<uint32_t>::max())), 1.0f);
CORRADE_COMPARE((Math::normalize<double, long long>(numeric_limits<long long>::min())), 0.0); CORRADE_COMPARE((Math::normalize<double, int64_t>(numeric_limits<int64_t>::min())), 0.0);
CORRADE_COMPARE((Math::normalize<double, long long>(numeric_limits<long long>::max())), 1.0); CORRADE_COMPARE((Math::normalize<double, int64_t>(numeric_limits<int64_t>::max())), 1.0);
CORRADE_COMPARE((Math::normalize<double, unsigned long long>(0)), 0.0); CORRADE_COMPARE((Math::normalize<double, uint64_t>(0)), 0.0);
CORRADE_COMPARE((Math::normalize<double, unsigned long long>(numeric_limits<unsigned long long>::max())), 1.0); CORRADE_COMPARE((Math::normalize<double, uint64_t>(numeric_limits<uint64_t>::max())), 1.0);
} }
void MathTest::denormalize() { void MathTest::denormalize() {
/* Range for signed and unsigned */ /* Range for signed and unsigned */
CORRADE_COMPARE(Math::denormalize<char>(0.0f), -128); CORRADE_COMPARE(Math::denormalize<int8_t>(0.0f), -128);
CORRADE_COMPARE(Math::denormalize<char>(1.0f), 127); CORRADE_COMPARE(Math::denormalize<int8_t>(1.0f), 127);
CORRADE_COMPARE(Math::denormalize<unsigned char>(0.0f), 0); CORRADE_COMPARE(Math::denormalize<uint8_t>(0.0f), 0);
CORRADE_COMPARE(Math::denormalize<unsigned char>(1.0f), 255); CORRADE_COMPARE(Math::denormalize<uint8_t>(1.0f), 255);
/* Between */ /* Between */
CORRADE_COMPARE(Math::denormalize<short>(0.33f), -11141); CORRADE_COMPARE(Math::denormalize<int16_t>(0.33f), -11141);
CORRADE_COMPARE(Math::denormalize<short>(0.66f), 10485); CORRADE_COMPARE(Math::denormalize<int16_t>(0.66f), 10485);
/* Test overflow for large types */ /* Test overflow for large types */
CORRADE_COMPARE(Math::denormalize<int>(0.0f), numeric_limits<int>::min()); CORRADE_COMPARE(Math::denormalize<int32_t>(0.0f), numeric_limits<int32_t>::min());
CORRADE_COMPARE(Math::denormalize<unsigned int>(0.0f), 0); CORRADE_COMPARE(Math::denormalize<uint32_t>(0.0f), 0);
CORRADE_COMPARE(Math::denormalize<long long>(0.0), numeric_limits<long long>::min()); CORRADE_COMPARE(Math::denormalize<int64_t>(0.0), numeric_limits<int64_t>::min());
CORRADE_COMPARE(Math::denormalize<unsigned long long>(0.0), 0); CORRADE_COMPARE(Math::denormalize<uint64_t>(0.0), 0);
CORRADE_COMPARE(Math::denormalize<int>(1.0), numeric_limits<int>::max()); CORRADE_COMPARE(Math::denormalize<int32_t>(1.0), numeric_limits<int32_t>::max());
CORRADE_COMPARE(Math::denormalize<unsigned int>(1.0), numeric_limits<unsigned int>::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_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<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<unsigned long long, long double>(1.0)), numeric_limits<unsigned long long>::max());
} // }
} }
void MathTest::clamp() { void MathTest::clamp() {

2
src/Math/Test/MathTest.h

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

20
src/Math/Test/MathTypeTraitsTest.cpp

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

43
src/Math/Test/Matrix3Test.cpp

@ -17,8 +17,8 @@
#include <sstream> #include <sstream>
#include "Constants.h"
#include "Matrix3.h" #include "Matrix3.h"
#include "Math.h"
CORRADE_TEST_MAIN(Magnum::Math::Test::Matrix3Test) CORRADE_TEST_MAIN(Magnum::Math::Test::Matrix3Test)
@ -28,12 +28,17 @@ using namespace Corrade::Utility;
namespace Magnum { namespace Math { namespace Test { namespace Magnum { namespace Math { namespace Test {
typedef Math::Matrix3<float> Matrix3; typedef Math::Matrix3<float> Matrix3;
typedef Math::Matrix<2, float> Matrix2;
typedef Math::Vector2<float> Vector2;
Matrix3Test::Matrix3Test() { Matrix3Test::Matrix3Test() {
addTests(&Matrix3Test::constructIdentity, addTests(&Matrix3Test::constructIdentity,
&Matrix3Test::translation, &Matrix3Test::translation,
&Matrix3Test::scaling, &Matrix3Test::scaling,
&Matrix3Test::rotation, &Matrix3Test::rotation,
&Matrix3Test::rotationScalingPart,
&Matrix3Test::rotationPart,
&Matrix3Test::translationPart,
&Matrix3Test::debug, &Matrix3Test::debug,
&Matrix3Test::configuration); &Matrix3Test::configuration);
} }
@ -90,6 +95,42 @@ void Matrix3Test::rotation() {
CORRADE_COMPARE(Matrix3::rotation(deg(15.0f)), matrix); 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() { void Matrix3Test::debug() {
Matrix3 m( Matrix3 m(
3.0f, 5.0f, 8.0f, 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 translation();
void scaling(); void scaling();
void rotation(); void rotation();
void rotationScalingPart();
void rotationPart();
void translationPart();
void debug(); void debug();
void configuration(); void configuration();

64
src/Math/Test/Matrix4Test.cpp

@ -17,8 +17,8 @@
#include <sstream> #include <sstream>
#include "Constants.h"
#include "Matrix4.h" #include "Matrix4.h"
#include "Math.h"
CORRADE_TEST_MAIN(Magnum::Math::Test::Matrix4Test) CORRADE_TEST_MAIN(Magnum::Math::Test::Matrix4Test)
@ -28,15 +28,20 @@ using namespace Corrade::Utility;
namespace Magnum { namespace Math { namespace Test { namespace Magnum { namespace Math { namespace Test {
typedef Math::Matrix4<float> Matrix4; typedef Math::Matrix4<float> Matrix4;
typedef Math::Matrix3<float> Matrix3; typedef Math::Matrix<3, float> Matrix3;
typedef Math::Vector3<float> Vector3;
Matrix4Test::Matrix4Test() { Matrix4Test::Matrix4Test() {
addTests(&Matrix4Test::constructIdentity, addTests(&Matrix4Test::constructIdentity,
&Matrix4Test::translation, &Matrix4Test::translation,
&Matrix4Test::scaling, &Matrix4Test::scaling,
&Matrix4Test::rotation, &Matrix4Test::rotation,
&Matrix4Test::rotationX,
&Matrix4Test::rotationY,
&Matrix4Test::rotationZ,
&Matrix4Test::rotationScalingPart, &Matrix4Test::rotationScalingPart,
&Matrix4Test::rotationPart, &Matrix4Test::rotationPart,
&Matrix4Test::translationPart,
&Matrix4Test::debug, &Matrix4Test::debug,
&Matrix4Test::configuration); &Matrix4Test::configuration);
} }
@ -88,14 +93,46 @@ void Matrix4Test::scaling() {
} }
void Matrix4Test::rotation() { 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( Matrix4 matrix(
0.35612214f, -0.80181062f, 0.47987163f, 0.0f, 0.35612214f, -0.80181062f, 0.47987163f, 0.0f,
0.47987163f, 0.59757638f, 0.6423595f, 0.0f, 0.47987163f, 0.59757638f, 0.6423595f, 0.0f,
-0.80181062f, 0.0015183985f, 0.59757638f, 0.0f, -0.80181062f, 0.0015183985f, 0.59757638f, 0.0f,
0.0f, 0.0f, 0.0f, 1.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() { void Matrix4Test::rotationScalingPart() {
@ -122,13 +159,22 @@ void Matrix4Test::rotationPart() {
-0.80181062f, 0.0015183985f, 0.59757638f -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); 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); 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() { void Matrix4Test::debug() {
Matrix4 m( Matrix4 m(
3.0f, 5.0f, 8.0f, 4.0f, 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