Browse Source

Merge branch 'master' into compatibility

Conflicts:
	src/Magnum/AbstractTexture.cpp
	src/Magnum/Context.cpp
	src/Magnum/CubeMapTexture.h
	src/Magnum/CubeMapTextureArray.h
	src/Magnum/Magnum.h
	src/Magnum/MeshTools/Duplicate.h
	src/Magnum/Platform/Sdl2Application.h
	src/Magnum/SceneGraph/Object.hpp
	src/Magnum/Shader.cpp
	src/Magnum/Shapes/Test/ShapeTest.cpp
	src/Magnum/Test/AbstractShaderProgramTest.cpp
	src/Magnum/Test/ColorTest.cpp
Vladimír Vondruš 12 years ago
parent
commit
f923a36d3a
  1. 58
      CMakeLists.txt
  2. 14
      Doxyfile
  3. 1
      README.md
  4. 23
      doc/best-practices.dox
  5. 136
      doc/building.dox
  6. 35
      doc/cmake.dox
  7. 1
      doc/mainpage.dox
  8. 120
      doc/matrix-vector.dox
  9. 3
      doc/opengl-mapping.dox
  10. 13
      doc/opengl-support.dox
  11. 14
      doc/platform.dox
  12. 17
      doc/portability.dox
  13. 58
      doc/shapes.dox
  14. 71
      doc/types.dox
  15. 76
      modules/FindCorrade.cmake
  16. 227
      modules/FindMagnum.cmake
  17. 6
      modules/FindOpenGLES3.cmake
  18. 5
      package/archlinux/PKGBUILD
  19. 42
      package/archlinux/PKGBUILD-android-arm
  20. 42
      package/archlinux/PKGBUILD-android-x86
  21. 3
      package/archlinux/PKGBUILD-clang
  22. 3
      package/archlinux/PKGBUILD-clang-libc++
  23. 3
      package/archlinux/PKGBUILD-emscripten
  24. 3
      package/archlinux/PKGBUILD-es2
  25. 3
      package/archlinux/PKGBUILD-es2desktop
  26. 3
      package/archlinux/PKGBUILD-es3
  27. 3
      package/archlinux/PKGBUILD-es3desktop
  28. 3
      package/archlinux/PKGBUILD-gcc46
  29. 3
      package/archlinux/PKGBUILD-gcc47
  30. 3
      package/archlinux/PKGBUILD-gcc49
  31. 4
      package/archlinux/PKGBUILD-mingw32
  32. 2
      package/archlinux/PKGBUILD-nacl-glibc
  33. 4
      package/archlinux/PKGBUILD-nacl-newlib
  34. 40
      package/archlinux/PKGBUILD-release
  35. 1
      package/archlinux/magnum-git/PKGBUILD
  36. 1
      package/ci/jenkins-emscripten.xml
  37. 2
      package/ci/jenkins-gltests.xml
  38. 3
      package/ci/jenkins-mingw32.xml
  39. 3
      package/ci/jenkins-nacl.xml
  40. 11
      package/ci/jenkins.xml
  41. 1
      package/debian/rules
  42. 77
      src/Magnum/AbstractShaderProgram.cpp
  43. 156
      src/Magnum/AbstractShaderProgram.h
  44. 211
      src/Magnum/AbstractTexture.cpp
  45. 145
      src/Magnum/AbstractTexture.h
  46. 1
      src/Magnum/Audio/CMakeLists.txt
  47. 39
      src/Magnum/Buffer.h
  48. 9
      src/Magnum/CMakeLists.txt
  49. 110
      src/Magnum/Context.cpp
  50. 28
      src/Magnum/Context.h
  51. 30
      src/Magnum/CubeMapTexture.h
  52. 28
      src/Magnum/CubeMapTextureArray.h
  53. 1
      src/Magnum/DebugTools/CMakeLists.txt
  54. 7
      src/Magnum/Extensions.h
  55. 4
      src/Magnum/Image.h
  56. 59
      src/Magnum/Implementation/TextureState.cpp
  57. 12
      src/Magnum/Implementation/TextureState.h
  58. 5
      src/Magnum/Implementation/setupDriverWorkarounds.cpp
  59. 54
      src/Magnum/Magnum.h
  60. 14
      src/Magnum/Math/Angle.h
  61. 4
      src/Magnum/Math/Complex.h
  62. 9
      src/Magnum/Math/Functions.h
  63. 2
      src/Magnum/Math/TypeTraits.h
  64. 3
      src/Magnum/Math/Vector.h
  65. 6
      src/Magnum/Mesh.cpp
  66. 32
      src/Magnum/Mesh.h
  67. 7
      src/Magnum/MeshTools/CMakeLists.txt
  68. 17
      src/Magnum/MeshTools/CombineIndexedArrays.cpp
  69. 22
      src/Magnum/MeshTools/CombineIndexedArrays.h
  70. 157
      src/Magnum/MeshTools/Compile.cpp
  71. 81
      src/Magnum/MeshTools/Compile.h
  72. 2
      src/Magnum/MeshTools/CompressIndices.h
  73. 5
      src/Magnum/MeshTools/Duplicate.h
  74. 206
      src/Magnum/MeshTools/Interleave.h
  75. 57
      src/Magnum/MeshTools/Test/InterleaveTest.cpp
  76. 3
      src/Magnum/MeshView.h
  77. 78
      src/Magnum/MultisampleTexture.h
  78. 32
      src/Magnum/Platform/AbstractXApplication.h
  79. 266
      src/Magnum/Platform/AndroidApplication.cpp
  80. 594
      src/Magnum/Platform/AndroidApplication.h
  81. 34
      src/Magnum/Platform/CMakeLists.txt
  82. 25
      src/Magnum/Platform/GlutApplication.cpp
  83. 195
      src/Magnum/Platform/GlutApplication.h
  84. 27
      src/Magnum/Platform/GlxApplication.h
  85. 54
      src/Magnum/Platform/Implementation/Egl.cpp
  86. 33
      src/Magnum/Platform/Implementation/Egl.h
  87. 42
      src/Magnum/Platform/Implementation/EglContextHandler.cpp
  88. 3
      src/Magnum/Platform/Implementation/EglContextHandler.h
  89. 117
      src/Magnum/Platform/NaClApplication.h
  90. 5
      src/Magnum/Platform/Sdl2Application.cpp
  91. 198
      src/Magnum/Platform/Sdl2Application.h
  92. 41
      src/Magnum/Platform/WindowlessGlxApplication.h
  93. 41
      src/Magnum/Platform/WindowlessNaClApplication.h
  94. 36
      src/Magnum/Platform/XEglApplication.h
  95. 26
      src/Magnum/Platform/magnum-info.cpp
  96. 1
      src/Magnum/Primitives/CMakeLists.txt
  97. 2
      src/Magnum/Query.cpp
  98. 8
      src/Magnum/Query.h
  99. 53
      src/Magnum/RectangleTexture.h
  100. 9
      src/Magnum/Renderer.h
  101. Some files were not shown because too many files have changed in this diff Show More

58
CMakeLists.txt

@ -41,7 +41,7 @@ option(WITH_FIND_MODULE "Install FindMagnum.cmake module into CMake's module dir
# Parts of the library
option(WITH_AUDIO "Build Audio library" OFF)
option(WITH_DEBUGTOOLS "Build DebugTools library" ON)
cmake_dependent_option(WITH_MESHTOOLS "Build MeshTools library" ON "NOT WITH_DEBUGTOOLS" ON)
cmake_dependent_option(WITH_MESHTOOLS "Build MeshTools library" ON "NOT WITH_DEBUGTOOLS;NOT WITH_OBJIMPORTER" ON)
cmake_dependent_option(WITH_PRIMITIVES "Builf Primitives library" ON "NOT WITH_DEBUGTOOLS" ON)
cmake_dependent_option(WITH_SCENEGRAPH "Build SceneGraph library" ON "NOT WITH_DEBUGTOOLS;NOT WITH_SHAPES" ON)
cmake_dependent_option(WITH_SHADERS "Build Shaders library" ON "NOT WITH_DEBUGTOOLS" ON)
@ -49,23 +49,35 @@ cmake_dependent_option(WITH_SHAPES "Build Shapes library" ON "NOT WITH_DEBUGTOOL
option(WITH_TEXT "Build Text library" ON)
cmake_dependent_option(WITH_TEXTURETOOLS "Build TextureTools library" ON "NOT WITH_TEXT;NOT WITH_DISTANCEFIELDCONVERTER" ON)
# Application libraries
# NaCl-specific application libraries
if(CORRADE_TARGET_NACL)
option(WITH_NACLAPPLICATION "Build NaClApplication library" OFF)
cmake_dependent_option(WITH_WINDOWLESSNACLAPPLICATION "Build WindowlessNaClApplication library" OFF "NOT WITH_MAGNUMINFO" ON)
else()
# Android-specific application libraries
elseif(CORRADE_TARGET_ANDROID)
option(WITH_ANDROIDAPPLICATION "Build AndroidApplication library" OFF)
# X11, GLX and EGL-specific application libraries
elseif(CORRADE_TARGET_UNIX AND NOT APPLE)
option(WITH_GLXAPPLICATION "Build GlxApplication library" OFF)
cmake_dependent_option(WITH_WINDOWLESSGLXAPPLICATION "Build WindowlessGlxApplication library" OFF "NOT WITH_MAGNUMINFO;NOT WITH_DISTANCEFIELDCONVERTER" ON)
cmake_dependent_option(WITH_XEGLAPPLICATION "Build XEglApplication library" OFF "TARGET_GLES" OFF)
endif()
# Platform-independent (almost) application libraries
if(NOT CORRADE_TARGET_NACL AND NOT CORRADE_TARGET_ANDROID)
cmake_dependent_option(WITH_GLUTAPPLICATION "Build GlutApplication library" OFF "NOT TARGET_GLES" OFF)
option(WITH_SDL2APPLICATION "Build Sdl2Application library" OFF)
endif()
# Utilities (currently depending on WindowlessGlxApplication)
if(UNIX OR CORRADE_TARGET_NACL)
# Magnum Info (currently only using GLX or NaCl)
if((CORRADE_TARGET_UNIX AND NOT APPLE) OR CORRADE_TARGET_NACL)
option(WITH_MAGNUMINFO "Build magnum-info utility" OFF)
endif()
if(UNIX)
# Utilities (currently depending on WindowlessGlxApplication)
if(CORRADE_TARGET_UNIX AND NOT APPLE)
cmake_dependent_option(WITH_FONTCONVERTER "Build magnum-fontconverter utility" OFF "NOT TARGET_GLES" OFF)
cmake_dependent_option(WITH_DISTANCEFIELDCONVERTER "Build magnum-distancefieldconverter utility" OFF "NOT TARGET_GLES" OFF)
endif()
@ -73,6 +85,7 @@ endif()
# Plugins
cmake_dependent_option(WITH_MAGNUMFONT "Build MagnumFont plugin" OFF "WITH_TEXT" OFF)
cmake_dependent_option(WITH_MAGNUMFONTCONVERTER "Build MagnumFontConverter plugin" OFF "NOT MAGNUM_TARGET_GLES;WITH_TEXT" OFF)
option(WITH_OBJIMPORTER "Build ObjImporter plugin" OFF)
cmake_dependent_option(WITH_TGAIMAGECONVERTER "Build TgaImageConverter plugin" OFF "NOT WITH_MAGNUMFONTCONVERTER" ON)
cmake_dependent_option(WITH_TGAIMPORTER "Build TgaImporter plugin" OFF "NOT WITH_MAGNUMFONT" ON)
cmake_dependent_option(WITH_WAVAUDIOIMPORTER "Build WavAudioImporter plugin" OFF "WITH_AUDIO" OFF)
@ -104,9 +117,15 @@ if(CORRADE_TARGET_NACL OR CORRADE_TARGET_EMSCRIPTEN)
set(TARGET_GLES2 1)
endif()
# If targeting Android, set explicit OpenGL ES support. Decision between 2.0
# and 3.0 is up to the user
if(CORRADE_TARGET_ANDROID)
set(TARGET_GLES 1)
endif()
# NaCl newlib toolchain supports only static linking, dynamic linking is
# meaningless on Emscripten
if(CORRADE_TARGET_NACL_NEWLIB OR CORRADE_TARGET_EMSCRIPTEN)
# meaningless on Emscripten and too inconvenient on Android
if(CORRADE_TARGET_NACL_NEWLIB OR CORRADE_TARGET_EMSCRIPTEN OR CORRADE_TARGET_ANDROID)
set(BUILD_STATIC ON)
endif()
@ -123,7 +142,7 @@ else()
find_package(OpenGLES3 REQUIRED)
endif()
# Configuration variables (saved later to corradeConfigure.h)
# Configuration variables (saved later to configure.h)
if(TARGET_GLES)
set(MAGNUM_TARGET_GLES 1)
if(TARGET_GLES2)
@ -132,6 +151,9 @@ if(TARGET_GLES)
set(MAGNUM_TARGET_GLES3 1)
endif()
endif()
if(CORRADE_TARGET_EMSCRIPTEN)
set(MAGNUM_TARGET_WEBGL 1)
endif()
if(TARGET_DESKTOP_GLES)
set(MAGNUM_TARGET_DESKTOP_GLES 1)
endif()
@ -156,12 +178,18 @@ endif()
include(CorradeLibSuffix)
set(MAGNUM_BINARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/bin)
set(MAGNUM_LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX})
set(MAGNUM_PLUGINS_INSTALL_DIR ${MAGNUM_LIBRARY_INSTALL_DIR}/magnum)
set(MAGNUM_PLUGINS_FONT_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/fonts)
set(MAGNUM_PLUGINS_FONTCONVERTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/fontconverters)
set(MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/imageconverters)
set(MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/importers)
set(MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/audioimporters)
set(MAGNUM_PLUGINS_DEBUG_INSTALL_DIR ${MAGNUM_LIBRARY_INSTALL_DIR}/magnum-d)
set(MAGNUM_PLUGINS_RELEASE_INSTALL_DIR ${MAGNUM_LIBRARY_INSTALL_DIR}/magnum)
set(MAGNUM_PLUGINS_FONT_DEBUG_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_INSTALL_DIR}/fonts)
set(MAGNUM_PLUGINS_FONT_RELEASE_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_INSTALL_DIR}/fonts)
set(MAGNUM_PLUGINS_FONTCONVERTER_DEBUG_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_INSTALL_DIR}/fontconverters)
set(MAGNUM_PLUGINS_FONTCONVERTER_RELEASE_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_INSTALL_DIR}/fontconverters)
set(MAGNUM_PLUGINS_IMAGECONVERTER_DEBUG_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_INSTALL_DIR}/imageconverters)
set(MAGNUM_PLUGINS_IMAGECONVERTER_RELEASE_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_INSTALL_DIR}/imageconverters)
set(MAGNUM_PLUGINS_IMPORTER_DEBUG_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_INSTALL_DIR}/importers)
set(MAGNUM_PLUGINS_IMPORTER_RELEASE_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_INSTALL_DIR}/importers)
set(MAGNUM_PLUGINS_AUDIOIMPORTER_DEBUG_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_INSTALL_DIR}/audioimporters)
set(MAGNUM_PLUGINS_AUDIOIMPORTER_RELEASE_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_INSTALL_DIR}/audioimporters)
set(MAGNUM_DATA_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/share/magnum)
set(MAGNUM_CMAKE_FIND_MODULE_INSTALL_DIR ${CMAKE_ROOT}/Modules)
set(MAGNUM_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/Magnum)

14
Doxyfile

@ -1653,7 +1653,19 @@ INCLUDE_FILE_PATTERNS =
# instead of the = operator.
PREDEFINED = DOXYGEN_GENERATING_OUTPUT \
MAGNUM_BUILD_DEPRECATED CORRADE_DEPRECATED(message)=
MAGNUM_BUILD_DEPRECATED CORRADE_DEPRECATED(message)= \
MAGNUM_EXPORT= \
MAGNUM_AUDIO_EXPORT= \
MAGNUM_DEBUGTOOLS_EXPORT= \
MAGNUM_MATH_EXPORT= \
MAGNUM_MESHTOOLS_EXPORT= \
MAGNUM_PLATFORM_EXPORT= \
MAGNUM_PRIMITIVES_EXPORT= \
MAGNUM_SCENEGRAPH_EXPORT= \
MAGNUM_SHADERS_EXPORT= \
MAGNUM_SHAPES_EXPORT= \
MAGNUM_TEXT_EXPORT= \
MAGNUM_TEXTURETOOLS_EXPORT=
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.

1
README.md

@ -52,6 +52,7 @@ Platforms:
GLUT or SDL2 toolkit)
* **Windows** (through GLUT or SDL2 toolkit)
* **OS X** (through SDL2 toolkit, thanks to [Miguel Martin](https://github.com/miguelishawt))
* **Android** 2.3 (API Level 9) and higher
* **Google Chrome** (through [Native Client](https://developers.google.com/native-client/),
both `newlib` and `glibc` toolchains are supported)
* **HTML5/JavaScript** (through [Emscripten](https://github.com/kripken/emscripten/wiki))

23
doc/best-practices.dox

@ -54,21 +54,22 @@ information.
- [Best Practices for Working with Texture Data](http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/TechniquesForWorkingWithTextureData/TechniquesForWorkingWithTextureData.html)
- [Best Practices for Shaders](http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/BestPracticesforShaders/BestPracticesforShaders.html#//apple_ref/doc/uid/TP40008793-CH7-SW3)
@subsection best-practices-nacl Google Chrome Native Client
@subsection best-practices-webgl WebGL (Emscripten)
- [Best practices for 3D graphics](https://developers.google.com/native-client/beta/devguide/coding/3D-graphics#best-practices)
WebGL is subset of OpenGL ES 2.0 with some [specific restrictions and features](http://www.khronos.org/registry/webgl/specs/latest/1.0/#6), namely requirement
for unique buffer target binding, aligned buffer offset and stride and some
other restrictions and also support for combined depth/stencil buffer
attachments. See @ref Buffer, @ref Framebuffer, @ref Texture::setSubImage() "*Texture::setSubImage()",
@ref Mesh::addVertexBuffer(), @ref Renderer::setStencilFunction(),
@ref Renderer::setStencilMask() and @ref Renderer::setBlendFunction()
documentation for more information.
@subsection best-practices-web-buffer-types Native Client and Emscripten require unique buffer binding
@subsection best-practices-nacl Google Chrome Native Client
As noted in the above link, buffers in NaCl implementation and and also in
WebGL need to be bound only to one unique target, i.e., @ref Buffer bound to
@ref Buffer::Target::Array cannot be later rebound to @ref Buffer::Target::ElementArray.
However, %Magnum by default uses any sufficient target when binding the buffer
internally (e.g. for setting data or copying). To avoid this, set target hint
to desired target, either in constructor or using @ref Buffer::setTargetHint().
- [Best practices for 3D graphics](https://developers.google.com/native-client/beta/devguide/coding/3D-graphics#best-practices)
To ease up the development, @ref Mesh checks proper target hint when adding
vertex and index buffers in both Native Client and Emscripten.
Similarly to WebGL, buffers in NaCl implementation need to be bound only to one
unique target. See @ref Buffer class documentation for more information.
@section best-practices-hw Hardware-specific

136
doc/building.dox

@ -69,7 +69,7 @@ assuming you have at least basic knowledge of CMake.
On Unix-based OSs, the library (for example with support for GLUT applications)
can be built and installed using these four commands:
mkdir -p build && cd build
mkdir build && cd build
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr \
-DWITH_GLUTAPPLICATION=ON
@ -102,8 +102,7 @@ The most straightforward way to build and install the library is again via the
command-line. The bonus point is that you don't even need to wait for Visual
Studio to load:
mkdir build
cd build
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX="C:/Sys" ..
cmake --build .
cmake --build . --target install
@ -135,6 +134,14 @@ plan to use them with shared libraries later, enable also position-independent
code with `BUILD_STATIC_PIC`. If you want to build with another compiler (e.g.
Clang), pass `-DCMAKE_CXX_COMPILER=clang++` to CMake.
Libraries and static plugins built in `Debug` configuration (e.g. with
`CMAKE_BUILD_TYPE` set to `Debug`) have `-d` suffix to make it possible to have
both debug and release libraries installed alongside each other. *Dynamic*
plugins in `Debug` configuration are installed to `magnum-d` subdirectory
instead of `magnum`. Headers and other files are the same for both. The library
and plugin distinction is handled semi-automatically when using %Magnum in
depending projects, see @ref cmake for more information.
%Magnum by default does not install `FindMagnum.cmake`, as you should bundle
the module with your code instead of depending on it being in system location.
You can install it by enabling `WITH_FIND_MODULE`.
@ -186,6 +193,7 @@ None of the @ref Platform "application libraries" is built by default (and you
need at least one). Choose the one which suits your requirements and your
platform best:
- `WITH_ANDROIDAPPLICATION` - @ref Platform::AndroidApplication "AndroidApplication"
- `WITH_GLUTAPPLICATION` - @ref Platform::GlutApplication "GlutApplication"
- `WITH_GLXAPPLICATION` - @ref Platform::GlxApplication "GlxApplication"
- `WITH_NACLAPPLICATION` - @ref Platform::NaClApplication "NaClApplication"
@ -216,6 +224,7 @@ default.
- `WITH_MAGNUMFONTCONVERTER` -- @ref Text::MagnumFontConverter "MagnumFontConverter"
plugin. Available only if `WITH_TEXT` is enabled. Enables also building of
@ref Trade::TgaImageConverter "TgaImageConverter" plugin.
- `WITH_OBJIMPORTER` -- @ref Trade::ObjImporter "ObjImporter" plugin.
- `WITH_TGAIMPORTER` -- @ref Trade::TgaImporter "TgaImporter" plugin.
- `WITH_TGAIMAGECONVERTER` -- @ref Trade::TgaImageConverter "TgaImageConverter"
plugin.
@ -317,8 +326,9 @@ contents in `toolchains/` subdirectory.
@subsection building-cross-win Crosscompiling for Windows using MinGW
@note This guide is tailored mainly for crosscompiling from ArchLinux. For
this system there is also prepared `mingw32-magnum` development package in
root, named `PKGBUILD-mingw32`.
this system there is also prepared `mingw32-magnum` development package in
`package/archlinux`, named `PKGBUILD-mingw32`. See
@ref building-packages-arch "above" for more information.
You will need MinGW32 versions of the compiler and all dependent libraries
(Corrade), i.e. these ArchLinux packages:
@ -327,19 +337,18 @@ You will need MinGW32 versions of the compiler and all dependent libraries
- `mingw32-runtime`
- `mingw32-corrade`
Then create build directory and run cmake and make. You may need to modify the
`basic-mingw32.cmake` file and `CMAKE_INSTALL_PREFIX` to suit your distribution
filesystem hierarchy.
Then create build directory and run cmake and build command in it. You may need
to modify the `basic-mingw32.cmake` file and `CMAKE_INSTALL_PREFIX` to suit
your distribution filesystem hierarchy.
mkdir build-win
cd build-win
mkdir build-win && cd build-win
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=../toolchains/archlinux/basic-mingw32.cmake \
-DCMAKE_INSTALL_PREFIX=/usr/i486-mingw32
make
cmake --build .
Then you can install the package using `make install` to make it available for
depending projects.
Then you can install the package using `cmake --build . --target install` to
make it available for depending projects.
@subsection building-cross-nacl Crosscompiling for Google Chrome Native Client
@ -354,14 +363,13 @@ adapt `NACL_PREFIX` variable in `generic/NaCl-*-x86-32.cmake` and
to find the compiler. NaCl currently supports only OpenGL ES 2, thus
`TARGET_GLES` and `TARGET_GLES2` is always enabled.
Then create build directories for x86-32 and x86-64 and run cmake and make in
them. The toolchains need access to the platform file, so be sure to properly
set **absolute** path to `modules/` directory containing `Platform/NaCl.cmake`.
Also adapt `CMAKE_INSTALL_PREFIX` to the same value as in `NACL_PREFIX` in
toolchain file.
Then create build directories for x86-32 and x86-64 and run cmake and build
command in them. The toolchains need access to the platform file, so be sure to
properly set **absolute** path to `modules/` directory containing
`Platform/NaCl.cmake`. Also adapt `CMAKE_INSTALL_PREFIX` to the same value as
in `NACL_PREFIX` in toolchain file.
mkdir -p build-nacl-x86-32
cd build-nacl-x86-32
mkdir build-nacl-x86-32 && cd build-nacl-x86-32
cmake .. \
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/NaCl-newlib-x86-32.cmake" \
@ -369,23 +377,24 @@ toolchain file.
-DCMAKE_INSTALL_PREFIX=/usr/nacl \
-DWITH_NACLAPPLICATION=ON \
-DLIB_SUFFIX=/32
make
cmake --build .
mkdir -p build-nacl-x86-64
cd build-nacl-x86-64
mkdir build-nacl-x86-64 && cd build-nacl-x86-64
cmake .. \
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/NaCl-newlib-x86-64.cmake" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/nacl \
-DWITH_NACLAPPLICATION=ON
make
cmake --build .
Then you can install both versions using `make install` to make them available
for depending projects. The headers are shared by both versions.
Then you can install both versions using `cmake --build . --target install` to
make them available for depending projects. The headers are shared by both
versions.
For ArchLinux there are also prepared package files in root, named
`PKGBUILD-nacl-glibc` and `PKGBUILD-nacl-newlib`.
For ArchLinux there are also prepared package files in `package/archlinux`,
named `PKGBUILD-nacl-glibc` and `PKGBUILD-nacl-newlib`, see
@ref building-packages-arch "above" for more information.
@subsection building-cross-emscripten Crosscompiling for Emscripten
@ -397,34 +406,81 @@ to path where Emscripten is installed. Default is `/usr/emscripten`. Emscripten
supports dynamic libraries only to simplify porting and they are generally
slower, thus `BUILD_STATIC` is implicitly enabled.
Then create build directory and run cmake and make in it. The toolchain needs
access to its platform file, so be sure to properly set **absolute** path to
`modules/` directory containing `Platform/Emscripten.cmake`. Also set
`CMAKE_INSTALL_PREFIX` to value which is contained in `CMAKE_FIND_ROOT_PATH` in
toolchain file.
Then create build directory and run cmake and build command in it. The
toolchain needs access to its platform file, so be sure to properly set
**absolute** path to `modules/` directory containing `Platform/Emscripten.cmake`.
Also set `CMAKE_INSTALL_PREFIX` to path contained in `EMSCRIPTEN_TOOLCHAIN_PATH`.
mkdir -p build-emscripten
cd build-emscripten
mkdir build-emscripten && cd build-emscripten
cmake .. \
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/Emscripten.cmake" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/emscripten/system \
-DWITH_SDL2APPLICATION=ON
make
cmake --build .
Then you can install the library using `make install` to make it available for
depending projects.
Then you can install the library using `cmake --build . --target install` to
make it available for depending projects.
If you have Node.js installed, you can also build and run unit tests using
`ctest`. See `BUILD_TESTS` above.
For ArchLinux there is also prepared package file in `package/archlinux`,
named `PKGBUILD-emscripten`, see @ref building-packages-arch "above" for more
information.
@subsection building-cross-android Crosscompiling for Android ARM and x86
You will need [Android NDK](https://developer.android.com/tools/sdk/ndk/index.html)
installed and configured.
Don't forget to adapt `ANDROID_NDK_ROOT` in `generic/Android-*.cmake` to path
where NDK is installed. Default is `/opt/android-ndk`. Adapt also
`ANDROID_SYSROOT` to your preferred API level. You might also need to update
`ANDROID_TOOLCHAIN_PREFIX` and `ANDROID_TOOLCHAIN_ROOT` to fit your system.
Then create build directory and run cmake and build command in it. The
toolchain needs access to its platform file, so be sure to properly set **absolute**
path to `modules/` directory containing `Platform/Android.cmake`. Also set
`CMAKE_INSTALL_PREFIX` to `/usr` subdirectory of `ANDROID_SYSROOT`.
Note that `BUILD_STATIC` is implicitly enabled, because manually loading all
depending shared libraries using JNI would be too inconvenient. Decision
between OpenGL ES 2.0 and ES 3.0 is left up to the user (i.e. you need to set
`TARGET_GLES2` to `ON` or `OFF`).
mkdir build-android-arm && cd build-android-arm
cmake .. \
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/Android-ARM.cmake" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/opt/android-ndk/platforms/android-19/arch-arm/usr \
-DTARGET_GLES=ON -DTARGET_GLES2=ON
cmake --build .
mkdir build-android-x86 && cd build-android-x86
cmake .. \
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/Android-x86.cmake" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/opt/android-ndk/platforms/android-19/arch-x86/usr \
-DTARGET_GLES=ON -DTARGET_GLES2=ON
cmake --build .
Then you can install the library using `cmake --build . --target install` to
make it available for depending projects.
For ArchLinux there are also prepared package files in `package/archlinux`,
named `PKGBUILD-android-arm` and `PKGBUILD-android-x86`, see
@ref building-packages-arch "above" for more information.
@section building-ci-jenkins Jenkins Continuous Integration
In `package/ci/` there are `jenkins.xml` and `jenkins-gltests.xml` files
containing job configuration, one for build and non-GL tests and the other for
GL tests only. Setup your Jenkins server, enable the **Git** and
**Text-finder** plugin and download the CLI application from here:
GL tests only. Setup your Jenkins server, enable the **Git** and **Text-finder**
plugin and download the CLI application from here:
http://your-jenkins-server/cli

35
doc/cmake.dox

@ -51,17 +51,19 @@ variables:
- `MAGNUM_FOUND` -- Whether the library was found
- `MAGNUM_LIBRARIES` -- %Magnum library and dependent libraries
- `MAGNUM_INCLUDE_DIRS` -- Root include dir and include dirs of dependencies
- `MAGNUM_PLUGINS_DIR` -- Base directory with plugins, defaults to `magnum/`
subdirectory of dir where Magnum library was found. You can modify it (e.g.
set it to `.` when deploying on Windows with plugins stored relatively to
the executable), the following `MAGNUM_PLUGINS_*_DIR` variables depend on
it.
- `MAGNUM_PLUGINS_FONT_DIR` -- Directory with font plugins
- `MAGNUM_PLUGINS_FONTCONVERTER_DIR` -- Directory with font converter plugins
- `MAGNUM_PLUGINS_IMAGECONVERTER_DIR` -- Directory with image converter
- `MAGNUM_PLUGINS_DIR` -- Base directory with dynamic plugins, defaults to
`magnum/` subdirectory of dir where Magnum library was found (or
`magnum-d/` in debug build). . You can modify it (e.g. set it to `.` when
deploying on Windows with plugins stored relatively to the executable),
the following `MAGNUM_PLUGINS_*_DIR` variables depend on it.
- `MAGNUM_PLUGINS_FONT_DIR` -- Directory with dynamic font plugins
- `MAGNUM_PLUGINS_FONTCONVERTER_DIR` -- Directory with dynamic font converter
plugins
- `MAGNUM_PLUGINS_IMAGECONVERTER_DIR` -- Directory with dynamic image
converter plugins
- `MAGNUM_PLUGINS_IMPORTER_DIR` -- Directory with dynamic importer plugins
- `MAGNUM_PLUGINS_AUDIOIMPORTER_DIR` -- Directory with dynamic audio importer
plugins
- `MAGNUM_PLUGINS_IMPORTER_DIR` -- Directory with importer plugins
- `MAGNUM_PLUGINS_AUDIOIMPORTER_DIR` -- Directory with audio importer plugins
However, this command will try to find only the base library, not the optional
components. The base library depends on %Corrade and OpenGL libraries (or
@ -103,6 +105,8 @@ dependencies, you need to find the dependency and then link to it.
`%Text` component and `TgaImporter` plugin)
- `MagnumFontConverter` -- @ref Text::MagnumFontConverter "MagnumFontConverter"
plugin (depends on `%Text` component and `%TgaImageConverter` plugin)
- `ObjImporter` -- @ref Trade::ObjImporter "ObjImporter" plugin (depends on
`%MeshTools` component)
- `TgaImageConverter` -- @ref Trade::TgaImageConverter "TgaImageConverter"
plugin
- `TgaImporter` -- @ref Trade::TgaImporter "TgaImporter" plugin
@ -130,6 +134,17 @@ convenience aliases `MAGNUM_APPLICATION_LIBRARIES` /
`MAGNUM_WINDOWLESSAPPLICATION_LIBRARIES` and `MAGNUM_APPLICATION_INCLUDE_DIRS`
/ `MAGNUM_WINDOWLESSAPPLICATION_INCLUDE_DIRS` to simplify porting.
The package is found if either debug or release version of each requested
library (or plugin) is found. If both debug and release libraries (or plugins)
are found, proper version is chosen based on actual build configuration of the
project (i.e. `Debug` build is linked to debug libraries, `Release` build to
release libraries). Note that this autodetection might fail for the
`MAGNUM_PLUGINS_DIR` variable, i.e. you might need to switch it manually to
`magnum-d/` or `magnum/` subdirectory based on whether you want to dynamically
load plugins with or without debug information. You can also make use of
`CMAKE_BUILD_TYPE` or `CMAKE_CFG_INTDIR` CMake variables for compile-time
decision.
Features of found %Magnum library are exposed in these CMake variables, they
are also available as preprocessor variables if including Magnum.h:

1
doc/mainpage.dox

@ -78,6 +78,7 @@ Platforms:
GLUT or SDL2 toolkit)
- **Windows** (through GLUT or SDL2 toolkit)
- **OS X** (through SDL2 toolkit, thanks to [Miguel Martin](https://github.com/miguelishawt))
- **Android** 2.3 (API Level 9) and higher
- **Google Chrome** (through [Native Client](https://developers.google.com/native-client/),
both `newlib` and `glibc` toolchains are supported)
- **HTML5/JavaScript** (through [Emscripten](https://github.com/kripken/emscripten/wiki))

120
doc/matrix-vector.dox

@ -77,13 +77,14 @@ Vector3i b; // zero-filled
Matrix3 identity; // diagonal set to 1
Matrix3 zero(Matrix::Zero); // zero-filled
Color4 black1; // {0.0f, 0.0f, 0.0f, 1.0f}
BasicColor4<UnsignedByte> black2; // {0, 0, 0, 255}
Color4 black1; // {0.0f, 0.0f, 0.0f, 1.0f}
Color4ub black2; // {0, 0, 0, 255}
@endcode
Most common and most efficient way to create vector is to pass all values to
constructor, matrix is created by passing all column vectors to the
constructor.
constructor. All constructors check number of passed arguments and the errors
are catched at compile time.
@code
Vector3i vec(0, 1, 2);
@ -91,11 +92,9 @@ Matrix3 mat({0.0f, 1.9f, 2.2f},
{3.5f, 4.0f, 5.1f},
{6.0f, 7.3f, 8.0f});
@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 or you can create diagonal matrix from vector:
You can specify all components of vector or whole diagonal of square matrix
with single value or create diagonal matrix from vector:
@code
Matrix3 diag(Matrix3::Identity, 2.0f); // diagonal set to 2.0f, zeros elsewhere
Vector3i fill(10); // {10, 10, 10}
@ -121,20 +120,14 @@ Int[] mat = { 2, 4, 6,
1, 3, 5 };
Math::Matrix2x3<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 *explicitly* convert between data types:
@code
Vector4 floating(1.3f, 2.7f, -15.0f, 7.0f);
auto integral = Vector4i(floating); // {1, 2, -15, 7}
@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.
@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:
brackets:
@code
Matrix3x2 a;
a[2] /= 2.0f; // third column (column major indexing, see explanation below)
@ -145,7 +138,7 @@ b[1] = 1; // second element
@endcode
Row vectors can be accessed too, but only for reading, and the access is slower
due to the way the matrix is stored (see explanation below):
due to the way the matrix is stored (see @ref matrix-vector-column-major "explanation below"):
@code
Vector2i c = a.row(2); // third row
@endcode
@ -170,6 +163,38 @@ Vector4i bgra = swizzle<'b', 'g', 'r', 'a'>(original); // { 3, 2, -1, 4 }
Math::Vector<6, Int> w10xyz = swizzle<'w', '1', '0', 'x', 'y', 'z'>(original); // { 4, 1, 0, -1, 2, 3 }
@endcode
@section matrix-vector-conversion Converting between different underlying types
All vector, matrix and other classes in @ref Math namespace and also
@ref Color3 and @ref Color4 classes are able to be constructed from type with
different underlying type (e.g. convert between integer and floating-point or
betweeen @ref Float and @ref Double). Unlike with plain C++ data types, the
conversion is done via *explicit* constructor. That might sound inconvenient,
but doing the conversion explicitly avoids common issues like precision loss
(or, on the other hand, doing computations in unnecessarily high precision).
To further emphasise the intent of conversion (so it doesn't look like accident
or typo), you are encouraged to use `auto b = Type{a}` instead of `Type b{a}`.
@code
Vector3 a{2.2f, 0.25f, -5.1f};
//Vector3i b = a; // error, implicit conversion not allowed
auto c = Vector3i{a}; // {2, 0, -5}
auto d = Vector3d{a}; // {2.2, 0.25, -5.1}
@endcode
For normalizing and denormalizing there are @ref Math::normalize() and
@ref Math::denormalize() functions:
@code
Color3 a{0.8f, 1.0f, 0.3f};
auto b = Math::denormalize<Color3ub>(a); // {204, 255, 76}
Color3ub c{64, 127, 89};
auto d = Math::normalize<Color3>(c); // {0.251, 0.498, 0.349}
@endcode
See @ref matrix-vector-componentwise "below" for more information about other
available component-wise operations.
@section matrix-vector-operations Operations with matrices and vectors
Vectors can be added, subtracted, negated and multiplied or divided with
@ -193,8 +218,8 @@ In %Magnum all mulitplication/division operations involving integral vectors
will have integral result, you need to convert both arguments to the same
floating-point type to have floating-point result.
@code
BasicColor3<UnsignedByte> color(80, 116, 34);
BasicColor3<UnsignedByte> lighter = color*1.5f; // lighter = {120, 174, 51}
Color3ub color(80, 116, 34);
Color3ub lighter = color*1.5f; // lighter = {120, 174, 51}
Vector3i a(4, 18, -90);
Vector3 multiplier(2.2f, 0.25f, 0.1f);
@ -230,6 +255,63 @@ Math::RectangularMatrix<4, 1, Float> d;
Matrix4x3 e = b*d;
@endcode
@section matrix-vector-componentwise Component-wise and inter-vector operations
As shown above, vectors can be added and multiplied component-wise using the
`+` or `*` operator. You can use @ref Math::Vector::sum() "sum()" and
@ref Math::Vector::product() "product()" for sum or product of components in
one vector:
@code
Float a = Vector3{1.5f, 0.3f, 8.0f}.sum(); // 8.8f
Int b = Vector3i{32, -5, 7}.product() // 1120
@endcode
Component-wise minimum and maximum of two vectors can be done using
@ref Math::min(), @ref Math::max() or @ref Math::minmax(), similarly with
@ref Vector::min() "min()", @ref Vector::max() "max()" and
@ref Vector2::minmax() "minmax()" for components in one vector.
@code
Vector3i a{-5, 7, 24};
Vector3i b{8, -2, 12};
Vector3i min = Math::min(a, b); // {-5, -2, 12}
Int max = a.max(); // 24
@endcode
The vectors can be also compared component-wise, the result is returned in
@ref Math::BoolVector class:
@code
BoolVector<3> largerOrEqual = a >= b; // {false, true, true}
bool anySmaller = (a < b).any(); // true
bool allLarger = (a > b).all(); // false
@endcode
There are also function for component-wise rounding, sign operations, square
root, various interpolation and (de)normalization functionality:
@code
Vector3 a{5.5f, -0.3f, 75.0f};
Vector3 b = Math::round(a); // {5.0f, 0.0f, 75.0f}
Vector3 c = Math::abs(a); // {5.5f, -0.3f, 75.0f}
Vector3 d = Math::clamp(a, -0.2f, 55.0f); // {5.5f, -0.2f, 55.0f}
@endcode
Component-wise functions are implemented only for vectors and not for matrices
to keep the math library in sane and maintainable size. Instead, you can
reinterpret the matrix as vector and do the operation on it (and vice versa):
@code
Matrix3x2 mat;
Math::Vector<6, Float> vec = mat.toVector();
// ...
mat = Matrix3x2::fromVector(vec);
@endcode
Note that all component-wise functions in Math namespace work also for scalars:
@code
std::pair<Int, Int> minmax = Math::minmax(24, -5); // -5, 24
Int a = Math::lerp(0, 360, 0.75f); // 270
auto b = Math::denormalize<UnsignedByte>(0.89f); // 226
@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

3
doc/opengl-mapping.dox

@ -62,8 +62,7 @@ OpenGL function | Matching API
@fn_gl{BindRenderbuffer} | not needed, handhled internally in @ref Renderbuffer
@fn_gl{BindSampler} | |
@fn_gl{BindSamplers} | |
@fn_gl{BindTexture}, \n @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} | @ref AbstractTexture::bind()
@fn_gl{BindTextures} | |
@fn_gl{BindTexture}, \n @fn_gl{BindTextures}, \n @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} | @ref AbstractTexture::bind()
@fn_gl{BindTransformFeedback} | |
@fn_gl{BindVertexArray} | not needed, handhled internally in @ref Mesh
@fn_gl{BindVertexBuffer} | |

13
doc/opengl-support.dox

@ -71,7 +71,7 @@ following:
@extension{EXT,texture_shared_exponent} | done
@extension{EXT,framebuffer_sRGB} | |
@extension{EXT,draw_buffers2} | |
@extension{EXT,texture_integer} | missing integer color specification functions
@extension{EXT,texture_integer} | done (GL 3.0 subset)
@extension{EXT,transform_feedback} | |
@extension{NV,half_float} | done (GL 3.0 subset)
@extension{NV,depth_buffer_float} | |
@ -100,7 +100,7 @@ following:
@extension{ARB,provoking_vertex} | done
@extension{ARB,seamless_cube_map} | done
@extension{ARB,sync} | |
@extension{ARB,texture_multisample} | |
@extension{ARB,texture_multisample} | missing sample location queries and sample mask
@extension{ARB,vertex_array_bgra} | done
@subsection opengl-support-33 OpenGL 3.3
@ -187,7 +187,7 @@ following:
@extension{ARB,stencil_texturing} | |
@extension{ARB,texture_buffer_range} | done
@extension{ARB,texture_query_levels} | done (shading language only)
@extension{ARB,texture_storage_multisample} | |
@extension{ARB,texture_storage_multisample} | done
@extension{ARB,texture_view} | |
@extension{ARB,vertex_attrib_binding} | |
@ -201,7 +201,7 @@ following:
@extension{ARB,buffer_storage} | |
@extension{ARB,clear_texture} | |
@extension{ARB,enhanced_layouts} | done (shading language only)
@extension{ARB,multi_bind} | |
@extension{ARB,multi_bind} | only texture binding
@extension{ARB,query_buffer_object} | |
@extension{ARB,texture_mirror_clamp_to_edge} | done
@extension{ARB,texture_stencil8} | done
@ -222,6 +222,7 @@ following:
@extension{EXT,texture_filter_anisotropic} (also in ES) | done
@extension{EXT,texture_mirror_clamp} | only GL 4.4 subset
@extension{EXT,direct_state_access} | done for implemented functionality
@extension{EXT,shader_integer_mix} (also in ES) | done (shading language only)
@extension2{EXT,debug_label} (also in ES) | missing pipeline, transform feedback and sampler label
@extension2{EXT,debug_marker} (also in ES) | missing marker groups
@extension{GREMEDY,string_marker} | done
@ -244,6 +245,7 @@ supported.
@es_extension{ANGLE,framebuffer_multisample} | done
@es_extension{ANGLE,depth_texture} | done
@es_extension{APPLE,framebuffer_multisample} | done (ES 3.0 subset)
@es_extension{APPLE,texture_max_level} | done
@es_extension{ARM,rgba8} | done
@es_extension{EXT,texture_type_2_10_10_10_REV} | done
@es_extension{EXT,discard_framebuffer} | done
@ -324,7 +326,8 @@ add any performance gains, is not supported in %Magnum. See also
with serious performance drops. Multisampling is far superior solution.
- Fixed precision data types (`GL_FIXED` in OpenGL ES) are not supported, as
they occupy the same memory as floats and they aren't faster than floats on
current hardware anymore.
current hardware anymore. They are also not available in WebGL or desktop
GL.
- Shader compiler is assumed to be present (`GL_SHADER_COMPILER` returning
true), as all desktop GL implementations and also ES3 are required to
support it.

14
doc/platform.dox

@ -66,10 +66,10 @@ blue color is shown in the following code listing.
repository.
@code
#include <Color.h>
#include <DefaultFramebuffer.h>
#include <Renderer.h>
#include <Platform/GlutApplication.h>
#include <Magnum/Color.h>
#include <Magnum/DefaultFramebuffer.h>
#include <Magnum/Renderer.h>
#include <Magnum/Platform/GlutApplication.h>
using namespace Magnum;
@ -88,7 +88,7 @@ MyApplication::MyApplication(const Arguments& arguments): Platform::Application(
void MyApplication::drawEvent() {
// Clear the window
defaultFramebuffer.clear(DefaultFramebuffer::Clear::Color);
defaultFramebuffer.clear(FramebufferClear::Color);
// The context is double-buffered, swap buffers
swapBuffers();
@ -148,8 +148,8 @@ renderer string and exits is in the following code listing.
repository.
@code
#include <Context.h>
#include <Platform/WindowlessGlxApplication.h>
#include <Magnum/Context.h>
#include <Magnum/Platform/WindowlessGlxApplication.h>
using namespace Magnum;

17
doc/portability.dox

@ -40,9 +40,10 @@ format is not supported.
If you include @ref Magnum.h, you get these predefined macros:
- @ref MAGNUM_TARGET_GLES if targeting OpenGL ES
- @ref MAGNUM_TARGET_GLES2 if targeting OpenGL ES 2.0
- @ref MAGNUM_TARGET_GLES3 if targeting OpenGL ES 3.0
- @ref MAGNUM_TARGET_GLES if targeting OpenGL ES
- @ref MAGNUM_TARGET_GLES2 if targeting OpenGL ES 2.0
- @ref MAGNUM_TARGET_GLES3 if targeting OpenGL ES 3.0
- @ref MAGNUM_TARGET_WEBGL if targeting WebGL
Example usage:
@code
@ -57,7 +58,7 @@ Renderer::setPolygonMode(Renderer::PolygonMode::Lines);
Each feature is marked accordingly if it is not available in some targets. See
also @ref requires-gl, @ref requires-gles20 and @ref requires-gles30.
@section portability-compiler Compiler-specific code
@section portability-compiler Compiler- and platform-specific code
%Magnum is attempting to be future-proof and as intuitive for users as
possible. Many features from C++11 are used to simplify things and make them
@ -73,6 +74,10 @@ platform) which compiler your code will support, code written for e.g. GCC 4.6
will work also on Magnum compiled with support for newer compilers, although
newer compilers may catch errors that weren't spotted by earlier versions.
Some functionality (such as dynamic plugin loading or filesystem access) might
not be available on particular platforms. @ref Corrade.h contains defintions
which you can use for platform-aware code.
@section portability-extensions Extension-aware code
Some functionality is depending on support of particular extension and thus
@ -156,8 +161,8 @@ if(!Context::instance()->isExtensionSupported<Extensions::GL::ARB::explicit_attr
@endcode
See also @ref AbstractShaderProgram class documentation for information about
specifying attribute location, uniform location and texture layer in various
OpenGL versions.
specifying attribute location, uniform location and texture binding unit in
various OpenGL versions.
All shaders in @ref Shaders namespace support desktop OpenGL starting from
version 2.1 and also OpenGL ES 2.0 and 3.0. Feel free to look into their

58
doc/shapes.dox

@ -77,9 +77,9 @@ is least efficient.
@section shapes-composition Creating shape compositions
%Shapes can be composed together using one of three available logical
operations: AND, OR and NOT. These operations are mapped to operator&&(),
operator||() and operator!(), so for example creating negation of logical OR
of line segment and point is simple as this:
operations: AND, OR and NOT. These operations are mapped to `&&`, `||` and `!`
operators, so for example creating negation of logical OR of line segment and
point is simple as this:
@code
Shapes::LineSegment3D segment;
Shapes::Point3D point;
@ -97,9 +97,9 @@ If there are many shapes composed together, it might hurt performance of
collision detection, because it might be testing collision with more shapes
than necessary. It's then good to specify simplified version of such shape,
so the collision detection is done on the complex one if and only if collision
was detected with the simplified shape. It is in fact logical AND using
operator&&() - the collision is initially detected on first (simplified) shape
and then on the other:
was detected with the simplified shape. It is in fact logical AND using the
`&&` operator -- the collision is initially detected on first (simplified)
shape and then on the other:
@code
Shapes::Sphere3D sphere;
Shapes::Box3D box;
@ -111,7 +111,7 @@ Shapes::Composition3D composition = simplified && (sphere || box);
@section shapes-collisions Detecting shape collisions
%Shape pairs which have collision occurence detection implemented can be tested
for collision using operator%(). The operator returns boolean describing
for collision using the `%` operator. The operator returns boolean describing
whether the collision happened or not. Example:
@code
Shapes::Point3D point;
@ -123,12 +123,12 @@ bool collide = point % sphere;
As this is useful for e.g. menu handling and simple particle systems, for
serious physics you often need more information like contact point, separation
normal and penetration depth. For shape pairs which have implemented this
detailed collision detection you can use `operator/()`, which returns @ref Collision
object. Note that unlike with `operator%()` mentioned above, this operation is
not commutative. See @ref Collision class documentation for more information
about the returned data. Example:
detailed collision detection you can use the `/` operator, which returns
@ref Collision object. Note that unlike with the `%` operator mentioned above,
this operation is not commutative. See @ref Collision class documentation for
more information about the returned data. Example:
@code
Shapes::Collision3D c = point/sphere;
const Shapes::Collision3D c = point/sphere;
if(c) {
Vector3 translation = c.separationNormal()*c.separationDistance();
// translate point by translation...
@ -137,15 +137,37 @@ if(c) {
@section shapes-scenegraph Integration with scene graph
%Shape can be attached to object in the scene using Shapes::Shape feature and
then used for collision detection. You can also use DebugTools::ShapeRenderer
to visualize the shape for debugging purposes.
%Shape can be attached to object in the scene using @ref Shapes::Shape feature.
In conjunction with @ref Shapes::ShapeGroup you can use
@ref Shapes::Shape::collides() and @ref Shapes::Shape::collision() similarly to
the `%` and `/` operators above. Please note that the shape group caches the
absolute transformations of all shapes and thus you need to explicitly call
@ref Shapes::ShapeGroup::setClean() before computing the collisions if you did
any modifications to the objects in the scene.
Scenegraph-flavored equivalent to the above code:
@code
Object3D object;
auto shape = Shapes::Shape<Shapes::Sphere3D>(object, {{}, 23.0f});
Shapes::ShapeGroup3D shapes;
Object3D& a;
auto aShape = new Shapes::Shape<Shapes::Sphere3D>(a, {{}, 23.0f}, &shapes);
Object3D& b;
auto bShape = new Shapes::Shape<Shapes::Point3D>(b, {{1.0f, 0.2f, 3.0f}}, &shapes);
// Translate point so the objects no longer collide
shapes.setClean();
if(aShape->collides(*bShape)) {
const Shapes::Collision3D c = aShape->collision(*bShape);
b.translate(c.separationNormal()*c.separationDistance());
}
@endcode
See also @ref scenegraph for introduction.
There is also @ref Shapes::ShapeGroup::firstCollision() function which returns
arbitrary first collision for given shape in whole group (or `nullptr`, if
there isn't any collision).
You can also use @ref DebugTools::ShapeRenderer to visualize the shapes for
debugging purposes. See also @ref scenegraph for introduction.
- Previous page: @ref scenegraph
- Next page: @ref debug-tools

71
doc/types.dox

@ -87,21 +87,82 @@ underlying type.
Any super- or sub-class of the same size and underlying type can be used
equivalently (e.g. @ref Math::Vector or @ref Color3 instead of @ref Vector3).
@section types-binary Binary representation
Scalar types with GLSL equivalent are verified to be exactly the same as
corresponding `GL*` types. Matrix and vector classes have the same binary
representation as corresponding array of numeric values without any additional
data or padding (e.g. `sizeof(Vector3i) == sizeof(Int[3])`), all matrices are
stored in column-major order.
This means that all scalar, matrix and vector types can be used directly for
filling GPU buffers and textures without any need for data extraction or
conversion. For convenience all vector and matrix classes provide
@ref Math::RectangularMatrix::data() "data()" function, which returns pointer
to the internal data array.
@section types-special Special types
%Magnum has special type for strongly-typed representation of angles, namely
the @ref Deg and @ref Rad classes (or @ref Degd and @ref Radd with @ref Double
as underlying type). Their only purpose is to avoid common degree-vs-radian
bugs (i.e. entering degree value where radians should be) and make the
conversion between these two representations easier. They are just a tiny
`inline` `constexpr` wrapper around the native type and they support all
meaningful numeric operations, so using them won't have any performance or
usability impact in practice.
These classes are *not* implicitly constructible or convertible from/to
@ref Float or @ref Double, you have to either construct/convert them explicitly
or use custom `_degf`/`_deg` and `_radf`/`_rad` literals:
@code
//Deg a = 60.0f // error, no implicit conversion from Float
Deg a = 60.0_degf; // okay
Float b = 3.2831853f;
auto tau = Rad{b} + 3.0_radf;
Radd pi = 3.141592653589793_rad;
//Double c = pi; // error, no implicit conversion to Double
auto c = Double{pi}; // okay
@endcode
They can be implicitly converted to each other, but conversion to different
underlying type is *explicit* to avoid precision loss (or, on the other hand,
unnecessarily high precision) during computations:
@code
Rad d = 60.0_degf; // 1.0471976f
auto e = Degd{pi}; // 180.0
//Rad f = pi; // error, no implicit conversion of underlying types
auto f = Rad{pi}; // 3.141592654f
@endcode
These classes are used exclusively in all functions taking and returning angles
-- trigonometry, angle computation, rotating transformation etc. Thanks to
implicit conversion you can seamlessly use either radians or degrees without
any need to care about what input the function expects:
@code
Float a = Math::sin(1.32457_radf);
Complex b = Complex::rotation(60.0_degf);
@endcode
@section types-other Other types
Other types, which don't have their GLSL equivalent, are:
- @ref Complex or @ref Complexd, @ref DualComplex or @ref DualComplexd
- @ref Quaternion or @ref Quaterniond, @ref DualQuaternion or @ref DualQuaterniond
- @ref Range1D / @ref Range2D / @ref Range3D, @ref Range1Di / @ref Range2Di / @ref Range3Di or
@ref Range1Dd / @ref Range2Dd / @ref Range3Dd
- @ref Quaternion or @ref Quaterniond, @ref DualQuaternion or
@ref DualQuaterniond
- @ref Range1D / @ref Range2D / @ref Range3D, @ref Range1Di / @ref Range2Di /
@ref Range3Di or @ref Range1Dd / @ref Range2Dd / @ref Range3Dd
These types can be used in GLSL either by extracting values from their
underlying structure or converting them to types supported by GLSL (e.g.
quaternion to matrix).
For your convenience, there is also alias for class with often used constants --
@ref Constants or @ref Constantsd.
For your convenience, there is also alias for class with often used constants
-- @ref Constants or @ref Constantsd.
- Previous page: @ref platform
- Next page: @ref matrix-vector

76
modules/FindCorrade.cmake

@ -3,7 +3,7 @@
# Basic usage:
# find_package(Corrade [REQUIRED])
# This module tries to find Corrade library and then defines:
# CORRADE_FOUND - True if Corrade library is found
# CORRADE_FOUND - True if Corrade is found
# CORRADE_INCLUDE_DIR - Root include dir
# CORRADE_INTERCONNECT_LIBRARIES - Interconnect library and dependent
# libraries
@ -14,9 +14,14 @@
# CORRADE_TESTSUITE_LIBRARIES - TestSuite library and dependent
# libraries
# CORRADE_RC_EXECUTABLE - Resource compiler executable
# The package is found if either debug or release version of each library is
# found. If both debug and release libraries are found, proper version is
# chosen based on actual build configuration of the project (i.e. Debug build
# is linked to debug libraries, Release build to release libraries).
#
# Corrade configures the compiler to use C++11 standard. Additionally you can
# use CORRADE_CXX_FLAGS to enable additional pedantic set of warnings and enable
# hidden visibility by default.
# use CORRADE_CXX_FLAGS to enable additional pedantic set of warnings and
# enable hidden visibility by default.
#
# Features of found Corrade library are exposed in these variables:
# CORRADE_GCC47_COMPATIBILITY - Defined if compiled with compatibility
@ -42,6 +47,7 @@
# CORRADE_TARGET_NACL_GLIBC - Defined if compiled for Google Chrome
# Native Client with `glibc` toolchain
# CORRADE_TARGET_EMSCRIPTEN - Defined if compiled for Emscripten
# CORRADE_TARGET_ANDROID - Defined if compiled for Android
#
# If CORRADE_BUILD_DEPRECATED is defined, the CORRADE_INCLUDE_DIR variable also
# contains path directly to Corrade directory (i.e. for includes without
@ -71,15 +77,15 @@
# add_executable(app source1 source2 ... ${app_resources})
#
# Add dynamic plugin.
# corrade_add_plugin(plugin_name install_dir metadata_file
# sources...)
# corrade_add_plugin(plugin_name debug_install_dir release_install_dir
# metadata_file sources...)
# The macro adds preprocessor directive CORRADE_DYNAMIC_PLUGIN. Additional
# libraries can be linked in via target_link_libraries(plugin_name ...). If
# install_dir is set to CMAKE_CURRENT_BINARY_DIR (e.g. for testing purposes),
# the files are copied directly, without the need to run `make install`. Note
# that the files are actually put into configuration-based subdirectory, i.e.
# ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}. See documentation of
# CMAKE_CFG_INTDIR variable for more information.
# debug_install_dir is set to CMAKE_CURRENT_BINARY_DIR (e.g. for testing
# purposes), the files are copied directly, without the need to perform install
# step. Note that the files are actually put into configuration-based
# subdirectory, i.e. ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}. See
# documentation of CMAKE_CFG_INTDIR variable for more information.
#
#
# Add static plugin.
@ -88,7 +94,11 @@
# The macro adds preprocessor directive CORRADE_STATIC_PLUGIN. Additional
# libraries can be linked in via target_link_libraries(plugin_name ...). If
# install_dir is set to CMAKE_CURRENT_BINARY_DIR (e.g. for testing purposes),
# no installation is performed.
# no installation rules are added.
#
# Note that plugins built in debug configuration (e.g. with CMAKE_BUILD_TYPE
# set to Debug) have "-d" suffix to make it possible to have both debug and
# release plugins installed alongside each other.
#
#
# Additionally these variables are defined for internal usage:
@ -98,6 +108,9 @@
# CORRADE_PLUGINMANAGER_LIBRARY - Plugin manager library (w/o
# dependencies)
# CORRADE_TESTSUITE_LIBRARY - TestSuite library (w/o dependencies)
# CORRADE_*_LIBRARY_DEBUG - Debug version of given library, if found
# CORRADE_*_LIBRARY_RELEASE - Release version of given library, if
# found
#
#
@ -126,10 +139,28 @@
#
# Libraries
find_library(CORRADE_INTERCONNECT_LIBRARY CorradeInterconnect)
find_library(CORRADE_UTILITY_LIBRARY CorradeUtility)
find_library(CORRADE_PLUGINMANAGER_LIBRARY CorradePluginManager)
find_library(CORRADE_TESTSUITE_LIBRARY CorradeTestSuite)
foreach(_component Interconnect Utility PluginManager TestSuite)
string(TOUPPER ${_component} _COMPONENT)
# Try to find both debug and release version
find_library(CORRADE_${_COMPONENT}_LIBRARY_DEBUG Corrade${_component}-d)
find_library(CORRADE_${_COMPONENT}_LIBRARY_RELEASE Corrade${_component})
# Set the _LIBRARY variable based on what was found
if(CORRADE_${_COMPONENT}_LIBRARY_DEBUG AND CORRADE_${_COMPONENT}_LIBRARY_RELEASE)
set(CORRADE_${_COMPONENT}_LIBRARY
debug ${CORRADE_${_COMPONENT}_LIBRARY_DEBUG}
optimized ${CORRADE_${_COMPONENT}_LIBRARY_RELEASE})
elseif(CORRADE_${_COMPONENT}_LIBRARY_DEBUG)
set(CORRADE_${_COMPONENT}_LIBRARY ${CORRADE_${_COMPONENT}_LIBRARY_DEBUG})
elseif(CORRADE_${_COMPONENT}_LIBRARY_RELEASE)
set(CORRADE_${_COMPONENT}_LIBRARY ${CORRADE_${_COMPONENT}_LIBRARY_RELEASE})
endif()
mark_as_advanced(CORRADE_${_COMPONENT}_LIBRARY_DEBUG
CORRADE_${_COMPONENT}_LIBRARY_RELEASE
CORRADE_${_COMPONENT}_LIBRARY)
endforeach()
# RC executable
find_program(CORRADE_RC_EXECUTABLE corrade-rc)
@ -219,6 +250,10 @@ string(FIND "${_corradeConfigure}" "#define CORRADE_TARGET_EMSCRIPTEN" _TARGET_E
if(NOT _TARGET_EMSCRIPTEN EQUAL -1)
set(CORRADE_TARGET_EMSCRIPTEN 1)
endif()
string(FIND "${_corradeConfigure}" "#define CORRADE_TARGET_ANDROID" _TARGET_ANDROID)
if(NOT _TARGET_ANDROID EQUAL -1)
set(CORRADE_TARGET_ANDROID 1)
endif()
set(CORRADE_UTILITY_LIBRARIES ${CORRADE_UTILITY_LIBRARY})
set(CORRADE_INTERCONNECT_LIBRARIES ${CORRADE_INTERCONNECT_LIBRARY} ${CORRADE_UTILITY_LIBRARIES})
@ -230,11 +265,12 @@ if(CORRADE_TARGET_UNIX OR CORRADE_TARGET_NACL_GLIBC)
set(CORRADE_PLUGINMANAGER_LIBRARIES ${CORRADE_PLUGINMANAGER_LIBRARIES} ${CMAKE_DL_LIBS})
endif()
mark_as_advanced(CORRADE_UTILITY_LIBRARY
CORRADE_INTERCONNECT_LIBRARY
CORRADE_PLUGINMANAGER_LIBRARY
CORRADE_TESTSUITE_LIBRARY
_CORRADE_INCLUDE_DIR
# AndroidLogStreamBuffer class needs to be linked to log library
if(CORRADE_TARGET_ANDROID)
set(CORRADE_UTILITY_LIBRARIES ${CORRADE_UTILITY_LIBRARIES} log)
endif()
mark_as_advanced(_CORRADE_INCLUDE_DIR
_CORRADE_MODULE_DIR)
# Add Corrade dir to include path if this is deprecated build

227
modules/FindMagnum.cmake

@ -7,16 +7,19 @@
# MAGNUM_LIBRARIES - Magnum library and dependent libraries
# MAGNUM_INCLUDE_DIRS - Root include dir and include dirs of
# dependencies
# MAGNUM_PLUGINS_DIR - Base directory with plugins, defaults to
# `magnum/` subdirectory of dir where Magnum library was found. You can
# modify it (e.g. set it to `.` when deploying on Windows with plugins
# stored relatively to the executable), the following MAGNUM_PLUGINS_*_DIR
# variables depend on it.
# MAGNUM_PLUGINS_FONT_DIR - Directory with font plugins
# MAGNUM_PLUGINS_FONTCONVERTER_DIR - Directory with font converter plugins
# MAGNUM_PLUGINS_IMAGECONVERTER_DIR - Directory with image converter plugins
# MAGNUM_PLUGINS_IMPORTER_DIR - Directory with importer plugins
# MAGNUM_PLUGINS_AUDIOIMPORTER_DIR - Directory with audio importer plugins
# MAGNUM_PLUGINS_DIR - Base directory with dynamic plugins, defaults
# to magnum/ subdirectory of dir where Magnum library was found (or magnum-d/
# in debug build). You can modify it (e.g. set it to `.` when deploying on
# Windows with plugins stored relatively to the executable), the following
# MAGNUM_PLUGINS_*_DIR variables depend on it.
# MAGNUM_PLUGINS_FONT_DIR - Directory with dynamic font plugins
# MAGNUM_PLUGINS_FONTCONVERTER_DIR - Directory with dynamic font converter
# plugins
# MAGNUM_PLUGINS_IMAGECONVERTER_DIR - Directory with dynamic image converter
# plugins
# MAGNUM_PLUGINS_IMPORTER_DIR - Directory with dynamic importer plugins
# MAGNUM_PLUGINS_AUDIOIMPORTER_DIR - Directory with dynamic audio importer
# plugins
# This command will try to find only the base library, not the optional
# components. The base library depends on Corrade and OpenGL libraries (or
# OpenGL ES libraries). Additional dependencies are specified by the
@ -35,6 +38,7 @@
# and TgaImporter plugin)
# MagnumFontConverter - Magnum bitmap font converter plugin (depends on Text
# component and TgaImageConverter plugin)
# ObjImporter - OBJ importer plugin
# TgaImageConverter - TGA image converter plugin
# TgaImporter - TGA importer plugin
# WavAudioImporter - WAV audio importer plugin (depends on Audio component)
@ -58,6 +62,17 @@
# MAGNUM_WINDOWLESSAPPLICATION_LIBRARIES and MAGNUM_APPLICATION_INCLUDE_DIRS
# / MAGNUM_WINDOWLESSAPPLICATION_INCLUDE_DIRS to simplify porting.
#
# The package is found if either debug or release version of each requested
# library (or plugin) is found. If both debug and release libraries (or
# plugins) are found, proper version is chosen based on actual build
# configuration of the project (i.e. Debug build is linked to debug libraries,
# Release build to release libraries). Note that this autodetection might fail
# for the MAGNUM_PLUGINS_DIR variable, i.e. you might need to switch it
# manually to magnum-d/ or magnum/ subdirectory based on whether you want
# to dynamically load plugins with or without debug information. You can also
# make use of CMAKE_BUILD_TYPE or CMAKE_CFG_INTDIR CMake variables for
# compile-time decision.
#
# Features of found Magnum library are exposed in these variables:
# MAGNUM_BUILD_DEPRECATED - Defined if compiled with deprecated APIs
# included
@ -74,29 +89,29 @@
# plugins (i.e. instead of `MagnumPlugins/` prefix).
#
# Additionally these variables are defined for internal usage:
# MAGNUM_INCLUDE_DIR - Root include dir (w/o
# dependencies)
# MAGNUM_LIBRARY - Magnum library (w/o
# dependencies)
# MAGNUM_*_LIBRARY - Component libraries (w/o
# dependencies)
# MAGNUM_LIBRARY_INSTALL_DIR - Library installation directory
# MAGNUM_PLUGINS_INSTALL_DIR - Plugin installation directory
# MAGNUM_PLUGINS_FONT_INSTALL_DIR - Font plugin installation
# directory
# MAGNUM_PLUGINS_FONTCONVERTER_INSTALL_DIR - Font converter plugin
# installation directory
# MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR - Image converter plugin
# installation directory
# MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR - Importer plugin installation
# MAGNUM_INCLUDE_DIR - Root include dir (w/o dependencies)
# MAGNUM_LIBRARY - Magnum library (w/o dependencies)
# MAGNUM_LIBRARY_DEBUG - Debug version of Magnum library, if found
# MAGNUM_LIBRARY_RELEASE - Release version of Magnum library, if found
# MAGNUM_*_LIBRARY - Component libraries (w/o dependencies)
# MAGNUM_*_LIBRARY_DEBUG - Debug version of given library, if found
# MAGNUM_*_LIBRARY_RELEASE - Release version of given library, if found
# MAGNUM_LIBRARY_INSTALL_DIR - Library installation directory
# MAGNUM_PLUGINS_[DEBUG|RELEASE]_INSTALL_DIR - Plugin installation directory
# MAGNUM_PLUGINS_FONT_[DEBUG|RELEASE]_INSTALL_DIR - Font plugin installation
# directory
# MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR - Audio omporter plugin
# MAGNUM_PLUGINS_FONTCONVERTER_[DEBUG|RELEASE]_INSTALL_DIR - Font converter
# plugin installation directory
# MAGNUM_PLUGINS_IMAGECONVERTER_[DEBUG|RELEASE]_INSTALL_DIR - Image converter
# plugin installation directory
# MAGNUM_PLUGINS_IMPORTER_[DEBUG|RELEASE]_INSTALL_DIR - Importer plugin
# installation directory
# MAGNUM_CMAKE_FIND_MODULE_INSTALL_DIR - Installation dir for CMake
# Find* modules
# MAGNUM_INCLUDE_INSTALL_DIR - Header installation directory
# MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR - Plugin header installation
# directory
# MAGNUM_PLUGINS_AUDIOIMPORTER_[DEBUG|RELEASE]_INSTALL_DIR - Audio importer
# plugin installation directory
# MAGNUM_CMAKE_FIND_MODULE_INSTALL_DIR - Installation dir for CMake Find*
# modules
# MAGNUM_INCLUDE_INSTALL_DIR - Header installation directory
# MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR - Plugin header installation directory
#
#
@ -127,8 +142,29 @@
# Dependencies
find_package(Corrade REQUIRED)
# Magnum library
find_library(MAGNUM_LIBRARY Magnum)
# Base Magnum library
find_library(MAGNUM_LIBRARY_DEBUG Magnum-d)
find_library(MAGNUM_LIBRARY_RELEASE Magnum)
# Set the MAGNUM_LIBRARY variable based on what was found, use that information
# to guess also build type of dynamic plugins
if(MAGNUM_LIBRARY_DEBUG AND MAGNUM_LIBRARY_RELEASE)
set(MAGNUM_LIBRARY
debug ${MAGNUM_LIBRARY_DEBUG}
optimized ${MAGNUM_LIBRARY_RELEASE})
get_filename_component(_MAGNUM_LIBRARY_PATH ${MAGNUM_LIBRARY_DEBUG} PATH)
# TODO: how to handle this with MSVC and other multi-configuration tools?
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(_MAGNUM_PLUGINS_DIR_SUFFIX "-d")
endif()
elseif(MAGNUM_LIBRARY_DEBUG)
set(MAGNUM_LIBRARY ${MAGNUM_LIBRARY_DEBUG})
get_filename_component(_MAGNUM_LIBRARY_PATH ${MAGNUM_LIBRARY_DEBUG} PATH)
set(_MAGNUM_PLUGINS_DIR_SUFFIX "-d")
elseif(MAGNUM_LIBRARY_RELEASE)
set(MAGNUM_LIBRARY ${MAGNUM_LIBRARY_RELEASE})
get_filename_component(_MAGNUM_LIBRARY_PATH ${MAGNUM_LIBRARY_RELEASE} PATH)
endif()
# Root include dir
find_path(MAGNUM_INCLUDE_DIR
@ -162,10 +198,22 @@ if(NOT _TARGET_DESKTOP_GLES EQUAL -1)
set(MAGNUM_TARGET_DESKTOP_GLES 1)
endif()
# Dependent libraries and includes
set(MAGNUM_INCLUDE_DIRS ${MAGNUM_INCLUDE_DIR}
${MAGNUM_INCLUDE_DIR}/MagnumExternal/OpenGL
${CORRADE_INCLUDE_DIR})
set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARY}
${CORRADE_UTILITY_LIBRARIES}
${CORRADE_PLUGINMANAGER_LIBRARIES})
if(NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES)
find_package(OpenGL REQUIRED)
else()
set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARIES} ${OPENGL_gl_LIBRARY})
elseif(MAGNUM_TARGET_GLES2)
find_package(OpenGLES2 REQUIRED)
set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARIES} ${OPENGLES2_LIBRARY})
elseif(MAGNUM_TARGET_GLES3)
find_package(OpenGLES3 REQUIRED)
set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARIES} ${OPENGLES3_LIBRARY})
endif()
# On Windows and in static builds, *Application libraries need to have
@ -225,8 +273,30 @@ foreach(component ${Magnum_FIND_COMPONENTS})
# break something else
set(_tmp_prefixes ${CMAKE_FIND_LIBRARY_PREFIXES})
set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} "")
find_library(MAGNUM_${_COMPONENT}_LIBRARY ${component}
PATH_SUFFIXES magnum/${_MAGNUM_${_COMPONENT}_PATH_SUFFIX})
# Try to find both debug and release version. Dynamic and static debug
# libraries are on different places.
find_library(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG ${component}
PATH_SUFFIXES magnum-d/${_MAGNUM_${_COMPONENT}_PATH_SUFFIX})
find_library(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG ${component}-d
PATH_SUFFIXES magnum/${_MAGNUM_${_COMPONENT}_PATH_SUFFIX})
find_library(MAGNUM_${_COMPONENT}_LIBRARY_RELEASE ${component}
PATH_SUFFIXES magnum/${_MAGNUM_${_COMPONENT}_PATH_SUFFIX})
# Set the _LIBRARY variable based on what was found
if(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG AND MAGNUM_${_COMPONENT}_LIBRARY_RELEASE)
set(MAGNUM_${_COMPONENT}_LIBRARY
debug ${MAGNUM_${_COMPONENT}_LIBRARY_DEBUG}
optimized ${MAGNUM_${_COMPONENT}_LIBRARY_RELEASE})
elseif(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG)
set(MAGNUM_${_COMPONENT}_LIBRARY ${MAGNUM_${_COMPONENT}_LIBRARY_DEBUG})
elseif(MAGNUM_${_COMPONENT}_LIBRARY_RELEASE)
set(MAGNUM_${_COMPONENT}_LIBRARY ${MAGNUM_${_COMPONENT}_LIBRARY_RELEASE})
endif()
set(CMAKE_FIND_LIBRARY_PREFIXES ${_tmp_prefixes})
# Set library defaults, find the library
@ -234,13 +304,37 @@ foreach(component ${Magnum_FIND_COMPONENTS})
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Magnum/${component})
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES ${component}.h)
find_library(MAGNUM_${_COMPONENT}_LIBRARY Magnum${component})
# Try to find both debug and release version
find_library(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG Magnum${component}-d)
find_library(MAGNUM_${_COMPONENT}_LIBRARY_RELEASE Magnum${component})
# Set the _LIBRARY variable based on what was found
if(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG AND MAGNUM_${_COMPONENT}_LIBRARY_RELEASE)
set(MAGNUM_${_COMPONENT}_LIBRARY
debug ${MAGNUM_${_COMPONENT}_LIBRARY_DEBUG}
optimized ${MAGNUM_${_COMPONENT}_LIBRARY_RELEASE})
elseif(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG)
set(MAGNUM_${_COMPONENT}_LIBRARY ${MAGNUM_${_COMPONENT}_LIBRARY_DEBUG})
elseif(MAGNUM_${_COMPONENT}_LIBRARY_RELEASE)
set(MAGNUM_${_COMPONENT}_LIBRARY ${MAGNUM_${_COMPONENT}_LIBRARY_RELEASE})
endif()
endif()
# Applications
if(${component} MATCHES .+Application)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Magnum/Platform)
# Android application dependencies
if(${component} STREQUAL AndroidApplication)
find_package(EGL)
if(EGL_FOUND)
set(_MAGNUM_${_COMPONENT}_LIBRARIES android ${EGL_LIBRARY} ${_WINDOWCONTEXT_MAGNUM_LIBRARIES_DEPENDENCY})
set(_MAGNUM_${_COMPONENT}_INCLUDE_DIRS ${ANDROID_NATIVE_APP_GLUE_INCLUDE_DIR})
else()
unset(MAGNUM_${_COMPONENT}_LIBRARY)
endif()
endif()
# GLUT application dependencies
if(${component} STREQUAL GlutApplication)
find_package(GLUT)
@ -311,6 +405,9 @@ foreach(component ${Magnum_FIND_COMPONENTS})
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Atlas.h)
endif()
# The plugins don't have any dependencies, nothing additional to do for
# them
# Try to find the includes
if(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES)
find_path(_MAGNUM_${_COMPONENT}_INCLUDE_DIR
@ -326,7 +423,11 @@ foreach(component ${Magnum_FIND_COMPONENTS})
set(Magnum_${component}_FOUND TRUE)
# Don't expose variables w/o dependencies to end users
mark_as_advanced(FORCE MAGNUM_${_COMPONENT}_LIBRARY _MAGNUM_${_COMPONENT}_INCLUDE_DIR)
mark_as_advanced(FORCE
MAGNUM_${_COMPONENT}_LIBRARY_DEBUG
MAGNUM_${_COMPONENT}_LIBRARY_RELEASE
MAGNUM_${_COMPONENT}_LIBRARY
_MAGNUM_${_COMPONENT}_INCLUDE_DIR)
# Global aliases for Windowless*Application and *Application components.
# If already set, unset them to avoid ambiguity.
@ -357,41 +458,42 @@ find_package_handle_standard_args(Magnum
REQUIRED_VARS MAGNUM_LIBRARY MAGNUM_INCLUDE_DIR
HANDLE_COMPONENTS)
# Dependent libraries and includes
set(MAGNUM_INCLUDE_DIRS ${MAGNUM_INCLUDE_DIR}
${MAGNUM_INCLUDE_DIR}/MagnumExternal/OpenGL
${CORRADE_INCLUDE_DIR})
set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARY}
${CORRADE_UTILITY_LIBRARIES}
${CORRADE_PLUGINMANAGER_LIBRARIES})
if(NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES)
set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARIES} ${OPENGL_gl_LIBRARY})
else()
set(MAGNUM_LIBRARIES ${MAGNUM_LIBRARIES} ${OPENGLES2_LIBRARY})
endif()
# Installation dirs
include(CorradeLibSuffix)
set(MAGNUM_LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX})
set(MAGNUM_PLUGINS_INSTALL_DIR ${MAGNUM_LIBRARY_INSTALL_DIR}/magnum)
set(MAGNUM_PLUGINS_FONT_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/fonts)
set(MAGNUM_PLUGINS_FONTCONVERTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/fontconverters)
set(MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/imageconverters)
set(MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/importers)
set(MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/audioimporters)
set(MAGNUM_PLUGINS_DEBUG_INSTALL_DIR ${MAGNUM_LIBRARY_INSTALL_DIR}/magnum-d)
set(MAGNUM_PLUGINS_RELEASE_INSTALL_DIR ${MAGNUM_LIBRARY_INSTALL_DIR}/magnum)
set(MAGNUM_PLUGINS_FONT_DEBUG_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_INSTALL_DIR}/fonts)
set(MAGNUM_PLUGINS_FONT_RELEASE_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_INSTALL_DIR}/fonts)
set(MAGNUM_PLUGINS_FONTCONVERTER_DEBUG_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_INSTALL_DIR}/fontconverters)
set(MAGNUM_PLUGINS_FONTCONVERTER_RELEASE_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_INSTALL_DIR}/fontconverters)
set(MAGNUM_PLUGINS_IMAGECONVERTER_DEBUG_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_INSTALL_DIR}/imageconverters)
set(MAGNUM_PLUGINS_IMAGECONVERTER_RELEASE_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_INSTALL_DIR}/imageconverters)
set(MAGNUM_PLUGINS_IMPORTER_DEBUG_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_INSTALL_DIR}/importers)
set(MAGNUM_PLUGINS_IMPORTER_RELEASE_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_INSTALL_DIR}/importers)
set(MAGNUM_PLUGINS_AUDIOIMPORTER_DEBUG_INSTALL_DIR ${MAGNUM_PLUGINS_DEBUG_INSTALL_DIR}/audioimporters)
set(MAGNUM_PLUGINS_AUDIOIMPORTER_RELEASE_INSTALL_DIR ${MAGNUM_PLUGINS_RELEASE_INSTALL_DIR}/audioimporters)
set(MAGNUM_CMAKE_FIND_MODULE_INSTALL_DIR ${CMAKE_ROOT}/Modules)
set(MAGNUM_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/Magnum)
set(MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/MagnumPlugins)
mark_as_advanced(FORCE
MAGNUM_LIBRARY_DEBUG
MAGNUM_LIBRARY_RELEASE
MAGNUM_LIBRARY
MAGNUM_INCLUDE_DIR
MAGNUM_LIBRARY_INSTALL_DIR
MAGNUM_PLUGINS_INSTALL_DIR
MAGNUM_PLUGINS_FONT_INSTALL_DIR
MAGNUM_PLUGINS_FONTCONVERTER_INSTALL_DIR
MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR
MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR
MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR
MAGNUM_PLUGINS_DEBUG_INSTALL_DIR
MAGNUM_PLUGINS_RELEASE_INSTALL_DIR
MAGNUM_PLUGINS_FONT_DEBUG_INSTALL_DIR
MAGNUM_PLUGINS_FONT_RELEASE_INSTALL_DIR
MAGNUM_PLUGINS_FONTCONVERTER_DEBUG_INSTALL_DIR
MAGNUM_PLUGINS_FONTCONVERTER_RELEASE_INSTALL_DIR
MAGNUM_PLUGINS_IMAGECONVERTER_DEBUG_INSTALL_DIR
MAGNUM_PLUGINS_IMAGECONVERTER_RELEASE_INSTALL_DIR
MAGNUM_PLUGINS_IMPORTER_DEBUG_INSTALL_DIR
MAGNUM_PLUGINS_IMPORTER_RELEASE_INSTALL_DIR
MAGNUM_PLUGINS_AUDIOIMPORTER_DEBUG_INSTALL_DIR
MAGNUM_PLUGINS_AUDIOIMPORTER_RELEASE_INSTALL_DIR
MAGNUM_CMAKE_MODULE_INSTALL_DIR
MAGNUM_INCLUDE_INSTALL_DIR
MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR)
@ -406,8 +508,7 @@ if(MAGNUM_BUILD_DEPRECATED)
endif()
# Get base plugin directory from main library location
get_filename_component(_MAGNUM_LIBRARY_PATH ${MAGNUM_LIBRARY} PATH)
set(MAGNUM_PLUGINS_DIR ${_MAGNUM_LIBRARY_PATH}/magnum
set(MAGNUM_PLUGINS_DIR ${_MAGNUM_LIBRARY_PATH}/magnum${_MAGNUM_PLUGINS_DIR_SUFFIX}
CACHE PATH "Base directory where to look for Magnum plugins")
# Plugin directories

6
modules/FindOpenGLES3.cmake

@ -34,7 +34,11 @@
# Library
find_library(OPENGLES3_LIBRARY NAMES
GLESv2) # wtf?
GLESv3
# On some platforms (e.g. desktop emulation with Mesa or NVidia) ES3
# support is provided in ES2 lib
GLESv2)
# Include dir
find_path(OPENGLES3_INCLUDE_DIR

5
package/archlinux/PKGBUILD

@ -13,7 +13,7 @@ provides=('magnum-git')
build() {
mkdir -p "$startdir/build"
cd "$startdir/build/"
cd "$startdir/build"
# Disable optimization (saves A LOT of compilation time)
newcxxflags=$(echo $CXXFLAGS | sed s/-O.//g | sed s/-D_FORTIFY_SOURCE=.//g)
@ -29,6 +29,7 @@ build() {
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -43,7 +44,7 @@ build() {
check() {
cd "$startdir/build"
ctest --output-on-failure
ctest --output-on-failure -j5
}
package() {

42
package/archlinux/PKGBUILD-android-arm

@ -0,0 +1,42 @@
# Author: mosra <mosra@centrum.cz>
pkgname=android-arm-magnum
pkgver=dev
pkgrel=1
pkgdesc="C++11 and OpenGL 2D/3D graphics engine (Android ARM)"
arch=('any')
url="http://mosra.cz/blog/magnum.php"
license=('MIT')
depends=('android-arm-corrade')
makedepends=('cmake' 'ninja' 'android-ndk')
options=('!strip' '!buildflags' 'staticlibs')
build() {
if [ ! -d "$startdir/build-android-arm" ] ; then
mkdir "$startdir/build-android-arm"
cd "$startdir/build-android-arm"
cmake .. \
-DCMAKE_MODULE_PATH="$startdir/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="$startdir/toolchains/generic/Android-ARM.cmake" \
-DTARGET_GLES=ON \
-DTARGET_GLES2=ON \
-G Ninja
fi
cd "$startdir/build-android-arm"
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/opt/android-ndk/platforms/android-19/arch-arm/usr \
-DWITH_MAGNUMFONT=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_ANDROIDAPPLICATION=ON
ninja
}
package() {
cd "$startdir/build-android-arm"
DESTDIR="$pkgdir/" ninja install
}

42
package/archlinux/PKGBUILD-android-x86

@ -0,0 +1,42 @@
# Author: mosra <mosra@centrum.cz>
pkgname=android-x86-magnum
pkgver=dev
pkgrel=1
pkgdesc="C++11 and OpenGL 2D/3D graphics engine (Android x86)"
arch=('any')
url="http://mosra.cz/blog/magnum.php"
license=('MIT')
depends=('android-x86-corrade')
makedepends=('cmake' 'ninja' 'android-ndk')
options=('!strip' '!buildflags' 'staticlibs')
build() {
if [ ! -d "$startdir/build-android-x86" ] ; then
mkdir "$startdir/build-android-x86"
cd "$startdir/build-android-x86"
cmake .. \
-DCMAKE_MODULE_PATH="$startdir/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="$startdir/toolchains/generic/Android-x86.cmake" \
-DTARGET_GLES=ON \
-DTARGET_GLES2=ON \
-G Ninja
fi
cd "$startdir/build-android-x86"
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/opt/android-ndk/platforms/android-19/arch-x86/usr \
-DWITH_MAGNUMFONT=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_ANDROIDAPPLICATION=ON
ninja
}
package() {
cd "$startdir/build-android-x86"
DESTDIR="$pkgdir/" ninja install
}

3
package/archlinux/PKGBUILD-clang

@ -33,6 +33,7 @@ build() {
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -46,7 +47,7 @@ build() {
check() {
cd "$startdir/build-clang"
ctest --output-on-failure
ctest --output-on-failure -j5
}
package() {

3
package/archlinux/PKGBUILD-clang-libc++

@ -35,6 +35,7 @@ build() {
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -48,7 +49,7 @@ build() {
check() {
cd "$startdir/build-clang-libc++"
ctest --output-on-failure
ctest --output-on-failure -j5
}
package() {

3
package/archlinux/PKGBUILD-emscripten

@ -18,7 +18,6 @@ build() {
cmake .. \
-DCMAKE_MODULE_PATH="$startdir/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="$startdir/toolchains/generic/Emscripten.cmake" \
-DWITH_AUDIO=OFF \
-G Ninja
fi
@ -27,9 +26,9 @@ build() {
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/emscripten/system \
-DWITH_AUDIO=OFF \
-DWITH_SDL2APPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON

3
package/archlinux/PKGBUILD-es2

@ -23,6 +23,7 @@ build() {
-DWITH_AUDIO=ON \
-DWITH_XEGLAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -33,7 +34,7 @@ build() {
check() {
cd "$startdir/build-es2"
ctest --output-on-failure
ctest --output-on-failure -j5
}
package() {

3
package/archlinux/PKGBUILD-es2desktop

@ -26,6 +26,7 @@ build() {
-DWITH_GLXAPPLICATION=ON \
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -38,7 +39,7 @@ build() {
check() {
cd "$startdir/build-es2desktop"
ctest --output-on-failure
ctest --output-on-failure -j5
}
package() {

3
package/archlinux/PKGBUILD-es3

@ -23,6 +23,7 @@ build() {
-DWITH_AUDIO=ON \
-DWITH_XEGLAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -33,7 +34,7 @@ build() {
check() {
cd "$startdir/build-es3"
ctest --output-on-failure
ctest --output-on-failure -j5
}
package() {

3
package/archlinux/PKGBUILD-es3desktop

@ -26,6 +26,7 @@ build() {
-DWITH_GLXAPPLICATION=ON \
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -38,7 +39,7 @@ build() {
check() {
cd "$startdir/build-es3desktop"
ctest --output-on-failure
ctest --output-on-failure -j5
}
package() {

3
package/archlinux/PKGBUILD-gcc46

@ -33,6 +33,7 @@ build() {
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -46,7 +47,7 @@ build() {
check() {
cd "$startdir/build-gcc46"
ctest --output-on-failure
ctest --output-on-failure -j5
}
package() {

3
package/archlinux/PKGBUILD-gcc47

@ -33,6 +33,7 @@ build() {
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -46,7 +47,7 @@ build() {
check() {
cd "$startdir/build-gcc47"
ctest --output-on-failure
ctest --output-on-failure -j5
}
package() {

3
package/archlinux/PKGBUILD-gcc49

@ -33,6 +33,7 @@ build() {
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -46,7 +47,7 @@ build() {
check() {
cd "$startdir/build-gcc49"
ctest --output-on-failure
ctest --output-on-failure -j5
}
package() {

4
package/archlinux/PKGBUILD-mingw32

@ -12,7 +12,7 @@ options=('!buildflags' '!strip' 'staticlibs')
build() {
mkdir -p "$startdir/build-win"
cd "$startdir/build-win/"
cd "$startdir/build-win"
unset LDFLAGS
@ -20,9 +20,11 @@ build() {
-DCMAKE_TOOLCHAIN_FILE=../toolchains/archlinux/basic-mingw32.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/i486-mingw32 \
-DWITH_AUDIO=ON \
-DWITH_GLUTAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \

2
package/archlinux/PKGBUILD-nacl-glibc

@ -24,6 +24,7 @@ build() {
-DWITH_NACLAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -44,6 +45,7 @@ build() {
-DWITH_NACLAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \

4
package/archlinux/PKGBUILD-nacl-newlib

@ -20,12 +20,12 @@ build() {
-DCMAKE_TOOLCHAIN_FILE="$startdir/toolchains/generic/NaCl-newlib-x86-32.cmake" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/nacl \
-DWITH_AUDIO=OFF \
-DWITH_MAGNUMINFO=ON \
-DWITH_NACLAPPLICATION=ON \
-DWITH_WINDOWLESSNACLAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -42,12 +42,12 @@ build() {
-DCMAKE_TOOLCHAIN_FILE="$startdir/toolchains/generic/NaCl-newlib-x86-64.cmake" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/nacl \
-DWITH_AUDIO=OFF \
-DWITH_MAGNUMINFO=ON \
-DWITH_NACLAPPLICATION=ON \
-DWITH_WINDOWLESSNACLAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \

40
package/archlinux/PKGBUILD-release

@ -2,18 +2,43 @@
pkgname=magnum
pkgver=dev.release
pkgrel=1
pkgdesc="C++11 and OpenGL 2D/3D graphics engine"
pkgdesc="C++11 and OpenGL 2D/3D graphics engine (debug+release libs)"
arch=('i686' 'x86_64')
url="http://mosra.cz/blog/magnum.php"
license=('MIT')
depends=('corrade' 'openal' 'sdl2' 'freeglut')
makedepends=('cmake' 'ninja')
options=('!strip' 'staticlibs')
provides=('magnum-git')
options=('staticlibs')
build() {
mkdir -p "$startdir/build"
cd "$startdir/build/"
cd "$startdir/build"
cmake .. \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_INSTALL_PREFIX=/usr \
-DWITH_AUDIO=ON \
-DWITH_GLUTAPPLICATION=ON \
-DWITH_GLXAPPLICATION=ON \
-DWITH_SDL2APPLICATION=ON \
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
-DWITH_DISTANCEFIELDCONVERTER=ON \
-DWITH_FONTCONVERTER=ON \
-DWITH_MAGNUMINFO=ON \
-DBUILD_TESTS=ON \
-DBUILD_GL_TESTS=ON \
-G Ninja
ninja
mkdir -p "$startdir/build-release"
cd "$startdir/build-release"
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
@ -25,6 +50,7 @@ build() {
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -39,10 +65,16 @@ build() {
check() {
cd "$startdir/build"
ctest --output-on-failure
ctest --output-on-failure -j5
cd "$startdir/build-release"
ctest --output-on-failure -j5
}
package() {
cd "$startdir/build"
DESTDIR="$pkgdir/" ninja install
cd "$startdir/build-release"
DESTDIR="$pkgdir/" ninja install/strip
}

1
package/archlinux/magnum-git/PKGBUILD

@ -45,6 +45,7 @@ build() {
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \

1
package/ci/jenkins-emscripten.xml

@ -73,6 +73,7 @@ cmake .. \
`#-DWITH_AUDIO=ON` \
-DWITH_SDL2APPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
`#-DWITH_WAVAUDIOIMPORTER=ON` \

2
package/ci/jenkins-gltests.xml

@ -82,7 +82,7 @@ cd build-${compiler}-${libraries}-${compatibility}-${gl}
ninja
ctest --output-on-failure -R GLTest || true
ctest --output-on-failure -R GLTest -j5 || true
]]>
</command>
</hudson.tasks.Shell>

3
package/ci/jenkins-mingw32.xml

@ -87,6 +87,7 @@ cmake .. \
`#-DWITH_SDL2APPLICATION=ON` \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -96,7 +97,7 @@ cmake .. \
-G Ninja
ninja
ninja install
ninja install/strip
]]>
</command>
</hudson.tasks.Shell>

3
package/ci/jenkins-nacl.xml

@ -81,6 +81,7 @@ cmake .. \
-DWITH_NACLAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
`#-DWITH_WAVAUDIOIMPORTER=ON` \
@ -88,7 +89,7 @@ cmake .. \
-G Ninja
ninja
ninja install
ninja install/strip
]]>
</command>
</hudson.tasks.Shell>

11
package/ci/jenkins.xml

@ -99,22 +99,27 @@ fi
if [ ${gl} = "desktop" ] ; then
desktop_flag=ON
es_flag=OFF
windowless_flag=ON
elif [ ${gl} = "es2" ] ; then
gl_flags="-DTARGET_GLES=ON -DTARGET_GLES2=ON"
desktop_flag=OFF
es_flag=ON
windowless_flag=OFF
elif [ ${gl} = "es2desktop" ] ; then
gl_flags="-DTARGET_GLES=ON -DTARGET_GLES2=ON -DTARGET_DESKTOP_GLES=ON"
desktop_flag=OFF
es_flag=OFF
windowless_flag=ON
elif [ ${gl} = "es3" ] ; then
gl_flags="-DTARGET_GLES=ON -DTARGET_GLES2=OFF"
desktop_flag=OFF
es_flag=ON
windowless_flag=OFF
elif [ ${gl} = "es3desktop" ] ; then
gl_flags="-DTARGET_GLES=ON -DTARGET_GLES2=OFF -DTARGET_DESKTOP_GLES=ON"
desktop_flag=OFF
es_flag=OFF
windowless_flag=ON
fi
@ -137,8 +142,10 @@ cmake .. \
-DWITH_GLUTAPPLICATION=ON \
-DWITH_GLXAPPLICATION=ON \
-DWITH_SDL2APPLICATION=ON \
-DWITH_XEGLAPPLICATION=${es_flag} \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=${desktop_flag} \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \
@ -148,8 +155,8 @@ cmake .. \
-G Ninja
ninja
ctest --output-on-failure -E GLTest || true
ninja install
ctest --output-on-failure -E GLTest -j5 || true
ninja install/strip
]]>
</command>
</hudson.tasks.Shell>

1
package/debian/rules vendored

@ -11,6 +11,7 @@ override_dh_auto_configure:
-DWITH_WINDOWLESSGLXAPPLICATION=ON \
-DWITH_MAGNUMFONT=ON \
-DWITH_MAGNUMFONTCONVERTER=ON \
-DWITH_OBJIMPORTER=ON \
-DWITH_TGAIMAGECONVERTER=ON \
-DWITH_TGAIMPORTER=ON \
-DWITH_WAVAUDIOIMPORTER=ON \

77
src/Magnum/AbstractShaderProgram.cpp

@ -271,40 +271,53 @@ void AbstractShaderProgram::bindFragmentDataLocationIndexed(UnsignedInt location
}
#endif
bool AbstractShaderProgram::link() {
/* Link shader program */
glLinkProgram(_id);
/* Check link status */
GLint success, logLength;
glGetProgramiv(_id, GL_LINK_STATUS, &success);
glGetProgramiv(_id, GL_INFO_LOG_LENGTH, &logLength);
/* Error or warning message. The string is returned null-terminated, scrap
the \0 at the end afterwards */
std::string message(logLength, '\n');
if(message.size() > 1)
glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]);
message.resize(std::max(logLength, 1)-1);
/* Show error log and delete shader */
if(!success) {
Error out;
out.setFlag(Debug::NewLineAtTheEnd, false);
out.setFlag(Debug::SpaceAfterEachValue, false);
out << "AbstractShaderProgram: linking failed with the following message:\n"
<< message;
/* Or just warnings, if there are any */
} else if(!message.empty()) {
Debug out;
out.setFlag(Debug::NewLineAtTheEnd, false);
out.setFlag(Debug::SpaceAfterEachValue, false);
out << "AbstractShaderProgram: linking succeeded with the following message:\n"
<< message;
bool AbstractShaderProgram::link(std::initializer_list<std::reference_wrapper<AbstractShaderProgram>> shaders) {
bool allSuccess = true;
/* Invoke (possibly parallel) linking on all shaders */
for(AbstractShaderProgram& shader: shaders) glLinkProgram(shader._id);
/* After linking phase, check status of all shaders */
Int i = 1;
for(AbstractShaderProgram& shader: shaders) {
GLint success, logLength;
glGetProgramiv(shader._id, GL_LINK_STATUS, &success);
glGetProgramiv(shader._id, GL_INFO_LOG_LENGTH, &logLength);
/* Error or warning message. The string is returned null-terminated,
scrap the \0 at the end afterwards */
std::string message(logLength, '\n');
if(message.size() > 1)
glGetProgramInfoLog(shader._id, message.size(), nullptr, &message[0]);
message.resize(std::max(logLength, 1)-1);
/* Show error log */
if(!success) {
Error out;
out.setFlag(Debug::NewLineAtTheEnd, false);
out.setFlag(Debug::SpaceAfterEachValue, false);
out << "AbstractShaderProgram::link(): linking";
if(shaders.size() != 1) out << " of shader " << std::to_string(i);
out << " failed with the following message:\n"
<< message;
/* Or just warnings, if any */
} else if(!message.empty()) {
Warning out;
out.setFlag(Debug::NewLineAtTheEnd, false);
out.setFlag(Debug::SpaceAfterEachValue, false);
out << "AbstractShaderProgram::link(): linking";
if(shaders.size() != 1) out << " of shader " << std::to_string(i);
out << " succeeded with the following message:\n"
<< message;
}
/* Success of all depends on each of them */
allSuccess = allSuccess && success;
++i;
}
return success;
return allSuccess;
}
Int AbstractShaderProgram::uniformLocation(const std::string& name) {

156
src/Magnum/AbstractShaderProgram.h

@ -29,6 +29,7 @@
* @brief Class @ref Magnum::AbstractShaderProgram
*/
#include <functional>
#include <string>
#include <Corrade/Containers/EnumSet.h>
@ -63,27 +64,21 @@ enum: UnsignedInt {
NormalOutput = 1
};
@endcode
- **Uniform locations** for setting uniform data (see below) (private
variables), for example:
@code
Int TransformationUniform = 0,
ProjectionUniform = 1,
DiffuseTextureUniform = 2,
SpecularTextureUniform = 3;
@endcode
- **Constructor**, which attaches particular shaders, links the program and
gets uniform locations, for example:
- **Constructor**, which loads, compiles and attaches particular shaders and
links the program together, for example:
@code
MyShader() {
// Load shaders, compile them and attach them to the program
// Load shader sources
Shader vert(Version::GL430, Shader::Type::Vertex);
vert.attachFile("PhongShader.vert");
CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile());
attachShader(vert);
Shader frag(Version::GL430, Shader::Type::Fragment);
frag.attachFile("PhongShader.vert");
CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile());
vert.addFile("PhongShader.vert");
frag.addFile("PhongShader.vert");
// Invoke parallel compilation for best performance
CORRADE_INTERNAL_ASSERT_OUTPUT(Shader::compile({vert, frag}));
// Attach the shaders
attachShader(vert);
attachShader(frag);
// Link the program together
@ -94,24 +89,29 @@ MyShader() {
protected @ref setUniform() functions. For usability purposes you can
implement also method chaining. Example:
@code
MyShader& setTransformation(const Matrix4& matrix) {
setUniform(TransformationUniform, matrix);
MyShader& setProjectionMatrix(const Matrix4& matrix) {
setUniform(0, matrix);
return *this;
}
MyShader& setTransformationMatrix(const Matrix4& matrix) {
setUniform(1, matrix);
return *this;
}
MyShader& setProjection(const Matrix4& matrix) {
setUniform(ProjectionUniform, matrix);
MyShader& setNormalMatrix(const Matrix3x3& matrix) {
setUniform(2, matrix);
return *this;
}
@endcode
- **Texture setting functions** in which you bind the textures to particular
layers using @ref AbstractTexture::bind() and equivalent, for example:
- <strong>%Texture setting functions</strong> in which you bind the textures
to particular texture units using @ref Texture::bind() "*Texture::bind()"
and equivalents, for example:
@code
MyShader& setDiffuseTexture(Texture2D& texture) {
texture->bind(0);
texture.bind(0);
return *this;
}
MyShader& setSpecularTexture(Texture2D& texture) {
texture->bind(1);
texture.bind(1);
return *this;
}
@endcode
@ -141,7 +141,7 @@ If you don't have the required extension, declare the attributes without
`layout()` qualifier and use functions @ref bindAttributeLocation() and
@ref bindFragmentDataLocation() / @ref bindFragmentDataLocationIndexed() between
attaching the shaders and linking the program. Note that additional syntax
changes may be needed for GLSL 1.20 and GLSL ES 1.0.
changes may be needed for GLSL 1.20 and GLSL ES.
@code
in vec4 position;
in vec3 normal;
@ -191,21 +191,24 @@ code, e.g.:
@code
// GLSL 4.30, or
#extension GL_ARB_explicit_uniform_location: enable
layout(location = 0) uniform mat4 transformation;
layout(location = 1) uniform mat4 projection;
layout(location = 0) uniform mat4 projectionMatrix;
layout(location = 1) uniform mat4 transformationMatrix;
layout(location = 2) uniform mat3 normalMatrix;
@endcode
If you don't have the required extension, declare the uniforms without the
`layout()` qualifier and get uniform location using @ref uniformLocation()
*after* linking stage. Note that additional syntax changes may be needed for
GLSL 1.20 and GLSL ES 1.0.
`layout()` qualifier, get uniform location using @ref uniformLocation() *after*
linking stage and then use the queried location in uniform setting functions.
Note that additional syntax changes may be needed for GLSL 1.20 and GLSL ES.
@code
uniform mat4 transformation;
uniform mat4 projection;
uniform mat4 projectionMatrix;
uniform mat4 transformationMatrix;
uniform mat3 normalMatrix;
@endcode
@code
Int transformationUniform = uniformLocation("transformation");
Int projectionUniform = uniformLocation("projection");
Int projectionMatrixUniform = uniformLocation("projectionMatrix");
Int transformationMatrixUniform = uniformLocation("transformationMatrix");
Int normalMatrixUniform = uniformLocation("normalMatrix");
@endcode
@see @ref maxUniformLocations()
@ -216,10 +219,10 @@ Int projectionUniform = uniformLocation("projection");
@ref Magnum::AbstractShaderProgram::uniformLocation() "uniformLocation()"
instead.
@subsection AbstractShaderProgram-texture-layer Binding texture layer uniforms
@subsection AbstractShaderProgram-texture-units Specifying texture binding units
The preferred workflow is to specify texture layers directly in the shader
code, e.g.:
The preferred workflow is to specify texture binding unit directly in the
shader code, e.g.:
@code
// GLSL 4.20, or
#extension GL_ARB_shading_language_420pack: enable
@ -227,25 +230,24 @@ layout(binding = 0) uniform sampler2D diffuseTexture;
layout(binding = 1) uniform sampler2D specularTexture;
@endcode
If you don't have the required extension (or if you want to change the layer
later), declare the uniforms without the `layout()` qualifier and set the
texture layer uniform using @ref setUniform(Int, const T&) "setUniform(Int, Int)".
Note that additional syntax changes may be needed for GLSL 1.20 and GLSL ES
1.0.
If you don't have the required extension, declare the uniforms without the
`layout()` qualifier and set the texture binding unit using
@ref setUniform(Int, const T&) "setUniform(Int, Int)". Note that additional
syntax changes may be needed for GLSL 1.20 and GLSL ES 1.0.
@code
uniform sampler2D diffuseTexture;
uniform sampler2D specularTexture;
@endcode
@code
setUniform(DiffuseTextureUniform, 0);
setUniform(SpecularTextureUniform, 1);
setUniform(uniformLocation("diffuseTexture"), 0);
setUniform(uniformLocation("specularTexture"), 1);
@endcode
@see @ref Shader::maxTextureImageUnits()
@requires_gl42 %Extension @extension{ARB,shading_language_420pack} for explicit
texture layer binding instead of using
texture binding unit instead of using
@ref Magnum::AbstractShaderProgram::setUniform(Int, const T&) "setUniform(Int, Int)".
@requires_gl Explicit texture layer binding is not supported in OpenGL ES. Use
@requires_gl Explicit texture binding unit is not supported in OpenGL ES. Use
@ref Magnum::AbstractShaderProgram::setUniform(Int, const T&) "setUniform(Int, Int)"
instead.
@ -320,8 +322,6 @@ comes in handy.
@see @ref portability-shaders
@todo Use Containers::ArrayReference for setting uniform arrays?
@todo Compiling and linking more than one shader in parallel, then checking
status, should be faster -- https://twitter.com/g_truc/status/352778836657700866
@todo `GL_NUM_{PROGRAM,SHADER}_BINARY_FORMATS` + `GL_{PROGRAM,SHADER}_BINARY_FORMATS` (vector), (@extension{ARB,ES2_compatibility})
*/
class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject {
@ -343,15 +343,6 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject {
*/
static Int maxVertexAttributes();
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copydoc maxVertexAttributes()
* @deprecated Use @ref Magnum::AbstractShaderProgram::maxVertexAttributes() "maxVertexAttributes()"
* instead.
*/
static CORRADE_DEPRECATED("use maxVertexAttributes() instead") Int maxSupportedVertexAttributeCount() { return maxVertexAttributes(); }
#endif
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Max supported atomic counter buffer size
@ -562,6 +553,21 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject {
#endif
protected:
/**
* @brief Link the shader
*
* Returns `false` if linking of any shader failed, `true` if
* everything succeeded. Linker message (if any) is printed to error
* output. All attached shaders must be compiled with
* @ref Shader::compile() before linking. The operation is batched in a
* way that allows the driver to link multiple shaders simultaenously
* (i.e. in multiple threads).
* @see @fn_gl{LinkProgram}, @fn_gl{GetProgram} with
* @def_gl{LINK_STATUS} and @def_gl{INFO_LOG_LENGTH},
* @fn_gl{GetProgramInfoLog}
*/
static bool link(std::initializer_list<std::reference_wrapper<AbstractShaderProgram>> shaders);
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Allow retrieving program binary
@ -655,14 +661,12 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject {
/**
* @brief Link the shader
*
* Returns `false` if linking failed, `true` otherwise. Compiler
* message (if any) is printed to error output. All attached shaders
* must be compiled with @ref Shader::compile() before linking.
* @see @fn_gl{LinkProgram}, @fn_gl{GetProgram} with
* @def_gl{LINK_STATUS} and @def_gl{INFO_LOG_LENGTH},
* @fn_gl{GetProgramInfoLog}
* Links single shader. If possible, prefer to link multiple shaders
* at once using @ref link(std::initializer_list<std::reference_wrapper<AbstractShaderProgram>>)
* for improved performance, see its documentation for more
* information.
*/
bool link();
bool link() { return link({*this}); }
/**
* @brief Get uniform location
@ -963,9 +967,17 @@ template<UnsignedInt location, class T> class AbstractShaderProgram::Attribute {
* @brief Type
*
* Type used in shader code.
* @see @ref DataType
* @see @ref ScalarType, @ref DataType
*/
typedef T Type;
/**
* @brief Scalar type
*
* The underlying scalar type of the attribute.
* @see @ref Type, @ref DataType
*/
typedef typename Implementation::Attribute<T>::Type Type;
typedef typename Implementation::Attribute<T>::ScalarType ScalarType;
/**
* @brief Component count
@ -1257,7 +1269,7 @@ template<class> struct Attribute;
/* Base for float attributes */
struct FloatAttribute {
typedef Float Type;
typedef Float ScalarType;
enum class DataType: GLenum {
UnsignedByte = GL_UNSIGNED_BYTE,
@ -1300,7 +1312,7 @@ Debug MAGNUM_EXPORT operator<<(Debug debug, FloatAttribute::DataType value);
#ifndef MAGNUM_TARGET_GLES2
/* Base for int attributes */
struct IntAttribute {
typedef Int Type;
typedef Int ScalarType;
enum class DataType: GLenum {
UnsignedByte = GL_UNSIGNED_BYTE,
@ -1327,7 +1339,7 @@ Debug MAGNUM_EXPORT operator<<(Debug debug, IntAttribute::DataType value);
/* Base for unsigned int attributes */
struct UnsignedIntAttribute {
typedef UnsignedInt Type;
typedef UnsignedInt ScalarType;
typedef IntAttribute::DataType DataType;
#if !defined(CORRADE_GCC45_COMPATIBILITY) && !defined(CORRADE_MSVC2013_COMPATIBILITY)
@ -1349,7 +1361,7 @@ struct UnsignedIntAttribute {
#ifndef MAGNUM_TARGET_GLES
/* Base for double attributes */
struct DoubleAttribute {
typedef Double Type;
typedef Double ScalarType;
enum class DataType: GLenum {
Double = GL_DOUBLE
@ -1372,7 +1384,7 @@ Debug MAGNUM_EXPORT operator<<(Debug debug, DoubleAttribute::DataType value);
/* Floating-point four-component vector is absolutely special case */
template<> struct Attribute<Math::Vector<4, Float>> {
typedef Float Type;
typedef Float ScalarType;
enum class Components: GLint {
One = 1,

211
src/Magnum/AbstractTexture.cpp

@ -48,7 +48,6 @@ namespace Magnum {
#ifdef MAGNUM_BUILD_DEPRECATED
Int AbstractTexture::maxLayers() { return Shader::maxCombinedTextureImageUnits(); }
Int AbstractTexture::maxSupportedLayerCount() { return Shader::maxCombinedTextureImageUnits(); }
#endif
#ifndef MAGNUM_TARGET_GLES
@ -92,6 +91,72 @@ Int AbstractTexture::maxIntegerSamples() {
}
#endif
void AbstractTexture::unbind(const Int textureUnit) {
Implementation::TextureState* const textureState = Context::current()->state().texture;
/* If given texture unit is already unbound, nothing to do */
if(textureState->bindings[textureUnit].second == 0) return;
/* Unbind the texture, reset state tracker */
Context::current()->state().texture->unbindImplementation(textureUnit);
textureState->bindings[textureUnit] = {};
}
void AbstractTexture::unbindImplementationDefault(const GLint textureUnit) {
Implementation::TextureState* const textureState = Context::current()->state().texture;
/* Activate given texture unit if not already active, update state tracker */
if(textureState->currentTextureUnit != textureUnit)
glActiveTexture(GL_TEXTURE0 + (textureState->currentTextureUnit = textureUnit));
CORRADE_INTERNAL_ASSERT(textureState->bindings[textureUnit].first != 0);
glBindTexture(textureState->bindings[textureUnit].first, 0);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::unbindImplementationMulti(const GLint textureUnit) {
constexpr static GLuint zero = 0;
glBindTextures(textureUnit, 1, &zero);
}
void AbstractTexture::unbindImplementationDSA(const GLint textureUnit) {
Implementation::TextureState* const textureState = Context::current()->state().texture;
CORRADE_INTERNAL_ASSERT(textureState->bindings[textureUnit].first != 0);
glBindMultiTextureEXT(GL_TEXTURE0 + textureUnit, textureState->bindings[textureUnit].first, 0);
}
#endif
void AbstractTexture::bind(const Int firstTextureUnit, std::initializer_list<AbstractTexture*> textures) {
/* State tracker is updated in the implementations */
Context::current()->state().texture->bindMultiImplementation(firstTextureUnit, textures);
}
void AbstractTexture::bindImplementationFallback(const GLint firstTextureUnit, std::initializer_list<AbstractTexture*> textures) {
Int unit = firstTextureUnit;
for(AbstractTexture* const texture: textures) {
if(texture) texture->bind(unit);
else unbind(unit);
++unit;
}
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::bindImplementationMulti(const GLint firstTextureUnit, std::initializer_list<AbstractTexture*> textures) {
Implementation::TextureState* const textureState = Context::current()->state().texture;
/* Create array of IDs and also update bindings in state tracker */
Containers::Array<GLuint> ids{textures.size()};
Int i{};
for(const AbstractTexture* const texture: textures) {
textureState->bindings[firstTextureUnit + i].second = ids[i] = texture ? texture->id() : 0;
++i;
}
glBindTextures(firstTextureUnit, ids.size(), ids);
}
#endif
AbstractTexture::AbstractTexture(GLenum target): _target(target) {
glGenTextures(1, &_id);
}
@ -101,9 +166,9 @@ AbstractTexture::~AbstractTexture() {
if(!_id) return;
/* Remove all bindings */
std::vector<GLuint>& bindings = Context::current()->state().texture->bindings;
std::vector<std::pair<GLenum, GLuint>>& bindings = Context::current()->state().texture->bindings;
for(auto it = bindings.begin(); it != bindings.end(); ++it)
if(*it == _id) *it = 0;
if(it->second == _id) *it = {};
glDeleteTextures(1, &_id);
}
@ -117,32 +182,53 @@ AbstractTexture& AbstractTexture::setLabel(const std::string& label) {
return *this;
}
void AbstractTexture::bind(Int layer) {
void AbstractTexture::bind(Int textureUnit) {
Implementation::TextureState* const textureState = Context::current()->state().texture;
/* If already bound in given layer, nothing to do */
if(textureState->bindings[layer] == _id) return;
/* If already bound in given texture unit, nothing to do */
if(textureState->bindings[textureUnit].second == _id) return;
(this->*Context::current()->state().texture->bindImplementation)(layer);
/* Update state tracker, bind the texture to the unit */
textureState->bindings[textureUnit] = {_target, _id};
(this->*Context::current()->state().texture->bindImplementation)(textureUnit);
}
void AbstractTexture::bindImplementationDefault(GLint layer) {
void AbstractTexture::bindImplementationDefault(GLint textureUnit) {
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));
/* Activate given texture unit if not already active, update state tracker */
if(textureState->currentTextureUnit != textureUnit)
glActiveTexture(GL_TEXTURE0 + (textureState->currentTextureUnit = textureUnit));
/* Bind the texture to the layer */
glBindTexture(_target, (textureState->bindings[layer] = _id));
glBindTexture(_target, _id);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::bindImplementationDSA(GLint layer) {
glBindMultiTextureEXT(GL_TEXTURE0 + layer, _target, (Context::current()->state().texture->bindings[layer] = _id));
void AbstractTexture::bindImplementationMulti(GLint textureUnit) {
glBindTextures(textureUnit, 1, &_id);
}
void AbstractTexture::bindImplementationDSA(GLint textureUnit) {
glBindMultiTextureEXT(GL_TEXTURE0 + textureUnit, _target, _id);
}
#endif
#ifndef MAGNUM_TARGET_GLES2
void AbstractTexture::setBaseLevel(Int level) {
(this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_BASE_LEVEL, level);
}
#endif
void AbstractTexture::setMaxLevel(Int level) {
(this->*Context::current()->state().texture->parameteriImplementation)(
#ifndef MAGNUM_TARGET_GLES2
GL_TEXTURE_MAX_LEVEL
#else
GL_TEXTURE_MAX_LEVEL_APPLE
#endif
, level);
}
void AbstractTexture::setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap) {
(this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_MIN_FILTER, GLint(filter)|GLint(mipmap));
}
@ -159,6 +245,16 @@ void AbstractTexture::setBorderColor(const Color4& color) {
#endif
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::setBorderColor(const Vector4ui& color) {
(this->*Context::current()->state().texture->parameterIuivImplementation)(GL_TEXTURE_BORDER_COLOR, color.data());
}
void AbstractTexture::setBorderColor(const Vector4i& color) {
(this->*Context::current()->state().texture->parameterIivImplementation)(GL_TEXTURE_BORDER_COLOR, color.data());
}
#endif
void AbstractTexture::setMaxAnisotropy(const Float anisotropy) {
(this->*Context::current()->state().texture->setMaxAnisotropyImplementation)(anisotropy);
}
@ -183,21 +279,26 @@ void AbstractTexture::mipmapImplementationDSA() {
#endif
void AbstractTexture::bindInternal() {
/* Using glBindTextures() here is meaningless, because the non-DSA
functions need to have the texture bound in *currently active* unit,
so we would need to call glActiveTexture() afterwards anyway. */
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)
/* If the texture is already bound in current unit, nothing to do */
if(textureState->bindings[textureState->currentTextureUnit].second == _id)
return;
/* Set internal layer as active if not already */
CORRADE_INTERNAL_ASSERT(textureState->maxLayers > 1);
const GLint internalLayer = textureState->maxLayers-1;
if(textureState->currentLayer != internalLayer)
glActiveTexture(GL_TEXTURE0 + (textureState->currentLayer = internalLayer));
/* Set internal unit as active if not already, update state tracker */
CORRADE_INTERNAL_ASSERT(textureState->maxTextureUnits > 1);
const GLint internalTextureUnit = textureState->maxTextureUnits-1;
if(textureState->currentTextureUnit != internalTextureUnit)
glActiveTexture(GL_TEXTURE0 + (textureState->currentTextureUnit = internalTextureUnit));
/* Bind the texture to internal layer, if not already */
if(textureState->bindings[internalLayer] != _id)
glBindTexture(_target, (textureState->bindings[internalLayer] = _id));
/* Bind the texture to internal unit if not already, update state tracker */
if(textureState->bindings[internalTextureUnit].second == _id) return;
textureState->bindings[internalTextureUnit] = {_target, _id};
glBindTexture(_target, _id);
}
ColorFormat AbstractTexture::imageFormatForInternalFormat(const TextureFormat internalFormat) {
@ -602,6 +703,26 @@ void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLfloat
}
#endif
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLuint* values) {
bindInternal();
glTexParameterIuiv(_target, parameter, values);
}
void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLuint* values) {
glTextureParameterIuivEXT(_id, _target, parameter, values);
}
void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLint* values) {
bindInternal();
glTexParameterIiv(_target, parameter, values);
}
void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLint* values) {
glTextureParameterIivEXT(_id, _target, parameter, values);
}
#endif
void AbstractTexture::setMaxAnisotropyImplementationNoOp(GLfloat) {}
void AbstractTexture::setMaxAnisotropyImplementationExt(GLfloat anisotropy) {
@ -768,6 +889,36 @@ void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, Te
}
#endif
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::storageMultisampleImplementationFallback(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector2i& size, const GLboolean fixedSampleLocations) {
bindInternal();
glTexImage2DMultisample(target, samples, GLenum(internalFormat), size.x(), size.y(), fixedSampleLocations);
}
void AbstractTexture::storageMultisampleImplementationDefault(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector2i& size, const GLboolean fixedSampleLocations) {
bindInternal();
glTexStorage2DMultisample(target, samples, GLenum(internalFormat), size.x(), size.y(), fixedSampleLocations);
}
void AbstractTexture::storageMultisampleImplementationDSA(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector2i& size, const GLboolean fixedSampleLocations) {
glTextureStorage2DMultisampleEXT(_id, target, samples, GLenum(internalFormat), size.x(), size.y(), fixedSampleLocations);
}
void AbstractTexture::storageMultisampleImplementationFallback(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector3i& size, const GLboolean fixedSampleLocations) {
bindInternal();
glTexImage3DMultisample(target, samples, GLenum(internalFormat), size.x(), size.y(), size.z(), fixedSampleLocations);
}
void AbstractTexture::storageMultisampleImplementationDefault(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector3i& size, const GLboolean fixedSampleLocations) {
bindInternal();
glTexStorage3DMultisample(target, samples, GLenum(internalFormat), size.x(), size.y(), size.z(), fixedSampleLocations);
}
void AbstractTexture::storageMultisampleImplementationDSA(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector3i& size, const GLboolean fixedSampleLocations) {
glTextureStorage3DMultisampleEXT(_id, target, samples, GLenum(internalFormat), size.x(), size.y(), size.z(), fixedSampleLocations);
}
#endif
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::getImageImplementationDefault(const GLenum target, const GLint level, const ColorFormat format, const ColorType type, const std::size_t, GLvoid* const data) {
bindInternal();
@ -975,6 +1126,16 @@ void AbstractTexture::DataHelper<3>::setStorage(AbstractTexture& texture, const
(texture.*Context::current()->state().texture->storage3DImplementation)(target, levels, internalFormat, size);
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::DataHelper<2>::setStorageMultisample(AbstractTexture& texture, const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector2i& size, const GLboolean fixedSampleLocations) {
(texture.*Context::current()->state().texture->storage2DMultisampleImplementation)(target, samples, internalFormat, size, fixedSampleLocations);
}
void AbstractTexture::DataHelper<3>::setStorageMultisample(AbstractTexture& texture, const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector3i& size, const GLboolean fixedSampleLocations) {
(texture.*Context::current()->state().texture->storage3DMultisampleImplementation)(target, samples, internalFormat, size, fixedSampleLocations);
}
#endif
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::DataHelper<1>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference1D& image) {
Buffer::unbind(Buffer::Target::PixelUnpack);

145
src/Magnum/AbstractTexture.h

@ -49,20 +49,31 @@ Encapsulates one OpenGL texture object. See @ref Texture, @ref CubeMapTexture
and @ref CubeMapTextureArray documentation for more information and usage
examples.
@section AbstractTexture-webgl-restrictions WebGL restrictions
@ref MAGNUM_TARGET_WEBGL "WebGL" puts some restrictions on type of data
submitted to @ref Texture::setSubImage() "*Texture::setSubImage()", see its
documentation for details.
@section AbstractTexture-performance-optimization Performance optimizations and security
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 and
The engine tracks currently bound textures in all available texture units to
avoid unnecessary calls to @fn_gl{ActiveTexture} and @fn_gl{BindTexture}.
%Texture configuration functions use dedicated highest available texture unit
to not affect active bindings in user units. %Texture limits and
implementation-defined values (such as @ref maxColorSamples()) are cached, so
repeated queries don't result in repeated @fn_gl{Get} calls.
If extension @extension{EXT,direct_state_access} is available, @ref bind() uses
DSA function to avoid unnecessary calls to @fn_gl{ActiveTexture}. Also all
texture configuration and data updating functions use DSA functions to avoid
unnecessary calls to @fn_gl{ActiveTexture} and @fn_gl{BindTexture}. See
respective function documentation for more information.
If extension @extension{ARB,multi_bind} is available, @ref bind() uses
@fn_gl{BindTextures} to avoid unnecessary calls to @fn_gl{ActiveTexture}.
Otherwise, if extension @extension{EXT,direct_state_access} is available,
@ref bind() uses @fn_gl_extension{BindMultiTexture,EXT,direct_state_access}
function.
In addition, if extension @extension{EXT,direct_state_access} is available,
also all texture configuration and data updating functions use DSA functions
to avoid unnecessary calls to @fn_gl{ActiveTexture} and @fn_gl{BindTexture}.
See respective function documentation for more information.
If extension @extension{ARB,robustness} is available, image reading operations
(such as @ref Texture::image()) are protected from buffer overflow. However, if
@ -72,7 +83,7 @@ there isn't any function combining both features.
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. First configure the texture
dedicated units, not occupied by other textures. First configure the texture
and *then* set the data, so OpenGL can optimize them to match the settings. To
avoid redundant consistency checks and memory reallocations when updating
texture data, set texture storage at once using @ref Texture::setStorage() "setStorage()"
@ -85,7 +96,7 @@ OpenGL ES 3.0 or @es_extension{EXT,texture_storage} in OpenGL ES 2.0 is not
available, the feature is emulated with sequence of @ref Texture::setImage() "setImage()"
calls.
You can use functions @ref Texture::invalidateImage() and
You can use functions @ref Texture::invalidateImage() "invalidateImage()" and
@ref Texture::invalidateSubImage() "invalidateSubImage()" if you don't need
texture data anymore to avoid unnecessary memory operations performed by OpenGL
in order to preserve the data. If running on OpenGL ES or extension
@ -103,6 +114,10 @@ functions do nothing.
@todo `GL_NUM_COMPRESSED_TEXTURE_FORMATS` when compressed textures are implemented
@todo `GL_MAX_SAMPLE_MASK_WORDS` when @extension{ARB,texture_multisample} is done
@todo Query for immutable levels (@extension{ARB,ES3_compatibility})
@bug If using @extension{ARB,multi_bind} and the texture is bound right after
construction, the @fn_gl{BindTextures} call will fail with
Renderer::Error::InvalidOperation, because the texture doesn't yet have
associated target
*/
class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
friend struct Implementation::TextureState;
@ -117,15 +132,6 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
static CORRADE_DEPRECATED("use Shader::maxCombinedTextureImageUnits() instead") Int maxLayers();
#endif
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief Shader::maxCombinedTextureImageUnits()
* @deprecated Use @ref Magnum::Shader::maxCombinedTextureImageUnits() "Shader::maxCombinedTextureImageUnits()"
* instead.
*/
static CORRADE_DEPRECATED("use Shader::maxCombinedTextureImageUnits() instead") Int maxSupportedLayerCount();
#endif
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Max supported color sample count
@ -162,12 +168,32 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
#endif
/**
* @brief Destructor
* @brief Unbind any texture from given texture unit
*
* Deletes associated OpenGL texture.
* @see @fn_gl{DeleteTextures}
* If @extension{ARB,multi_bind} (part of OpenGL 4.4) or
* @extension{EXT,direct_state_access} is not available, the texture
* unit is made active before binding the texture.
* @note This function is meant to be used only internally from
* @ref AbstractShaderProgram subclasses. See its documentation
* for more information.
* @see @ref bind(), @ref Shader::maxCombinedTextureImageUnits(),
* @fn_gl{ActiveTexture}, @fn_gl{BindTexture}, @fn_gl{BindTextures}
* or @fn_gl_extension{BindMultiTexture,EXT,direct_state_access}
*/
~AbstractTexture();
static void unbind(Int textureUnit);
/**
* @brief Bind textures to given range of texture units
*
* Binds first texture in the list to @p firstTextureUnit, second to
* `firstTextureUnit + 1` etc. If any texture is `nullptr`, given
* texture unit is unbound. If @extension{ARB,multi_bind} (part of
* OpenGL 4.4) is not available, the feature is emulated with sequence
* of @ref bind(Int) / @ref unbind() calls.
* @see @fn_gl{BindTextures}, eventually @fn_gl{ActiveTexture},
* @fn_gl{BindTexture} or @fn_gl_extension{BindMultiTexture,EXT,direct_state_access}
*/
static void bind(Int firstTextureUnit, std::initializer_list<AbstractTexture*> textures);
/** @brief Copying is not allowed */
AbstractTexture(const AbstractTexture&) = delete;
@ -175,6 +201,14 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
/** @brief Move constructor */
AbstractTexture(AbstractTexture&& other) noexcept;
/**
* @brief Destructor
*
* Deletes associated OpenGL texture.
* @see @fn_gl{DeleteTextures}
*/
~AbstractTexture();
/** @brief Copying is not allowed */
AbstractTexture& operator=(const AbstractTexture&) = delete;
@ -211,19 +245,20 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
GLuint id() const { return _id; }
/**
* @brief Bind texture for rendering
* @brief Bind texture to given texture unit
*
* Sets current texture as active in given layer. Note that only one
* texture can be bound to given layer. If @extension{EXT,direct_state_access}
* is not available, the layer is made active before binding the
* texture.
* If @extension{ARB,multi_bind} (part of OpenGL 4.4) or
* @extension{EXT,direct_state_access} is not available, the texture
* unit is made active before binding the texture.
* @note This function is meant to be used only internally from
* @ref AbstractShaderProgram subclasses. See its documentation
* for more information.
* @see @ref maxLayers(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} or
* @fn_gl_extension{BindMultiTexture,EXT,direct_state_access}
* @see @ref bind(Int, std::initializer_list<AbstractTexture*>),
* @ref unbind(), @ref Shader::maxCombinedTextureImageUnits(),
* @fn_gl{ActiveTexture}, @fn_gl{BindTexture}, @fn_gl{BindTextures}
* or @fn_gl_extension{BindMultiTexture,EXT,direct_state_access}
*/
void bind(Int layer);
void bind(Int textureUnit);
#ifdef DOXYGEN_GENERATING_OUTPUT
private:
@ -234,12 +269,18 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
explicit AbstractTexture(GLenum target);
/* Unlike bind() this also sets the binding layer as active */
/* Unlike bind() this also sets the texture binding unit as active */
void MAGNUM_LOCAL bindInternal();
#ifndef MAGNUM_TARGET_GLES2
void setBaseLevel(Int level);
#endif
void setMaxLevel(Int level);
void setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap);
void setMagnificationFilter(Sampler::Filter filter);
void setBorderColor(const Color4& color);
void setBorderColor(const Vector4i& color);
void setBorderColor(const Vector4ui& color);
void setMaxAnisotropy(Float anisotropy);
void invalidateImage(Int level);
void generateMipmap();
@ -252,24 +293,36 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
GLenum _target;
private:
void MAGNUM_LOCAL bindImplementationDefault(GLint layer);
static void MAGNUM_LOCAL unbindImplementationDefault(GLint textureUnit);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL bindImplementationDSA(GLint layer);
static void MAGNUM_LOCAL unbindImplementationMulti(GLint textureUnit);
static void MAGNUM_LOCAL unbindImplementationDSA(GLint textureUnit);
#endif
void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLint value);
static void MAGNUM_LOCAL bindImplementationFallback(GLint firstTextureUnit, std::initializer_list<AbstractTexture*> textures);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLint value);
static void MAGNUM_LOCAL bindImplementationMulti(GLint firstTextureUnit, std::initializer_list<AbstractTexture*> textures);
#endif
void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLfloat value);
void MAGNUM_LOCAL bindImplementationDefault(GLint textureUnit);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLfloat value);
void MAGNUM_LOCAL bindImplementationMulti(GLint textureUnit);
void MAGNUM_LOCAL bindImplementationDSA(GLint textureUnit);
#endif
void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLint value);
void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLfloat value);
void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, const GLfloat* values);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, const GLuint* values);
void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, const GLint* values);
#endif
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLint value);
void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLfloat value);
void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, const GLfloat* values);
void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, const GLuint* values);
void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, const GLint* values);
#endif
void MAGNUM_LOCAL setMaxAnisotropyImplementationNoOp(GLfloat);
@ -303,6 +356,16 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject {
void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size);
#endif
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL storageMultisampleImplementationFallback(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector2i& size, GLboolean fixedsamplelocations);
void MAGNUM_LOCAL storageMultisampleImplementationDefault(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector2i& size, GLboolean fixedsamplelocations);
void MAGNUM_LOCAL storageMultisampleImplementationDSA(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector2i& size, GLboolean fixedsamplelocations);
void MAGNUM_LOCAL storageMultisampleImplementationFallback(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector3i& size, GLboolean fixedsamplelocations);
void MAGNUM_LOCAL storageMultisampleImplementationDefault(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector3i& size, GLboolean fixedsamplelocations);
void MAGNUM_LOCAL storageMultisampleImplementationDSA(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector3i& size, GLboolean fixedsamplelocations);
#endif
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL getImageImplementationDefault(GLenum target, GLint level, ColorFormat format, ColorType type, std::size_t dataSize, GLvoid* data);
void MAGNUM_LOCAL getImageImplementationDSA(GLenum target, GLint level, ColorFormat format, ColorType type, std::size_t dataSize, GLvoid* data);
@ -399,6 +462,8 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> {
static void setStorage(AbstractTexture& texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size);
static void setStorageMultisample(AbstractTexture& texture, GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector2i& size, GLboolean fixedSampleLocations);
static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, const ImageReference2D& image);
#ifndef MAGNUM_TARGET_GLES2
static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, BufferImage2D& image);
@ -434,6 +499,8 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> {
static void setStorage(AbstractTexture& texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size);
static void setStorageMultisample(AbstractTexture& texture, GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector3i& size, GLboolean fixedSampleLocations);
static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, const ImageReference3D& image);
#ifndef MAGNUM_TARGET_GLES2
static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, BufferImage3D& image);

1
src/Magnum/Audio/CMakeLists.txt

@ -46,6 +46,7 @@ set(MagnumAudio_HEADERS
visibility.h)
add_library(MagnumAudio ${SHARED_OR_STATIC} ${MagnumAudio_SOURCES})
set_target_properties(MagnumAudio PROPERTIES DEBUG_POSTFIX "-d")
target_link_libraries(MagnumAudio ${CORRADE_PLUGINMANAGER_LIBRARIES} ${OPENAL_LIBRARY})
install(TARGETS MagnumAudio

39
src/Magnum/Buffer.h

@ -166,6 +166,23 @@ for(std::size_t i: {7, 27, 56, 128}) {
CORRADE_INTERNAL_ASSERT_OUTPUT(buffer.unmap());
@endcode
@section Buffer-webgl-restrictions WebGL and NaCl restrictions
Buffers in @ref MAGNUM_TARGET_WEBGL "WebGL" and @ref CORRADE_TARGET_NACL "NaCl"
need to be bound only to one unique target, i.e., @ref Buffer bound to
@ref Buffer::Target::Array cannot be later rebound to
@ref Buffer::Target::ElementArray. However, %Magnum by default uses any
sufficient target when binding the buffer internally (e.g. for setting data).
To avoid GL errors, set target hint to desired target, either in constructor or
using @ref Buffer::setTargetHint():
@code
Buffer vertices{Buffer::Target::Array};
Buffer indices{Buffer::Target::ElementArray};
@endcode
To ease up the development, @ref Mesh checks proper target hint when adding
vertex and index buffers in both WebGL and NaCl.
@section Buffer-performance-optimization Performance optimizations
The engine tracks currently bound buffers to avoid unnecessary calls to
@ -661,17 +678,6 @@ class MAGNUM_EXPORT Buffer: public AbstractObject {
*/
Buffer& setData(Containers::ArrayReference<const void> data, BufferUsage usage);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief setData(Containers::ArrayReference<const void>, BufferUsage)
* @deprecated Use @ref Magnum::Buffer::setData(Containers::ArrayReference<const void>, BufferUsage) "setData(Containers::ArrayReference<const void>, BufferUsage)"
* instead.
*/
CORRADE_DEPRECATED("use setData(Containers::ArrayReference, BufferUsage) instead") Buffer& setData(GLsizeiptr size, const GLvoid* data, BufferUsage usage) {
return setData({data, std::size_t(size)}, usage);
}
#endif
/** @overload */
template<class T> Buffer& setData(const std::vector<T>& data, BufferUsage usage) {
setData({data.data(), data.size()}, usage);
@ -698,17 +704,6 @@ class MAGNUM_EXPORT Buffer: public AbstractObject {
*/
Buffer& setSubData(GLintptr offset, Containers::ArrayReference<const void> data);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief setSubData(GLintptr, Containers::ArrayReference<const void>)
* @deprecated Use @ref Magnum::Buffer::setSubData(GLintptr, Containers::ArrayReference<const void>) "setSubData(GLintptr, Containers::ArrayReference<const void>)"
* instead.
*/
CORRADE_DEPRECATED("use setSubData(GLintptr, Containers::ArrayReference) instead") Buffer& setSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data) {
return setSubData(offset, {data, std::size_t(size)});
}
#endif
/** @overload */
template<class T> Buffer& setSubData(GLintptr offset, const std::vector<T>& data) {
setSubData(offset, {data.data(), data.size()});

9
src/Magnum/CMakeLists.txt

@ -130,9 +130,7 @@ set(Magnum_HEADERS
# Deprecated headers
if(BUILD_DEPRECATED)
set(Magnum_HEADERS ${Magnum_HEADERS}
DebugMarker.h
ImageFormat.h
Swizzle.h)
DebugMarker.h)
endif()
# Desktop-only headers and libraries
@ -162,6 +160,7 @@ add_library(MagnumMathObjects OBJECT ${MagnumMath_SRCS})
add_library(Magnum ${SHARED_OR_STATIC}
${Magnum_SRCS}
$<TARGET_OBJECTS:MagnumMathObjects>)
set_target_properties(Magnum PROPERTIES DEBUG_POSTFIX "-d")
# TODO: fix when CMake sets target_EXPORTS for OBJECT targets as well
if(NOT BUILD_STATIC OR BUILD_STATIC_PIC)
@ -237,7 +236,9 @@ if(BUILD_TESTS)
# Libraries with graceful assert for testing
add_library(MagnumMathTestLib ${SHARED_OR_STATIC}
$<TARGET_OBJECTS:MagnumMathObjects>)
set_target_properties(MagnumMathTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
set_target_properties(MagnumMathTestLib PROPERTIES
COMPILE_FLAGS "-DCORRADE_GRACEFUL_ASSERT"
DEBUG_POSTFIX "-d")
target_link_libraries(MagnumMathTestLib ${CORRADE_UTILITY_LIBRARY})
# On Windows we need to install first and then run the tests to avoid "DLL

110
src/Magnum/Context.cpp

@ -61,6 +61,7 @@ const std::vector<Extension>& Extension::extensions(Version version) {
_extension(GL,EXT,texture_filter_anisotropic),
_extension(GL,EXT,texture_mirror_clamp),
_extension(GL,EXT,direct_state_access),
_extension(GL,EXT,shader_integer_mix),
_extension(GL,EXT,debug_label),
_extension(GL,EXT,debug_marker),
_extension(GL,GREMEDY,string_marker)};
@ -213,6 +214,7 @@ const std::vector<Extension>& Extension::extensions(Version version) {
_extension(GL,ANGLE,framebuffer_multisample),
_extension(GL,ANGLE,depth_texture),
_extension(GL,APPLE,framebuffer_multisample),
_extension(GL,APPLE,texture_max_level),
_extension(GL,ARM,rgba8),
_extension(GL,EXT,texture_type_2_10_10_10_REV),
_extension(GL,EXT,discard_framebuffer),
@ -283,7 +285,7 @@ Context::Context() {
everything possible. */
if(ogl_LoadFunctions() == ogl_LOAD_FAILED) {
Error() << "ExtensionWrangler: cannot initialize glLoadGen";
std::exit(1);
std::exit(64);
}
#endif
@ -313,7 +315,7 @@ Context::Context() {
const std::string version = versionString();
#ifndef MAGNUM_TARGET_GLES
if(version.compare(0, 4, "2.1 ") == 0)
#elif defined(CORRADE_TARGET_EMSCRIPTEN)
#elif defined(MAGNUM_TARGET_WEBGL)
if(version.find("WebGL 1") != std::string::npos)
#else
if(version.find("OpenGL ES 2.0") != std::string::npos)
@ -327,7 +329,7 @@ Context::Context() {
#endif
} else {
Error() << "Context: unsupported version string:" << version;
std::exit(1);
std::exit(65);
}
}
#endif
@ -346,17 +348,17 @@ Context::Context() {
#ifndef MAGNUM_TARGET_GLES
if(!isVersionSupported(Version::GL210))
#elif defined(MAGNUM_TARGET_GLES2)
if(!isVersionSupported(Version::GLES200))
if(_version != Version::GLES200)
#else
if(!isVersionSupported(Version::GLES300))
if(_version != Version::GLES300)
#endif
{
#ifndef MAGNUM_TARGET_GLES
Error() << "Context: unsupported OpenGL version" << Int(_version);
Error() << "Context: unsupported OpenGL version" << Magnum::version(_version);
#else
Error() << "Context: unsupported OpenGL ES version" << Int(_version);
Error() << "Context: unsupported OpenGL ES version" << Magnum::version(_version);
#endif
std::exit(1);
std::exit(66);
}
/* Context flags are supported since GL 3.0 */
@ -411,46 +413,15 @@ Context::Context() {
#endif
}
/* Check for presence of extensions in future versions */
#ifndef MAGNUM_TARGET_GLES2
GLint extensionCount = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
#ifndef MAGNUM_TARGET_GLES3
if(extensionCount || isVersionSupported(Version::GL300))
#endif
{
_supportedExtensions.reserve(extensionCount);
for(GLint i = 0; i != extensionCount; ++i) {
const std::string extension(reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i)));
auto found = futureExtensions.find(extension);
if(found != futureExtensions.end()) {
_supportedExtensions.push_back(found->second);
extensionStatus.set(found->second._index);
}
/* Check for presence of future and vendor extensions */
const std::vector<std::string> extensions = extensionStrings();
for(const std::string& extension: extensions) {
const auto found = futureExtensions.find(extension);
if(found != futureExtensions.end()) {
_supportedExtensions.push_back(found->second);
extensionStatus.set(found->second._index);
}
}
#ifndef MAGNUM_TARGET_GLES3
else
#endif
#endif
#ifndef MAGNUM_TARGET_GLES3
/* OpenGL 2.1 / OpenGL ES 2.0 doesn't have glGetStringi() */
{
/* Don't crash when glGetString() returns nullptr */
const char* e = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if(e) {
std::vector<std::string> extensions = Utility::String::split(e, ' ');
for(auto it = extensions.begin(); it != extensions.end(); ++it) {
auto found = futureExtensions.find(*it);
if(found != futureExtensions.end()) {
_supportedExtensions.push_back(found->second);
extensionStatus.set(found->second._index);
}
}
}
}
#endif
/* Reset minimal required version to Version::None for whole array */
for(auto it = _extensionRequiredVersion.begin(); it != _extensionRequiredVersion.end(); ++it)
@ -504,6 +475,38 @@ std::vector<std::string> Context::shadingLanguageVersionStrings() const {
#endif
}
std::vector<std::string> Context::extensionStrings() const {
std::vector<std::string> extensions;
#ifndef MAGNUM_TARGET_GLES2
GLint extensionCount = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
#ifndef MAGNUM_TARGET_GLES3
if(extensionCount || isVersionSupported(Version::GL300))
#endif
{
extensions.reserve(extensionCount);
for(GLint i = 0; i != extensionCount; ++i)
extensions.push_back(reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i)));
}
#ifndef MAGNUM_TARGET_GLES3
else
#endif
#endif
#ifndef MAGNUM_TARGET_GLES3
/* OpenGL 2.1 / OpenGL ES 2.0 doesn't have glGetStringi() */
{
/* Don't crash when glGetString() returns nullptr (i.e. don't trust the
old implementations) */
const char* e = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if(e) extensions = Utility::String::splitWithoutEmptyParts(e, ' ');
}
#endif
return extensions;
}
Version Context::supportedVersion(std::initializer_list<Version> versions) const {
for(auto it = versions.begin(); it != versions.end(); ++it)
if(isVersionSupported(*it)) return *it;
@ -515,4 +518,19 @@ Version Context::supportedVersion(std::initializer_list<Version> versions) const
#endif
}
#ifndef DOXYGEN_GENERATING_OUTPUT
Debug operator<<(Debug debug, const Context::Flag value) {
switch(value) {
#define _c(value) case Context::Flag::value: return debug << "Context::Flag::" #value;
_c(Debug)
#ifndef MAGNUM_TARGET_GLES
_c(RobustAccess)
#endif
#undef _c
}
return debug << "Context::Flag::(invalid)";
}
#endif
}

28
src/Magnum/Context.h

@ -107,7 +107,7 @@ class MAGNUM_EXPORT Context {
/**
* @brief Context flag
*
* @see @ref Flags, @ref flags()
* @see @ref Flags, @ref flags(), @ref Platform::Sdl2Application::Configuration::setFlags() "Platform::*Application::Configuration::setFlags()"
*/
enum class Flag: GLint {
/**
@ -123,14 +123,22 @@ class MAGNUM_EXPORT Context {
#ifndef MAGNUM_TARGET_GLES
/**
* Context with robust buffer access
* Context with robust access
* @requires_extension %Extension @extension{ARB,robustness}
* @requires_es_extension %Extension @es_extension{EXT,robustness}
* @todo In ES available under glGetIntegerv(CONTEXT_ROBUST_ACCESS_EXT),
* how to make it compatible?
*/
RobustAccess = GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB,
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief Context::Flag::RobustAccess
* @deprecated Use @ref Magnum::Context::Flag::RobustAccess "Context::Flag::RobustAccess" instead.
*/
Robustness = GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB
#endif
#endif
};
/**
@ -237,6 +245,19 @@ class MAGNUM_EXPORT Context {
*/
std::vector<std::string> shadingLanguageVersionStrings() const;
/**
* @brief Extension strings
*
* The result is *not* cached, repeated queries will result in repeated
* OpenGL calls. Note that this function returns list of all extensions
* reported by the driver (even those not supported by %Magnum), see
* @ref supportedExtensions(), @ref Extension::extensions() or
* @ref isExtensionSupported() for alternatives.
* @see @fn_gl{Get} with @def_gl{NUM_EXTENSIONS}, @fn_gl{GetString}
* with @def_gl{EXTENSIONS}
*/
std::vector<std::string> extensionStrings() const;
/** @brief Context flags */
Flags flags() const { return _flags; }
@ -386,6 +407,9 @@ class MAGNUM_EXPORT Context {
Implementation::State* _state;
};
/** @debugoperator{Magnum::Context} */
MAGNUM_EXPORT Debug operator<<(Debug debug, Context::Flag value);
/** @hideinitializer
@brief Assert that given OpenGL version is supported
@param version Version

30
src/Magnum/CubeMapTexture.h

@ -108,6 +108,20 @@ class CubeMapTexture: public AbstractTexture {
}
#endif
#ifndef MAGNUM_TARGET_GLES2
/** @copydoc Texture::setBaseLevel() */
CubeMapTexture& setBaseLevel(Int level) {
AbstractTexture::setBaseLevel(level);
return *this;
}
#endif
/** @copydoc Texture::setMaxLevel() */
CubeMapTexture& setMaxLevel(Int level) {
AbstractTexture::setMaxLevel(level);
return *this;
}
/** @copydoc Texture::setMinificationFilter() */
CubeMapTexture& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) {
AbstractTexture::setMinificationFilter(filter, mipmap);
@ -126,12 +140,26 @@ class CubeMapTexture: public AbstractTexture {
return *this;
}
/** @copydoc Texture::setBorderColor() */
/** @copydoc Texture::setBorderColor(const Color4&) */
CubeMapTexture& setBorderColor(const Color4& color) {
AbstractTexture::setBorderColor(color);
return *this;
}
#ifndef MAGNUM_TARGET_GLES
/** @copydoc Texture::setBorderColor(const Vector4ui&) */
CubeMapTexture& setBorderColor(const Vector4ui& color) {
AbstractTexture::setBorderColor(color);
return *this;
}
/** @copydoc Texture::setBorderColor(const Vector4i&) */
CubeMapTexture& setBorderColor(const Vector4i& color) {
AbstractTexture::setBorderColor(color);
return *this;
}
#endif
/** @copydoc Texture::setMaxAnisotropy() */
CubeMapTexture& setMaxAnisotropy(Float anisotropy) {
AbstractTexture::setMaxAnisotropy(anisotropy);

28
src/Magnum/CubeMapTextureArray.h

@ -99,6 +99,18 @@ class CubeMapTextureArray: public AbstractTexture {
}
#endif
/** @copydoc Texture::setBaseLevel() */
CubeMapTextureArray& setBaseLevel(Int level) {
AbstractTexture::setBaseLevel(level);
return *this;
}
/** @copydoc Texture::setMaxLevel() */
CubeMapTextureArray& setMaxLevel(Int level) {
AbstractTexture::setMaxLevel(level);
return *this;
}
/** @copydoc Texture::setMinificationFilter() */
CubeMapTextureArray& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) {
AbstractTexture::setMinificationFilter(filter, mipmap);
@ -123,6 +135,18 @@ class CubeMapTextureArray: public AbstractTexture {
return *this;
}
/** @copydoc Texture::setBorderColor(const Vector4ui&) */
CubeMapTextureArray& setBorderColor(const Vector4ui& color) {
AbstractTexture::setBorderColor(color);
return *this;
}
/** @copydoc Texture::setBorderColor(const Vector4i&) */
CubeMapTextureArray& setBorderColor(const Vector4i& color) {
AbstractTexture::setBorderColor(color);
return *this;
}
/** @copydoc Texture::setMaxAnisotropy() */
CubeMapTextureArray& setMaxAnisotropy(Float anisotropy) {
AbstractTexture::setMaxAnisotropy(anisotropy);
@ -150,14 +174,12 @@ class CubeMapTextureArray: public AbstractTexture {
return *this;
}
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Read given mip level of texture to image
* @param level Mip level
* @param image %Image where to put the data
*
* See @ref Texture::image(Int, Image&) for more information.
* @requires_gl %Texture image queries are not available in OpenGL ES.
*/
void image(Int level, Image3D& image) {
AbstractTexture::image<3>(GL_TEXTURE_CUBE_MAP_ARRAY, level, image);
@ -171,12 +193,10 @@ class CubeMapTextureArray: public AbstractTexture {
*
* See @ref Texture::image(Int, BufferImage&, BufferUsage) for more
* information.
* @requires_gl %Texture image queries are not available in OpenGL ES.
*/
void image(Int level, BufferImage3D& image, BufferUsage usage) {
AbstractTexture::image<3>(GL_TEXTURE_CUBE_MAP_ARRAY, level, image, usage);
}
#endif
/**
* @brief Set image data

1
src/Magnum/DebugTools/CMakeLists.txt

@ -51,6 +51,7 @@ set(MagnumDebugTools_HEADERS
visibility.h)
add_library(MagnumDebugTools ${SHARED_OR_STATIC} ${MagnumDebugTools_SRCS})
set_target_properties(MagnumDebugTools PROPERTIES DEBUG_POSTFIX "-d")
if(BUILD_STATIC_PIC)
# TODO: CMake 2.8.9 has this as POSITION_INDEPENDENT_CODE property
set_target_properties(MagnumDebugTools PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")

7
src/Magnum/Extensions.h

@ -182,6 +182,7 @@ namespace GL {
_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
_extension(GL,EXT,shader_integer_mix, GL300, None) // #437
_extension(GL,EXT,debug_label, GL210, None) // #439
_extension(GL,EXT,debug_marker, GL210, None) // #440
} namespace GREMEDY {
@ -211,6 +212,9 @@ namespace GL {
_extension(GL,APPLE,framebuffer_multisample, GLES200, GLES300) // #78
#endif
_extension(GL,APPLE,texture_format_BGRA8888, GLES200, None) // #79
#ifdef MAGNUM_TARGET_GLES2
_extension(GL,APPLE,texture_max_level, GLES200, None) // #80
#endif
} namespace ARM {
#ifdef MAGNUM_TARGET_GLES2
_extension(GL,ARM,rgba8, GLES200, GLES300) // #82
@ -245,6 +249,9 @@ namespace GL {
_extension(GL,EXT,map_buffer_range, GLES200, GLES300) // #121
#endif
_extension(GL,EXT,disjoint_timer_query, GLES200, None) // #150
#ifndef MAGNUM_TARGET_GLES2
_extension(GL,EXT,shader_integer_mix, GLES300, None) // #161
#endif
} namespace KHR {
_extension(GL,KHR,debug, GLES200, None) // #118
} namespace NV {

4
src/Magnum/Image.h

@ -138,8 +138,8 @@ template<UnsignedInt dimensions> class Image: public AbstractImage {
/**
* @brief Release data storage
*
* Returns the data pointer and resets internal state to default.
* Deleting the returned array is user responsibility.
* Releases the ownership of the data pointer and resets internal state
* to default. Deleting the returned array is then user responsibility.
* @see @ref setData()
*/
unsigned char* release();

59
src/Magnum/Implementation/TextureState.cpp

@ -36,20 +36,45 @@
namespace Magnum { namespace Implementation {
TextureState::TextureState(Context& context, std::vector<std::string>& extensions): maxLayers(0), maxMaxAnisotropy(0.0f), currentLayer(0)
TextureState::TextureState(Context& context, std::vector<std::string>& extensions): maxTextureUnits(0), maxMaxAnisotropy(0.0f), currentTextureUnit(0)
#ifndef MAGNUM_TARGET_GLES
, maxColorSamples(0), maxDepthSamples(0), maxIntegerSamples(0), bufferOffsetAlignment(0)
#endif
{
/* Bind implementation */
#ifndef MAGNUM_TARGET_GLES
if(context.isExtensionSupported<Extensions::GL::ARB::multi_bind>()) {
extensions.push_back(Extensions::GL::ARB::multi_bind::string());
unbindImplementation = &AbstractTexture::unbindImplementationMulti;
bindMultiImplementation = &AbstractTexture::bindImplementationMulti;
bindImplementation = &AbstractTexture::bindImplementationMulti;
} else if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
/* Extension name added below */
unbindImplementation = &AbstractTexture::unbindImplementationDSA;
bindMultiImplementation = &AbstractTexture::bindImplementationFallback;
bindImplementation = &AbstractTexture::bindImplementationDSA;
} else
#endif
{
unbindImplementation = &AbstractTexture::unbindImplementationDefault;
bindMultiImplementation = &AbstractTexture::bindImplementationFallback;
bindImplementation = &AbstractTexture::bindImplementationDefault;
}
/* DSA/non-DSA implementation */
#ifndef MAGNUM_TARGET_GLES
if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
extensions.push_back(Extensions::GL::EXT::direct_state_access::string());
bindImplementation = &AbstractTexture::bindImplementationDSA;
parameteriImplementation = &AbstractTexture::parameterImplementationDSA;
parameterfImplementation = &AbstractTexture::parameterImplementationDSA;
parameterfvImplementation = &AbstractTexture::parameterImplementationDSA;
parameterIuivImplementation = &AbstractTexture::parameterImplementationDSA;
parameterIivImplementation = &AbstractTexture::parameterImplementationDSA;
getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDSA;
mipmapImplementation = &AbstractTexture::mipmapImplementationDSA;
getImageImplementation = &AbstractTexture::getImageImplementationDSA;
@ -65,11 +90,12 @@ TextureState::TextureState(Context& context, std::vector<std::string>& extension
} else
#endif
{
bindImplementation = &AbstractTexture::bindImplementationDefault;
parameteriImplementation = &AbstractTexture::parameterImplementationDefault;
parameterfImplementation = &AbstractTexture::parameterImplementationDefault;
parameterfvImplementation = &AbstractTexture::parameterImplementationDefault;
#ifndef MAGNUM_TARGET_GLES
parameterIuivImplementation = &AbstractTexture::parameterImplementationDefault;
parameterIivImplementation = &AbstractTexture::parameterImplementationDefault;
getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDefault;
#endif
mipmapImplementation = &AbstractTexture::mipmapImplementationDefault;
@ -153,6 +179,25 @@ TextureState::TextureState(Context& context, std::vector<std::string>& extension
}
#endif
#ifndef MAGNUM_TARGET_GLES
/* Storage implementation for multisample textures. The fallback doesn't
have DSA alternative, so it must be handled specially. */
if(context.isExtensionSupported<Extensions::GL::ARB::texture_storage_multisample>()) {
extensions.push_back(Extensions::GL::ARB::texture_storage_multisample::string());
if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
storage2DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationDSA;
storage3DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationDSA;
} else {
storage2DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationDefault;
storage3DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationDefault;
}
} else {
storage2DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationFallback;
storage3DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationFallback;
}
#endif
/* Anisotropic filter implementation */
if(context.isExtensionSupported<Extensions::GL::EXT::texture_filter_anisotropic>()) {
extensions.push_back(Extensions::GL::EXT::texture_filter_anisotropic::string());
@ -160,10 +205,10 @@ TextureState::TextureState(Context& context, std::vector<std::string>& extension
setMaxAnisotropyImplementation = &AbstractTexture::setMaxAnisotropyImplementationExt;
} else setMaxAnisotropyImplementation = &AbstractTexture::setMaxAnisotropyImplementationNoOp;
/* Resize bindings array to hold all possible layers */
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxLayers);
CORRADE_INTERNAL_ASSERT(maxLayers > 0);
bindings.resize(maxLayers);
/* Resize bindings array to hold all possible texture units */
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
CORRADE_INTERNAL_ASSERT(maxTextureUnits > 0);
bindings.resize(maxTextureUnits);
}
TextureState::~TextureState() = default;

12
src/Magnum/Implementation/TextureState.h

@ -55,10 +55,14 @@ struct TextureState {
explicit TextureState(Context& context, std::vector<std::string>& extensions);
~TextureState();
void(*unbindImplementation)(GLint);
void(*bindMultiImplementation)(GLint, std::initializer_list<AbstractTexture*>);
void(AbstractTexture::*bindImplementation)(GLint);
void(AbstractTexture::*parameteriImplementation)(GLenum, GLint);
void(AbstractTexture::*parameterfImplementation)(GLenum, GLfloat);
void(AbstractTexture::*parameterfvImplementation)(GLenum, const GLfloat*);
void(AbstractTexture::*parameterIuivImplementation)(GLenum, const GLuint*);
void(AbstractTexture::*parameterIivImplementation)(GLenum, const GLint*);
void(AbstractTexture::*setMaxAnisotropyImplementation)(GLfloat);
void(AbstractTexture::*getLevelParameterivImplementation)(GLenum, GLint, GLenum, GLint*);
void(AbstractTexture::*mipmapImplementation)();
@ -68,6 +72,8 @@ struct TextureState {
void(AbstractTexture::*storage2DImplementation)(GLenum, GLsizei, TextureFormat, const Vector2i&);
void(AbstractTexture::*storage3DImplementation)(GLenum, GLsizei, TextureFormat, const Vector3i&);
#ifndef MAGNUM_TARGET_GLES
void(AbstractTexture::*storage2DMultisampleImplementation)(GLenum, GLsizei, TextureFormat, const Vector2i&, GLboolean);
void(AbstractTexture::*storage3DMultisampleImplementation)(GLenum, GLsizei, TextureFormat, const Vector3i&, GLboolean);
void(AbstractTexture::*getImageImplementation)(GLenum, GLint, ColorFormat, ColorType, std::size_t, GLvoid*);
void(AbstractTexture::*image1DImplementation)(GLenum, GLint, TextureFormat, const Math::Vector<1, GLsizei>&, ColorFormat, ColorType, const GLvoid*);
#endif
@ -86,9 +92,9 @@ struct TextureState {
void(BufferTexture::*setBufferRangeImplementation)(BufferTextureFormat, Buffer&, GLintptr, GLsizeiptr);
#endif
GLint maxLayers;
GLint maxTextureUnits;
GLfloat maxMaxAnisotropy;
GLint currentLayer;
GLint currentTextureUnit;
#ifndef MAGNUM_TARGET_GLES
GLint maxColorSamples,
maxDepthSamples,
@ -96,7 +102,7 @@ struct TextureState {
bufferOffsetAlignment;
#endif
std::vector<GLuint> bindings;
std::vector<std::pair<GLenum, GLuint>> bindings;
};
}}

5
src/Magnum/Implementation/setupDriverWorkarounds.cpp

@ -35,8 +35,8 @@ void Context::setupDriverWorkarounds() {
#ifndef MAGNUM_TARGET_GLES
/* This extension causes crash in GLSL compiler on AMD linux drivers 13.251 */
const std::string renderer = rendererString();
if(renderer.find("Advanced Micro Devices") != std::string::npos)
const std::string vendor = vendorString();
if(vendor.find("ATI Technologies Inc.") != std::string::npos)
_setRequiredVersion(GL::ARB::explicit_uniform_location, None);
#endif
@ -79,6 +79,7 @@ void Context::setupDriverWorkarounds() {
_setRequiredVersion(GL::NV::draw_buffers, None);
_setRequiredVersion(GL::NV::fbo_color_attachments, None); // ??
_setRequiredVersion(GL::NV::read_buffer, None);
_setRequiredVersion(GL::NV::framebuffer_blit, None);
_setRequiredVersion(GL::NV::framebuffer_multisample, None);
_setRequiredVersion(GL::OES::texture_3D, None);
_setRequiredVersion(GL::OES::vertex_array_object, None);

54
src/Magnum/Magnum.h

@ -100,7 +100,7 @@ Defined if the engine is built for OpenGL ES 3.0 or OpenGL ES 2.0.
#undef MAGNUM_TARGET_GLES
/**
@brief OpenGL ES 2.0 target.
@brief OpenGL ES 2.0 target
Defined if the engine is built for OpenGL ES 2.0. Implies also
@ref MAGNUM_TARGET_GLES.
@ -110,7 +110,7 @@ Defined if the engine is built for OpenGL ES 2.0. Implies also
#undef MAGNUM_TARGET_GLES2
/**
@brief OpenGL ES 3.0 target.
@brief OpenGL ES 3.0 target
Defined if the engine is built for OpenGL ES 3.0. Implies also
@ref MAGNUM_TARGET_GLES.
@ -124,10 +124,24 @@ Defined if the engine is built for OpenGL ES 3.0. Implies also
Defined if the engine is built for OpenGL ES 3.0 or OpenGL ES 2.0 emulated
within standard desktop OpenGL. Implies also @ref MAGNUM_TARGET_GLES.
@see @ref MAGNUM_TARGET_GLES2, @ref building
@see @ref MAGNUM_TARGET_GLES2, @ref MAGNUM_TARGET_GLES3, @ref building
*/
#define MAGNUM_TARGET_DESKTOP_GLES
#undef MAGNUM_TARGET_DESKTOP_GLES
/**
@brief WebGL target
Defined if the engine is built for WebGL (using Emscripten). WebGL is nearly
equivalent to OpenGL ES 2.0, thus in most cases you don't need to treat it
differently, but there are some
[specific restrictions and features](http://www.khronos.org/registry/webgl/specs/latest/1.0/#6)
which you might want to be aware of. Implies also @ref MAGNUM_TARGET_GLES and
@ref MAGNUM_TARGET_GLES2.
@see @ref CORRADE_TARGET_EMSCRIPTEN, @ref building
*/
#define MAGNUM_TARGET_WEBGL
#undef MAGNUM_TARGET_WEBGL
#endif
/** @{ @name Basic type definitions
@ -153,11 +167,21 @@ typedef std::uint32_t UnsignedInt;
/** @brief Signed int (32bit) */
typedef std::int32_t Int;
/** @brief Unsigned long (64bit) */
#ifndef MAGNUM_TARGET_WEBGL
/**
@brief Unsigned long (64bit)
@attention 64-bit integers are not available in @ref MAGNUM_TARGET_WEBGL "WebGL".
*/
typedef std::uint64_t UnsignedLong;
/** @brief Signed long (64bit) */
/**
@brief Signed long (64bit)
@attention 64-bit integers are not available in @ref MAGNUM_TARGET_WEBGL "WebGL".
*/
typedef std::int64_t Long;
#endif
/** @brief Float (32bit) */
typedef float Float;
@ -210,14 +234,6 @@ typedef Math::Matrix2x2<Float> Matrix2x2;
typedef Math::Matrix<2, Float> Matrix2x2;
#endif
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@copybrief Matrix2x2
@deprecated Use @ref Magnum::Matrix2x2 "Matrix2x2" instead.
*/
typedef Math::Matrix<2, Float> Matrix2;
#endif
/**
@brief 3x3 float matrix
@ -387,14 +403,6 @@ typedef Math::Matrix2x2<Double> Matrix2x2d;
typedef Math::Matrix<2, Double> Matrix2x2d;
#endif
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@copybrief Matrix2x2d
@deprecated Use @ref Magnum::Matrix2x2d "Matrix2x2d" instead.
*/
typedef CORRADE_DEPRECATED("use Matrix2x2d instead") Math::Matrix<2, Double> Matrix2d;
#endif
/**
@brief 3x3 double matrix
@ -560,9 +568,6 @@ typedef BasicColor4<UnsignedByte> Color4ub;
#ifndef CORRADE_GCC45_COMPATIBILITY
enum class ColorFormat: GLenum;
enum class ColorType: GLenum;
/** @todo Remove this when dropping backward compatibility */
typedef ColorFormat ImageFormat;
typedef ColorType ColorType;
#endif
class Context;
@ -596,6 +601,7 @@ class Mesh;
class MeshView;
#ifndef MAGNUM_TARGET_GLES
/* MultisampleTextureSampleLocations enum used only in the function */
template<UnsignedInt> class MultisampleTexture;
typedef MultisampleTexture<2> MultisampleTexture2D;
typedef MultisampleTexture<3> MultisampleTexture2DArray;

14
src/Magnum/Math/Angle.h

@ -98,7 +98,7 @@ The requirement of explicit conversions from and to unitless types helps to
reduce unit-based errors. Consider following example with implicit conversions
allowed:
@code
Float std::sin(Float angle);
namespace std { float sin(float angle); }
Float sine(Rad<Float> angle);
Float a = 60.0f; // degrees
@ -110,13 +110,13 @@ std::sin(b); // silent error, std::sin() expected radians
These silent errors are easily avoided by requiring explicit conversions:
@code
//sine(angleInDegrees); // compilation error
sine(Deg<Float>(angleInDegrees)); // explicitly specifying unit
//sine(a); // compilation error
sine(Deg<Float>{a}); // explicitly specifying unit
//std::sin(angleInDegrees); // compilation error
std::sin(Float(Rad<Float>(angleInDegrees)); // required explicit conversion hints
// to user that this case needs special
// attention (i.e., conversion to radians)
//std::sin(b); // compilation error
std::sin(Float(Rad<Float>(b)); // required explicit conversion hints to user
// that this case needs special attention
// (i.e., conversion to radians)
@endcode
@see Magnum::Deg, Magnum::Degd

4
src/Magnum/Math/Complex.h

@ -343,8 +343,8 @@ template<class T> class Complex {
* @see isNormalized()
*/
T length() const {
/** @todo Remove when NaCl's newlib has this fixed */
#ifndef CORRADE_TARGET_NACL_NEWLIB
/** @todo Remove when newlib has this fixed */
#if !defined(CORRADE_TARGET_NACL_NEWLIB) && !defined(CORRADE_TARGET_ANDROID)
return std::hypot(_real, _imaginary);
#else
return std::sqrt(dot());

9
src/Magnum/Math/Functions.h

@ -252,7 +252,8 @@ template<std::size_t size, class T> Vector<size, T> floor(const Vector<size, T>&
template<class T> inline T round(const T& a);
#else
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type round(T a) {
#ifndef CORRADE_TARGET_NACL_NEWLIB
/** @todo Remove when newlib has this fixed */
#if !defined(CORRADE_TARGET_NACL_NEWLIB) && !defined(CORRADE_TARGET_ANDROID)
return std::round(a);
#else
return (a > T(0)) ? std::floor(a + T(0.5)) : std::ceil(a - T(0.5));
@ -261,7 +262,7 @@ template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T
template<std::size_t size, class T> Vector<size, T> round(const Vector<size, T>& a) {
Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i) {
#ifndef CORRADE_TARGET_NACL_NEWLIB
#if !defined(CORRADE_TARGET_NACL_NEWLIB) && !defined(CORRADE_TARGET_ANDROID)
out[i] = std::round(a[i]);
#else
out[i] = round(a[i]);
@ -397,8 +398,8 @@ Computes and returns @f$ ab + c @f$.
template<class T> inline T fma(const T& a, const T& b, const T& c);
#else
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type fma(T a, T b, T c) {
/** @todo Remove when NaCl's newlib has this fixed */
#ifndef CORRADE_TARGET_NACL_NEWLIB
/** @todo Remove when newlib has this fixed */
#if !defined(CORRADE_TARGET_NACL_NEWLIB) && !defined(CORRADE_TARGET_ANDROID)
return std::fma(a, b, c);
#else
return a*b + c;

2
src/Magnum/Math/TypeTraits.h

@ -145,6 +145,7 @@ template<> struct TypeTraits<Int>: Implementation::TypeTraitsIntegral<Int> {
typedef Double FloatingPointType;
#endif
};
#ifndef MAGNUM_TARGET_WEBGL
template<> struct TypeTraits<UnsignedLong>: Implementation::TypeTraitsIntegral<UnsignedLong> {
#ifndef MAGNUM_TARGET_GLES
typedef long double FloatingPointType;
@ -155,6 +156,7 @@ template<> struct TypeTraits<Long>: Implementation::TypeTraitsIntegral<Long> {
typedef long double FloatingPointType;
#endif
};
#endif
/* Floating-point scalar types */
namespace Implementation {

3
src/Magnum/Math/Vector.h

@ -408,7 +408,8 @@ template<std::size_t size, class T> class Vector {
* @brief Multiply vector component-wise
*
* @see operator*(T) const, operator*=(const Vector<size, T>&),
* operator*(const Vector<size, Integral>&, const Vector<size, FloatingPoint>&)
* operator*(const Vector<size, Integral>&, const Vector<size, FloatingPoint>&),
* @ref product()
*/
Vector<size, T> operator*(const Vector<size, T>& other) const {
return Vector<size, T>(*this) *= other;

6
src/Magnum/Mesh.cpp

@ -148,7 +148,7 @@ Mesh& Mesh::setLabel(const std::string& label) {
}
Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end) {
#if defined(CORRADE_TARGET_NACL) || defined(CORRADE_TARGET_EMSCRIPTEN)
#if defined(CORRADE_TARGET_NACL) || defined(MAGNUM_TARGET_WEBGL)
CORRADE_ASSERT(buffer.targetHint() == Buffer::Target::ElementArray,
"Mesh::setIndexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::ElementArray << "but got" << buffer.targetHint(), *this);
#endif
@ -270,7 +270,7 @@ void Mesh::destroyImplementationVAO() {
}
void Mesh::attributePointerImplementationDefault(const Attribute& attribute) {
#if defined(CORRADE_TARGET_NACL) || defined(CORRADE_TARGET_EMSCRIPTEN)
#if defined(CORRADE_TARGET_NACL) || defined(MAGNUM_TARGET_WEBGL)
CORRADE_ASSERT(attribute.buffer->targetHint() == Buffer::Target::Array,
"Mesh::addVertexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::Array << "but got" << attribute.buffer->targetHint(), );
#endif
@ -279,7 +279,7 @@ void Mesh::attributePointerImplementationDefault(const Attribute& attribute) {
}
void Mesh::attributePointerImplementationVAO(const Attribute& attribute) {
#if defined(CORRADE_TARGET_NACL) || defined(CORRADE_TARGET_EMSCRIPTEN)
#if defined(CORRADE_TARGET_NACL) || defined(MAGNUM_TARGET_WEBGL)
CORRADE_ASSERT(attribute.buffer->targetHint() == Buffer::Target::Array,
"Mesh::addVertexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::Array << "but got" << attribute.buffer->targetHint(), );
#endif

32
src/Magnum/Mesh.h

@ -291,6 +291,11 @@ respective shader, bind required textures (see
@ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation"
for more infromation) and call @ref Mesh::draw().
@section Mesh-webgl-restrictions WebGL restrictions
@ref MAGNUM_TARGET_WEBGL "WebGL" puts some restrictions on vertex buffer
layout, see @ref addVertexBuffer() for details.
@section Mesh-performance-optimization Performance optimizations
If @extension{APPLE,vertex_array_object} (part of OpenGL 3.0), OpenGL ES 3.0 or
@ -553,6 +558,12 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
* mesh, you must ensure it will exist for whole lifetime of the
* mesh and delete it afterwards.
*
* @attention In @ref MAGNUM_TARGET_WEBGL "WebGL" the data must be
* properly aligned (e.g. all float data must start at addresses
* divisible by four). Also the maximum stride of attribute data
* must be at most 255 bytes. This is not required anywhere else,
* but doing so may have performance benefits.
*
* @see @ref maxVertexAttributes(), @ref setPrimitive(),
* @ref setVertexCount(), @fn_gl{BindVertexArray},
* @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer},
@ -635,7 +646,8 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief draw(AbstractShaderProgram&)
* @deprecated Use @ref Magnum::Mesh::draw(AbstractShaderProgram&) instead.
* @deprecated Use @ref Magnum::Mesh::draw(AbstractShaderProgram&) "draw(AbstractShaderProgram&)"
* instead.
*/
void draw() {
#ifndef MAGNUM_TARGET_GLES2
@ -682,28 +694,28 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
#endif
/* Computing stride of interleaved vertex attributes */
template<UnsignedInt location, class T, class ...U> inline static GLsizei strideOfInterleaved(const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
template<UnsignedInt location, class T, class ...U> static GLsizei strideOfInterleaved(const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
return attribute.vectorSize()*AbstractShaderProgram::Attribute<location, T>::VectorCount + strideOfInterleaved(attributes...);
}
template<class ...T> inline static GLsizei strideOfInterleaved(GLintptr gap, const T&... attributes) {
template<class ...T> static GLsizei strideOfInterleaved(GLintptr gap, const T&... attributes) {
return gap + strideOfInterleaved(attributes...);
}
inline static GLsizei strideOfInterleaved() { return 0; }
static GLsizei strideOfInterleaved() { return 0; }
/* Adding interleaved vertex attributes */
template<UnsignedInt location, class T, class ...U> inline void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
template<UnsignedInt location, class T, class ...U> void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
addVertexAttribute(buffer, attribute, offset, stride);
/* Add size of this attribute to offset for next attribute */
addVertexBufferInternal(buffer, offset+attribute.vectorSize()*AbstractShaderProgram::Attribute<location, T>::VectorCount, stride, attributes...);
}
template<class ...T> inline void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, GLintptr gap, const T&... attributes) {
template<class ...T> void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, GLintptr gap, const T&... attributes) {
/* Add the gap to offset for next attribute */
addVertexBufferInternal(buffer, offset+gap, stride, attributes...);
}
inline void addVertexBufferInternal(Buffer&, GLsizei, GLintptr) {}
void addVertexBufferInternal(Buffer&, GLsizei, GLintptr) {}
template<UnsignedInt location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_same<typename Implementation::Attribute<T>::Type, Float>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
template<UnsignedInt location, class T> void addVertexAttribute(typename std::enable_if<std::is_same<typename Implementation::Attribute<T>::ScalarType, Float>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
for(UnsignedInt i = 0; i != AbstractShaderProgram::Attribute<location, T>::VectorCount; ++i)
attributePointerInternal(Attribute{
&buffer,
@ -717,7 +729,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_integral<typename Implementation::Attribute<T>::Type>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
template<UnsignedInt location, class T> void addVertexAttribute(typename std::enable_if<std::is_integral<typename Implementation::Attribute<T>::ScalarType>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
attributePointerInternal(IntegerAttribute{
&buffer,
location,
@ -729,7 +741,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
}
#ifndef MAGNUM_TARGET_GLES
template<UnsignedInt location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_same<typename Implementation::Attribute<T>::Type, Double>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
template<UnsignedInt location, class T> void addVertexAttribute(typename std::enable_if<std::is_same<typename Implementation::Attribute<T>::ScalarType, Double>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
for(UnsignedInt i = 0; i != AbstractShaderProgram::Attribute<location, T>::VectorCount; ++i)
attributePointerInternal(LongAttribute{
&buffer,

7
src/Magnum/MeshTools/CMakeLists.txt

@ -25,6 +25,7 @@
# Files shared between main library and unit test library
set(MagnumMeshTools_SRCS
Compile.cpp
CompressIndices.cpp
FullScreenTriangle.cpp
Tipsify.cpp)
@ -37,6 +38,7 @@ set(MagnumMeshTools_GracefulAssert_SRCS
set(MagnumMeshTools_HEADERS
CombineIndexedArrays.h
Compile.h
CompressIndices.h
Duplicate.h
FlipNormals.h
@ -64,6 +66,7 @@ endif()
add_library(MagnumMeshTools ${SHARED_OR_STATIC}
$<TARGET_OBJECTS:MagnumMeshToolsObjects>
${MagnumMeshTools_GracefulAssert_SRCS})
set_target_properties(MagnumMeshTools PROPERTIES DEBUG_POSTFIX "-d")
if(BUILD_STATIC_PIC)
# TODO: CMake 2.8.9 has this as POSITION_INDEPENDENT_CODE property
set_target_properties(MagnumMeshTools PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
@ -81,7 +84,9 @@ if(BUILD_TESTS)
add_library(MagnumMeshToolsTestLib ${SHARED_OR_STATIC}
$<TARGET_OBJECTS:MagnumMeshToolsObjects>
${MagnumMeshTools_GracefulAssert_SRCS})
set_target_properties(MagnumMeshToolsTestLib PROPERTIES COMPILE_FLAGS "-DCORRADE_GRACEFUL_ASSERT -DMagnumMeshTools_EXPORTS")
set_target_properties(MagnumMeshToolsTestLib PROPERTIES
COMPILE_FLAGS "-DCORRADE_GRACEFUL_ASSERT -DMagnumMeshTools_EXPORTS"
DEBUG_POSTFIX "-d")
target_link_libraries(MagnumMeshToolsTestLib Magnum)
# On Windows we need to install first and then run the tests to avoid "DLL

17
src/Magnum/MeshTools/CombineIndexedArrays.cpp

@ -56,26 +56,24 @@ std::pair<std::vector<UnsignedInt>, std::vector<UnsignedInt>> interleaveAndCombi
/* Combine them */
std::vector<UnsignedInt> combinedIndices;
std::tie(combinedIndices, interleavedArrays) = combineIndexArrays(interleavedArrays, stride);
std::tie(combinedIndices, interleavedArrays) = MeshTools::combineIndexArrays(interleavedArrays, stride);
return {combinedIndices, interleavedArrays};
}
}
std::vector<UnsignedInt> combineIndexArrays(const std::initializer_list<std::reference_wrapper<std::vector<UnsignedInt>>> arrays) {
std::vector<UnsignedInt> combineIndexArrays(const std::reference_wrapper<std::vector<UnsignedInt>>* const begin, const std::reference_wrapper<std::vector<UnsignedInt>>* const end) {
/* Interleave and combine the arrays */
std::vector<UnsignedInt> combinedIndices;
std::vector<UnsignedInt> interleavedCombinedArrays;
std::tie(combinedIndices, interleavedCombinedArrays) = Implementation::interleaveAndCombineIndexArrays(
/* This will bite me hard once. */
reinterpret_cast<const std::reference_wrapper<const std::vector<UnsignedInt>>*>(arrays.begin()),
reinterpret_cast<const std::reference_wrapper<const std::vector<UnsignedInt>>*>(arrays.end()));
reinterpret_cast<const std::reference_wrapper<const std::vector<UnsignedInt>>*>(begin),
reinterpret_cast<const std::reference_wrapper<const std::vector<UnsignedInt>>*>(end));
/* Update the original indices */
const UnsignedInt stride = arrays.size();
const UnsignedInt stride = end - begin;
const UnsignedInt outputSize = interleavedCombinedArrays.size()/stride;
for(UnsignedInt offset = 0; offset != stride; ++offset) {
auto& array = (arrays.begin()+offset)->get();
auto& array = (begin+offset)->get();
CORRADE_INTERNAL_ASSERT(array.size() >= outputSize);
array.resize(outputSize);
for(UnsignedInt i = 0; i != outputSize; ++i)
@ -85,6 +83,8 @@ std::vector<UnsignedInt> combineIndexArrays(const std::initializer_list<std::ref
return combinedIndices;
}
}
namespace {
class IndexHash {
@ -116,6 +116,7 @@ class IndexEqual {
}
std::pair<std::vector<UnsignedInt>, std::vector<UnsignedInt>> combineIndexArrays(const std::vector<UnsignedInt>& interleavedArrays, const UnsignedInt stride) {
CORRADE_ASSERT(stride != 0, "MeshTools::combineIndexArrays(): stride can't be zero", {});
CORRADE_ASSERT(interleavedArrays.size() % stride == 0, "MeshTools::combineIndexArrays(): array size is not divisible by stride", {});
/* Hash map with index combinations, containing just indices into

22
src/Magnum/MeshTools/CombineIndexedArrays.h

@ -32,6 +32,7 @@
#include <functional>
#include <tuple>
#include <vector>
#include <Corrade/Utility/Assert.h>
#include "Magnum/Types.h"
#include "Magnum/MeshTools/visibility.h"
@ -42,6 +43,10 @@
namespace Magnum { namespace MeshTools {
namespace Implementation {
MAGNUM_MESHTOOLS_EXPORT std::vector<UnsignedInt> combineIndexArrays(const std::reference_wrapper<std::vector<UnsignedInt>>* begin, const std::reference_wrapper<std::vector<UnsignedInt>>* end);
}
/**
@brief Combine index arrays
@ -81,7 +86,14 @@ This function calls @ref combineIndexArrays(const std::vector<UnsignedInt>&, Uns
internally. See also @ref combineIndexedArrays() which does the vertex data
reordering automatically.
*/
MAGNUM_MESHTOOLS_EXPORT std::vector<UnsignedInt> combineIndexArrays(std::initializer_list<std::reference_wrapper<std::vector<UnsignedInt>>> arrays);
inline std::vector<UnsignedInt> combineIndexArrays(const std::vector<std::reference_wrapper<std::vector<UnsignedInt>>>& arrays) {
return Implementation::combineIndexArrays(&arrays[0], &arrays[0] + arrays.size());
}
/** @overload */
inline std::vector<UnsignedInt> combineIndexArrays(std::initializer_list<std::reference_wrapper<std::vector<UnsignedInt>>> arrays) {
return Implementation::combineIndexArrays(arrays.begin(), arrays.end());
}
/**
@brief Combine index arrays
@ -111,10 +123,14 @@ namespace Implementation {
MAGNUM_MESHTOOLS_EXPORT std::pair<std::vector<UnsignedInt>, std::vector<UnsignedInt>> interleaveAndCombineIndexArrays(const std::reference_wrapper<const std::vector<UnsignedInt>>* begin, const std::reference_wrapper<const std::vector<UnsignedInt>>* end);
template<class T> void writeCombinedArray(const UnsignedInt stride, const UnsignedInt offset, const std::vector<UnsignedInt>& interleavedCombinedIndexArrays, std::vector<T>& array) {
/* Can't use duplicate() here because we aren't accessing the index data sequentially */
std::vector<T> output;
output.reserve(interleavedCombinedIndexArrays.size()/stride);
for(std::size_t i = 0, max = interleavedCombinedIndexArrays.size()/stride; i != max; ++i)
output.push_back(array[interleavedCombinedIndexArrays[offset + i*stride]]);
for(std::size_t i = 0, max = interleavedCombinedIndexArrays.size()/stride; i != max; ++i) {
const UnsignedInt index = interleavedCombinedIndexArrays[offset + i*stride];
CORRADE_ASSERT(index < array.size(), "MeshTools::combineIndexedArrays(): index out of range", );
output.push_back(array[index]);
}
std::swap(output, array);
}

157
src/Magnum/MeshTools/Compile.cpp

@ -0,0 +1,157 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014
Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is 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 Software.
THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "Compile.h"
#include "Magnum/Math/Vector3.h"
#include "Magnum/MeshTools/CompressIndices.h"
#include "Magnum/MeshTools/Interleave.h"
#include "Magnum/Trade/MeshData2D.h"
#include "Magnum/Trade/MeshData3D.h"
/* This header is included only privately and doesn't introduce any linker
dependency, thus it's completely safe */
#include "Magnum/Shaders/Generic.h"
namespace Magnum { namespace MeshTools {
std::tuple<Mesh, std::unique_ptr<Buffer>, std::unique_ptr<Buffer>> compile(const Trade::MeshData2D& meshData, const BufferUsage usage) {
Mesh mesh;
mesh.setPrimitive(meshData.primitive());
/* Decide about stride and offsets */
UnsignedInt stride = sizeof(Shaders::Generic2D::Position::Type);
const UnsignedInt normalOffset = sizeof(Shaders::Generic2D::Position::Type);
if(meshData.hasTextureCoords2D())
stride += sizeof(Shaders::Generic2D::TextureCoordinates::Type);
/* Create vertex buffer */
std::unique_ptr<Buffer> vertexBuffer{new Buffer{Buffer::Target::Array}};
/* Interleave positions */
std::size_t vertexCount;
Containers::Array<char> data;
std::tie(vertexCount, std::ignore, data) = MeshTools::interleave(
meshData.positions(0),
stride - sizeof(Shaders::Generic2D::Position::Type));
mesh.addVertexBuffer(*vertexBuffer, 0,
Shaders::Generic2D::Position(),
stride - sizeof(Shaders::Generic2D::Position::Type));
/* Add also texture coordinates, if present */
if(meshData.hasTextureCoords2D()) {
MeshTools::interleaveInto(data,
normalOffset,
meshData.textureCoords2D(0),
stride - normalOffset - sizeof(Shaders::Generic2D::TextureCoordinates::Type));
mesh.addVertexBuffer(*vertexBuffer, 0,
normalOffset,
Shaders::Generic2D::TextureCoordinates(),
stride - normalOffset - sizeof(Shaders::Generic2D::TextureCoordinates::Type));
}
/* Fill vertex buffer with interleaved data and finalize mesh
configuration */
vertexBuffer->setData(data, BufferUsage::StaticDraw);
mesh.setVertexCount(vertexCount);
/* Fill index buffer */
std::unique_ptr<Buffer> indexBuffer;
if(meshData.isIndexed()) {
indexBuffer.reset(new Buffer{Buffer::Target::ElementArray});
MeshTools::compressIndices(mesh, *indexBuffer, usage, meshData.indices());
}
return std::make_tuple(std::move(mesh), std::move(vertexBuffer), std::move(indexBuffer));
}
std::tuple<Mesh, std::unique_ptr<Buffer>, std::unique_ptr<Buffer>> compile(const Trade::MeshData3D& meshData, const BufferUsage usage) {
Mesh mesh;
mesh.setPrimitive(meshData.primitive());
/* Decide about stride and offsets */
UnsignedInt stride = sizeof(Shaders::Generic3D::Position::Type);
const UnsignedInt normalOffset = sizeof(Shaders::Generic3D::Position::Type);
UnsignedInt textureCoordsOffset = sizeof(Shaders::Generic3D::Position::Type);
if(meshData.hasNormals()) {
stride += sizeof(Shaders::Generic3D::Normal::Type);
textureCoordsOffset += sizeof(Shaders::Generic3D::Normal::Type);
}
if(meshData.hasTextureCoords2D())
stride += sizeof(Shaders::Generic3D::TextureCoordinates::Type);
/* Create vertex buffer */
std::unique_ptr<Buffer> vertexBuffer{new Buffer{Buffer::Target::Array}};
/* Interleave positions */
std::size_t vertexCount;
Containers::Array<char> data;
std::tie(vertexCount, std::ignore, data) = MeshTools::interleave(
meshData.positions(0),
stride - sizeof(Shaders::Generic3D::Position::Type));
mesh.addVertexBuffer(*vertexBuffer, 0,
Shaders::Generic3D::Position(),
stride - sizeof(Shaders::Generic3D::Position::Type));
/* Add also normals, if present */
if(meshData.hasNormals()) {
MeshTools::interleaveInto(data,
normalOffset,
meshData.normals(0),
stride - normalOffset - sizeof(Shaders::Generic3D::Normal::Type));
mesh.addVertexBuffer(*vertexBuffer, 0,
normalOffset,
Shaders::Generic3D::Normal(),
stride - normalOffset - sizeof(Shaders::Generic3D::Normal::Type));
}
/* Add also texture coordinates, if present */
if(meshData.hasTextureCoords2D()) {
MeshTools::interleaveInto(data,
textureCoordsOffset,
meshData.textureCoords2D(0),
stride - textureCoordsOffset - sizeof(Shaders::Generic3D::TextureCoordinates::Type));
mesh.addVertexBuffer(*vertexBuffer, 0,
textureCoordsOffset,
Shaders::Generic3D::TextureCoordinates(),
stride - textureCoordsOffset - sizeof(Shaders::Generic3D::TextureCoordinates::Type));
}
/* Fill vertex buffer with interleaved data and finalize mesh
configuration */
vertexBuffer->setData(data, BufferUsage::StaticDraw);
mesh.setVertexCount(vertexCount);
/* Fill index buffer */
std::unique_ptr<Buffer> indexBuffer;
if(meshData.isIndexed()) {
indexBuffer.reset(new Buffer{Buffer::Target::ElementArray});
MeshTools::compressIndices(mesh, *indexBuffer, usage, meshData.indices());
}
return std::make_tuple(std::move(mesh), std::move(vertexBuffer), std::move(indexBuffer));
}
}}

81
src/Magnum/MeshTools/Compile.h

@ -0,0 +1,81 @@
#ifndef Magnum_MeshTools_Compile_h
#define Magnum_MeshTools_Compile_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014
Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is 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 Software.
THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/** @file
* @brief Function @ref Magnum::MeshTools::compile()
*/
#include <tuple>
#include <memory>
#include "Magnum/Magnum.h"
#include "Magnum/Trade/Trade.h"
#include "Magnum/MeshTools/visibility.h"
namespace Magnum { namespace MeshTools {
/**
@brief Compile 2D mesh data
Configures mesh for @ref Shaders::Generic2D shader with vertex buffer and
possibly also index buffer, if the mesh is indexed. Positions are bound to
@ref Shaders::Generic2D::Position attribute. If the mesh contains texture
coordinates, they are bound to @ref Shaders::Generic2D::TextureCoordinates
attribute. No data compression or index optimization (except for index buffer
packing) is done. The @p usage parameter is used for both vertex and index
buffer.
The second returned buffer may be `nullptr` if the mesh is not indexed.
This is just a convenience function for creating generic meshes, you might want
to use @ref interleave() and @ref compressIndices() functions instead for
greater flexibility.
*/
MAGNUM_MESHTOOLS_EXPORT std::tuple<Mesh, std::unique_ptr<Buffer>, std::unique_ptr<Buffer>> compile(const Trade::MeshData2D& meshData, BufferUsage usage);
/**
@brief Compile 3D mesh data
Configures mesh for @ref Shaders::Generic3D shader with vertex buffer and
possibly also index buffer, if the mesh is indexed. Positions are bound to
@ref Shaders::Generic3D::Position attribute. If the mesh contains normals, they
are bound to @ref Shaders::Generic3D::Normal attribute, texture coordinates are
bound to @ref Shaders::Generic2D::TextureCoordinates attribute. No data
compression or index optimization (except for index buffer packing) is done.
The @p usage parameter is used for both vertex and index buffer.
The second returned buffer may be `nullptr` if the mesh is not indexed.
This is just a convenience function for creating generic meshes, you might want
to use @ref interleave() and @ref compressIndices() functions instead for
greater flexibility.
*/
MAGNUM_MESHTOOLS_EXPORT std::tuple<Mesh, std::unique_ptr<Buffer>, std::unique_ptr<Buffer>> compile(const Trade::MeshData3D& meshData, BufferUsage usage);
}}
#endif

2
src/Magnum/MeshTools/CompressIndices.h

@ -73,7 +73,7 @@ function writes the output to given buffer and calls @ref Mesh::setIndexCount()
and @ref Mesh::setIndexBuffer(), thus you don't need to do anything else for
mesh index configuration.
@see @ref MeshTools::interleave()
@see @ref MeshTools::interleave(), @ref MeshTools::compile()
*/
void MAGNUM_MESHTOOLS_EXPORT compressIndices(Mesh& mesh, Buffer& buffer, BufferUsage usage, const std::vector<UnsignedInt>& indices);

5
src/Magnum/MeshTools/Duplicate.h

@ -30,6 +30,7 @@
*/
#include <vector>
#include <Corrade/Utility/Assert.h>
#include "Magnum/Types.h"
@ -45,8 +46,10 @@ index array `{1, 1, 0, 3, 2, 2}` will be converted to `{b, b, a, d, c, c}`.
template<class T> std::vector<T> duplicate(const std::vector<UnsignedInt>& indices, const std::vector<T>& data) {
std::vector<T> out;
out.reserve(indices.size());
for(auto it = indices.begin(); it != indices.end(); ++it)
for(auto it = indices.begin(); it != indices.end(); ++it) {
CORRADE_ASSERT(*it < data.size(), "MeshTools::duplicate(): index out of range", out);
out.push_back(data[*it]);
}
return out;
}

206
src/Magnum/MeshTools/Interleave.h

@ -26,7 +26,7 @@
*/
/** @file
* @brief Function @ref Magnum::MeshTools::interleave()
* @brief Function @ref Magnum::MeshTools::interleave(), @ref Magnum::MeshTools::interleaveInto()
*/
#include <cstring>
@ -41,93 +41,52 @@ namespace Magnum { namespace MeshTools {
namespace Implementation {
class Interleave {
public:
Interleave(): _attributeCount(0), _stride(0) {}
template<class ...T> std::tuple<std::size_t, std::size_t, Containers::Array<char>> operator()(const T&... attributes) {
/* Compute buffer size and stride */
_attributeCount = attributeCount(attributes...);
Containers::Array<char> data;
if(_attributeCount && _attributeCount != ~std::size_t(0)) {
_stride = stride(attributes...);
/* Create output buffer */
data = Containers::Array<char>(_attributeCount*_stride);
/* Save the data */
write(data.begin(), attributes...);
}
return std::make_tuple(_attributeCount, _stride, std::move(data));
}
template<class ...T> void operator()(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T&... attributes) {
Containers::Array<char> data;
std::tie(std::ignore, std::ignore, data) = operator()(attributes...);
mesh.setVertexCount(_attributeCount);
buffer.setData(data, usage);
}
/* Specialization for only one attribute array */
template<class T> typename std::enable_if<!std::is_convertible<T, std::size_t>::value, void>::type operator()(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T& attribute) {
mesh.setVertexCount(attribute.size());
buffer.setData(attribute, usage);
}
template<class T, class ...U> static typename std::enable_if<!std::is_convertible<T, std::size_t>::value, std::size_t>::type attributeCount(const T& first, const U&... next) {
CORRADE_ASSERT(sizeof...(next) == 0 || attributeCount(next...) == first.size() || attributeCount(next...) == ~std::size_t(0), "MeshTools::interleave(): attribute arrays don't have the same length, expected" << first.size() << "but got" << attributeCount(next...), 0);
return first.size();
}
template<class... T> static std::size_t attributeCount(std::size_t, const T&... next) {
return attributeCount(next...);
}
template<class ...T> static std::size_t attributeCount(std::size_t) {
return ~std::size_t(0);
}
template<class T, class ...U> static typename std::enable_if<!std::is_convertible<T, std::size_t>::value, std::size_t>::type stride(const T&, const U&... next) {
return sizeof(typename T::value_type) + stride(next...);
}
template<class... T> static std::size_t stride(std::size_t gap, const T&... next) {
return gap + stride(next...);
}
private:
template<class T, class ...U> void write(char* startingOffset, const T& first, const U&... next) {
write(startingOffset+writeOne(startingOffset, first), next...);
}
/* Copy data to the buffer */
template<class T> typename std::enable_if<!std::is_convertible<T, std::size_t>::value, std::size_t>::type writeOne(char* startingOffset, const T& attributeList) {
auto it = attributeList.begin();
for(std::size_t i = 0; i != _attributeCount; ++i, ++it)
std::memcpy(startingOffset+i*_stride, reinterpret_cast<const char*>(&*it), sizeof(typename T::value_type));
/* Attribute count, skipping gaps. If the attributes are just gaps, returns
~std::size_t{0}. It must be in the structure to have proper overload
resolution (the functions would otherwise need to be de-inlined to break
cyclic dependencies) */
struct AttributeCount {
template<class T, class ...U> typename std::enable_if<!std::is_convertible<T, std::size_t>::value, std::size_t>::type operator()(const T& first, const U&... next) const {
CORRADE_ASSERT(sizeof...(next) == 0 || AttributeCount{}(next...) == first.size() || AttributeCount{}(next...) == ~std::size_t(0), "MeshTools::interleave(): attribute arrays don't have the same length, expected" << first.size() << "but got" << AttributeCount{}(next...), 0);
return first.size();
}
template<class T, class... U> std::size_t operator()(std::size_t, const T& first, const U&... next) const {
return AttributeCount{}(first, next...);
}
constexpr std::size_t operator()(std::size_t) const { return ~std::size_t(0); }
constexpr std::size_t operator()() const { return 0; }
};
return sizeof(typename T::value_type);
}
/* Stride, taking gaps into account. It must be in the structure, same reason
as above */
struct Stride {
template<class T, class ...U> typename std::enable_if<!std::is_convertible<T, std::size_t>::value, std::size_t>::type operator()(const T&, const U&... next) const {
return sizeof(typename T::value_type) + Stride{}(next...);
}
template<class... T> std::size_t operator()(std::size_t gap, const T&... next) const {
return gap + Stride{}(next...);
}
constexpr std::size_t operator()() const { return 0; }
};
/* Fill gap with zeros */
std::size_t writeOne(char* startingOffset, std::size_t gap) {
for(std::size_t i = 0; i != _attributeCount; ++i)
std::memset(startingOffset+i*_stride, 0, gap);
/* Copy data to the buffer */
template<class T> typename std::enable_if<!std::is_convertible<T, std::size_t>::value, std::size_t>::type writeOneInterleaved(std::size_t stride, char* startingOffset, const T& attributeList) {
auto it = attributeList.begin();
for(std::size_t i = 0; i != attributeList.size(); ++i, ++it)
std::memcpy(startingOffset + i*stride, reinterpret_cast<const char*>(&*it), sizeof(typename T::value_type));
return gap;
}
return sizeof(typename T::value_type);
}
/* Terminator functions for recursive calls */
static std::size_t attributeCount() { return 0; }
static std::size_t stride() { return 0; }
void write(char*) {}
/* Skip gap */
inline constexpr std::size_t writeOneInterleaved(std::size_t, char*, std::size_t gap) { return gap; }
std::size_t _attributeCount;
std::size_t _stride;
};
/* Write interleaved data */
inline void writeInterleaved(std::size_t, char*) {}
template<class T, class ...U> void writeInterleaved(std::size_t stride, char* startingOffset, const T& first, const U&... next) {
writeInterleaved(stride, startingOffset + writeOneInterleaved(stride, startingOffset, first), next...);
}
}
@ -155,15 +114,15 @@ It's often desirable to align data for one vertex on 32bit boundaries. To
achieve that, you can specify gaps between the attributes:
@code
std::vector<Vector4> positions;
std::vector<GLushort> weights;
std::vector<BasicColor3<GLubyte>> vertexColors;
std::vector<UnsignedShort> weights;
std::vector<Color3ub> vertexColors;
std::size_t attributeCount;
std::size_t stride;
Containers::Array<char> data;
std::tie(attributeCount, stride, data) = MeshTools::interleave(positions, weights, 2, textureCoordinates, 1);
@endcode
This way vertex stride is 24 bytes, without gaps it would be 21 bytes, causing
possible performance loss.
All gap bytes are set zero. This way vertex stride is 24 bytes, without gaps it
would be 21 bytes, causing possible performance loss.
@attention The function expects that all arrays have the same size.
@ -173,15 +132,53 @@ possible performance loss.
will be `std::vector` or `std::array`.
See also @ref interleave(Mesh&, Buffer&, BufferUsage, const T&...),
which writes the interleaved array directly into buffer of given mesh.
which writes the interleaved array directly into buffer of given mesh or
@ref interleaveInto() which writes the data into existing buffer instead of
creating new one.
*/
/* enable_if to avoid clash with overloaded function below */
template<class T, class ...U> inline typename std::enable_if<!std::is_same<T, Mesh>::value, std::tuple<std::size_t, std::size_t, Containers::Array<char>>>::type interleave(const T& first, const U&... next) {
return Implementation::Interleave()(first, next...);
template<class T, class ...U> typename std::enable_if<!std::is_same<T, Mesh>::value, std::tuple<std::size_t, std::size_t, Containers::Array<char>>>::type interleave(const T& first, const U&... next) {
/* Compute buffer size and stride */
const std::size_t attributeCount = Implementation::AttributeCount{}(first, next...);
const std::size_t stride = Implementation::Stride{}(first, next...);
/* Create output buffer only if we have some attributes */
if(attributeCount && attributeCount != ~std::size_t(0)) {
Containers::Array<char> data = Containers::Array<char>::zeroInitialized(attributeCount*stride);
Implementation::writeInterleaved(stride, data.begin(), first, next...);
return std::make_tuple(attributeCount, stride, std::move(data));
/* Otherwise return nullptr */
} else return std::make_tuple(0, stride, nullptr);
}
/**
@brief %Interleave vertex attributes into existing buffer
Unlike @ref interleave() this function interleaves the data into existing
buffer and leaves gaps untouched instead of zero-initializing them. This
function can thus be used for interleaving data depending on runtime
parameters.
@attention Similarly to @ref interleave(), this function expects that all
arrays have the same size. The passed buffer must also be large enough to
contain the interleaved data.
*/
template<class T, class ...U> std::tuple<std::size_t, std::size_t> interleaveInto(Containers::ArrayReference<char> buffer, const T& first, const U&... next) {
/* Verify expected buffer size */
const std::size_t attributeCount = Implementation::AttributeCount{}(first, next...);
const std::size_t stride = Implementation::Stride{}(first, next...);
CORRADE_ASSERT(attributeCount*stride <= buffer.size(), "MeshTools::interleaveInto(): the data buffer is too small, expected" << attributeCount*stride << "but got" << buffer.size(), {});
/* Write data */
Implementation::writeInterleaved(stride, buffer.begin(), first, next...);
return std::make_tuple(attributeCount, stride);
}
/**
@brief %Interleave vertex attributes and write them to array buffer
@brief %Interleave vertex attributes, write them to array buffer and configure the mesh
@param mesh Output mesh
@param buffer Output vertex buffer
@param usage Vertex buffer usage
@ -194,18 +191,31 @@ so you don't have to call @ref Mesh::setVertexCount() on your own.
@attention You still must call @ref Mesh::setPrimitive() and
@ref Mesh::addVertexBuffer() on the mesh afterwards.
For only one attribute array this function is convenient equivalent to the
following, without any performance loss:
@see @ref compressIndices(), @ref compile()
@todo rework so Mesh & Buffer doesn't need to be included in header
*/
template<class ...T> void interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T&... attributes) {
Containers::Array<char> data;
std::size_t attributeCount;
std::tie(attributeCount, std::ignore, data) = interleave(attributes...);
mesh.setVertexCount(attributeCount);
buffer.setData(data, usage);
}
/**
@brief Write vertex attribute to array buffer and configure the mesh
Simplified specialization of the above function for only one attribute array,
equivalent to the following:
@code
buffer.setData(attribute, usage);
mesh.setVertexCount(attribute.size());
@endcode
@see @ref MeshTools::compressIndices()
@todo rework so Mesh & Buffer doesn't need to be included in header
*/
template<class ...T> inline void interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T&... attributes) {
return Implementation::Interleave()(mesh, buffer, usage, attributes...);
template<class T> typename std::enable_if<!std::is_convertible<T, std::size_t>::value, void>::type interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T& attribute) {
mesh.setVertexCount(attribute.size());
buffer.setData(attribute, usage);
}
}}

57
src/Magnum/MeshTools/Test/InterleaveTest.cpp

@ -42,6 +42,8 @@ class InterleaveTest: public Corrade::TestSuite::Tester {
void strideGaps();
void write();
void writeGaps();
void interleaveInto();
};
InterleaveTest::InterleaveTest() {
@ -50,36 +52,38 @@ InterleaveTest::InterleaveTest() {
&InterleaveTest::stride,
&InterleaveTest::strideGaps,
&InterleaveTest::write,
&InterleaveTest::writeGaps});
&InterleaveTest::writeGaps,
&InterleaveTest::interleaveInto});
}
void InterleaveTest::attributeCount() {
std::stringstream ss;
Error::setOutput(&ss);
CORRADE_COMPARE((Implementation::Interleave::attributeCount(std::vector<Byte>{0, 1, 2},
CORRADE_COMPARE((Implementation::AttributeCount{}(std::vector<Byte>{0, 1, 2},
std::vector<Byte>{0, 1, 2, 3, 4, 5})), std::size_t(0));
CORRADE_COMPARE(ss.str(), "MeshTools::interleave(): attribute arrays don't have the same length, expected 3 but got 6\n");
CORRADE_COMPARE((Implementation::Interleave::attributeCount(std::vector<Byte>{0, 1, 2},
CORRADE_COMPARE((Implementation::AttributeCount{}(std::vector<Byte>{0, 1, 2},
std::vector<Byte>{3, 4, 5})), std::size_t(3));
}
void InterleaveTest::attributeCountGaps() {
CORRADE_COMPARE((Implementation::Interleave::attributeCount(std::vector<Byte>{0, 1, 2}, 3,
CORRADE_COMPARE((Implementation::AttributeCount{}(std::vector<Byte>{0, 1, 2}, 3,
std::vector<Byte>{3, 4, 5}, 5)), std::size_t(3));
/* No arrays from which to get size */
CORRADE_COMPARE(Implementation::Interleave::attributeCount(3, 5), ~std::size_t(0));
CORRADE_COMPARE(Implementation::AttributeCount{}(3, 5), ~std::size_t(0));
}
void InterleaveTest::stride() {
CORRADE_COMPARE(Implementation::Interleave::stride(std::vector<Byte>()), std::size_t(1));
CORRADE_COMPARE(Implementation::Interleave::stride(std::vector<Int>()), std::size_t(4));
CORRADE_COMPARE((Implementation::Interleave::stride(std::vector<Byte>(), std::vector<Int>())), std::size_t(5));
CORRADE_COMPARE(Implementation::Stride{}(std::vector<Byte>()), std::size_t(1));
CORRADE_COMPARE(Implementation::Stride{}(std::vector<Int>()), std::size_t(4));
CORRADE_COMPARE((Implementation::Stride{}(std::vector<Byte>(), std::vector<Int>())), std::size_t(5));
}
void InterleaveTest::strideGaps() {
CORRADE_COMPARE((Implementation::Interleave::stride(2, std::vector<Byte>(), 1, std::vector<Int>(), 12)), std::size_t(20));
CORRADE_COMPARE((Implementation::Stride{}(2, std::vector<Byte>(), 1, std::vector<Int>(), 12)), std::size_t(20));
}
void InterleaveTest::write() {
@ -137,6 +141,41 @@ void InterleaveTest::writeGaps() {
}
}
void InterleaveTest::interleaveInto() {
std::size_t attributeCount;
std::size_t stride;
auto data = Containers::Array<char>::from(
0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77,
0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77,
0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77,
0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77
);
std::tie(attributeCount, stride) = MeshTools::interleaveInto(data,
2, std::vector<Int>{4, 5, 6, 7}, 1, std::vector<Short>{0, 1, 2, 3}, 3);
CORRADE_COMPARE(attributeCount, std::size_t{4});
CORRADE_COMPARE(stride, std::size_t{12});
if(!Utility::Endianness::isBigEndian()) {
/* _______gap, int___________________, _gap, short_____, _____________gap */
CORRADE_COMPARE(std::vector<char>(data.begin(), data.end()), (std::vector<char>{
0x11, 0x33, 0x04, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x33, 0x55, 0x77,
0x11, 0x33, 0x05, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x33, 0x55, 0x77,
0x11, 0x33, 0x06, 0x00, 0x00, 0x00, 0x55, 0x02, 0x00, 0x33, 0x55, 0x77,
0x11, 0x33, 0x07, 0x00, 0x00, 0x00, 0x55, 0x03, 0x00, 0x33, 0x55, 0x77
}));
} else {
/* _______gap, ___________________int, _gap, _____short, _____________gap */
CORRADE_COMPARE(std::vector<char>(data.begin(), data.end()), (std::vector<char>{
0x11, 0x33, 0x00, 0x00, 0x00, 0x04, 0x55, 0x00, 0x00, 0x33, 0x55, 0x77,
0x11, 0x33, 0x00, 0x00, 0x00, 0x05, 0x55, 0x00, 0x01, 0x33, 0x55, 0x77,
0x11, 0x33, 0x00, 0x00, 0x00, 0x06, 0x55, 0x00, 0x02, 0x33, 0x55, 0x77,
0x11, 0x33, 0x00, 0x00, 0x00, 0x07, 0x55, 0x00, 0x03, 0x33, 0x55, 0x77
}));
}
}
}}}
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::InterleaveTest)

3
src/Magnum/MeshView.h

@ -126,7 +126,8 @@ class MAGNUM_EXPORT MeshView {
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief draw(AbstractShaderProgram&)
* @deprecated Use
* @deprecated Use @ref Magnum::MeshView::draw(AbstractShaderProgram&) "draw(AbstractShaderProgram&)"
* instead.
*/
CORRADE_DEPRECATED("use draw(AbstractShaderProgram&) instead") void draw();
#endif

78
src/Magnum/MultisampleTexture.h

@ -44,6 +44,16 @@ namespace Implementation {
template<> inline constexpr GLenum multisampleTextureTarget<3>() { return GL_TEXTURE_2D_MULTISAMPLE_ARRAY; }
}
/**
@brief Multisample texture sample locations
@see @ref MultisampleTexture::setStorage()
*/
enum class MultisampleTextureSampleLocations: GLboolean {
NotFixed = GL_FALSE,
Fixed = GL_TRUE
};
/**
@brief Mulitsample texture
@ -77,19 +87,67 @@ template<UnsignedInt dimensions> class MultisampleTexture: public AbstractTextur
*/
explicit MultisampleTexture(): AbstractTexture(Implementation::multisampleTextureTarget<dimensions>()) {}
#ifndef MAGNUM_TARGET_GLES
/** @copydoc Texture::imageSize() */
typename DimensionTraits<dimensions, Int>::VectorType imageSize(Int level) {
return DataHelper<dimensions>::imageSize(*this, _target, level);
/**
* @brief %Image size
*
* The result is not cached in any way. If
* @extension{EXT,direct_state_access} is not available, the texture
* is bound to some texture unit before the operation.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and
* @fn_gl{GetTexLevelParameter} or @fn_gl_extension{GetTextureLevelParameter,EXT,direct_state_access}
* with @def_gl{TEXTURE_WIDTH}, @def_gl{TEXTURE_HEIGHT} or
* @def_gl{TEXTURE_DEPTH}
*/
typename DimensionTraits<dimensions, Int>::VectorType imageSize() {
return DataHelper<dimensions>::imageSize(*this, _target, 0);
}
/**
* @brief Set storage
* @param samples Sample count
* @param internalFormat Internal format
* @param size %Texture size
* @param sampleLocations Whether to use fixed sample locations
* @return Reference to self (for method chaining)
*
* After calling this function the texture is immutable and calling
* @ref setStorage() again is not allowed.
*
* If @extension{EXT,direct_state_access} is not available, the texture
* is bound to some texture unit before the operation. If
* @extension{ARB,texture_storage_multisample} (part of OpenGL 4.3) is
* not available, the feature is emulated using plain
* @extension{ARB,texture_storage} functionality (which unfortunately
* doesn't have any DSA alternative, so the texture must be bound
* to some texture unit before).
* @see @ref maxColorSamples(), @ref maxDepthSamples(),
* @ref maxIntegerSamples(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture}
* and @fn_gl{TexStorage2DMultisample}/@fn_gl{TexStorage3DMultisample}
* or @fn_gl_extension{TextureStorage2DMultisample,EXT,direct_state_access}/
* @fn_gl_extension{TextureStorage3DMultisample,EXT,direct_state_access}
* eventually @fn_gl{TexImage2DMultisample}/@fn_gl{TexImage3DMultisample}
* @todoc Remove the workaround when it stops breaking Doxygen layout so badly
*/
/* The default parameter value was chosen based on discussion in
ARB_texture_multisample specs (fixed locations is treated as the
special case) */
MultisampleTexture<dimensions>& setStorage(Int samples, TextureFormat internalFormat, const typename DimensionTraits<dimensions, Int>::VectorType& size, MultisampleTextureSampleLocations sampleLocations =
#ifndef DOXYGEN_GENERATING_OUTPUT
MultisampleTextureSampleLocations::NotFixed
#else
NotFixed
#endif
) {
DataHelper<dimensions>::setStorageMultisample(*this, _target, samples, internalFormat, size, GLboolean(sampleLocations));
return *this;
}
#endif
/** @copydoc Texture::invalidateImage() */
void invalidateImage(Int level) { AbstractTexture::invalidateImage(level); }
/** @copydoc RectangleTexture::invalidateImage() */
void invalidateImage() { AbstractTexture::invalidateImage(0); }
/** @copydoc Texture::invalidateSubImage() */
void invalidateSubImage(Int level, const typename DimensionTraits<dimensions, Int>::VectorType& offset, const typename DimensionTraits<dimensions, Int>::VectorType& size) {
DataHelper<dimensions>::invalidateSubImage(*this, level, offset, size);
/** @copydoc RectangleTexture::invalidateSubImage() */
void invalidateSubImage(const typename DimensionTraits<dimensions, Int>::VectorType& offset, const typename DimensionTraits<dimensions, Int>::VectorType& size) {
DataHelper<dimensions>::invalidateSubImage(*this, 0, offset, size);
}
/* Overloads to remove WTF-factor from method chaining order */

32
src/Magnum/Platform/AbstractXApplication.h

@ -92,7 +92,10 @@ class AbstractXApplication {
/**
* @brief Execute main loop
* @return Value for returning from `main()`.
* @return Value for returning from `main()`
*
* See @ref MAGNUM_GLXAPPLICATION_MAIN() or
* @ref MAGNUM_XEGLAPPLICATION_MAIN() for usage information.
*/
int exec();
@ -268,33 +271,6 @@ class AbstractXApplication::InputEvent {
Ctrl = ControlMask, /**< Ctrl */
Alt = Mod1Mask, /**< Alt */
AltGr = Mod5Mask, /**< AltGr */
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief Button::Left
* @deprecated Use @ref Magnum::Platform::AbstractXApplication::InputEvent::buttons() "buttons()"
* and @ref Magnum::Platform::AbstractXApplication::InputEvent::Button::Left "Button::Left"
* instead.
*/
LeftButton = Button1Mask,
/**
* @copybrief Button::Middle
* @deprecated Use @ref Magnum::Platform::AbstractXApplication::InputEvent::buttons() "buttons()"
* and @ref Magnum::Platform::AbstractXApplication::InputEvent::Button::Middle "Button::Middle"
* instead.
*/
MiddleButton = Button2Mask,
/**
* @copybrief Button::Right
* @deprecated Use @ref Magnum::Platform::AbstractXApplication::InputEvent::buttons() "buttons()"
* and @ref Magnum::Platform::AbstractXApplication::InputEvent::Button::Right "Button::Right"
* instead.
*/
RightButton = Button3Mask,
#endif
CapsLock = LockMask, /**< Caps lock */
NumLock = Mod2Mask /**< Num lock */
};

266
src/Magnum/Platform/AndroidApplication.cpp

@ -0,0 +1,266 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014
Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is 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 Software.
THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "AndroidApplication.h"
#include <Corrade/Utility/AndroidStreamBuffer.h>
#include <Corrade/Utility/Debug.h>
#include "Magnum/Context.h"
#include "Implementation/Egl.h"
namespace Magnum { namespace Platform {
/** @todo Delegating constructors when support for GCC 4.6 can be dropped */
AndroidApplication::AndroidApplication(const Arguments& arguments, const Configuration& configuration): _state(arguments) {
initialize();
createContext(configuration);
}
#ifndef DOXYGEN_GENERATING_OUTPUT
AndroidApplication::AndroidApplication(const Arguments& arguments): _state(arguments) {
initialize();
createContext();
}
#endif
AndroidApplication::AndroidApplication(const Arguments& arguments, std::nullptr_t): _state(arguments) {
initialize();
}
AndroidApplication::~AndroidApplication() {
eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(_display, _context);
eglDestroySurface(_display, _surface);
eglTerminate(_display);
}
struct AndroidApplication::LogOutput {
LogOutput();
Utility::AndroidLogStreamBuffer debugBuffer, warningBuffer, errorBuffer;
std::ostream debugStream, warningStream, errorStream;
};
AndroidApplication::LogOutput::LogOutput():
debugBuffer(Utility::AndroidLogStreamBuffer::LogPriority::Info, "magnum"),
warningBuffer(Utility::AndroidLogStreamBuffer::LogPriority::Warning, "magnum"),
errorBuffer(Utility::AndroidLogStreamBuffer::LogPriority::Error, "magnum"),
debugStream(&debugBuffer), warningStream(&warningBuffer), errorStream(&errorBuffer)
{
Debug::setOutput(&debugStream);
Warning::setOutput(&warningStream);
Error::setOutput(&errorStream);
}
void AndroidApplication::initialize() {
/* Redirect debug output to Android log */
_logOutput.reset(new LogOutput);
}
void AndroidApplication::createContext() { createContext({}); }
void AndroidApplication::createContext(const Configuration& configuration) {
if(!tryCreateContext(configuration)) std::exit(32);
}
bool AndroidApplication::tryCreateContext(const Configuration& configuration) {
/* Initialize EGL */
_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if(!eglInitialize(_display, nullptr, nullptr)) {
Error() << "Platform::AndroidApplication::tryCreateContext(): cannot initialize EGL:"
<< Implementation::eglErrorString(eglGetError());
return false;
}
/* Choose config */
const EGLint configAttributes[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
EGLint configCount;
EGLConfig config;
if(!eglChooseConfig(_display, configAttributes, &config, 1, &configCount)) {
Error() << "Platform::AndroidApplication::tryCreateContext(): cannot choose EGL config:"
<< Implementation::eglErrorString(eglGetError());
return false;
}
/* Resize native window and match it to the selected format */
EGLint format;
CORRADE_INTERNAL_ASSERT_OUTPUT(eglGetConfigAttrib(_display, config, EGL_NATIVE_VISUAL_ID, &format));
ANativeWindow_setBuffersGeometry(_state->window,
configuration.size().isZero() ? 0 : configuration.size().x(),
configuration.size().isZero() ? 0 : configuration.size().y(), format);
/* Create surface and context */
if(!(_surface = eglCreateWindowSurface(_display, config, _state->window, nullptr))) {
Error() << "Platform::AndroidApplication::tryCreateContext(): cannot create EGL window surface:"
<< Implementation::eglErrorString(eglGetError());
return false;
}
const EGLint contextAttributes[] = {
#ifdef MAGNUM_TARGET_GLES2
EGL_CONTEXT_CLIENT_VERSION, 2,
#elif defined(MAGNUM_TARGET_GLES3)
EGL_CONTEXT_CLIENT_VERSION, 3,
#else
#error Android with desktop OpenGL? Wow, that is a new thing.
#endif
EGL_NONE
};
if(!(_context = eglCreateContext(_display, config, EGL_NO_CONTEXT, contextAttributes))) {
Error() << "Platform::AndroidApplication::tryCreateContext(): cannot create EGL context:"
<< Implementation::eglErrorString(eglGetError());
return false;
}
/* Make the context current */
CORRADE_INTERNAL_ASSERT_OUTPUT(eglMakeCurrent(_display, _surface, _surface, _context));
_c.reset(new Context);
return true;
}
void AndroidApplication::swapBuffers() {
eglSwapBuffers(_display, _surface);
}
void AndroidApplication::viewportEvent(const Vector2i&) {}
void AndroidApplication::mousePressEvent(MouseEvent&) {}
void AndroidApplication::mouseReleaseEvent(MouseEvent&) {}
void AndroidApplication::mouseMoveEvent(MouseMoveEvent&) {}
namespace {
struct Data {
Data(std::unique_ptr<AndroidApplication>(*instancer)(const AndroidApplication::Arguments&)): instancer(instancer) {}
std::unique_ptr<AndroidApplication>(*instancer)(const AndroidApplication::Arguments&);
std::unique_ptr<AndroidApplication> instance;
};
}
void AndroidApplication::commandEvent(android_app* state, int32_t cmd) {
Data& data = *static_cast<Data*>(state->userData);
switch (cmd) {
case APP_CMD_SAVE_STATE:
/** @todo Make use of this */
break;
case APP_CMD_INIT_WINDOW:
/* Create the application */
if(!data.instance) {
data.instance = data.instancer(state);
data.instance->drawEvent();
}
break;
case APP_CMD_TERM_WINDOW:
/* Destroy the application */
data.instance.reset();
break;
case APP_CMD_GAINED_FOCUS:
case APP_CMD_LOST_FOCUS:
/** @todo Make use of these */
break;
}
}
std::int32_t AndroidApplication::inputEvent(android_app* state, AInputEvent* event) {
CORRADE_INTERNAL_ASSERT(static_cast<Data*>(state->userData)->instance);
AndroidApplication& app = *static_cast<Data*>(state->userData)->instance;
if(AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
const std::int32_t action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK;
switch(action) {
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_UP: {
MouseEvent e(event);
action == AMOTION_EVENT_ACTION_DOWN ? app.mousePressEvent(e) : app.mouseReleaseEvent(e);
return e.isAccepted() ? 1 : 0;
}
case AMOTION_EVENT_ACTION_MOVE: {
MouseMoveEvent e(event);
app.mouseMoveEvent(e);
return e.isAccepted() ? 1 : 0;
}
}
/** @todo Implement also other input events */
}
return 0;
}
void AndroidApplication::exec(android_app* state, std::unique_ptr<AndroidApplication>(*instancer)(const Arguments&)) {
state->onAppCmd = commandEvent;
state->onInputEvent = inputEvent;
/* Make sure the glue isn't stripped. WHY WHYYY CAN'T THIS BE DONE SOME
SANE WAY WHYY */
app_dummy();
/** @todo Make use of saved state */
Data data{instancer};
state->userData = &data;
for(;;) {
/* Read all pending events. Block and wait for them only if the app
doesn't want to redraw immediately WHY THIS GODDAMN THING DOESNT
HAVE SOMETHING LIKE WAIT FOR EVENT SO I NEED TO TANGLE THIS TANGLED
MESS OF HELL */
int ident, events;
android_poll_source* source;
while((ident = ALooper_pollAll(
data.instance && (data.instance->_flags & Flag::Redraw) ? 0 : -1,
nullptr, &events, reinterpret_cast<void**>(&source))) >= 0)
{
/* Process this event OH SIR MAY MY POOR EXISTENCE CALL THIS
FUNCTION FOR YOU IF YOU DON'T MIND? */
if(source) source->process(state, source);
/* Exit WHY THIS HAS TO BE HANDLED HERE WHILE EVERY OTHER THING
IS HANDLED THROUGH CALLBACK GODDAMMIT */
if(state->destroyRequested != 0) return;
}
/* Redraw the app if it wants to be redrawn. Frame limiting is done by
Android itself */
if(data.instance && (data.instance->_flags & Flag::Redraw))
data.instance->drawEvent();
}
state->userData = nullptr;
}
}}

594
src/Magnum/Platform/AndroidApplication.h

@ -0,0 +1,594 @@
#ifndef Magnum_Platform_AndroidApplication_h
#define Magnum_Platform_AndroidApplication_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014
Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is 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 Software.
THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/** @file
* @brief Class @ref Magnum::Platform::AndroidApplication
*/
#include <memory>
#include <EGL/egl.h>
#include <android_native_app_glue.h>
#include "Magnum/Magnum.h"
#include "Magnum/Math/Vector2.h"
#include "Magnum/Platform/Platform.h"
#ifndef CORRADE_TARGET_ANDROID
#error This file is available only on Android
#endif
/* Undef Xlib nonsense which might get pulled in by EGL */
#undef None
namespace Magnum { namespace Platform {
/** @nosubgrouping
@brief Android application
Application running in Android.
This application library is available only in
@ref CORRADE_TARGET_ANDROID "Android", see respective sections
in @ref building-corrade-cross-android "Corrade's" and @ref building-cross-android "Magnum's"
building documentation. It is built if `WITH_ANDROIDAPPLICATION` is enabled in
CMake.
## Bootstrap application
Fully contained base application using @ref GlutApplication for desktop build
and @ref AndroidApplication for Android build along with full Android packaging
stuff and CMake setup is available in `base-android` branch of
[Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap) repository,
download it as [tar.gz](https://github.com/mosra/magnum-bootstrap/archive/base-android.tar.gz)
or [zip](https://github.com/mosra/magnum-bootstrap/archive/base-android.zip) file.
After extracting the downloaded archive, you can do the desktop build in the
same way as with @ref GlutApplication. For the Android build you also
need to put the contents of toolchains repository from https://github.com/mosra/toolchains
in `toolchains/` subdirectory. Don't forget to adapt `ANDROID_NDK_ROOT` in
`toolchains/generic/Android-*.cmake` to path where NDK is installed. Default is
`/opt/android-ndk`. Adapt also `ANDROID_SYSROOT` to your preferred API level.
You might also need to update `ANDROID_TOOLCHAIN_PREFIX` and
`ANDROID_TOOLCHAIN_ROOT` to fit your system.
First you need to update Android project files with the following command. It
will create `build.xml` file for Ant and a bunch of other files. You need to
specify the target for which you will build in the `-t` parameter. List of all
targets can be obtained by calling `android list target`.
android update project -p . -t "android-19"
Then create build directories for ARM and x86 and run `cmake` and build command
in them. The toolchains need access to the platform file, so be sure to
properly set **absolute** path to `toolchains/modules/` directory containing
`Platform/Android.cmake`.
mkdir build-android-arm && cd build-android-arm
cmake .. \
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/Android-ARM.cmake"
cmake --build .
mkdir build-android-x86 && cd build-android-x86
cmake .. \
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/Android-x86.cmake"
cmake --build .
The compiled binaries will be put into `lib/armeabi-v7a` and `lib/x86`. You can
then build the APK package simply by running `ant`. The resulting APK package
can be then installed directly on the device or emulator using `adb install`.
ant debug
adb install bin/NativeActivity-debug.apk
## General usage
For CMake you need to copy `FindEGL.cmake` and `FindOpenGLES2.cmake` (or
`FindOpenGLES3.cmake`) from `modules/` directory in %Magnum source to `modules/`
dir in your project (so it is able to find EGL and OpenGL ES libraries).
Request `%AndroidApplication` component, add
`${MAGNUM_ANDROIDAPPLICATION_INCLUDE_DIRS}` to include path and link to
`${MAGNUM_ANDROIDAPPLICATION_LIBRARIES}`. If no other application is requested,
you can also use generic `${MAGNUM_APPLICATION_INCLUDE_DIRS}` and
`${MAGNUM_APPLICATION_LIBRARIES}` aliases to simplify porting. See
@ref building and @ref cmake for more information. Note that unlike on other
platforms you need to create *shared library* instead of executable. The
resulting binary then needs to be copied to `lib/armeabi-v7a` and `lib/x86`,
you can do that automatically in CMake using the following commands:
file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}")
In C++ code you need to implement at least @ref drawEvent() to be able to draw
on the screen. The subclass must be then made accessible from JNI using
@ref MAGNUM_ANDROIDAPPLICATION_MAIN() macro. See @ref platform for more
information.
@code
class MyApplication: public Platform::AndroidApplication {
// implement required methods...
};
MAGNUM_ANDROIDAPPLICATION_MAIN(MyApplication)
@endcode
If no other application header is included, this class is also aliased to
`Platform::Application` and the macro is aliased to `MAGNUM_APPLICATION_MAIN()`
to simplify porting.
### Android packaging stuff
The application needs at least the `AndroidManifest.xml` with the following
contents:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cz.mosra.magnum.application" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="9" />
<uses-feature android:glEsVersion="0x00020000" />
<application android:label="Magnum Android Application" android:hasCode="false">
<activity android:name="android.app.NativeActivity" android:label="Magnum Android Application">
<meta-data android:name="android.app.lib_name" android:value="{{application}}" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Modify `android:label` to your liking, set unique `package` name and replace
`{{application}}` with name of the binary file (without extension). If you plan
to use OpenGL ES, set `android:glEsVersion` to `0x00030000`. The resulting APK
file will be named `NativeActivity.apk` by default, you can change that either
by passing `-n` parameter to `android update project` or later by editing first
line of the generated `build.xml` file.
## Redirecting output to Android log buffer
The application by default redirects @ref Corrade::Utility::Debug "Debug",
@ref Corrade::Utility::Warning "Warning" and @ref Corrade::Utility::Error "Error"
output to Android log buffer with tag `"magnum"`, which can be then accessed
through `logcat` utility. See also @ref Corrade::Utility::AndroidLogStreamBuffer
for more information.
*/
class AndroidApplication {
public:
/** @brief Application arguments */
typedef android_app* Arguments;
class Configuration;
class InputEvent;
class MouseEvent;
class MouseMoveEvent;
/**
* @brief Execute the application
*
* See @ref MAGNUM_ANDROIDAPPLICATION_MAIN() for usage information.
*/
static void exec(android_app* state, std::unique_ptr<AndroidApplication>(*instancer)(const Arguments&));
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class T> static std::unique_ptr<AndroidApplication> instancer(const Arguments& arguments) {
return std::unique_ptr<AndroidApplication>{new T{arguments}};
}
#endif
/** @copydoc Sdl2Application::Sdl2Application(const Arguments&, const Configuration&) */
#ifdef DOXYGEN_GENERATING_OUTPUT
explicit AndroidApplication(const Arguments& arguments, const Configuration& configuration = Configuration());
#else
/* To avoid "invalid use of incomplete type" */
explicit AndroidApplication(const Arguments& arguments, const Configuration& configuration);
explicit AndroidApplication(const Arguments& arguments);
#endif
/** @copydoc Sdl2Application::Sdl2Application(const Arguments&, std::nullptr_t) */
explicit AndroidApplication(const Arguments& arguments, std::nullptr_t);
/** @brief Copying is not allowed */
AndroidApplication(const AndroidApplication&) = delete;
/** @brief Moving is not allowed */
AndroidApplication(AndroidApplication&&) = delete;
virtual ~AndroidApplication();
/** @brief Copying is not allowed */
AndroidApplication& operator=(const AndroidApplication&) = delete;
/** @brief Moving is not allowed */
AndroidApplication& operator=(AndroidApplication&&) = delete;
protected:
/** @copydoc Sdl2Application::createContext() */
#ifdef DOXYGEN_GENERATING_OUTPUT
void createContext(const Configuration& configuration = Configuration());
#else
/* To avoid "invalid use of incomplete type" */
void createContext(const Configuration& configuration);
void createContext();
#endif
/** @copydoc Sdl2Application::tryCreateContext() */
bool tryCreateContext(const Configuration& configuration);
/** @{ @name Screen handling */
/** @copydoc Sdl2Application::swapBuffers() */
void swapBuffers();
/** @copydoc Sdl2Application::redraw() */
void redraw() { _flags |= Flag::Redraw; }
#ifdef DOXYGEN_GENERATING_OUTPUT
protected:
#else
private:
#endif
/** @copydoc Sdl2Application::viewportEvent() */
virtual void viewportEvent(const Vector2i& size);
/** @copydoc Sdl2Application::drawEvent() */
virtual void drawEvent() = 0;
/*@}*/
/** @{ @name Mouse handling */
#ifdef DOXYGEN_GENERATING_OUTPUT
protected:
#else
private:
#endif
/**
* @brief Mouse press event
*
* Called when mouse button is pressed. Default implementation does
* nothing.
*/
virtual void mousePressEvent(MouseEvent& event);
/**
* @brief Mouse release event
*
* Called when mouse button is released. Default implementation does
* nothing.
*/
virtual void mouseReleaseEvent(MouseEvent& event);
/**
* @brief Mouse move event
*
* Called when mouse is moved. Default implementation does nothing.
*/
virtual void mouseMoveEvent(MouseMoveEvent& event);
/*@}*/
private:
struct LogOutput;
enum class Flag: UnsignedByte {
Redraw = 1 << 0
};
typedef Containers::EnumSet<Flag, UnsignedByte> Flags;
static void commandEvent(android_app* state, std::int32_t cmd);
static std::int32_t inputEvent(android_app* state, AInputEvent* event);
void initialize();
android_app* const _state;
Flags _flags;
EGLDisplay _display;
EGLSurface _surface;
EGLContext _context;
std::unique_ptr<Context> _c;
std::unique_ptr<LogOutput> _logOutput;
CORRADE_ENUMSET_FRIEND_OPERATORS(Flags)
};
CORRADE_ENUMSET_OPERATORS(AndroidApplication::Flags)
/**
@brief %Configuration
Double-buffered RGBA canvas with depth and stencil buffers.
@see @ref AndroidApplication(), @ref createContext(), @ref tryCreateContext()
*/
class AndroidApplication::Configuration {
public:
constexpr /*implicit*/ Configuration() {}
/**
* @brief Set window title
* @return Reference to self (for method chaining)
*
* @note This function does nothing and is included only for
* compatibility with other toolkits. You need to set the title
* separately in the `AndroidManifest.xml` file.
*/
template<class T> Configuration& setTitle(const T&) { return *this; }
/** @brief Window size */
Vector2i size() const { return _size; }
/**
* @brief Set window size
* @return Reference to self (for method chaining)
*
* Default is `{0, 0}`, which means that the size of the physical
* window will be used. If set to different value than the physical
* size, the surface will be scaled.
*/
Configuration& setSize(const Vector2i& size) {
_size = size;
return *this;
}
/**
* @brief Set context version
*
* @note This function does nothing and is included only for
* compatibility with other toolkits. @ref Version::GLES200 or
* @ref Version::GLES300 is used based on engine compile-time
* settings.
*/
Configuration& setVersion(Version) { return *this; }
private:
Vector2i _size;
};
/**
@brief Base for input events
@see @ref MouseEvent, @ref MouseMoveEvent, @ref mousePressEvent(),
@ref mouseReleaseEvent(), @ref mouseMoveEvent()
*/
class AndroidApplication::InputEvent {
public:
/** @brief Copying is not allowed */
InputEvent(const InputEvent&) = delete;
/** @brief Moving is not allowed */
InputEvent(InputEvent&&) = delete;
/** @brief Copying is not allowed */
InputEvent& operator=(const InputEvent&) = delete;
/** @brief Moving is not allowed */
InputEvent& operator=(InputEvent&&) = delete;
/**
* @brief Set event as accepted
*
* If the event is ignored (i.e., not set as accepted), it will be
* propagated elsewhere, for example to the Android system or to
* another screen when using @ref BasicScreenedApplication "ScreenedApplication".
* By default is each event ignored and thus propagated.
*/
void setAccepted(bool accepted = true) { _accepted = accepted; }
/** @brief Whether the event is accepted */
bool isAccepted() const { return _accepted; }
#ifndef DOXYGEN_GENERATING_OUTPUT
protected:
explicit InputEvent(AInputEvent* event): _event(event), _accepted(false) {}
~InputEvent() = default;
AInputEvent* _event;
#endif
private:
bool _accepted;
};
/**
@brief Mouse event
@see @ref MouseMoveEvent, @ref mousePressEvent(), @ref mouseReleaseEvent()
*/
class AndroidApplication::MouseEvent: public InputEvent {
friend class AndroidApplication;
public:
/**
* @brief Mouse button
*
* @see @ref button()
*/
enum class Button: std::int32_t {
/** No button was pressed (touch or stylus event) */
None = 0,
/**
* Left mouse button. Note that this button is not set if only
* touch or stylus event occured.
* @attention Available since Android 4.0 (API level 14), not
* detectable in earlier versions.
*/
#if defined(DOXYGEN_GENERATING_OUTPUT) || __ANDROID_API__ >= 14
Left = AMOTION_EVENT_BUTTON_PRIMARY,
#else
Left = 1 << 0,
#endif
/**
* Middle mouse button or second stylus button
* @attention Available since Android 4.0 (API level 14), not
* detectable in earlier versions.
*/
#if defined(DOXYGEN_GENERATING_OUTPUT) || __ANDROID_API__ >= 14
Middle = AMOTION_EVENT_BUTTON_TERTIARY,
#else
Middle = 1 << 1,
#endif
/**
* Right mouse button or first stylus button
* @attention Available since Android 4.0 (API level 14), not
* detectable in earlier versions.
*/
#if defined(DOXYGEN_GENERATING_OUTPUT) || __ANDROID_API__ >= 14
Right = AMOTION_EVENT_BUTTON_SECONDARY
#else
Right = 1 << 2
#endif
};
/** @brief Button */
Button button() {
#if __ANDROID_API__ >= 14
return Button(AMotionEvent_getButtonState(_event));
#else
return Button::None;
#endif
}
/** @brief Position */
Vector2i position() {
return {Int(AMotionEvent_getX(_event, 0)),
Int(AMotionEvent_getY(_event, 0))};
}
private:
MouseEvent(AInputEvent* event): InputEvent(event) {}
};
/**
@brief Mouse move event
@see @ref MouseEvent, @ref mouseMoveEvent()
*/
class AndroidApplication::MouseMoveEvent: public InputEvent {
friend class AndroidApplication;
public:
/**
* @brief Mouse button
*
* @see @ref buttons()
*/
enum class Button: std::int32_t {
/**
* Left mouse button. Note that this button is not set if only
* touch or stylus event occured.
* @attention Available since Android 4.0 (API level 14), not
* detectable in earlier versions.
*/
#if defined(DOXYGEN_GENERATING_OUTPUT) || __ANDROID_API__ >= 14
Left = AMOTION_EVENT_BUTTON_PRIMARY,
#else
Left = 1 << 0,
#endif
/**
* Middle mouse button or second stylus button
* @attention Available since Android 4.0 (API level 14), not
* detectable in earlier versions.
*/
#if defined(DOXYGEN_GENERATING_OUTPUT) || __ANDROID_API__ >= 14
Middle = AMOTION_EVENT_BUTTON_TERTIARY,
#else
Middle = 1 << 1,
#endif
/**
* Right mouse button or first stylus button
* @attention Available since Android 4.0 (API level 14), not
* detectable in earlier versions.
*/
#if defined(DOXYGEN_GENERATING_OUTPUT) || __ANDROID_API__ >= 14
Right = AMOTION_EVENT_BUTTON_SECONDARY
#else
Right = 1 << 2
#endif
};
/**
* @brief Set of mouse buttons
*
* @see @ref buttons()
*/
typedef Containers::EnumSet<Button, std::int32_t> Buttons;
/** @brief Position */
Vector2i position() const {
return {Int(AMotionEvent_getX(_event, 0)),
Int(AMotionEvent_getY(_event, 0))};
}
/** @brief Mouse buttons */
Buttons buttons() const {
#if __ANDROID_API__ >= 14
return Button(AMotionEvent_getButtonState(_event));
#else
return {};
#endif
}
private:
MouseMoveEvent(AInputEvent* event): InputEvent(event) {}
};
CORRADE_ENUMSET_OPERATORS(AndroidApplication::MouseMoveEvent::Buttons)
/** @hideinitializer
@brief Entry point for Android applications
@param className Class name
See @ref Magnum::Platform::AndroidApplication "Platform::AndroidApplication"
for usage information. This macro abstracts out platform-specific entry point
code (the classic `main()` function cannot be used in Android). See
@ref portability-applications for more information. When no other application
header is included this macro is also aliased to `MAGNUM_APPLICATION_MAIN()`.
*/
#define MAGNUM_ANDROIDAPPLICATION_MAIN(className) \
void android_main(android_app* state) { \
Magnum::Platform::AndroidApplication::exec(state, \
Magnum::Platform::AndroidApplication::instancer<className>); \
}
#ifndef DOXYGEN_GENERATING_OUTPUT
#ifndef MAGNUM_APPLICATION_MAIN
typedef AndroidApplication Application;
typedef BasicScreen<AndroidApplication> Screen;
typedef BasicScreenedApplication<AndroidApplication> ScreenedApplication;
#define MAGNUM_APPLICATION_MAIN(className) MAGNUM_ANDROIDAPPLICATION_MAIN(className)
#else
#undef MAGNUM_APPLICATION_MAIN
#endif
#endif
}}
#endif

34
src/Magnum/Platform/CMakeLists.txt

@ -32,11 +32,32 @@ set(Platform_HEADERS
install(FILES ${Platform_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
# Android application
if(WITH_ANDROIDAPPLICATION)
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL Android)
message(FATAL_ERROR "AndroidApplication is available only when targeting Android. Set WITH_ANDROIDAPPLICATION to OFF to skip building it.")
endif()
include_directories(${ANDROID_NATIVE_APP_GLUE_INCLUDE_DIR})
add_library(MagnumAndroidApplication STATIC
AndroidApplication.cpp
Implementation/Egl.cpp
${ANDROID_NATIVE_APP_GLUE_SRC})
set_target_properties(MagnumAndroidApplication PROPERTIES DEBUG_POSTFIX "-d")
install(FILES AndroidApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
install(TARGETS MagnumAndroidApplication
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
LIBRARY DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}
ARCHIVE DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
endif()
# GLUT application
if(WITH_GLUTAPPLICATION)
find_package(GLUT)
if(GLUT_FOUND)
add_library(MagnumGlutApplication STATIC GlutApplication.cpp)
set_target_properties(MagnumGlutApplication PROPERTIES DEBUG_POSTFIX "-d")
install(FILES GlutApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
install(TARGETS MagnumGlutApplication
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
@ -53,6 +74,7 @@ if(WITH_SDL2APPLICATION)
if(SDL2_FOUND)
include_directories(${SDL2_INCLUDE_DIR})
add_library(MagnumSdl2Application STATIC Sdl2Application.cpp)
set_target_properties(MagnumSdl2Application PROPERTIES DEBUG_POSTFIX "-d")
install(FILES Sdl2Application.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
install(TARGETS MagnumSdl2Application
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
@ -70,6 +92,7 @@ if(WITH_NACLAPPLICATION)
endif()
add_library(MagnumNaClApplication STATIC NaClApplication.cpp)
set_target_properties(MagnumNaClApplication PROPERTIES DEBUG_POSTFIX "-d")
install(FILES NaClApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
install(TARGETS MagnumNaClApplication
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
@ -84,6 +107,7 @@ if(WITH_WINDOWLESSNACLAPPLICATION)
endif()
add_library(MagnumWindowlessNaClApplication STATIC WindowlessNaClApplication.cpp)
set_target_properties(MagnumWindowlessNaClApplication PROPERTIES DEBUG_POSTFIX "-d")
install(FILES WindowlessNaClApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
install(TARGETS MagnumWindowlessNaClApplication
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
@ -109,6 +133,7 @@ if(WITH_GLXAPPLICATION)
$<TARGET_OBJECTS:MagnumAbstractXApplication>
$<TARGET_OBJECTS:MagnumGlxContextHandler>
GlxApplication.cpp)
set_target_properties(MagnumGlxApplication PROPERTIES DEBUG_POSTFIX "-d")
install(FILES GlxApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
install(TARGETS MagnumGlxApplication
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
@ -124,6 +149,7 @@ if(WITH_XEGLAPPLICATION)
$<TARGET_OBJECTS:MagnumAbstractXApplication>
$<TARGET_OBJECTS:MagnumEglContextHandler>
XEglApplication.cpp)
set_target_properties(MagnumXEglApplication PROPERTIES DEBUG_POSTFIX "-d")
install(FILES XEglApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
install(TARGETS MagnumXEglApplication
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
@ -142,7 +168,9 @@ endif()
if(WITH_WINDOWLESSGLXAPPLICATION)
add_library(MagnumWindowlessGlxApplication STATIC WindowlessGlxApplication.cpp)
# X11 macros are a mess, disable warnings for C-style casts
set_target_properties(MagnumWindowlessGlxApplication PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
set_target_properties(MagnumWindowlessGlxApplication PROPERTIES
COMPILE_FLAGS "-Wno-old-style-cast"
DEBUG_POSTFIX "-d")
install(FILES WindowlessGlxApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform)
install(TARGETS MagnumWindowlessGlxApplication
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
@ -171,7 +199,9 @@ if(NEED_EGLCONTEXT)
if(NOT EGL_FOUND)
message(FATAL_ERROR "EGL library, required by some window contexts, was not found. Set WITH_*EGL*APPLICATION to OFF to skip building them.")
endif()
add_library(MagnumEglContextHandler OBJECT Implementation/EglContextHandler.cpp)
add_library(MagnumEglContextHandler OBJECT
Implementation/EglContextHandler.cpp
Implementation/Egl.cpp)
# X11 macros are a mess, disable warnings for C-style casts
set_target_properties(MagnumEglContextHandler PROPERTIES COMPILE_FLAGS "-Wno-old-style-cast")
endif()

25
src/Magnum/Platform/GlutApplication.cpp

@ -96,12 +96,18 @@ bool GlutApplication::tryCreateContext(const Configuration& configuration) {
#endif
}
/* Set context flags */
glutInitContextFlags(int(configuration.flags()));
if(!glutCreateWindow(configuration.title().data())) {
Error() << "Platform::GlutApplication::tryCreateContext(): cannot create context";
return false;
}
glutReshapeFunc(staticViewportEvent);
glutSpecialFunc(staticKeyEvent);
glutKeyboardFunc(staticKeyPressEvent);
glutKeyboardUpFunc(staticKeyReleaseEvent);
glutSpecialFunc(staticSpecialKeyPressEvent);
glutSpecialUpFunc(staticSpecialKeyReleaseEvent);
glutMouseFunc(staticMouseEvent);
glutMotionFunc(staticMouseMoveEvent);
glutDisplayFunc(staticDrawEvent);
@ -114,11 +120,26 @@ GlutApplication::~GlutApplication() {
delete c;
}
void GlutApplication::staticKeyEvent(int key, int x, int y){
void GlutApplication::staticKeyPressEvent(unsigned char key, int x, int y) {
KeyEvent e(static_cast<KeyEvent::Key>(key), {x, y});
instance->keyPressEvent(e);
}
void GlutApplication::staticKeyReleaseEvent(unsigned char key, int x, int y) {
KeyEvent e(static_cast<KeyEvent::Key>(key), {x, y});
instance->keyReleaseEvent(e);
}
void GlutApplication::staticSpecialKeyPressEvent(int key, int x, int y){
KeyEvent e(static_cast<KeyEvent::Key>(key << 16), {x, y});
instance->keyPressEvent(e);
}
void GlutApplication::staticSpecialKeyReleaseEvent(int key, int x, int y){
KeyEvent e(static_cast<KeyEvent::Key>(key << 16), {x, y});
instance->keyReleaseEvent(e);
}
void GlutApplication::staticMouseEvent(int button, int state, int x, int y) {
MouseEvent e(static_cast<MouseEvent::Button>(button), {x, y});
if(state == GLUT_DOWN)

195
src/Magnum/Platform/GlutApplication.h

@ -52,25 +52,41 @@ namespace Platform {
/** @nosubgrouping
@brief GLUT application
Application using GLUT toolkit. Supports keyboard handling for limited subset
of keys, mouse handling with support for changing cursor and mouse tracking and
warping.
Application using GLUT toolkit. Supports keyboard and mouse handling with
support for changing cursor and mouse tracking and warping.
This application library is available only on desktop OpenGL (Linux, Windows,
OS X). It depends on **GLUT** library and is built if `WITH_GLUTAPPLICATION` is
enabled in CMake. To use it, you need to request `%GlutApplication` component
in CMake, add `${MAGNUM_GLUTAPPLICATION_INCLUDE_DIRS}` to include path and link
to `${MAGNUM_GLUTAPPLICATION_LIBRARIES}`. If no other application is requested,
enabled in CMake.
## Bootstrap application
Fully contained base application using @ref GlutApplication along with
CMake setup is available in `base` branch of
[Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap) repository,
download it as [tar.gz](https://github.com/mosra/magnum-bootstrap/archive/base.tar.gz)
or [zip](https://github.com/mosra/magnum-bootstrap/archive/base.zip) file.
After extracting the downloaded archive you can build and run the application
with these four commands:
mkdir build && cd build
cmake ..
cmake --build .
./src/MyApplication # or ./src/Debug/MyApplication
## General usage
In CMake you need to request `%GlutApplication` component, add
`${MAGNUM_GLUTAPPLICATION_INCLUDE_DIRS}` to include path and link to
`${MAGNUM_GLUTAPPLICATION_LIBRARIES}`. If no other application is requested,
you can also use generic `${MAGNUM_APPLICATION_INCLUDE_DIRS}` and
`${MAGNUM_APPLICATION_LIBRARIES}` aliases to simplify porting. See
@ref building and @ref cmake for more information.
@section GlutApplication-usage Usage
You need to implement at least @ref drawEvent() to be able to draw on the
screen. The subclass can be then used directly in `main()` -- see convenience
macro @ref MAGNUM_GLUTAPPLICATION_MAIN(). See @ref platform for more
information.
In C++ code you need to implement at least @ref drawEvent() to be able to draw
on the screen. The subclass can be then used directly in `main()` -- see
convenience macro @ref MAGNUM_GLUTAPPLICATION_MAIN(). See @ref platform for
more information.
@code
class MyApplication: public Platform::GlutApplication {
// implement required methods...
@ -124,7 +140,12 @@ class GlutApplication {
/** @brief Moving is not allowed */
GlutApplication& operator=(GlutApplication&&) = delete;
/** @copydoc Sdl2Application::exec() */
/**
* @brief Execute main loop
* @return Value for returning from `main()`
*
* See @ref MAGNUM_GLUTAPPLICATION_MAIN() for usage information.
*/
int exec() {
glutMainLoop();
return 0;
@ -173,12 +194,7 @@ class GlutApplication {
/** @copydoc Sdl2Application::keyPressEvent() */
virtual void keyPressEvent(KeyEvent& event);
/**
* @brief Key release event
*
* Included only for compatibility with other toolkits, doesn't get
* called at all.
*/
/** @copydoc Sdl2Application::keyReleaseEvent() */
virtual void keyReleaseEvent(KeyEvent& event);
/*@}*/
@ -245,7 +261,11 @@ class GlutApplication {
instance->viewportEvent({x, y});
}
static void staticKeyEvent(int key, int x, int y);
static void staticKeyPressEvent(unsigned char key, int x, int y);
static void staticKeyReleaseEvent(unsigned char key, int x, int y);
static void staticSpecialKeyPressEvent(int key, int x, int y);
static void staticSpecialKeyReleaseEvent(int key, int x, int y);
static void staticMouseEvent(int button, int state, int x, int y);
@ -268,6 +288,26 @@ Double-buffered RGBA window with depth and stencil buffers.
*/
class GlutApplication::Configuration {
public:
/**
* @brief Context flag
*
* @see @ref Flags @ref setFlags()
*/
enum class Flag: int {
Debug = GLUT_DEBUG /**< Create debug context */
};
/**
* @brief Context flags
*
* @see @ref setFlags()
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
typedef Containers::EnumSet<Flag, int, GLUT_DEBUG> Flags;
#else
typedef Containers::EnumSet<Flag, int> Flags;
#endif
/*implicit*/ Configuration();
~Configuration();
@ -299,6 +339,20 @@ class GlutApplication::Configuration {
return *this;
}
/** @brief Context flags */
Flags flags() const { return _flags; }
/**
* @brief Set context flags
* @return Reference to self (for method chaining)
*
* Default is no flag.
*/
Configuration& setFlags(Flags flags) {
_flags = flags;
return *this;
}
/** @brief Context version */
Version version() const { return _version; }
@ -336,8 +390,11 @@ class GlutApplication::Configuration {
Vector2i _size;
Int _sampleCount;
Version _version;
Flags _flags;
};
CORRADE_ENUMSET_OPERATORS(GlutApplication::Configuration::Flags)
/**
@brief Base for input events
@ -395,27 +452,76 @@ class GlutApplication::KeyEvent: public GlutApplication::InputEvent {
*
* @see @ref key()
*/
enum class Key: int {
Up = GLUT_KEY_UP, /**< Up arrow */
Down = GLUT_KEY_DOWN, /**< Down arrow */
Left = GLUT_KEY_LEFT, /**< Left arrow */
Right = GLUT_KEY_RIGHT, /**< Right arrow */
F1 = GLUT_KEY_F1, /**< F1 */
F2 = GLUT_KEY_F2, /**< F2 */
F3 = GLUT_KEY_F3, /**< F3 */
F4 = GLUT_KEY_F4, /**< F4 */
F5 = GLUT_KEY_F5, /**< F5 */
F6 = GLUT_KEY_F6, /**< F6 */
F7 = GLUT_KEY_F7, /**< F7 */
F8 = GLUT_KEY_F8, /**< F8 */
F9 = GLUT_KEY_F9, /**< F9 */
F10 = GLUT_KEY_F10, /**< F10 */
F11 = GLUT_KEY_F11, /**< F11 */
F12 = GLUT_KEY_F12, /**< F12 */
Home = GLUT_KEY_HOME, /**< Home */
End = GLUT_KEY_END, /**< End */
PageUp = GLUT_KEY_PAGE_UP, /**< Page up */
PageDown = GLUT_KEY_PAGE_DOWN /**< Page down */
enum class Key: UnsignedInt {
Esc = '\x1b', /**< Escape */
Up = GLUT_KEY_UP << 16, /**< Up arrow */
Down = GLUT_KEY_DOWN << 16, /**< Down arrow */
Left = GLUT_KEY_LEFT << 16, /**< Left arrow */
Right = GLUT_KEY_RIGHT << 16, /**< Right arrow */
F1 = GLUT_KEY_F1 << 16, /**< F1 */
F2 = GLUT_KEY_F2 << 16, /**< F2 */
F3 = GLUT_KEY_F3 << 16, /**< F3 */
F4 = GLUT_KEY_F4 << 16, /**< F4 */
F5 = GLUT_KEY_F5 << 16, /**< F5 */
F6 = GLUT_KEY_F6 << 16, /**< F6 */
F7 = GLUT_KEY_F7 << 16, /**< F7 */
F8 = GLUT_KEY_F8 << 16, /**< F8 */
F9 = GLUT_KEY_F9 << 16, /**< F9 */
F10 = GLUT_KEY_F10 << 16, /**< F10 */
F11 = GLUT_KEY_F11 << 16, /**< F11 */
F12 = GLUT_KEY_F12 << 16, /**< F12 */
Home = GLUT_KEY_HOME << 16, /**< Home */
End = GLUT_KEY_END << 16, /**< End */
PageUp = GLUT_KEY_PAGE_UP << 16, /**< Page up */
PageDown = GLUT_KEY_PAGE_DOWN << 16, /**< Page down */
Space = ' ', /**< Space */
Comma = ',', /**< Comma */
Period = '.', /**< Period */
Minus = '-', /**< Minus */
Plus = '+', /**< Plus */
Slash = '/', /**< Slash */
Percent = '%', /**< Percent */
Equal = '=', /**< Equal */
Zero = '0', /**< Zero */
One = '1', /**< One */
Two = '2', /**< Two */
Three = '3', /**< Three */
Four = '4', /**< Four */
Five = '5', /**< Five */
Six = '6', /**< Six */
Seven = '7', /**< Seven */
Eight = '8', /**< Eight */
Nine = '9', /**< Nine */
A = 'a', /**< Letter A */
B = 'b', /**< Letter B */
C = 'c', /**< Letter C */
D = 'd', /**< Letter D */
E = 'e', /**< Letter E */
F = 'f', /**< Letter F */
G = 'g', /**< Letter G */
H = 'h', /**< Letter H */
I = 'i', /**< Letter I */
J = 'j', /**< Letter J */
K = 'k', /**< Letter K */
L = 'l', /**< Letter L */
M = 'm', /**< Letter M */
N = 'n', /**< Letter N */
O = 'o', /**< Letter O */
P = 'p', /**< Letter P */
Q = 'q', /**< Letter Q */
R = 'r', /**< Letter R */
S = 's', /**< Letter S */
T = 't', /**< Letter T */
U = 'u', /**< Letter U */
V = 'v', /**< Letter V */
W = 'w', /**< Letter W */
X = 'x', /**< Letter X */
Y = 'y', /**< Letter Y */
Z = 'z' /**< Letter Z */
};
/** @brief Key */
@ -512,9 +618,10 @@ class GlutApplication::MouseMoveEvent: public GlutApplication::InputEvent {
@brief Entry point for GLUT-based applications
@param className Class name
Can be with @ref Magnum::Platform::GlutApplication "Platform::GlutApplication"
subclasses used as equivalent to the following code to achieve better
portability, see @ref portability-applications for more information.
See @ref Magnum::Platform::GlutApplication "Platform::GlutApplication" for
usage information. This macro abstracts out platform-specific entry point code
and is equivalent to the following, see @ref portability-applications for more
information.
@code
int main(int argc, char** argv) {
className app({argc, argv});

27
src/Magnum/Platform/GlxApplication.h

@ -42,18 +42,26 @@ Application using pure X11 and GLX. Supports keyboard and mouse handling.
This application library is available on desktop OpenGL and
@ref MAGNUM_TARGET_DESKTOP_GLES "OpenGL ES emulation on desktop" on Linux. It
depends on **X11** library and is built if `WITH_GLXAPPLICATION` is enabled in
CMake. To use it, you need to request `%GlxApplication` component in CMake, add
CMake.
## Bootstrap application
The usage is very similar to @ref Sdl2Application, for which fully contained
base application along with CMake setup is available, see its documentation for
more information.
## General usage
In CMake you need to request `%GlxApplication` component, add
`${MAGNUM_GLXAPPLICATION_INCLUDE_DIRS}` to include path and link to
`${MAGNUM_GLXAPPLICATION_LIBRARIES}`. If no other application is requested, you
can also use generic `${MAGNUM_APPLICATION_INCLUDE_DIRS}` and
`${MAGNUM_APPLICATION_LIBRARIES}` aliases to simplify porting. See
@ref building and @ref cmake for more information.
@section GlxApplication-usage Usage
You need to implement at least @ref drawEvent() to be able to draw on the
screen. The subclass can be then used directly in `main()` -- see convenience
macro @ref MAGNUM_GLXAPPLICATION_MAIN(). See @ref platform for more
In C++ code you need to implement at least @ref drawEvent() to be able to draw
on the screen. The subclass can be then used directly in `main()` -- see
convenience macro @ref MAGNUM_GLXAPPLICATION_MAIN(). See @ref platform for more
information.
@code
class MyApplication: public Platform::GlxApplication {
@ -88,9 +96,10 @@ class GlxApplication: public AbstractXApplication {
@brief Entry point for GLX-based applications
@param className Class name
Can be used with @ref Magnum::Platform::GlxApplication "Platform::GlxApplication"
subclasses as equivalent to the following code to achieve better portability,
see @ref portability-applications for more information.
See @ref Magnum::Platform::GlxApplication "Platform::GlxApplication" for usage
information. This macro abstracts out platform-specific entry point code and is
equivalent to the following, see @ref portability-applications for more
information.
@code
int main(int argc, char** argv) {
className app({argc, argv});

54
src/Magnum/Platform/Implementation/Egl.cpp

@ -0,0 +1,54 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014
Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is 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 Software.
THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "Egl.h"
namespace Magnum { namespace Platform { namespace Implementation {
const char* eglErrorString(const 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 "EGL_(invalid)";
}
}}}

33
src/Magnum/ImageFormat.h → src/Magnum/Platform/Implementation/Egl.h

@ -1,5 +1,5 @@
#ifndef Magnum_ImageFormat_h
#define Magnum_ImageFormat_h
#ifndef Magnum_Platform_Implementation_Egl_h
#define Magnum_Platform_Implementation_Egl_h
/*
This file is part of Magnum.
@ -25,33 +25,12 @@
DEALINGS IN THE SOFTWARE.
*/
#ifdef MAGNUM_BUILD_DEPRECATED
/** @file
* @brief Enum @ref Magnum::ImageFormat, @ref Magnum::ImageType
* @deprecated Use @ref ColorFormat.h instead.
*/
#endif
#include "Magnum/ColorFormat.h"
#ifdef MAGNUM_BUILD_DEPRECATED
namespace Magnum {
#include <EGL/egl.h>
/**
@copybrief ColorFormat
@deprecated Use @ref Magnum::ColorFormat "ColorFormat" instead.
*/
typedef CORRADE_DEPRECATED("use ColorFormat instead") ColorFormat ImageFormat;
namespace Magnum { namespace Platform { namespace Implementation {
/**
@copybrief ColorType
@deprecated Use @ref Magnum::ColorType "ColorType" instead.
*/
typedef CORRADE_DEPRECATED("use ColorType instead") ColorType ImageType;
const char* eglErrorString(EGLint error);
}
#else
#error this header is available only on deprecated build
#endif
}}}
#endif

42
src/Magnum/Platform/Implementation/EglContextHandler.cpp

@ -32,6 +32,8 @@
#include "Magnum/Context.h"
#include "Magnum/Version.h"
#include "Egl.h"
namespace Magnum { namespace Platform { namespace Implementation {
EglContextHandler::~EglContextHandler() {
@ -44,7 +46,7 @@ VisualId EglContextHandler::getVisualId(EGLNativeDisplayType nativeDisplay) {
/* Initialize */
display = eglGetDisplay(nativeDisplay);
if(!eglInitialize(display, nullptr, nullptr)) {
Error() << "Cannot initialize EGL:" << errorString(eglGetError());
Error() << "Cannot initialize EGL:" << Implementation::eglErrorString(eglGetError());
std::exit(1);
}
@ -54,7 +56,7 @@ VisualId EglContextHandler::getVisualId(EGLNativeDisplayType nativeDisplay) {
EGLenum api = EGL_OPENGL_ES_API;
#endif
if(!eglBindAPI(api)) {
Error() << "Cannot bind EGL API:" << errorString(eglGetError());
Error() << "Cannot bind EGL API:" << Implementation::eglErrorString(eglGetError());
std::exit(1);
}
@ -67,7 +69,7 @@ VisualId EglContextHandler::getVisualId(EGLNativeDisplayType nativeDisplay) {
#ifndef MAGNUM_TARGET_GLES
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
#elif defined(MAGNUM_TARGET_GLES3)
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
#elif defined(MAGNUM_TARGET_GLES2)
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#else
@ -77,7 +79,7 @@ VisualId EglContextHandler::getVisualId(EGLNativeDisplayType nativeDisplay) {
};
EGLint configCount;
if(!eglChooseConfig(display, attribs, &config, 1, &configCount)) {
Error() << "Cannot get EGL visual config:" << errorString(eglGetError());
Error() << "Cannot get EGL visual config:" << Implementation::eglErrorString(eglGetError());
std::exit(1);
}
@ -89,7 +91,7 @@ VisualId EglContextHandler::getVisualId(EGLNativeDisplayType nativeDisplay) {
/* Get visual ID */
EGLint visualId;
if(!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualId)) {
Error() << "Cannot get native visual ID:" << errorString(eglGetError());
Error() << "Cannot get native visual ID:" << Implementation::eglErrorString(eglGetError());
std::exit(1);
}
@ -140,40 +142,16 @@ void EglContextHandler::createContext(const AbstractXApplication::Configuration&
}
#endif
if(!eglCreateContext(display, config, EGL_NO_CONTEXT, attributes)) {
Error() << "Cannot create EGL context:" << errorString(eglGetError());
if(!(context = eglCreateContext(display, config, EGL_NO_CONTEXT, attributes))) {
Error() << "Cannot create EGL context:" << Implementation::eglErrorString(eglGetError());
std::exit(1);
}
if(!(surface = eglCreateWindowSurface(display, config, window, nullptr))) {
Error() << "Cannot create window surface:" << errorString(eglGetError());
Error() << "Cannot create window surface:" << Implementation::eglErrorString(eglGetError());
std::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 {};
}
}}}

3
src/Magnum/Platform/Implementation/EglContextHandler.h

@ -31,6 +31,7 @@
#include <EGL/egl.h>
/* undef Xlib nonsense to avoid conflicts */
#undef None
#undef Complex
#include <Corrade/compatibility.h>
@ -71,8 +72,6 @@ class EglContextHandler: public AbstractContextHandler<AbstractXApplication::Con
}
private:
const char* errorString(EGLint error);
EGLDisplay display;
EGLConfig config;
EGLSurface surface;

117
src/Magnum/Platform/NaClApplication.h

@ -52,6 +52,10 @@ namespace pp {
class Fullscreen;
}
#ifndef CORRADE_TARGET_NACL
#error This header is available only on Google Chrome Native Client
#endif
namespace Magnum { namespace Platform {
/** @nosubgrouping
@ -60,19 +64,68 @@ namespace Magnum { namespace Platform {
Application running in [Google Chrome Native Client](https://developers.google.com/native-client/).
Supports keyboard and mouse handling.
This application library is available only in @ref CORRADE_TARGET_NACL "Native Client".
It is built if `WITH_NACLAPPLICATION` is enabled in CMake. To use it, you need
to request `%NaClApplication` component in CMake, add
This application library is available only in
@ref CORRADE_TARGET_NACL "Google Chrome Native Client", see respective sections
in @ref building-corrade-cross-nacl "Corrade's" and @ref building-cross-nacl "Magnum's"
building documentation. It is built if `WITH_NACLAPPLICATION` is enabled in
CMake.
## Bootstrap application
Fully contained base application using @ref GlutApplication for desktop build
and @ref NaClApplication for Native Client build along with full HTML markup
and CMake setup is available in `base-nacl` branch of
[Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap) repository,
download it as [tar.gz](https://github.com/mosra/magnum-bootstrap/archive/base-nacl.tar.gz)
or [zip](https://github.com/mosra/magnum-bootstrap/archive/base-nacl.zip) file.
After extracting the downloaded archive, you can do the desktop build in the
same way as with @ref GlutApplication. For the Native Client build you also
need to put the contents of toolchains repository from https://github.com/mosra/toolchains
in `toolchains/` subdirectory. Don't forget to adapt `NACL_PREFIX` variable in
`toolchains/generic/NaCl-newlib-x86-32.cmake` and
`toolchains/generic/NaCl-newlib-x86-64.cmake` to path where your SDK is
installed. Default is `/usr/nacl`. You may need to adapt also
`NACL_TOOLCHAIN_PATH` so CMake is able to find the compiler.
Then create build directories for x86-32 and x86-64 and run `cmake` and
build/install commands in them. The toolchains need access to the platform
file, so be sure to properly set **absolute** path to `toolchains/modules/`
directory containing `Platform/NaCl.cmake`. Set `CMAKE_INSTALL_PREFIX` to
location of your webserver to have the files installed in proper location (e.g.
`/srv/http/nacl`).
mkdir build-nacl-x86-32 && cd build-nacl-x86-32
cmake .. \
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/NaCl-newlib-x86-32.cmake" \
-DCMAKE_INSTALL_PREFIX=/srv/http/nacl
cmake --build .
cmake --build . --target install
mkdir build-nacl-x86-64 && cd build-nacl-x86-64
cmake .. \
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/NaCl-newlib-x86-64.cmake" \
-DCMAKE_INSTALL_PREFIX=/srv/http/nacl
cmake --build .
cmake --build . --target install
You can then open `MyApplication` through your webserver in Chrome (e.g.
`http://localhost/nacl/MyApplication.html`).
## General usage
For CMake you need to copy `FindOpenGLES2.cmake` from `modules/` directory in
%Magnum source to `modules/` dir in your project (so it is able to find OpenGL
ES). Request `%NaClApplication` component, add
`${MAGNUM_NACLAPPLICATION_INCLUDE_DIRS}` to include path and link to
`${MAGNUM_NACLAPPLICATION_LIBRARIES}`. If no other application is requested,
you can also use generic `${MAGNUM_APPLICATION_INCLUDE_DIRS}` and
`${MAGNUM_APPLICATION_LIBRARIES}` aliases to simplify porting. See
@ref building and @ref cmake for more information.
@section NaClApplication-usage Usage
You need to implement at least @ref drawEvent() to be able to draw on the
screen. The subclass must be then registered to NaCl API using
In C++ code you need to implement at least @ref drawEvent() to be able to draw
on the screen. The subclass must be then registered to NaCl API using
@ref MAGNUM_NACLAPPLICATION_MAIN() macro. See @ref platform for more
information.
@code
@ -86,13 +139,14 @@ If no other application header is included, this class is also aliased to
`Platform::Application` and the macro is aliased to `MAGNUM_APPLICATION_MAIN()`
to simplify porting.
@section NaClApplication-html HTML markup and NMF file
### HTML markup and NMF file
You need to provide HTML markup for your application. Template one is below,
you can modify it to your liking. The markup references two files,
`NaClApplication.js` and `WebApplication.css`, both are in `Platform/`
directory in the source tree and are also installed into `share/magnum/` inside
your NaCl toolchain. Change `&lt;application&gt;` to name of your executable.
You need to provide HTML markup for your application. Template one is below or
in the bootstrap application, you can modify it to your liking. The markup
references two files, `NaClApplication.js` and `WebApplication.css`, both are
in `Platform/` directory in the source tree and are also installed into
`share/magnum/` inside your NaCl toolchain. Change `&lt;application&gt;` to
name of your executable.
@code
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
@ -135,9 +189,9 @@ If you target @ref CORRADE_TARGET_NACL_GLIBC "glibc", you need to specify also
all additional dependencies. See [Native Client](https://developers.google.com/native-client/)
documentation for more information.
@section NaClApplication-console Redirecting output to Chrome's JavaScript console
## Redirecting output to Chrome's JavaScript console
The application redirects @ref Corrade::Utility::Debug "Debug",
The application by default redirects @ref Corrade::Utility::Debug "Debug",
@ref Corrade::Utility::Warning "Warning" and @ref Corrade::Utility::Error "Error"
output to JavaScript console. See also @ref Corrade::Utility::NaClConsoleStreamBuffer
for more information.
@ -347,7 +401,7 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public
@brief %Configuration
Double-buffered RGBA canvas with depth and stencil buffers.
@see @ref NaClApplication(), @ref createContext()
@see @ref NaClApplication(), @ref createContext(), @ref tryCreateContext()
*/
class NaClApplication::Configuration {
public:
@ -428,33 +482,6 @@ class NaClApplication::InputEvent {
Ctrl = PP_INPUTEVENT_MODIFIER_CONTROLKEY, /**< Ctrl */
Alt = PP_INPUTEVENT_MODIFIER_ALTKEY, /**< Alt */
Meta = PP_INPUTEVENT_MODIFIER_METAKEY, /**< Meta */
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief Button::Left
* @deprecated Use @ref Magnum::Platform::NaClApplication::InputEvent::buttons() "buttons()"
* and @ref Magnum::Platform::NaClApplication::InputEvent::Button::Left "Button::Left"
* instead.
*/
LeftButton = PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN,
/**
* @copybrief Button::Middle
* @deprecated Use @ref Magnum::Platform::NaClApplication::InputEvent::buttons() "buttons()"
* and @ref Magnum::Platform::NaClApplication::InputEvent::Button::Middle "Button::Middle"
* instead.
*/
MiddleButton = PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN,
/**
* @copybrief Button::Right
* @deprecated Use @ref Magnum::Platform::NaClApplication::InputEvent::buttons() "buttons()"
* and @ref Magnum::Platform::NaClApplication::InputEvent::Button::Right "Button::Right"
* instead.
*/
RightButton = PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN,
#endif
CapsLock = PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY, /**< Caps lock */
NumLock = PP_INPUTEVENT_MODIFIER_NUMLOCKKEY /**< Num lock */
};
@ -718,7 +745,9 @@ namespace Implementation {
@brief Entry point for NaCl application
@param application Application class name
See @ref Magnum::Platform::NaClApplication "Platform::NaClApplication" and
See @ref Magnum::Platform::NaClApplication "Platform::NaClApplication" for
usage information. This macro abstracts out platform-specific entry point code
(the classic `main()` function cannot be used in NaCl). See
@ref portability-applications for more information. When no other application
header is included this macro is also aliased to `MAGNUM_APPLICATION_MAIN()`.
*/

5
src/Magnum/Platform/Sdl2Application.cpp

@ -115,6 +115,11 @@ bool Sdl2Application::tryCreateContext(const Configuration& configuration) {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, configuration.sampleCount() > 1 ? 1 : 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, configuration.sampleCount());
#ifndef CORRADE_TARGET_EMSCRIPTEN
/* Context flags */
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, int(configuration.flags()));
#endif
/* Flags: if not hidden, set as shown */
Uint32 windowFlags(configuration.windowFlags());
if(!(configuration.windowFlags() & Configuration::WindowFlag::Hidden)) windowFlags |= SDL_WINDOW_SHOWN;

198
src/Magnum/Platform/Sdl2Application.h

@ -46,10 +46,6 @@
#include "Magnum/Version.h"
#endif
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Utility/Macros.h>
#endif
namespace Magnum {
class Context;
@ -63,21 +59,70 @@ Application using [Simple DirectMedia Layer](http://www.libsdl.org/) toolkit.
Supports keyboard and mouse handling.
This application library is in theory available for all platforms for which
SDL2 is ported (thus also @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten", but not
@ref CORRADE_TARGET_NACL "NaCl"). It depends on **SDL2** library (Emscripten
has it built in) and is built if `WITH_SDL2APPLICATION` is enabled in CMake. To
use it, you need to copy `FindSDL2.cmake` from `modules/` directory in %Magnum
source to `modules/` dir in your project (so CMake is able to find SDL2),
request `%Sdl2Application` component in CMake, add
`${MAGNUM_SDL2APPLICATION_INCLUDE_DIRS}` to include path and link to
`${MAGNUM_SDL2APPLICATION_LIBRARIES}`. If no other application is requested,
you can also use generic `${MAGNUM_APPLICATION_INCLUDE_DIRS}` and
`${MAGNUM_APPLICATION_LIBRARIES}` aliases to simplify porting. See
SDL2 is ported (thus also @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten", see
respective sections in @ref building-corrade-cross-emscripten "Corrade's" and
@ref building-cross-emscripten "Magnum's" building documentation). It depends
on **SDL2** library (Emscripten has it built in) and is built if
`WITH_SDL2APPLICATION` is enabled in CMake.
## Bootstrap application
Fully contained base application using @ref Sdl2Application along with
CMake setup is available in `base-sdl2` branch of
[Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap) repository,
download it as [tar.gz](https://github.com/mosra/magnum-bootstrap/archive/base-sdl2.tar.gz)
or [zip](https://github.com/mosra/magnum-bootstrap/archive/base-sdl2.zip) file.
After extracting the downloaded archive you can build and run the application
with these four commands:
mkdir build && cd build
cmake ..
cmake --build .
./src/MyApplication # or ./src/Debug/MyApplication
## Bootstrap application for Emscripten
Fully contained base application using @ref Sdl2Application for both desktop
and Emscripten build along with full HTML markup and CMake setup is available
in `base-emscripten` branch of [Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap)
repository, download it as [tar.gz](https://github.com/mosra/magnum-bootstrap/archive/base-emscripten.tar.gz)
or [zip](https://github.com/mosra/magnum-bootstrap/archive/base-emscripten.zip)
file. After extracting the downloaded archive, you can do the desktop build in
the same way as above. For the Emscripten build you also need to put the
contents of toolchains repository from https://github.com/mosra/toolchains
in `toolchains/` subdirectory. Don't forget to adapt `EMSCRIPTEN_PREFIX`
variable in `toolchains/generic/Emscripten.cmake` to path where Emscripten is
installed. Default is `/usr/emscripten`.
Then create build directory and run `cmake` and build/install commands in it.
The toolchain needs access to its platform file, so be sure to properly set
**absolute** path to `toolchains/modules/` directory containing `Platform/Emscripten.cmake`.
Set `CMAKE_INSTALL_PREFIX` to have the files installed in proper location (a
webserver, e.g. `/srv/http/emscripten`).
mkdir build-emscripten && cd build-emscripten
cmake .. \
-DCMAKE_MODULE_PATH="/absolute/path/to/toolchains/modules" \
-DCMAKE_TOOLCHAIN_FILE="../toolchains/generic/Emscripten.cmake"
-DCMAKE_INSTALL_PREFIX=/srv/http/emscripten
cmake --build .
cmake --build . --target install
You can then open `MyApplication.html` in Chrome or Firefox (through webserver,
e.g. `http://localhost/emscripten/MyApplication.html`).
## General usage
For CMake you need to copy `FindSDL2.cmake` from `modules/` directory in
%Magnum source to `modules/` dir in your project (so it is able to find SDL2).
In case of Emscripten you need also `FindOpenGLES2.cmake`. Request
`%Sdl2Application` component, add `${MAGNUM_SDL2APPLICATION_INCLUDE_DIRS}`
to include path and link to `${MAGNUM_SDL2APPLICATION_LIBRARIES}`. If no other
application is requested, you can also use generic `${MAGNUM_APPLICATION_INCLUDE_DIRS}`
and `${MAGNUM_APPLICATION_LIBRARIES}` aliases to simplify porting. See
@ref building and @ref cmake for more information.
@section Sdl2Application-usage Usage
You need to implement at least @ref drawEvent() to be able to draw on the
In C++ code you need to implement at least @ref drawEvent() to be able to draw on the
screen. The subclass can be then used directly in `main()` -- see convenience
macro @ref MAGNUM_SDL2APPLICATION_MAIN(). See @ref platform for more
information.
@ -92,14 +137,15 @@ If no other application header is included, this class is also aliased to
`Platform::Application` and the macro is aliased to `MAGNUM_APPLICATION_MAIN()`
to simplify porting.
@section Sdl2Application-html Usage with Emscripten
### Usage with Emscripten
If you are targetting @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten", you need to
provide HTML markup for your application. Template one is below, you can modify
it to your liking. The markup references two files, `EmscriptenApplication.js`
and `WebApplication.css`, both are in `Platform/` directory in the source tree
and are also installed into `share/magnum/` inside your Emscripten toolchain.
Change `&lt;application&gt;` to name of your executable.
If you are targetting Emscripten, you need to provide HTML markup for your
application. Template one is below or in the bootstrap application, you can
modify it to your liking. The markup references two files,
`EmscriptenApplication.js` and `WebApplication.css`, both are in `Platform/`
directory in the source tree and are also installed into `share/magnum/` inside
your Emscripten toolchain. Change `&lt;application&gt;` to name of your
executable.
@code
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
@ -127,9 +173,11 @@ file contains event listeners which print loading status on the page. The
status displayed in the remaining two `&lt;div&gt;`s, if they are available.
The CSS file contains rudimentary style to avoid eye bleeding.
The application redirects @ref Corrade::Utility::Debug "Debug",
@ref Corrade::Utility::Warning "Warning" and @ref Corrade::Utility::Error "Error"
output to JavaScript console.
## Redirecting output to JavaScript console
The application redirects all output (thus also @ref Corrade::Utility::Debug "Debug",
@ref Corrade::Utility::Warning "Warning" and @ref Corrade::Utility::Error "Error")
to JavaScript console.
*/
class Sdl2Application {
public:
@ -189,7 +237,9 @@ class Sdl2Application {
/**
* @brief Execute main loop
* @return Value for returning from `main()`.
* @return Value for returning from `main()`
*
* See @ref MAGNUM_SDL2APPLICATION_MAIN() for usage information.
*/
int exec();
@ -237,7 +287,8 @@ class Sdl2Application {
* @brief Redraw immediately
*
* Marks the window for redrawing, resulting in call to @ref drawEvent()
* in the next iteration.
* in the next iteration. You can call it from @ref drawEvent() itself
* to redraw immediately without waiting for user input.
*/
void redraw() { flags |= Flag::Redraw; }
@ -380,6 +431,35 @@ depth buffer.
*/
class Sdl2Application::Configuration {
public:
#ifndef CORRADE_TARGET_EMSCRIPTEN
/**
* @brief Context flag
*
* @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten".
* @see @ref Flags @ref setFlags()
* @todo re-enable when Emscripten has proper SDL2 support
*/
enum class Flag: int {
Debug = SDL_GL_CONTEXT_DEBUG_FLAG, /**< Create debug context */
/** Create context with robust access */
RobustAccess = SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG
};
/**
* @brief Context flags
*
* @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten".
* @see @ref setFlags()
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
typedef Containers::EnumSet<Flag, int, SDL_GL_CONTEXT_DEBUG_FLAG|
SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG> Flags;
#else
typedef Containers::EnumSet<Flag, int> Flags;
#endif
#endif
/**
* @brief Window flag
*
@ -394,14 +474,6 @@ class Sdl2Application::Configuration {
MouseLocked = SDL_WINDOW_INPUT_GRABBED /**< Window with mouse locked */
};
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief WindowFlag
* @deprecated Use @ref Magnum::Platform::Sdl2Application::Configuration::WindowFlag "WindowFlag" instead.
*/
typedef CORRADE_DEPRECATED("use WindowFlag instead") WindowFlag Flag;
#endif
/**
* @brief Window flags
*
@ -415,14 +487,6 @@ class Sdl2Application::Configuration {
typedef Containers::EnumSet<WindowFlag, Uint32> WindowFlags;
#endif
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief WindowFlags
* @deprecated Use @ref Magnum::Platform::Sdl2Application::Configuration::WindowFlags "WindowFlags" instead.
*/
typedef CORRADE_DEPRECATED("use WindowFlags instead") WindowFlags Flags;
#endif
/*implicit*/ Configuration();
~Configuration();
@ -470,16 +534,6 @@ class Sdl2Application::Configuration {
/** @brief Window flags */
WindowFlags windowFlags() const { return _windowFlags; }
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copybrief windowFlags()
* @deprecated Use @ref Magnum::Platform::Sdl2Application::Configuration::windowFlags() "windowFlags()" instead.
*/
CORRADE_DEPRECATED("use windowFlags() instead") WindowFlags flags() const {
return windowFlags();
}
#endif
/**
* @brief Set window flags
* @return Reference to self (for method chaining)
@ -491,17 +545,26 @@ class Sdl2Application::Configuration {
return *this;
}
#ifdef MAGNUM_BUILD_DEPRECATED
#ifndef CORRADE_TARGET_EMSCRIPTEN
/**
* @brief Context flags
*
* @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten".
*/
Flags flags() const { return _flags; }
/**
* @copybrief setWindowFlags()
* @deprecated Use @ref Magnum::Platform::Sdl2Application::Configuration::setWindowFlags "setWindowFlags()" instead.
* @brief Set context flags
* @return Reference to self (for method chaining)
*
* Default is no flag.
* @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten".
*/
CORRADE_DEPRECATED("use setWindowFlags() instead") Configuration& setFlags(WindowFlags flags) {
return setWindowFlags(flags);
Configuration& setFlags(Flags flags) {
_flags = flags;
return *this;
}
#endif
#ifndef CORRADE_TARGET_EMSCRIPTEN
/**
* @brief Context version
*
@ -553,9 +616,13 @@ class Sdl2Application::Configuration {
Int _sampleCount;
#ifndef CORRADE_TARGET_EMSCRIPTEN
Version _version;
Flags _flags;
#endif
};
#ifndef CORRADE_TARGET_EMSCRIPTEN
CORRADE_ENUMSET_OPERATORS(Sdl2Application::Configuration::Flags)
#endif
CORRADE_ENUMSET_OPERATORS(Sdl2Application::Configuration::WindowFlags)
/**
@ -841,9 +908,10 @@ class Sdl2Application::MouseMoveEvent: public Sdl2Application::InputEvent {
@brief Entry point for SDL2-based applications
@param className Class name
Can be used with @ref Magnum::Platform::Sdl2Application "Platform::Sdl2Application"
subclasses as equivalent to the following code to achieve better portability,
see @ref portability-applications for more information.
See @ref Magnum::Platform::Sdl2Application "Platform::Sdl2Application" for
usage information. This macro abstracts out platform-specific entry point code
and is equivalent to the following, see @ref portability-applications for more
information.
@code
int main(int argc, char** argv) {
className app({argc, argv});

41
src/Magnum/Platform/WindowlessGlxApplication.h

@ -53,16 +53,33 @@ Application for offscreen rendering using pure X11 and GLX.
This application library is available on desktop OpenGL and
@ref MAGNUM_TARGET_DESKTOP_GLES "OpenGL ES emulation on desktop" on Linux. It
depends on **X11** library and is built if `WITH_WINDOWLESSGLXAPPLICATION` is
enabled in CMake. To use it, you need to request `%WindowlessGlxApplication`
component in CMake, add `${MAGNUM_WINDOWLESSGLXAPPLICATION_INCLUDE_DIRS}` to
include path and link to `${MAGNUM_WINDOWLESSGLXAPPLICATION_LIBRARIES}`. If no
other windowless application is requested, you can also use generic
enabled in CMake.
## Bootstrap application
Fully contained windowless application using @ref WindowlessGlxApplication
along with CMake setup is available in `base-windowless` branch of
[Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap)
repository, download it as [tar.gz](https://github.com/mosra/magnum-bootstrap/archive/base-windowless.tar.gz)
or [zip](https://github.com/mosra/magnum-bootstrap/archive/base-windowless.zip)
file. After extracting the downloaded archive you can build and run the
application with these four commands:
mkdir build && cd build
cmake ..
cmake --build .
./src/MyApplication # or ./src/Debug/MyApplication
## General usage
In CMake you need to request `%WindowlessGlxApplication` component, add
`${MAGNUM_WINDOWLESSGLXAPPLICATION_INCLUDE_DIRS}` to include path and link to
`${MAGNUM_WINDOWLESSGLXAPPLICATION_LIBRARIES}`. If no other windowless
application is requested, you can also use generic
`${MAGNUM_WINDOWLESSAPPLICATION_INCLUDE_DIRS}` and
`${MAGNUM_WINDOWLESSAPPLICATION_LIBRARIES}` aliases to simplify porting. See
@ref building and @ref cmake for more information.
@section WindowlessGlxApplication-usage Usage
Place your code into @ref exec(). The subclass can be then used directly in
`main()` -- see convenience macro @ref MAGNUM_WINDOWLESSGLXAPPLICATION_MAIN().
See @ref platform for more information.
@ -117,7 +134,10 @@ class WindowlessGlxApplication {
/**
* @brief Execute application
* @return Value for returning from `main()`.
* @return Value for returning from `main()`
*
* See @ref MAGNUM_WINDOWLESSGLXAPPLICATION_MAIN() for usage
* information.
*/
virtual int exec() = 0;
@ -161,9 +181,10 @@ class WindowlessGlxApplication::Configuration {
@brief Entry point for windowless GLX application
@param className Class name
Can be used with @ref Magnum::Platform::WindowlessGlxApplication "Platform::WindowlessGlxApplication"
subclasses as equivalent to the following code to achieve better portability,
see @ref portability-applications for more information.
See @ref Magnum::Platform::WindowlessGlxApplication "Platform::WindowlessGlxApplication"
for usage information. This macro abstracts out platform-specific entry point
code and is equivalent to the following, see @ref portability-applications for
more information.
@code
int main(int argc, char** argv) {
className app({argc, argv});

41
src/Magnum/Platform/WindowlessNaClApplication.h

@ -52,9 +52,20 @@ namespace Magnum { namespace Platform {
Application for offscreen rendering running in
[Google Chrome Native Client](https://developers.google.com/native-client/).
This application library is available only in @ref CORRADE_TARGET_NACL "Native Client".
It is built if `WITH_WINDOWLESSNACLAPPLICATION` is enabled in CMake. To use it,
you need to request `%WindowlessNaClApplication` component in CMake, add
This application library is available only in @ref CORRADE_TARGET_NACL "Native Client",
see respective sections in @ref building-corrade-cross-nacl "Corrade's" and
@ref building-cross-nacl "Magnum's" building documentation. It is built if
`WITH_WINDOWLESSNACLAPPLICATION` is enabled in CMake.
## Bootstrap application
The usage is very similar to @ref NaClApplication, for which fully contained
base application along with CMake setup is available, see its documentation for
more information.
## General Usage
In CMake you need to request `%WindowlessNaClApplication` component, add
`${MAGNUM_WINDOWLESSNACLAPPLICATION_INCLUDE_DIRS}` to include path and link to
`${MAGNUM_WINDOWLESSNACLAPPLICATION_LIBRARIES}`. If no other windowless
application is requested, you can also use generic
@ -62,8 +73,6 @@ application is requested, you can also use generic
`${MAGNUM_WINDOWLESSAPPLICATION_LIBRARIES}` aliases to simplify porting. See
@ref building and @ref cmake for more information.
@section WindowlessNaClApplication-usage Usage
Place your code into @ref exec(). The subclass must be then registered to NaCl
API using @ref MAGNUM_WINDOWLESSNACLAPPLICATION_MAIN() macro. See @ref platform
for more information.
@ -78,7 +87,7 @@ If no other application header is included, this class is also aliased to
`Platform::WindowlessApplication` and the macro is aliased to
`MAGNUM_WINDOWLESSAPPLICATION_MAIN()` to simplify porting.
@section WindowlessNaClApplication-html HTML markup and NMF file
### HTML markup and NMF file
You need to provide HTML markup containing `&lt;embed&gt;` pointing to `*.nmf`
file describing the application. See @ref NaClApplication for more information.
@ -86,9 +95,9 @@ You may want to hide the `&lt;embed&gt;` (for example using CSS
`visibility: hidden;`), as it probably won't display anything to default
framebuffer.
@section WindowlessNaClApplication-console Redirecting output to Chrome's JavaScript console
## Redirecting output to Chrome's JavaScript console
The application redirects @ref Corrade::Utility::Debug "Debug",
The application by default redirects @ref Corrade::Utility::Debug "Debug",
@ref Corrade::Utility::Warning "Warning" and @ref Corrade::Utility::Error "Error"
output to JavaScript console. See also @ref Corrade::Utility::NaClConsoleStreamBuffer
for more information.
@ -128,9 +137,17 @@ class WindowlessNaClApplication: public pp::Instance, public pp::Graphics3DClien
/** @brief Moving is not allowed */
WindowlessNaClApplication& operator=(WindowlessNaClApplication&&) = delete;
#ifdef DOXYGEN_GENERATING_OUTPUT
protected:
#else
private:
#endif
/**
* @brief Execute application
* @return Value for returning from `main()`.
* @return Value for returning from `main()`
*
* This function is not meant to be called from user code, see
* @ref MAGNUM_WINDOWLESSNACLAPPLICATION_MAIN() for usage information.
*/
virtual int exec() = 0;
@ -194,8 +211,10 @@ namespace Implementation {
@param application Application class name
See @ref Magnum::Platform::WindowlessNaClApplication "Platform::WindowlessNaClApplication"
and @ref portability-applications for more information. When no other
windowless application header is included this macro is also aliased to
for usage information. This macro abstracts out platform-specific entry point
code (the classic `main()` function cannot be used in NaCl). See
@ref portability-applications for more information. When no other windowless
application header is included this macro is also aliased to
`MAGNUM_WINDOWLESSAPPLICATION_MAIN()`.
*/
/* look at that insane placement of __attribute__. WTF. */

36
src/Magnum/Platform/XEglApplication.h

@ -41,21 +41,28 @@ Application using pure X11 and EGL. Supports keyboard and mouse handling.
This application library is available on both desktop OpenGL and
@ref MAGNUM_TARGET_GLES "OpenGL ES" on Linux. It depends on **X11** and **EGL**
libraries and is built if `WITH_XEGLAPPLICATION` is enabled in CMake. To use
it, you need to copy `FindEGL.cmake` from `modules/` directory in %Magnum
source to `modules/` dir in your project (so CMake is able to find EGL),
request `%XEglApplication` component in CMake, add `${MAGNUM_XEGLAPPLICATION_INCLUDE_DIRS}`
to include path and link to `${MAGNUM_XEGLAPPLICATION_LIBRARIES}`. If no other
libraries and is built if `WITH_XEGLAPPLICATION` is enabled in CMake.
## Bootstrap application
The usage is very similar to @ref Sdl2Application, for which fully contained
base application along with CMake setup is available, see its documentation for
more information.
## General usage
For CMake you need to copy `FindEGL.cmake` from `modules/` directory in %Magnum
source to `modules/` dir in your project (so it is able to find EGL), request
`%XEglApplication` component, add `${MAGNUM_XEGLAPPLICATION_INCLUDE_DIRS}` to
include path and link to `${MAGNUM_XEGLAPPLICATION_LIBRARIES}`. If no other
application is requested, you can also use generic `${MAGNUM_APPLICATION_INCLUDE_DIRS}`
and `${MAGNUM_APPLICATION_LIBRARIES}` aliases to simplify porting. See
@ref building and @ref cmake for more information.
@section XEglApplication-usage Usage
You need to implement at least @ref drawEvent() to be able to draw on the
screen. The subclass can be then used directly in `main()` -- see convenience
macro @ref MAGNUM_XEGLAPPLICATION_MAIN(). See @ref platform for more
information.
In C++ code you need to implement at least @ref drawEvent() to be able to draw
on the screen. The subclass can be then used directly in `main()` -- see
convenience macro @ref MAGNUM_XEGLAPPLICATION_MAIN(). See @ref platform for
more information.
@code
class MyApplication: public Platform::XEglApplication {
// implement required methods...
@ -89,9 +96,10 @@ class XEglApplication: public AbstractXApplication {
@brief Entry point for X/EGL-based applications
@param className Class name
Can be used with @ref Magnum::Platform::XEglApplication "Platform::XEglApplication"
subclasses as equivalent to the following code to achieve better portability,
see @ref portability-applications for more information.
See @ref Magnum::Platform::XEglApplication "Platform::XEglApplication" for
usage information. This macro abstracts out platform-specific entry point code
and is equivalent to the following, see @ref portability-applications for more
information.
@code
int main(int argc, char** argv) {
className app({argc, argv});

26
src/Magnum/Platform/magnum-info.cpp

@ -61,8 +61,8 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat
Utility::Arguments args;
args.addBooleanOption("all-extensions")
.setHelp("all-extensions", "show extensions also for fully supported versions")
.addBooleanOption("no-limits")
.setHelp("no-limits", "don't display limits and implementation-defined values")
.addBooleanOption("limits")
.setHelp("limits", "display also limits and implementation-defined values")
.setHelp("Displays information about Magnum engine and OpenGL capabilities.");
/**
@ -73,11 +73,6 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat
args.parse(arguments.argc, arguments.argv);
#endif
/* Create context after parsing arguments, so the help can be displayed
without creating context */
createContext();
Context* c = Context::current();
/* Pass debug output as messages to JavaScript */
#ifdef CORRADE_TARGET_NACL
Utility::NaClMessageStreamBuffer buffer(this);
@ -142,12 +137,27 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat
#ifdef MAGNUM_TARGET_DESKTOP_GLES
Debug() << " MAGNUM_TARGET_DESKTOP_GLES";
#endif
#ifdef MAGNUM_TARGET_WEBGL
Debug() << " MAGNUM_TARGET_WEBGL";
#endif
Debug() << "";
/* Create context here, so the context creation info is displayed at proper
place */
createContext();
Context* c = Context::current();
Debug() << "Vendor:" << c->vendorString();
Debug() << "Renderer:" << c->rendererString();
Debug() << "OpenGL version:" << c->version() << '(' + c->versionString() + ')';
Debug() << "Context flags:";
#ifndef MAGNUM_TARGET_GLES
for(const auto flag: {Context::Flag::Debug, Context::Flag::RobustAccess})
#else
for(const auto flag: {Context::Flag::Debug})
#endif
if(c->flags() & flag) Debug() << " " << flag;
Debug() << "Supported GLSL versions:";
const std::vector<std::string> shadingLanguageVersions = c->shadingLanguageVersionStrings();
for(auto it = shadingLanguageVersions.begin(); it != shadingLanguageVersions.end(); ++it)
@ -204,7 +214,7 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat
Debug() << "";
}
if(args.isSet("no-limits")) return;
if(!args.isSet("limits")) return;
/* Limits and implementation-defined values */
#define _h(val) Debug() << "\n " << Extensions::GL::val::string() + std::string(":");

1
src/Magnum/Primitives/CMakeLists.txt

@ -53,6 +53,7 @@ set(MagnumPrimitives_HEADERS
visibility.h)
add_library(MagnumPrimitives ${SHARED_OR_STATIC} ${MagnumPrimitives_SRCS})
set_target_properties(MagnumPrimitives PROPERTIES DEBUG_POSTFIX "-d")
if(BUILD_STATIC_PIC)
# TODO: CMake 2.8.9 has this as POSITION_INDEPENDENT_CODE property
set_target_properties(MagnumPrimitives PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")

2
src/Magnum/Query.cpp

@ -123,6 +123,7 @@ template<> Int AbstractQuery::result<Int>() {
return result;
}
#ifndef MAGNUM_TARGET_WEBGL
template<> UnsignedLong AbstractQuery::result<UnsignedLong>() {
CORRADE_ASSERT(!target, "AbstractQuery::result(): the query is currently running", {});
@ -151,6 +152,7 @@ template<> Long AbstractQuery::result<Long>() {
return result;
}
#endif
#endif
void AbstractQuery::begin(GLenum target) {
CORRADE_ASSERT(!this->target, "AbstractQuery::begin(): the query is already running", );

8
src/Magnum/Query.h

@ -107,6 +107,8 @@ class MAGNUM_EXPORT AbstractQuery: public AbstractObject {
* @requires_es_extension %Extension @es_extension{EXT,disjoint_timer_query}
* for result types @ref Magnum::Int "Int", @ref Magnum::UnsignedLong "UnsignedLong"
* @ref Magnum::Long "Long".
* @attention @ref Magnum::UnsignedLong "UnsignedLong" and @ref Magnum::Long "Long"
* result type is not available in @ref MAGNUM_TARGET_WEBGL "WebGL".
*/
template<class T> T result();
@ -147,16 +149,18 @@ class MAGNUM_EXPORT AbstractQuery: public AbstractObject {
template<> bool MAGNUM_EXPORT AbstractQuery::result<bool>();
template<> UnsignedInt MAGNUM_EXPORT AbstractQuery::result<UnsignedInt>();
template<> Int MAGNUM_EXPORT AbstractQuery::result<Int>();
#ifndef MAGNUM_TARGET_WEBGL
template<> UnsignedLong MAGNUM_EXPORT AbstractQuery::result<UnsignedLong>();
template<> Long MAGNUM_EXPORT AbstractQuery::result<Long>();
#endif
#endif
#ifndef MAGNUM_TARGET_GLES2
/**
@brief Query for primitives and elapsed time
@brief Query for primitives
Queries count of generated primitives from vertex shader, geometry shader or
transform feedback and elapsed time. Example usage:
transform feedback. Example usage:
@code
PrimitiveQuery q;

53
src/Magnum/RectangleTexture.h

@ -86,8 +86,8 @@ class RectangleTexture: public AbstractTexture {
*
* Sets filter used when the object pixel size is smaller than the
* texture size. If @extension{EXT,direct_state_access} is not
* available, the texture is bound to some layer before the operation.
* Initial value is @ref Sampler::Filter::Linear.
* available, the texture is bound to some texture unit before the
* operation. Initial value is @ref Sampler::Filter::Linear.
* @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}
@ -103,20 +103,17 @@ class RectangleTexture: public AbstractTexture {
return *this;
}
#ifndef MAGNUM_TARGET_GLES
/**
* @brief %Image size
*
* The result is not cached in any way. If
* @extension{EXT,direct_state_access} is not available, the texture
* is bound to some layer before the operation.
* is bound to some texture unit before the operation.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and
* @fn_gl{GetTexLevelParameter} or @fn_gl_extension{GetTextureLevelParameter,EXT,direct_state_access}
* with @def_gl{TEXTURE_WIDTH} and @def_gl{TEXTURE_HEIGHT}
* @requires_gl %Texture image queries are not available in OpenGL ES.
*/
Vector2i imageSize() { return DataHelper<2>::imageSize(*this, _target, 0); }
#endif
/**
* @brief Set wrapping
@ -124,9 +121,9 @@ class RectangleTexture: public AbstractTexture {
* @return Reference to self (for method chaining)
*
* Sets wrapping type for coordinates out of (0, textureSizeInGivenDirection-1)
* range for rectangle textures. If @extension{EXT,direct_state_access}
* is not available, the texture is bound to some layer before the
* operation. Initial value is @ref Sampler::Wrapping::ClampToEdge.
* range. If @extension{EXT,direct_state_access} is not available, the
* texture is bound to some texture unit before the operation. Initial
* value is @ref Sampler::Wrapping::ClampToEdge.
* @attention Only @ref Sampler::Wrapping::ClampToEdge and
* @ref Sampler::Wrapping::ClampToBorder is supported on this
* texture type.
@ -146,6 +143,20 @@ class RectangleTexture: public AbstractTexture {
return *this;
}
#ifndef MAGNUM_TARGET_GLES
/** @copydoc Texture::setBorderColor(const Vector4ui&) */
RectangleTexture& setBorderColor(const Vector4ui& color) {
AbstractTexture::setBorderColor(color);
return *this;
}
/** @copydoc Texture::setBorderColor(const Vector4i&) */
RectangleTexture& setBorderColor(const Vector4i& color) {
AbstractTexture::setBorderColor(color);
return *this;
}
#endif
/** @copydoc Texture::setMaxAnisotropy() */
RectangleTexture& setMaxAnisotropy(Float anisotropy) {
AbstractTexture::setMaxAnisotropy(anisotropy);
@ -155,7 +166,7 @@ class RectangleTexture: public AbstractTexture {
/**
* @brief Set storage
* @param internalFormat Internal format
* @param size Size
* @param size %Texture size
* @return Reference to self (for method chaining)
*
* Specifies entire structure of a texture at once, removing the need
@ -165,10 +176,10 @@ class RectangleTexture: public AbstractTexture {
* allowed.
*
* If @extension{EXT,direct_state_access} is not available, the texture
* is bound to some layer before the operation. If @extension{ARB,texture_storage}
* (part of OpenGL 4.2), OpenGL ES 3.0 or @es_extension{EXT,texture_storage}
* in OpenGL ES 2.0 is not available, the feature is emulated with
* @ref setImage() call.
* is bound to some texture unit before the operation. If
* @extension{ARB,texture_storage} (part of OpenGL 4.2), OpenGL ES 3.0
* or @es_extension{EXT,texture_storage} in OpenGL ES 2.0 is not
* available, the feature is emulated with @ref setImage() call.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexStorage2D}
* or @fn_gl_extension{TextureStorage2D,EXT,direct_state_access},
* eventually @fn_gl{TexImage2D} or
@ -189,7 +200,7 @@ class RectangleTexture: public AbstractTexture {
* @ref imageSize().
*
* If @extension{EXT,direct_state_access} is not available, the
* texture is bound to some layer before the operation. If
* texture is bound to some texture unit before the operation. If
* @extension{ARB,robustness} is available, the operation is protected
* from buffer overflow. However, if both @extension{EXT,direct_state_access}
* and @extension{ARB,robustness} are available, the DSA version is
@ -230,7 +241,7 @@ class RectangleTexture: public AbstractTexture {
* use @ref setStorage() and @ref setSubImage() instead.
*
* If @extension{EXT,direct_state_access} is not available, the
* texture is bound to some layer before the operation.
* texture is bound to some texture unit before the operation.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexImage2D}
* or @fn_gl_extension{TextureImage2D,EXT,direct_state_access}
*/
@ -260,7 +271,7 @@ class RectangleTexture: public AbstractTexture {
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available, the
* texture is bound to some layer before the operation.
* texture is bound to some texture unit before the operation.
* @see @ref setStorage(), @ref setImage(), @fn_gl{ActiveTexture},
* @fn_gl{BindTexture} and @fn_gl{TexSubImage2D} or
* @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access}
@ -286,8 +297,8 @@ class RectangleTexture: public AbstractTexture {
/**
* @brief Invalidate texture image
*
* If running on OpenGL ES or extension @extension{ARB,invalidate_subdata}
* (part of OpenGL 4.3) is not available, this function does nothing.
* If extension @extension{ARB,invalidate_subdata} (part of OpenGL 4.3)
* is not available, this function does nothing.
* @see @ref invalidateSubImage(), @fn_gl{InvalidateTexImage}
*/
void invalidateImage() { AbstractTexture::invalidateImage(0); }
@ -297,8 +308,8 @@ class RectangleTexture: public AbstractTexture {
* @param offset Offset into the texture
* @param size Size of invalidated data
*
* If running on OpenGL ES or extension @extension{ARB,invalidate_subdata}
* (part of OpenGL 4.3) is not available, this function does nothing.
* If extension @extension{ARB,invalidate_subdata} (part of OpenGL 4.3)
* is not available, this function does nothing.
* @see @ref invalidateImage(), @fn_gl{InvalidateTexSubImage}
*/
void invalidateSubImage(const Vector2i& offset, const Vector2i& size) {

9
src/Magnum/Renderer.h

@ -519,6 +519,9 @@ class MAGNUM_EXPORT Renderer {
* @param mask Mask for both reference and buffer value.
* Initial value is all `1`s.
*
* @attention In @ref MAGNUM_TARGET_WEBGL "WebGL" the reference value
* and mask must be the same for both front and back polygon
* facing.
* @see @ref Feature::StencilTest, @ref setStencilFunction(StencilFunction, Int, UnsignedInt),
* @ref setStencilOperation(), @fn_gl{StencilFuncSeparate}
*/
@ -606,6 +609,9 @@ class MAGNUM_EXPORT Renderer {
*
* Set given bit to `0` to disallow writing stencil value for given
* faces to it. Initial value is all `1`s.
*
* @attention In @ref MAGNUM_TARGET_WEBGL "WebGL" the mask must be the
* same for both front and back polygon facing.
* @see setStencilMask(UnsignedInt), setColorMask(), setDepthMask(),
* @fn_gl{StencilMaskSeparate}
*/
@ -812,6 +818,9 @@ class MAGNUM_EXPORT Renderer {
* @param destination How the destination blending factor is
* computed from framebuffer. Initial value is @ref BlendFunction::Zero.
*
* @attention In @ref MAGNUM_TARGET_WEBGL "WebGL", constant color and
* constant alpha cannot be used together as source and
* destination factors.
* @see @ref Feature::Blending, @ref setBlendFunction(BlendFunction, BlendFunction, BlendFunction, BlendFunction),
* @ref setBlendEquation(), @ref setBlendColor(),
* @fn_gl{BlendFunc}

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

Loading…
Cancel
Save