diff --git a/.gitignore b/.gitignore
index d1ef973af..d513341ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-build*
+build*/
pkg
*.kdev4
*~
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b400342aa..1018727c0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,6 +37,7 @@ cmake_dependent_option(TARGET_GLES2 "Build for OpenGL ES 2" ON "TARGET_GLES" OFF
cmake_dependent_option(TARGET_DESKTOP_GLES "Build for OpenGL ES on desktop" OFF "TARGET_GLES" OFF)
# Parts of the library
+option(WITH_AUDIO "Build Audio library" ON)
option(WITH_DEBUGTOOLS "Build DebugTools library" ON)
cmake_dependent_option(WITH_MESHTOOLS "Build MeshTools library" ON "NOT WITH_DEBUGTOOLS" ON)
cmake_dependent_option(WITH_PRIMITIVES "Builf Primitives library" ON "NOT WITH_DEBUGTOOLS" ON)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ec263025d..673ba7918 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -53,7 +53,8 @@ Code contribution
Contact
-------
-- Website - http://mosra.cz/blog/
-- GitHub - https://github.com/mosra/magnum
-- E-mail - mosra@centrum.cz
-- Jabber - mosra@jabbim.cz
+* Website - http://mosra.cz/blog/magnum.php
+* GitHub - https://github.com/mosra/magnum
+* Twitter - https://twitter.com/czmosra
+* E-mail - mosra@centrum.cz
+* Jabber - mosra@jabbim.cz
diff --git a/Doxyfile b/Doxyfile
index ec9dbea6a..9bb7567bd 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -142,7 +142,8 @@ STRIP_FROM_PATH = ../
# are normally passed to the compiler using the -I flag.
STRIP_FROM_INC_PATH = ../magnum/src \
- ../magnum-plugins/src
+ ../magnum-plugins/src \
+ ../magnum-integration/src
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
# (but less readable) file names. This can be useful if your file system
@@ -224,7 +225,9 @@ ALIASES = \
"requires_gles20=@xrefitem requires-gles20 \"Requires OpenGL ES 2.0\" \"Functionality requiring OpenGL ES 2.0 (not available in ES 3.0 and desktop OpenGL)\"" \
"requires_es_extension=@xrefitem requires-es-extension \"Requires OpenGL ES extension\" \"Functionality requiring specific OpenGL ES extension\"" \
"es_extension{2}=\1_\2" \
- "es_extension2{3}=\1_\2"
+ "es_extension2{3}=\1_\2" \
+ "fn_al{1}=`al\1()`" \
+ "def_al{1}=`AL_\1`"
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding
@@ -686,6 +689,8 @@ INPUT = src/ \
doc/ \
../magnum-plugins/src/ \
../magnum-plugins/doc/ \
+ ../magnum-integration/src/ \
+ ../magnum-integration/doc/ \
../magnum-examples/doc/
# This tag can be used to specify the character encoding of the source files
@@ -770,7 +775,8 @@ EXAMPLE_RECURSIVE = NO
# directories that contain image that are included in the documentation (see
# the \image command).
-IMAGE_PATH = ../magnum-examples/src/
+IMAGE_PATH = doc/ \
+ ../magnum-examples/src/
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
diff --git a/README.md b/README.md
index 292534235..bd95badec 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ DESIGN GOALS
SUPPORTED PLATFORMS
===================
-* **OpenGL** 2.1 through 4.3, core profile functionality and modern
+* **OpenGL** 2.1 through 4.4, core profile functionality and modern
extensions
* **OpenGL ES** 2.0, 3.0 and extensions to match desktop OpenGL functionality
* **Linux** and embedded Linux (natively using GLX/EGL and Xlib or through
@@ -72,13 +72,14 @@ more comprehensive guide for building, packaging and crosscompiling.
Minimal dependencies
--------------------
- * C++ compiler with good C++11 support. Currently there are two compilers
- which are tested to support everything needed: **GCC** >= 4.6 and **Clang**
- >= 3.1.
- * **CMake** >= 2.8.8 (needed for `OBJECT` library target)
- * **GLEW** - OpenGL extension wrangler (only if targeting desktop OpenGL)
- * **Corrade** - Plugin management and utility library. You can get it at
- https://github.com/mosra/corrade.
+* C++ compiler with good C++11 support. Currently there are two compilers
+ which are tested to support everything needed: **GCC** >= 4.6 and **Clang**
+ >= 3.1. On Windows you can use **MinGW**, Visual Studio compiler still
+ lacks some needed features.
+* **CMake** >= 2.8.8
+* **GLEW** - OpenGL extension wrangler (only if targeting desktop OpenGL)
+* **Corrade** - Plugin management and utility library. You can get it at
+ https://github.com/mosra/corrade.
Compilation, installation
-------------------------
@@ -121,26 +122,40 @@ in root directory (i.e. where `Doxyfile` is). Resulting HTML documentation
will be in `build/doc/` directory. You might need to create `build/` directory
if it doesn't exist yet.
-PLUGINS AND EXAMPLES
-====================
+GETTING STARTED
+===============
-Various importer plugins for image and 3D model formats are maintained in
+The Doxygen documentation has a thorough [guide how to start using Magnum](http://mosra.cz/blog/magnum-doc/getting-started.html)
+in your project.
+
+RELATED PROJECTS
+================
+
+The engine itself is kept as small as possible with only little dependencies.
+Additional functionality, often depending on external libraries, is provided in
+separate repositories. Integration with various external math and physics
+libraries can be found at https://github.com/mosra/magnum-integration. Various
+importer plugins for image, audio and 3D model formats are maintained in
separate repository, which can be found at https://github.com/mosra/magnum-plugins.
There are also examples of engine usage, varying from simple *Hello World*-like
example to more advanced applications, such as viewer for complex 3D models.
Example repository is at https://github.com/mosra/magnum-examples.
+Repository with bootstrap projects for many use cases, helping you get up and
+running in no time is located at https://github.com/mosra/magnum-bootstrap.
+
CONTACT
=======
-Want to learn more about the library? Found a bug or want to tell me an
-awesome idea? Feel free to visit my website or contact me at:
+Want to learn more about the library? Found a bug or want to tell me an awesome
+idea? Feel free to visit my website or contact me at:
- * Website - http://mosra.cz/blog/
- * GitHub - https://github.com/mosra/magnum
- * E-mail - mosra@centrum.cz
- * Jabber - mosra@jabbim.cz
+* Website - http://mosra.cz/blog/magnum.php
+* GitHub - https://github.com/mosra/magnum
+* Twitter - https://twitter.com/czmosra
+* E-mail - mosra@centrum.cz
+* Jabber - mosra@jabbim.cz
LICENSE
=======
diff --git a/doc/best-practices.dox b/doc/best-practices.dox
index 5e5c31ca1..e0f0c9331 100644
--- a/doc/best-practices.dox
+++ b/doc/best-practices.dox
@@ -65,6 +65,12 @@ to desired target, either in constructor or using Buffer::setTargetHint().
To ease up the development, @ref Mesh checks proper target hint when adding
vertex and index buffers.
+@section best-practices-hw Hardware-specific
+
+@subsection best-practices-intel Intel hardware
+
+- [Performance tuning applications for Intel Graphics for Linux and Chrome OS](http://software.intel.com/sites/default/files/Performance-tuning-applications-for-Intel-GEN-Graphics-for-Linux-and-Google-Chrome-OS.pdf) [PDF]
+
@subsection best-practices-powervr PowerVR hardware
- [PowerVR Performance Recommendations](http://www.imgtec.com/powervr/insider/docs/PowerVR.Performance%20Recommendations.1.0.28.External.pdf) [PDF]
diff --git a/doc/building.dox b/doc/building.dox
index def7912d6..97044ac8b 100644
--- a/doc/building.dox
+++ b/doc/building.dox
@@ -38,8 +38,9 @@ Minimal set of tools and libraries required for building is:
- C++ compiler with good C++11 support. Currently there are two compilers
which are tested to support everything needed: **GCC** >= 4.6 and **Clang**
- >= 3.1.
-- **CMake** >= 2.8.8 (needed for `OBJECT` library target)
+ >= 3.1. On Windows you can use **MinGW**, Visual Studio compiler still lacks
+ some needed features.
+- **CMake** >= 2.8.8
- **GLEW** - OpenGL extension wrangler (only if targeting desktop OpenGL)
- **Corrade** - Plugin management and utility library. See
@ref building-corrade "Corrade download and installation guide" for more
@@ -63,9 +64,10 @@ subdirectory.
@section building-compilation Compilation, installation
-The library (for example with support for GLUT applications) can be built and
-installed using these four commands. See below for more information about
-optional features.
+@subsection building-linux Via command-line (on Linux/Unix)
+
+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
cmake .. \
@@ -74,17 +76,68 @@ optional features.
make
make install
-The libraries are build as shared by default, pass `-DBUILD_STATIC=ON` to build
-them as static. If you plan them to use with shared libraries later, enable
-also position-independent code with `-DBUILD_STATIC_PIC=ON`. If you want to
-build with another compiler (e.g. Clang), pass `-DCMAKE_CXX_COMPILER=clang++`
-to CMake.
+The library provides a lot of CMake options (described in sections later). They
+can be passed to CMake either as `-Dname=value` parameters on command-line
+(like above) or set conveniently using `cmake-gui`:
+
+ cd build
+ cmake-gui .
+
+@subsection building-windows Using QtCreator and CMake GUI (on Windows)
+
+On Windows, if you don't want to touch the command-line, the easiest way is to
+install QtCreator (just QtCreator, you don't need the full Qt SDK) and
+configure it to use MinGW and CMake.
+
+For most convenient usage it's best to install (or copy/paste) all library
+dependencies into directory where MinGW is installed (e.g. `C:/MinGW/`),
+following proper filesystem hierarchy, i.e. headers into `include/` and
+binaries into `bin/` or `lib/`. CMake will then have no problem finding them
+and you won't need to explicitly specify path to each one.
+
+Then just open project's root `CMakeLists.txt` file within QtCreator. It then
+asks you where to create build directory, allows you to specify initial CMake
+parameters and then you can just press Configure and everything should be ready
+to be built. You might need to set some CMake parameters before configuring,
+they can be set with `-Dname=value`. See below for more information.
+
+After the initial import you might want to reconfigure some CMake variables
+(more information below). Start CMake GUI, point it to the recently created
+build dir, modify the variables and press Generate. QtCreator will detect the
+changes and reparse the project accordingly.
+
+For most convenient usage it's best to set `CMAKE_INSTALL_PREFIX` to directory
+where MinGW is installed (e.g. `C:/MinGW/`) and add `C:/MinGW/bin` and
+`C:/MinGW/lib` to `PATH`. Installation to given prefix can be then done from
+within QtCreator by adding new `make install` build rule.
-@subsection building-optional Enabling or disabling features
+@subsubsection building-windows-troubleshooting Windows troubleshooting
+
+If CMake isn't able to find dependencies (e.g. Corrade is not found) and you
+have installed them to MinGW directory, point to `CMAKE_FIND_ROOT_PATH` to
+MinGW installation prefix, e.g. specify `-DCMAKE_FIND_ROOT_PATH=C:/MinGW/`
+CMake parameter.
+
+If building fails with GLEW linking errors (`undefined reference to glew...`),
+you have to set `GLEW_LIBRARY_DLL` and `GLEW_LIBRARY_LIB` CMake variables
+manually. One of them should point to `glew32.dll` and the other to
+`glew32.lib`. CMake currently isn't able to distinguish between them and in
+most cases points both to the same location.
+
+See also Corrade's @ref building-corrade-windows-troubleshooting "troubleshooting section".
+
+@subsection building-features Enabling or disabling features
+
+The libraries are build as shared by default. If you are developing for
+platform which doesn't support shared libraries or if you just want to link
+them statically, enable `BUILD_STATIC` to build the libraries as static. If you
+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.
By default the engine is built for desktop OpenGL. Using `TARGET_*` CMake
-parameters you can target other platforms. Note that some features are available
-for desktop OpenGL only, see @ref requires-gl.
+parameters you can target other platforms. Note that some features are
+available for desktop OpenGL only, see @ref requires-gl.
- `TARGET_GLES` - Target OpenGL ES.
- `TARGET_GLES2` - Target OpenGL ES 2.0. Currently enabled by default when
@@ -92,10 +145,16 @@ for desktop OpenGL only, see @ref requires-gl.
- `TARGET_DESKTOP_GLES` - Target OpenGL ES on desktop, i.e. use OpenGL ES
emulation in desktop OpenGL library. Might not be supported in all drivers.
-By default the engine is built with everything except application libraries (see
-below). Using `WITH_*` CMake parameters you can specify which parts will be built
-and which not:
+The features used can be conveniently detected in depending projects both in
+CMake and C++ sources, see @ref cmake and @ref src/Magnum.h for more
+information. See also @ref corrade-cmake and @ref src/Corrade.h for additional
+information.
+
+By default the engine is built with everything except application libraries
+(see below). Using `WITH_*` CMake parameters you can specify which parts will
+be built and which not:
+ - `WITH_AUDIO` - Audio library. Requires **OpenAL** library.
- `WITH_DEBUGTOOLS` - DebugTools library. Enables also building of MeshTools,
Primitives, SceneGraph, Shaders and Shapes libraries.
- `WITH_MESHTOOLS` - MeshTools library. Enabled automatically if `WITH_DEBUGTOOLS`
@@ -134,13 +193,15 @@ platform best:
@subsection building-tests Building and running unit tests
-If you want to build also unit tests (which are not built by default), pass
-`-DBUILD_TESTS=ON` to CMake. Unit tests use Corrade's @ref Corrade::TestSuite
-"TestSuite" framework and can be run using
+If you want to build also unit tests (which are not built by default), enable
+`BUILD_TEST` in CMake. Unit tests use Corrade's @ref Corrade::TestSuite
+"TestSuite" framework and can be run either manually (the binaries are located
+in `Test/` subdirectories of build directory) or using
ctest --output-on-failure
-in build directory. Everything should pass ;-)
+in build directory. On Windows the tests require the library to be installed
+with DLLs accessible through `PATH`. See above for more information.
@subsection building-doc Building documentation
@@ -155,23 +216,31 @@ in root directory (i.e. where `Doxyfile` is). Resulting HTML documentation
will be in `build/doc/` directory. You might need to create `build/` directory
if it doesn't exist yet.
+@section building-related Related projects
+
+The engine itself is kept as small as possible with only little dependencies.
+Additional functionality, often depending on external libraries, is provided in
+separate repositories. Various importer plugins for image, audio and 3D model
+formats are maintained in @ref building-plugins "Plugins repository",
+Integration with various external math and physics libraries is provided by
+@ref building-integration "Integration library".
+
@section building-arch Building ArchLinux packages
In `package/archlinux` directory is currently one PKGBUILD for Git development
build. The package is also in AUR under the same name.
-There is also development PKGBUILD and MinGW development PKGBUILD in root,
-which allows you to build and install the package directly from source tree
-without downloading anything. The PKGBUILD also contains `check()` function
-which will run all unit tests before packaging. Note that the unit tests
-require Qt, as said above.
+There are also a few development PKGBUILDs in project root, which allow you to
+build and install the package directly from source tree without downloading
+anything. The native PKGBUILD also contains `check()` function which will run
+all unit tests before packaging.
If you want to build with another compiler (e.g. Clang), run makepkg this way:
CXX=clang++ makepkg
-Both development PKGBUILDs can detect when Clang is used and remove
-unsupported CXX flags.
+Development PKGBUILDs can detect when Clang is used and remove unsupported CXX
+flags.
@section building-win Crosscompiling for Windows using MinGW
diff --git a/doc/cmake.dox b/doc/cmake.dox
index b23a19c51..6ebd791d6 100644
--- a/doc/cmake.dox
+++ b/doc/cmake.dox
@@ -51,6 +51,7 @@ components. The base library depends on %Corrade, OpenGL and GLEW libraries (or
OpenGL ES libraries). Additional dependencies are specified by the components.
The optional components are:
+- `%Audio` -- Audio library (depends on OpenAL library)
- `%DebugTools` -- DebugTools library (depends on `%MeshTools`,
`%Primitives`, `%SceneGraph`, `%Shaders` and `%Shapes` components)
- `%MeshTools` -- MeshTools library
@@ -105,6 +106,8 @@ are also available as preprocessor variables if including Magnum.h:
%Corrade library provides also its own set of CMake macros and variables, see
@ref corrade-cmake "its documentation" for more information.
+@ref cmake-plugins "Plugins repository" and @ref cmake-integration "Integration library"
+have also their own CMake modules.
*/
}
diff --git a/doc/getting-started-blue.png b/doc/getting-started-blue.png
new file mode 100644
index 000000000..554613df2
Binary files /dev/null and b/doc/getting-started-blue.png differ
diff --git a/doc/getting-started.dox b/doc/getting-started.dox
new file mode 100644
index 000000000..d98af28d5
--- /dev/null
+++ b/doc/getting-started.dox
@@ -0,0 +1,202 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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.
+*/
+
+namespace Magnum {
+/** @page getting-started Getting started
+@brief Get started with %Magnum in matter of minutes.
+
+@tableofcontents
+
+@section getting-started-download Download, build and install Magnum
+
+Get latest version from GitHub and install it. Read full guide on
+@ref building "how to download, build and install Magnum" on platform of your
+choice. For our first project we will use GLUT toolkit, don't forget to enable
+it for building using `WITH_GLUTAPPLICATION` CMake parameter.
+
+@section getting-started-bootstrap Download bootstrap project
+
+Setting up a new project can be pretty gruesome and nobody likes repeating the
+same process every time. %Magnum provides "bootstrap" project structures for
+many use cases, helping you get up and running in no time.
+
+The [bootstrap repository](https://github.com/mosra/magnum-bootstrap) is
+located on GitHub. The `master` branch contains just an README file and the
+actual bootstrap projects are in various other branches, each covering some
+particular use case. For your first project you would need the `base` branch,
+which contains only the essential files you need. Download the branch [as an
+archive](https://github.com/mosra/magnum-bootstrap/archive/base.zip) and
+extract it somewhere. Do it rather than cloning the full repository, as it's
+better to init your own repository from scratch to avoid having the history
+polluted.
+
+@section getting-started-review Review project structure
+
+The base project consists of just seven files in two subfolders. %Magnum uses
+CMake build system, see @ref cmake for more information.
+
+ modules/FindCorrade.cmake
+ modules/FindMagnum.cmake
+ modules/FindGLEW.cmake
+ src/MyApplication.cpp
+ src/CMakeLists.txt
+ CMakeLists.txt
+ .gitignore
+
+In root there is pre-filled `.gitignore` for your Git project and also
+project-wide `CMakeLists.txt`. It just sets up project name, specifies module
+directory and delegates everything important to `CMakeLists.txt` in `src/`
+subdirectory.
+@code
+cmake_minimum_required(VERSION 2.8.8)
+project(MyApplication)
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/modules/")
+
+add_subdirectory(src)
+@endcode
+
+Directory `modules/` contains CMake modules for finding the needed
+dependencies. Unlike modules for finding e.g. GLUT and OpenGL, which are part
+of standard CMake installation, these aren't part of it and thus must be
+distributed with the project. These files are just verbatim copied from %Magnum
+repository.
+
+Directory `src/` contains the actual project. To keep things simple, the
+project consists of just one source file with the most minimal code possible:
+@code
+#include
+#include
+
+using namespace Magnum;
+
+class MyApplication: public Platform::Application {
+ public:
+ explicit MyApplication(const Arguments& arguments);
+
+ protected:
+ void viewportEvent(const Vector2i& size) override;
+ void drawEvent() override;
+};
+
+MyApplication::MyApplication(const Arguments& arguments): Platform::Application(arguments) {}
+
+void MyApplication::viewportEvent(const Vector2i& size) {
+ defaultFramebuffer.setViewport({{}, size});
+}
+
+void MyApplication::drawEvent() {
+ defaultFramebuffer.clear(FramebufferClear::Color);
+ swapBuffers();
+}
+
+MAGNUM_APPLICATION_MAIN(MyApplication)
+@endcode
+
+The application essentially does nothing, just clears properly sized screen
+framebuffer to default (black) color and then does buffer swap to actually
+display it on the screen. `CMakeLists.txt` finds %Magnum, sets up compiler
+flags, creates the executable and links it to all needed libraries:
+@code
+find_package(Magnum REQUIRED GlutApplication)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CORRADE_CXX_FLAGS}")
+include_directories(${MAGNUM_INCLUDE_DIRS} ${MAGNUM_APPLICATION_INCLUDE_DIRS})
+
+add_executable(MyApplication MyApplication.cpp)
+target_link_libraries(MyApplication
+ ${MAGNUM_LIBRARIES}
+ ${MAGNUM_APPLICATION_LIBRARIES})
+@endcode
+
+In the following tutorials the code will be explained more thoroughly.
+
+@section getting-started-build Build it and run
+
+In Linux (and other Unix-based OSs) you can build the example using the
+following three commands: create out-of-source build directory, run cmake in it
+and then run make. The application binary will then appear in src/ subdirectory
+of build dir:
+
+ mkdir -p build && cd build
+ cmake ..
+ make
+ ./src/MyApplication
+
+On Windows, if you don't want to touch the command-line, the easiest way is to
+open root `CMakeLists.txt` in QtCreator, let it import the project and then
+just build and run the application. If CMake isn't able to find the
+dependencies or the building fails for some reason, you might want to look at
+@ref building-windows-troubleshooting.
+
+@image html getting-started.png
+@image latex getting-started.png
+
+Now you can try to change something in the code. Without going too deep into
+the concepts of graphics programming, we can change clear color to something
+else and also print basic information about the GPU the engine is running on.
+First include the needed headers:
+@code
+#include
+#include
+#include
+@endcode
+
+And in the constructor (which is currently empty) change the clear color and
+print something to debug output:
+@code
+Renderer::setClearColor({0.07f, 0.44f, 0.73f});
+
+Debug() << "Hello! This application is running on" << Context::current()->version()
+ << "using" << Context::current()->rendererString();
+@endcode
+
+After rebuilding and starting the application, the clear color changes to
+blueish one and something like this would be printed to the console:
+@code
+Hello! This application is running on OpenGL 3.3 using Geforce GT 330M
+@endcode
+
+@image html getting-started-blue.png
+@image latex getting-started-blue.png
+
+@section getting-started-tutorials Follow tutorials and learn the principles
+
+Now that you have your first application up and running, the best way to
+continue is to render your first triangle in @ref example-index "step-by-step tutorial".
+Then you can dig deeper and try other examples, read about
+@ref features "fundamental principles" in the documentation and start
+experimenting on your own!
+
+@section getting-started-more Additional information
+
+- @subpage building
+- @subpage building-plugins
+- @subpage building-integration
+- @subpage cmake
+- @subpage cmake-plugins
+- @subpage cmake-integration
+
+*/
+}
diff --git a/doc/getting-started.png b/doc/getting-started.png
new file mode 100644
index 000000000..cc0fc6112
Binary files /dev/null and b/doc/getting-started.png differ
diff --git a/doc/mainpage.dox b/doc/mainpage.dox
index 7ed82d7d5..ff86d27a1 100644
--- a/doc/mainpage.dox
+++ b/doc/mainpage.dox
@@ -62,7 +62,7 @@ namespace Magnum {
@section mainpage-platforms Supported platforms
-- **OpenGL** 2.1 through 4.3, core profile functionality and modern
+- **OpenGL** 2.1 through 4.4, core profile functionality and modern
extensions
- **OpenGL ES** 2.0, 3.0 and extensions to match desktop OpenGL functionality
- **Linux** and embedded Linux (natively using GLX/EGL and Xlib or through
@@ -83,16 +83,10 @@ namespace Magnum {
- Pre-made shaders, primitives and other tools for easy prototyping and
debugging.
-@section mainpage-download-build Downloading and building Magnum
-
-Guide @ref building "how to download and build Magnum" on different platforms.
-
@section mainpage-getting-started Getting started
-The best way to get started is to render your first triangle in
-@ref example-index "step-by-step tutorial". Then you can dig deeper and try
-other examples, read about @ref features "fundamental principles" in the
-documentation or start experimenting on your own!
+Read thorough @ref getting-started "guide to download, build, install and start using Magnum"
+in your project.
@section mainpage-hacking Hacking Magnum
@@ -105,8 +99,9 @@ make the library as consistent and maintainable as possible.
Feel free to get more information or contact the author at:
+- Website - http://mosra.cz/blog/magnum.php
- GitHub - https://github.com/mosra/magnum
-- Website - http://mosra.cz/blog/
+- Twitter - https://twitter.com/czmosra
- E-mail - mosra@centrum.cz
- Jabber - mosra@jabbim.cz
diff --git a/doc/namespaces.dox b/doc/namespaces.dox
index 8a4e1b3b7..229abad25 100644
--- a/doc/namespaces.dox
+++ b/doc/namespaces.dox
@@ -88,6 +88,20 @@ This library is built by default and found by default in CMake. See
@ref building and @ref cmake for more information.
*/
+/** @dir Audio
+ * @brief Namespace Magnum::Audio
+ */
+/** @namespace Magnum::Audio
+@brief %Audio playback
+
+Audio import, playback and integration with @ref SceneGraph.
+
+This library is built when `WITH_AUDIO` is enabled and found as `%Audio`
+component in CMake. See @ref building and @ref cmake for more information.
+Additional plugins are part of plugin repository, see @ref building-plugins and
+@ref cmake-plugins for more information.
+*/
+
/** @dir DebugTools
* @brief Namespace Magnum::DebugTools
*/
@@ -177,6 +191,8 @@ Font texture creation and text layouting.
This library is built when `WITH_TEXT` is enabled and found as `%Text`
component in CMake. See @ref building and @ref cmake for more information.
+Additional plugins are part of plugin repository, see @ref building-plugins and
+@ref cmake-plugins for more information.
*/
/** @dir TextureTools
@@ -202,5 +218,7 @@ Contains plugin interfaces for importing data of various formats and classes
for direct access to the data.
This library is built by default and found by default in CMake. See
-@ref building and @ref cmake for more information.
+@ref building and @ref cmake for more information. Additional plugins are part
+of plugin repository, see @ref building-plugins and @ref cmake-plugins for more
+information.
*/
diff --git a/doc/shapes.dox b/doc/shapes.dox
index cb99d5454..1e5772d56 100644
--- a/doc/shapes.dox
+++ b/doc/shapes.dox
@@ -51,6 +51,7 @@ line and point. Collision of two lines can be detected only in 2D.
@subsection shapes-3D Three-dimensional shapes
- @ref Shapes::Sphere "Shapes::Sphere*D" -- @copybrief Shapes::Sphere
+- @ref Shapes::Cylinder "Shapes::Cylinder*D" -- @copybrief Shapes::Cylinder
- @ref Shapes::Capsule "Shapes::Capsule*D" -- @copybrief Shapes::Capsule
- @ref Shapes::AxisAlignedBox "Shapes::AxisAlignedBox*D" -- @copybrief Shapes::AxisAlignedBox
- @ref Shapes::Box "Shapes::Box*D" -- @copybrief Shapes::Box
diff --git a/doc/types.dox b/doc/types.dox
index 99d6f8755..3ddb332a6 100644
--- a/doc/types.dox
+++ b/doc/types.dox
@@ -69,7 +69,7 @@ type, `i` is @ref Int underlying type and `d` is for @ref Double underlying type
| --------------------------------- | ------------------------------------ |
| @ref Matrix2 or @ref Matrix2d | `mat2`/`mat2x2` or `dmat2`/`dmat2x2` |
| @ref Matrix3 or @ref Matrix3d | `mat3`/`mat3x3` or `dmat3`/`dmat3x3` |
-| @ref Matrix4 or @ref Matrix4d | `mat4`/`mat4x4` or `dmat3`/`dmat4x4` |
+| @ref Matrix4 or @ref Matrix4d | `mat4`/`mat4x4` or `dmat4`/`dmat4x4` |
| @ref Matrix2x3 or @ref Matrix2x3d | `mat2x3` or `dmat2x3` |
| @ref Matrix3x2 or @ref Matrix3x2d | `mat3x2` or `dmat3x2` |
| @ref Matrix2x4 or @ref Matrix2x4d | `mat2x4` or `dmat2x4` |
diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake
index 4cfaa9393..060f80595 100644
--- a/modules/FindMagnum.cmake
+++ b/modules/FindMagnum.cmake
@@ -7,14 +7,20 @@
# 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. 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
# This command will try to find only the base library, not the optional
# components. The base library depends on Corrade, OpenGL and GLEW
# libraries. Additional dependencies are specified by the components. The
# optional components are:
+# Audio - Audio library (depends on OpenAL library)
# DebugTools - DebugTools library (depends on MeshTools, Primitives,
# SceneGraph, Shaders and Shapes components)
# MeshTools - MeshTools library
@@ -70,6 +76,8 @@
# installation directory
# MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR - Importer plugin installation
# directory
+# MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR - Audio omporter plugin
+# installation directory
# MAGNUM_CMAKE_MODULE_INSTALL_DIR - Installation dir for CMake
# modules
# MAGNUM_INCLUDE_INSTALL_DIR - Header installation directory
@@ -215,6 +223,19 @@ foreach(component ${Magnum_FIND_COMPONENTS})
endif()
endif()
+ # Audio library
+ if(${component} STREQUAL Audio)
+ set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Audio.h)
+
+ find_package(OpenAL)
+ if(OPENAL_FOUND)
+ set(_MAGNUM_${_COMPONENT}_LIBRARIES ${OPENAL_LIBRARY})
+ set(_MAGNUM_${_COMPONENT}_INCLUDE_DIRS ${OPENAL_INCLUDE_DIR})
+ else()
+ unset(MAGNUM_${_COMPONENT}_LIBRARY)
+ endif()
+ endif()
+
# DebugTools library
if(${component} STREQUAL DebugTools)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES DebugTools.h)
@@ -325,6 +346,7 @@ 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_CMAKE_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/Magnum/Plugins)
@@ -337,19 +359,17 @@ mark_as_advanced(FORCE
MAGNUM_PLUGINS_FONTCONVERTER_INSTALL_DIR
MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR
MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR
+ MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR
MAGNUM_CMAKE_MODULE_INSTALL_DIR
MAGNUM_INCLUDE_INSTALL_DIR
MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR)
+set(MAGNUM_PLUGINS_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}
+ CACHE PATH "Base directory where to look for Magnum plugins")
+
# Plugin directories
-if(NOT WIN32)
- set(MAGNUM_PLUGINS_FONT_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/fonts)
- set(MAGNUM_PLUGINS_FONTCONVERTER_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/fontconverters)
- set(MAGNUM_PLUGINS_IMAGECONVERTER_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/imageconverters)
- set(MAGNUM_PLUGINS_IMPORTER_DIR ${MAGNUM_PLUGINS_INSTALL_DIR}/importers)
-else()
- set(MAGNUM_PLUGINS_FONT_DIR fonts)
- set(MAGNUM_PLUGINS_FONTCONVERTER_DIR fontconverters)
- set(MAGNUM_PLUGINS_IMAGECONVERTER_DIR imageconverters)
- set(MAGNUM_PLUGINS_IMPORTER_DIR importers)
-endif()
+set(MAGNUM_PLUGINS_FONT_DIR ${MAGNUM_PLUGINS_DIR}/fonts)
+set(MAGNUM_PLUGINS_FONTCONVERTER_DIR ${MAGNUM_PLUGINS_DIR}/fontconverters)
+set(MAGNUM_PLUGINS_IMAGECONVERTER_DIR ${MAGNUM_PLUGINS_DIR}/imageconverters)
+set(MAGNUM_PLUGINS_IMPORTER_DIR ${MAGNUM_PLUGINS_DIR}/importers)
+set(MAGNUM_PLUGINS_AUDIOIMPORTER_DIR ${MAGNUM_PLUGINS_DIR}/audioimporters)
diff --git a/package/archlinux/magnum-git/PKGBUILD b/package/archlinux/magnum-git/PKGBUILD
index 5e3128719..12dc8f573 100644
--- a/package/archlinux/magnum-git/PKGBUILD
+++ b/package/archlinux/magnum-git/PKGBUILD
@@ -1,17 +1,23 @@
# Author: mosra
pkgname=magnum-git
-pkgver=20120331
+pkgver=20130819
pkgrel=1
-pkgdesc="OpenGL 3 graphics engine (Git version)"
+pkgdesc="C++11 and OpenGL 2D/3D graphics engine (Git version)"
arch=('i686' 'x86_64')
-url="https://github.com/mosra/magnum"
+url="http://mosra.cz/blog/magnum.php"
license=('MIT')
-depends=('corrade-git' 'glew')
+depends=('corrade-git' 'glew' 'glut' 'openal')
makedepends=('cmake' 'git')
+provides=('magnum')
+conflicts=('magnum')
_gitroot="git://github.com/mosra/magnum.git"
_gitname="magnum"
+pkgver() {
+ date +%Y%m%d
+}
+
build() {
cd "$srcdir"
msg "Connecting to Git server..."
@@ -31,15 +37,14 @@ build() {
cmake ../$_gitname \
-DCMAKE_BUILD_TYPE=Release \
- -DCMAKE_INSTALL_PREFIX=/usr
+ -DCMAKE_INSTALL_PREFIX=/usr \
+ -DWITH_GLUTAPPLICATION=ON \
+ -DWITH_GLXAPPLICATION=ON \
+ -DWITH_WINDOWLESSGLXAPPLICATION=ON \
+ -DWITH_MAGNUMINFO=ON
make
}
-check() {
- cd "$startdir/build"
- ctest --output-on-failure -E Benchmark
-}
-
package() {
cd "$srcdir/build"
make DESTDIR="$pkgdir/" install
diff --git a/src/AbstractResourceLoader.h b/src/AbstractResourceLoader.h
index 3c7e4e697..830297489 100644
--- a/src/AbstractResourceLoader.h
+++ b/src/AbstractResourceLoader.h
@@ -161,6 +161,11 @@ template class AbstractResourceLoader {
*/
void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy);
+ /** @overload */
+ template void set(ResourceKey key, U&& data, ResourceDataState state, ResourcePolicy policy) {
+ set(key, new typename std::remove_cv::type>::type(std::forward(data)), state, policy);
+ }
+
/**
* @brief Set loaded resource to resource manager
*
@@ -171,6 +176,11 @@ template class AbstractResourceLoader {
set(key, data, ResourceDataState::Final, ResourcePolicy::Resident);
}
+ /** @overload */
+ template void set(ResourceKey key, U&& data) {
+ set(key, new typename std::remove_cv::type>::type(std::forward(data)));
+ }
+
/**
* @brief Mark resource as not found
*
diff --git a/src/Audio/AbstractImporter.cpp b/src/Audio/AbstractImporter.cpp
new file mode 100644
index 000000000..2e0ced0e3
--- /dev/null
+++ b/src/Audio/AbstractImporter.cpp
@@ -0,0 +1,97 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "AbstractImporter.h"
+
+#include
+#include
+#include
+
+namespace Magnum { namespace Audio {
+
+AbstractImporter::AbstractImporter() = default;
+
+AbstractImporter::AbstractImporter(PluginManager::AbstractManager* manager, std::string plugin): PluginManager::AbstractPlugin(manager, std::move(plugin)) {}
+
+bool AbstractImporter::openData(Containers::ArrayReference data) {
+ CORRADE_ASSERT(features() & Feature::OpenData,
+ "Audio::AbstractImporter::openData(): feature not supported", nullptr);
+
+ close();
+ doOpenData(data);
+ return isOpened();
+}
+
+void AbstractImporter::doOpenData(Containers::ArrayReference) {
+ CORRADE_ASSERT(false, "Audio::AbstractImporter::openData(): feature advertised but not implemented", );
+}
+
+bool AbstractImporter::openFile(const std::string& filename) {
+ close();
+ doOpenFile(filename);
+ return isOpened();
+}
+
+void AbstractImporter::doOpenFile(const std::string& filename) {
+ CORRADE_ASSERT(features() & Feature::OpenData, "Audio::AbstractImporter::openFile(): not implemented", );
+
+ /* Open file */
+ std::ifstream in(filename.data(), std::ios::binary);
+ if(!in.good()) {
+ Error() << "Trade::AbstractImporter::openFile(): cannot open file" << filename;
+ return;
+ }
+
+ /* Create array to hold file contents */
+ in.seekg(0, std::ios::end);
+ Containers::Array data(in.tellg());
+
+ /* Read data, close */
+ in.seekg(0, std::ios::beg);
+ in.read(reinterpret_cast(data.begin()), data.size());
+ in.close();
+
+ doOpenData(data);
+}
+
+void AbstractImporter::close() {
+ if(isOpened()) doClose();
+}
+
+Buffer::Format AbstractImporter::format() const {
+ CORRADE_ASSERT(isOpened(), "Audio::AbstractImporter::format(): no file opened", {});
+ return doFormat();
+}
+
+UnsignedInt AbstractImporter::frequency() const {
+ CORRADE_ASSERT(isOpened(), "Audio::AbstractImporter::frequency(): no file opened", {});
+ return doFrequency();
+}
+
+Containers::Array AbstractImporter::data() {
+ CORRADE_ASSERT(isOpened(), "Audio::AbstractImporter::data(): no file opened", {});
+ return doData();
+}
+
+}}
diff --git a/src/Audio/AbstractImporter.h b/src/Audio/AbstractImporter.h
new file mode 100644
index 000000000..9e49fc8bf
--- /dev/null
+++ b/src/Audio/AbstractImporter.h
@@ -0,0 +1,163 @@
+#ifndef Magnum_Audio_AbstractImporter_h
+#define Magnum_Audio_AbstractImporter_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 Audio/AbstractImporter.h
+ * @brief Class Magnum::Audio::AbstractImporter
+ */
+
+#include
+
+#include "Magnum.h"
+#include "Audio/Buffer.h"
+
+namespace Magnum { namespace Audio {
+
+/**
+@brief Base for audio importer plugins
+
+@section Audio-AbstractImporter-subclassing Subclassing
+
+Plugin implements function doFeatures(), doIsOpened(), one of or both
+doOpenData() and doOpenFile() functions, function doClose() and data access
+functions doFormat(), doFrequency() and doData().
+
+You don't need to do most of the redundant sanity checks, these things are
+checked by the implementation:
+
+- Functions doOpenData() and doOpenFile() are called after the previous file
+ was closed, function doClose() is called only if there is any file opened.
+- Function doOpenData() is called only if @ref Feature "Feature::OpenData"
+ is supported.
+- All `do*()` implementations working on opened file are called only if
+ there is any file opened.
+*/
+class MAGNUM_AUDIO_EXPORT AbstractImporter: public PluginManager::AbstractPlugin {
+ CORRADE_PLUGIN_INTERFACE("cz.mosra.magnum.Audio.AbstractImporter/0.1")
+
+ public:
+ /**
+ * @brief Features supported by this importer
+ *
+ * @see Features, features()
+ */
+ enum class Feature: UnsignedByte {
+ /** Opening files from raw data using openData() */
+ OpenData = 1 << 0
+ };
+
+ /**
+ * @brief Features supported by this importer
+ *
+ * @see features()
+ */
+ typedef Containers::EnumSet Features;
+
+ /** @brief Default constructor */
+ explicit AbstractImporter();
+
+ /** @brief Plugin manager constructor */
+ explicit AbstractImporter(PluginManager::AbstractManager* manager, std::string plugin);
+
+ /** @brief Features supported by this importer */
+ Features features() const { return doFeatures(); }
+
+ /** @brief Whether any file is opened */
+ bool isOpened() const { return doIsOpened(); }
+
+ /**
+ * @brief Open raw data
+ *
+ * Closes previous file, if it was opened, and tries to open given
+ * file. Available only if @ref Feature "Feature::OpenData" is
+ * supported. Returns `true` on success, `false` otherwise.
+ * @see features(), openFile()
+ */
+ bool openData(Containers::ArrayReference data);
+
+ /**
+ * @brief Open file
+ *
+ * Closes previous file, if it was opened, and tries to open given
+ * file. Returns `true` on success, `false` otherwise.
+ * @see features(), openData()
+ */
+ bool openFile(const std::string& filename);
+
+ /** @brief Close file */
+ void close();
+
+ /** @{ @name Data access */
+
+ /** @brief Sample format */
+ Buffer::Format format() const;
+
+ /** @brief Sample frequency */
+ UnsignedInt frequency() const;
+
+ /** @brief Sample data */
+ Containers::Array data();
+
+ /*@}*/
+
+ #ifndef DOXYGEN_GENERATING_OUTPUT
+ private:
+ #else
+ protected:
+ #endif
+ /** @brief Implementation for features() */
+ virtual Features doFeatures() const = 0;
+
+ /** @brief Implementation for isOpened() */
+ virtual bool doIsOpened() const = 0;
+
+ /** @brief Implementation for openData() */
+ virtual void doOpenData(Containers::ArrayReference data);
+
+ /**
+ * @brief Implementation for openFile()
+ *
+ * If @ref Feature "Feature::OpenData" is supported, default
+ * implementation opens the file and calls doOpenData() with its
+ * contents.
+ */
+ virtual void doOpenFile(const std::string& filename);
+
+ /** @brief Implementation for close() */
+ virtual void doClose() = 0;
+
+ /** @brief Implementation for format() */
+ virtual Buffer::Format doFormat() const = 0;
+
+ /** @brief Implementation for frequency() */
+ virtual UnsignedInt doFrequency() const = 0;
+
+ /** @brief Implementation for data() */
+ virtual Containers::Array doData() = 0;
+};
+
+}}
+
+#endif
diff --git a/src/Audio/Audio.cpp b/src/Audio/Audio.cpp
new file mode 100644
index 000000000..25c70e5e4
--- /dev/null
+++ b/src/Audio/Audio.cpp
@@ -0,0 +1,49 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+#include
+
+#include "Types.h"
+
+namespace Magnum { namespace Audio {
+
+/* Verify types */
+static_assert(std::is_same::value, "ALubyte is not the same as UnsignedByte");
+static_assert(std::is_same::value, "ALbyte is not the same as Byte");
+static_assert(std::is_same::value, "ALushort is not the same as UnsignedShort");
+static_assert(std::is_same::value, "ALshort is not the same as Short");
+static_assert(std::is_same::value, "ALuint is not the same as UnsignedInt");
+static_assert(std::is_same::value, "ALint is not the same as Int");
+static_assert(std::is_same::value, "ALsizei is not the same as Int");
+static_assert(std::is_same::value, "ALfloat is not the same as Float");
+#ifndef MAGNUM_TARGET_GLES
+static_assert(std::is_same::value, "ALdouble is not the same as Double");
+#endif
+
+/* Verify boolean values */
+static_assert(AL_FALSE == false, "AL_FALSE is not the same as false");
+static_assert(AL_TRUE == true, "AL_TRUE is not the same as true");
+
+}}
diff --git a/src/Audio/Audio.h b/src/Audio/Audio.h
new file mode 100644
index 000000000..7fd001759
--- /dev/null
+++ b/src/Audio/Audio.h
@@ -0,0 +1,41 @@
+#ifndef Magnum_Audio_Audio_h
+#define Magnum_Audio_Audio_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 Forward declarations for Magnum::Audio namespace
+ */
+
+namespace Magnum { namespace Audio {
+
+class AbstractImporter;
+class Buffer;
+class Context;
+class Source;
+/* Renderer used only statically */
+
+}}
+
+#endif
diff --git a/src/Audio/Buffer.cpp b/src/Audio/Buffer.cpp
new file mode 100644
index 000000000..1a28d95c1
--- /dev/null
+++ b/src/Audio/Buffer.cpp
@@ -0,0 +1,44 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "Buffer.h"
+
+#include
+
+namespace Magnum { namespace Audio {
+
+Debug operator<<(Debug debug, const Buffer::Format value) {
+ switch(value) {
+ #define _c(value) case Buffer::Format::value: return debug << "Audio::Buffer::Format::" #value;
+ _c(Mono8)
+ _c(Mono16)
+ _c(Stereo8)
+ _c(Stereo16)
+ #undef _c
+ }
+
+ return debug << "Audio::Buffer::Format::(invalid)";
+}
+
+}}
diff --git a/src/Audio/Buffer.h b/src/Audio/Buffer.h
new file mode 100644
index 000000000..31774c9e5
--- /dev/null
+++ b/src/Audio/Buffer.h
@@ -0,0 +1,120 @@
+#ifndef Magnum_Audio_Buffer_h
+#define Magnum_Audio_Buffer_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 Magnum::Audio::Buffer
+ */
+
+#include
+#include
+#include
+
+#include "Magnum.h"
+#include "Audio/magnumAudioVisibility.h"
+
+namespace Magnum { namespace Audio {
+
+/** @brief Sample buffer */
+class Buffer {
+ public:
+ /**
+ * @brief Sample format
+ *
+ * @note Multi-channel format is played without 3D spatialization
+ * (useful for background music)
+ * @see @ref setData()
+ */
+ enum class Format: ALenum {
+ Mono8 = AL_FORMAT_MONO8, /**< 8-bit unsigned mono */
+ Mono16 = AL_FORMAT_MONO16, /**< 16-bit signed mono */
+ Stereo8 = AL_FORMAT_STEREO8, /**< 8-bit interleaved unsigned stereo */
+ Stereo16 = AL_FORMAT_STEREO16 /**< 16-bit interleaved signed stereo */
+ };
+
+ /**
+ * @brief Constructor
+ *
+ * Creates OpenAL buffer object.
+ * @see @fn_al{GenBuffers}
+ */
+ explicit Buffer() { alGenBuffers(1, &_id); }
+
+ /**
+ * @brief Destructor
+ *
+ * Deletes OpenAL buffer object.
+ * @see @fn_al{DeleteBuffers}
+ */
+ ~Buffer() { if(_id) alDeleteBuffers(1, &_id); }
+
+ /** @brief Copying is not allowed */
+ Buffer(const Buffer&) = delete;
+
+ /** @brief Move constructor */
+ Buffer(Buffer&& other);
+
+ /** @brief Copying is not allowed */
+ Buffer& operator=(const Buffer&) = delete;
+
+ /** @brief Move assignment */
+ Buffer& operator=(Buffer&& other);
+
+ /** @brief OpenAL buffer ID */
+ ALuint id() const { return _id; }
+
+ /**
+ * @brief Set buffer data
+ * @param format Sample format
+ * @param data Data
+ * @param frequency Frequency
+ * @return Reference to self (for method chaining)
+ *
+ * @see @fn_al{BufferData}
+ */
+ Buffer& setData(Format format, Containers::ArrayReference data, ALsizei frequency) {
+ alBufferData(_id, ALenum(format), data, data.size(), frequency);
+ return *this;
+ }
+
+ private:
+ ALuint _id;
+};
+
+/** @debugoperator{Magnum::Audio::Buffer} */
+Debug MAGNUM_AUDIO_EXPORT operator<<(Debug debug, Buffer::Format value);
+
+inline Buffer::Buffer(Buffer&& other): _id(other._id) {
+ other._id = 0;
+}
+
+inline Buffer& Buffer::operator=(Buffer&& other) {
+ std::swap(_id, other._id);
+ return *this;
+}
+
+}}
+
+#endif
diff --git a/src/Audio/CMakeLists.txt b/src/Audio/CMakeLists.txt
new file mode 100644
index 000000000..ba125c954
--- /dev/null
+++ b/src/Audio/CMakeLists.txt
@@ -0,0 +1,55 @@
+#
+# This file is part of Magnum.
+#
+# Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+#
+# 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.
+#
+
+find_package(OpenAL REQUIRED)
+
+include_directories(${OPENAL_INCLUDE_DIR})
+
+set(MagnumAudio_SOURCES
+ AbstractImporter.cpp
+ Audio.cpp
+ Buffer.cpp
+ Context.cpp
+ Renderer.cpp
+ Source.cpp)
+
+set(MagnumAudio_HEADERS
+ AbstractImporter.h
+ Audio.h
+ Buffer.h
+ Context.h
+ Renderer.h
+ Source.h
+
+ magnumAudioVisibility.h)
+
+add_library(MagnumAudio ${SHARED_OR_STATIC} ${MagnumAudio_SOURCES})
+target_link_libraries(MagnumAudio ${CORRADE_PLUGINMANAGER_LIBRARIES} ${OPENAL_LIBRARY})
+
+install(TARGETS MagnumAudio DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
+install(FILES ${MagnumAudio_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Audio)
+
+if(BUILD_TESTS)
+ add_subdirectory(Test)
+endif()
diff --git a/src/Audio/Context.cpp b/src/Audio/Context.cpp
new file mode 100644
index 000000000..86af094de
--- /dev/null
+++ b/src/Audio/Context.cpp
@@ -0,0 +1,65 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "Context.h"
+
+#include
+#include
+#include
+
+#include "Magnum.h"
+
+namespace Magnum { namespace Audio {
+
+Context* Context::_current = nullptr;
+
+Context::Context() {
+ CORRADE_ASSERT(!_current, "Audio::Context: context already created", );
+
+ /* Open default device */
+ const ALCchar* const defaultDevice = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
+ _device = alcOpenDevice(defaultDevice);
+ if(!_device) {
+ Error() << "Audio::Context: cannot open sound device" << defaultDevice;
+ std::exit(1);
+ }
+
+ _context = alcCreateContext(_device, nullptr);
+ if(!_context) {
+ Error() << "Audio::Context: cannot create context:" << alcGetError(_device);
+ std::exit(1);
+ }
+
+ alcMakeContextCurrent(_context);
+ _current = this;
+}
+
+Context::~Context() {
+ CORRADE_INTERNAL_ASSERT(_current == this);
+
+ alcDestroyContext(_context);
+ alcCloseDevice(_device);
+}
+
+}}
diff --git a/src/Audio/Context.h b/src/Audio/Context.h
new file mode 100644
index 000000000..b28bba470
--- /dev/null
+++ b/src/Audio/Context.h
@@ -0,0 +1,95 @@
+#ifndef Magnum_Audio_Context_h
+#define Magnum_Audio_Context_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 Magnum::Audio::Context
+ */
+
+#include
+#include
+
+#include "Audio/magnumAudioVisibility.h"
+
+#ifndef DOXYGEN_GENERATING_OUTPUT
+typedef struct ALCdevice_struct ALCdevice;
+typedef struct ALCcontext_struct ALCcontext;
+#endif
+
+namespace Magnum { namespace Audio {
+
+/**
+@brief OpenAL context
+ */
+class MAGNUM_AUDIO_EXPORT Context {
+ public:
+ /** @brief Current context */
+ static Context* current() { return _current; }
+
+ /**
+ * @brief Constructor
+ *
+ * Creates OpenAL context.
+ */
+ explicit Context();
+
+ /**
+ * @brief Destructor
+ *
+ * Destroys OpenAL context.
+ */
+ ~Context();
+
+ /**
+ * @brief Vendor string
+ *
+ * @see rendererString(), @fn_al{GetString} with @def_al{VENDOR}
+ */
+ std::string vendorString() const { return alGetString(AL_VENDOR); }
+
+ /**
+ * @brief %Renderer string
+ *
+ * @see vendorString(), @fn_al{GetString} with @def_al{RENDERER}
+ */
+ std::string rendererString() const { return alGetString(AL_RENDERER); }
+
+ /**
+ * @brief Version string
+ *
+ * @see @fn_al{GetString} with @def_al{VERSION}
+ */
+ std::string versionString() const { return alGetString(AL_VERSION); }
+
+ private:
+ static Context* _current;
+
+ ALCdevice* _device;
+ ALCcontext* _context;
+};
+
+}}
+
+#endif
diff --git a/src/Audio/Renderer.cpp b/src/Audio/Renderer.cpp
new file mode 100644
index 000000000..4dbeae53f
--- /dev/null
+++ b/src/Audio/Renderer.cpp
@@ -0,0 +1,46 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "Renderer.h"
+
+#include
+
+namespace Magnum { namespace Audio {
+
+Debug operator<<(Debug debug, const Renderer::Error value) {
+ switch(value) {
+ #define _c(value) case Renderer::Error::value: return debug << "Audio::Renderer::Error::" #value;
+ _c(NoError)
+ _c(InvalidName)
+ _c(InvalidEnum)
+ _c(InvalidValue)
+ _c(InvalidOperation)
+ _c(OutOfMemory)
+ #undef _c
+ }
+
+ return debug << "Audio::Renderer::Error::(invalid)";
+}
+
+}}
diff --git a/src/Audio/Renderer.h b/src/Audio/Renderer.h
new file mode 100644
index 000000000..f8041e28a
--- /dev/null
+++ b/src/Audio/Renderer.h
@@ -0,0 +1,202 @@
+#ifndef Magnum_Audio_Renderer_h
+#define Magnum_Audio_Renderer_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 Magnum::Audio::Renderer
+ */
+
+#include
+
+#include "Math/Vector3.h"
+#include "Magnum.h"
+#include "Audio/magnumAudioVisibility.h"
+
+namespace Magnum { namespace Audio {
+
+/** @brief Global renderer configuration */
+class Renderer {
+ public:
+ Renderer() = delete;
+
+ /**
+ * @brief Error status
+ *
+ * @see error()
+ */
+ enum class Error: ALenum {
+ NoError = AL_NO_ERROR, /**< No error occured */
+ InvalidName = AL_INVALID_NAME, /**< Invalid name parameter */
+ InvalidEnum = AL_INVALID_ENUM, /**< Invalid enum parameter */
+ InvalidValue = AL_INVALID_VALUE, /**< Invalid enum value parameter */
+ InvalidOperation = AL_INVALID_OPERATION, /**< Illegal call */
+ OutOfMemory = AL_OUT_OF_MEMORY /**< Unable to allocate memory */
+ };
+
+ /** @brief Error status */
+ static Error error() { return Error(alGetError()); }
+
+ /** @{ @name Listener positioning */
+
+ /**
+ * @brief Set listener position
+ *
+ * Default is `{0.0f, 0.0f, 0.0f}`.
+ * @see @fn_al{Listenerfv} with @def_al{POSITION}
+ */
+ static void setListenerPosition(const Vector3& position) {
+ alListenerfv(AL_POSITION, position.data());
+ }
+
+ /** @overload
+ * @see @fn_al{Listeneriv} with @def_al{POSITION}
+ */
+ static void setListenerPosition(const Vector3i& position) {
+ alListeneriv(AL_POSITION, position.data());
+ }
+
+ /**
+ * @brief Set listener orientation
+ *
+ * The values must be linearly independent and don't need to be
+ * normalized. Default is -Z and +Y.
+ * @see @fn_al{Listenerfv} with @def_al{ORIENTATION}
+ */
+ static void setListenerOrientation(const Vector3& forward, const Vector3& up);
+
+ /** @overload
+ * @see @fn_al{Listeneriv} with @def_al{ORIENTATION}
+ */
+ static void setListenerOrientation(const Vector3i& forward, const Vector3i& up);
+
+ /**
+ * @brief Set listener velocity
+ *
+ * Default is `{0.0f, 0.0f, 0.0f}`.
+ * @see @fn_al{Listenerfv} with @def_al{VELOCITY}
+ */
+ static void setListenerVelocity(const Vector3& velocity) {
+ alListenerfv(AL_VELOCITY, velocity.data());
+ }
+
+ /** @overload
+ * @see @fn_al{Listeneriv} with @def_al{VELOCITY}
+ */
+ static void setListenerVelocity(const Vector3i& velocity) {
+ alListeneriv(AL_VELOCITY, velocity.data());
+ }
+
+ /*@}*/
+
+ /** @{ @name Global behavior */
+
+ /**
+ * @brief Distance model
+ *
+ * @see setDistanceModel()
+ */
+ enum class DistanceModel: ALenum {
+ /** No distance attenuation calculation */
+ None = AL_NONE,
+
+ /** Inverse distance */
+ Inverse = AL_INVERSE_DISTANCE,
+
+ /** Inverse distance, clamped */
+ InverseClamped = AL_INVERSE_DISTANCE_CLAMPED,
+
+ /** Linear distance */
+ Linear = AL_LINEAR_DISTANCE,
+
+ /** Linear distance, clamped */
+ LinearClamped = AL_LINEAR_DISTANCE_CLAMPED,
+
+ /** Exponential distance */
+ Exponent = AL_EXPONENT_DISTANCE,
+
+ /** Exponential distance, clamped */
+ ExponentClamped = AL_EXPONENT_DISTANCE_CLAMPED
+ };
+
+ /**
+ * @brief Set listener gain
+ *
+ * Default is `1.0f`, which means that the sound is unattenuated.
+ * If set to `0.0f`, all sound is muted.
+ * @see @fn_al{Listenerf} with @def_al{GAIN}
+ */
+ static void setListenerGain(Float gain) {
+ alListenerf(AL_GAIN, gain);
+ }
+
+ /**
+ * @brief Set Doppler factor
+ *
+ * Default is `1.0f`. If set to `0.0f`, the effect is disabled.
+ * @see @ref setSpeedOfSound(), @fn_al{DopplerFactor}
+ */
+ static void setDopplerFactor(Float factor) {
+ alDopplerFactor(factor);
+ }
+
+ /**
+ * @brief Set speed of sound
+ *
+ * Default is `343.3f` (meters per second).
+ * @see @ref setDopplerFactor(), @fn_al{SpeedOfSound}
+ */
+ static void setSpeedOfSound(Float speed) {
+ alSpeedOfSound(speed);
+ }
+
+ /**
+ * @brief Set distance model
+ *
+ * Default is @ref DistanceModel "DistanceModel::InverseClamped".
+ * @see @fn_al{DistanceModel}
+ */
+ static void setDistanceModel(DistanceModel model) {
+ alDistanceModel(ALenum(model));
+ }
+
+ /*@}*/
+};
+
+/** @debugoperator{Magnum::Audio::Renderer} */
+Debug MAGNUM_AUDIO_EXPORT operator<<(Debug debug, Renderer::Error value);
+
+inline void Renderer::setListenerOrientation(const Vector3& forward, const Vector3& up) {
+ const Vector3 data[] = {forward, up};
+ alListenerfv(AL_ORIENTATION, data[0].data());
+}
+
+inline void Renderer::setListenerOrientation(const Vector3i& forward, const Vector3i& up) {
+ const Vector3i data[] = {forward, up};
+ alListeneriv(AL_ORIENTATION, data[0].data());
+}
+
+}}
+
+#endif
diff --git a/src/Audio/Source.cpp b/src/Audio/Source.cpp
new file mode 100644
index 000000000..8eba148bc
--- /dev/null
+++ b/src/Audio/Source.cpp
@@ -0,0 +1,123 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "Source.h"
+
+#include "Audio/Buffer.h"
+
+namespace Magnum { namespace Audio {
+
+/** @todo C++14: use VLA to avoid unnecessary allocations */
+
+Source& Source::setBuffer(Buffer* buffer) {
+ alSourcei(_id, AL_BUFFER, buffer ? buffer->id() : 0);
+ return *this;
+}
+
+namespace {
+
+const ALuint* sourceIds(const std::initializer_list& sources) {
+ ALuint* const ids = new ALuint[sources.size()];
+ for(auto it = sources.begin(); it != sources.end(); ++it) {
+ CORRADE_INTERNAL_ASSERT(*it);
+ ids[it-sources.begin()] = (*it)->id();
+ }
+ return ids;
+}
+
+const ALuint* sourceIds(const std::vector& sources) {
+ ALuint* const ids = new ALuint[sources.size()];
+ for(auto it = sources.begin(); it != sources.end(); ++it) {
+ CORRADE_INTERNAL_ASSERT(*it);
+ ids[it-sources.begin()] = (*it)->id();
+ }
+ return ids;
+}
+
+}
+
+/** @todo Okay, this is too much code copying even for me */
+
+void Source::play(std::initializer_list sources) {
+ const ALuint* const ids = sourceIds(sources);
+ alSourcePlayv(sources.size(), ids);
+ delete[] ids;
+}
+
+void Source::play(const std::vector& sources) {
+ const ALuint* const ids = sourceIds(sources);
+ alSourcePlayv(sources.size(), ids);
+ delete[] ids;
+}
+
+void Source::pause(std::initializer_list sources) {
+ const ALuint* const ids = sourceIds(sources);
+ alSourcePausev(sources.size(), ids);
+ delete[] ids;
+}
+
+void Source::pause(const std::vector& sources) {
+ const ALuint* const ids = sourceIds(sources);
+ alSourcePausev(sources.size(), ids);
+ delete[] ids;
+}
+
+void Source::stop(std::initializer_list sources) {
+ const ALuint* const ids = sourceIds(sources);
+ alSourceStopv(sources.size(), ids);
+ delete[] ids;
+}
+
+void Source::stop(const std::vector& sources) {
+ const ALuint* const ids = sourceIds(sources);
+ alSourceStopv(sources.size(), ids);
+ delete[] ids;
+}
+
+void Source::rewind(std::initializer_list sources) {
+ const ALuint* const ids = sourceIds(sources);
+ alSourceRewindv(sources.size(), ids);
+ delete[] ids;
+}
+
+void Source::rewind(const std::vector& sources) {
+ const ALuint* const ids = sourceIds(sources);
+ alSourceRewindv(sources.size(), ids);
+ delete[] ids;
+}
+
+Debug operator<<(Debug debug, const Source::State value) {
+ switch(value) {
+ #define _c(value) case Source::State::value: return debug << "Audio::Source::State::" #value;
+ _c(Initial)
+ _c(Playing)
+ _c(Paused)
+ _c(Stopped)
+ #undef _c
+ }
+
+ return debug << "Audio::Source::State::(invalid)";
+}
+
+}}
diff --git a/src/Audio/Source.h b/src/Audio/Source.h
new file mode 100644
index 000000000..f96de05c1
--- /dev/null
+++ b/src/Audio/Source.h
@@ -0,0 +1,596 @@
+#ifndef Magnum_Audio_Source_h
+#define Magnum_Audio_Source_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 Magnum::Audio::Source
+ */
+
+#include
+#include
+#include
+
+#include "Math/Vector3.h"
+#include "Magnum.h"
+#include "Audio/Audio.h"
+#include "Audio/magnumAudioVisibility.h"
+
+namespace Magnum { namespace Audio {
+
+/**
+@brief %Source
+
+Manages positional audio source.
+@todo Expose convenient API for buffer queuing
+*/
+class MAGNUM_AUDIO_EXPORT Source {
+ public:
+ /**
+ * @brief Constructor
+ *
+ * Creates OpenAL source object.
+ * @see @fn_al{GenSources}
+ */
+ explicit Source() { alGenSources(1, &_id); }
+
+ /**
+ * @brief Destructor
+ *
+ * Deletes OpenAL source object.
+ * @see @fn_al{DeleteSources}
+ */
+ ~Source() { if(_id) alDeleteSources(1, &_id); }
+
+ /** @brief Copying is not allowed */
+ Source(const Source&) = delete;
+
+ /** @brief Move constructor */
+ Source(Source&& other);
+
+ /** @brief Copying is not allowed */
+ Source& operator=(const Source&) = delete;
+
+ /** @brief Move assignment */
+ Source& operator=(Source&& other);
+
+ /** @brief OpenAL source ID */
+ ALuint id() const { return _id; }
+
+ /** @{ @name Source positioning */
+
+ /**
+ * @brief Set position
+ * @return Reference to self (for method chaining)
+ *
+ * Default is `{0.0f, 0.0f, 0.0f}`.
+ * @see @ref setRelative(), @fn_al{Sourcefv} with @def_al{POSITION}
+ */
+ Source& setPosition(const Vector3& position) {
+ alSourcefv(_id, AL_POSITION, position.data());
+ return *this;
+ }
+
+ /** @overload
+ * @see @fn_al{Sourceiv} with @def_al{POSITION}
+ */
+ Source& setPosition(const Vector3i& position) {
+ alSourceiv(_id, AL_POSITION, position.data());
+ return *this;
+ }
+
+ /**
+ * @brief Set velocity
+ * @return Reference to self (for method chaining)
+ *
+ * Default is `{0.0f, 0.0f, 0.0f}`.
+ * @see @ref setRelative(), @fn_al{Sourcefv} with @def_al{VELOCITY}
+ */
+ Source& setVelocity(const Vector3& velocity) {
+ alSourcefv(_id, AL_VELOCITY, velocity.data());
+ return *this;
+ }
+
+ /** @overload
+ * @see @fn_al{Sourceiv} with @def_al{VELOCITY}
+ */
+ Source& setVelocity(const Vector3i& velocity) {
+ alSourceiv(_id, AL_VELOCITY, velocity.data());
+ return *this;
+ }
+
+ /**
+ * @brief Interpret source relatively to listener
+ *
+ * When enabled, source position, direction and velocity will be
+ * interpreted relatively to listener. Default is `false`.
+ * @see @ref setPosition(), @ref setDirection(), @ref setVelocity(),
+ * @fn_al{Sourcei} with @def_al{SOURCE_RELATIVE}
+ */
+ Source& setRelative(bool relative) {
+ alSourcei(_id, AL_SOURCE_RELATIVE, relative);
+ return *this;
+ }
+
+ /*@}*/
+
+ /** @{ @name Source behavior */
+
+ /**
+ * @brief Set gain
+ * @return Reference to self (for method chaining)
+ *
+ * Default is `1.0f`, which means that the sound is unattenuated.
+ * If set to `0.0f`, the source is muted.
+ * @see @ref setMinGain(), @ref setMaxGain(), @fn_al{Sourcef} with
+ * @def_al{GAIN}
+ */
+ Source& setGain(Float gain) {
+ alSourcef(_id, AL_GAIN, gain);
+ return *this;
+ }
+
+ /**
+ * @brief Set min gain
+ * @return Reference to self (for method chaining)
+ *
+ * If effective gain is lower than min gain, min gain is used. Note
+ * that this is done before listener gain is applied. Default is
+ * `0.0f`.
+ * @see @ref setMinGain(), @ref setGain(), @fn_al{Sourcef} with
+ * @def_al{MIN_GAIN}
+ */
+ Source& setMinGain(Float gain) {
+ alSourcef(_id, AL_MIN_GAIN, gain);
+ return *this;
+ }
+
+ /**
+ * @brief Set max gain
+ * @return Reference to self (for method chaining)
+ *
+ * If effective gain is higher than max gain, max gain is used. Note
+ * that this is done before listener gain is applied. Default is
+ * `1.0f`. If set to `0.0f`, the source is muted.
+ * @see @ref setMinGain(), @ref setGain(), @fn_al{Sourcef} with
+ * @def_al{MIN_GAIN}
+ */
+ Source& setMaxGain(Float gain) {
+ alSourcef(_id, AL_MAX_GAIN, gain);
+ return *this;
+ }
+
+ /**
+ * @brief Set reference distance
+ * @return Reference to self (for method chaining)
+ *
+ * Default is `1.0f`.
+ * @see @ref setRolloffFactor(), @fn_al{Sourcef} with
+ * @def_al{REFERENCE_DISTANCE}
+ */
+ Source& setReferenceDistance(Float distance) {
+ alSourcef(_id, AL_REFERENCE_DISTANCE, distance);
+ return *this;
+ }
+
+ /** @overload
+ * @see @fn_al{Sourcei} with @def_al{REFERENCE_DISTANCE}
+ */
+ Source& setReferenceDistance(Int distance) {
+ alSourcei(_id, AL_REFERENCE_DISTANCE, distance);
+ return *this;
+ }
+
+ /**
+ * @brief Set rolloff factor
+ * @return Reference to self (for method chaining)
+ *
+ * Default is `1.0f`.
+ * @see @ref setReferenceDistance(), @fn_al{Sourcef} with
+ * @def_al{ROLLOFF_FACTOR}
+ */
+ Source& setRolloffFactor(Float factor) {
+ alSourcef(_id, AL_ROLLOFF_FACTOR, factor);
+ return *this;
+ }
+
+ /** @overload
+ * @see @fn_al{Sourcei} with @def_al{ROLLOFF_FACTOR}
+ */
+ Source& setRolloffFactor(Int factor) {
+ alSourcei(_id, AL_ROLLOFF_FACTOR, factor);
+ return *this;
+ }
+
+ /**
+ * @brief Set max distance
+ * @return Reference to self (for method chaining)
+ *
+ * Default is max representable value.
+ * @see @fn_al{Sourcef} with @def_al{MAX_DISTANCE}
+ */
+ Source& setMaxDistance(Float distance) {
+ alSourcef(_id, AL_MAX_DISTANCE, distance);
+ return *this;
+ }
+
+ /** @overload
+ * @see @fn_al{Sourcei} with @def_al{MAX_DISTANCE}
+ */
+ Source& setMaxDistance(Int distance) {
+ alSourcef(_id, AL_MAX_DISTANCE, distance);
+ return *this;
+ }
+
+ /**
+ * @brief Set direction
+ * @return Reference to self (for method chaining)
+ *
+ * Default is `{0.0f, 0.0f, 0.0f}`, which means that the source is not
+ * directional.
+ * @see @ref setInnerConeAngle(), @ref setOuterConeAngle(),
+ * @ref setRelative(), @fn_al{Sourcefv} with @def_al{DIRECTION}
+ */
+ Source& setDirection(const Vector3& direction) {
+ alSourcefv(_id, AL_DIRECTION, direction.data());
+ return *this;
+ }
+
+ /** @overload
+ * @see @fn_al{Sourceiv} with @def_al{DIRECTION}
+ */
+ Source& setDirection(const Vector3i& direction) {
+ alSourceiv(_id, AL_DIRECTION, direction.data());
+ return *this;
+ }
+
+ /**
+ * @brief Set inner cone angle
+ * @return Reference to self (for method chaining)
+ *
+ * Has effect only if the source is directional. Default is
+ * `360.0_degf`.
+ * @see @ref setOuterConeAngle(), @ref setDirection(), @fn_al{Sourcef}
+ * with @def_al{CONE_INNER_ANGLE}
+ */
+ Source& setInnerConeAngle(Deg angle) {
+ alSourcef(_id, AL_CONE_INNER_ANGLE, Float(angle));
+ return *this;
+ }
+
+ /**
+ * @brief Set outer cone angle
+ * @return Reference to self (for method chaining)
+ *
+ * Has effect only if the source is directional. Default is
+ * `360.0_degf`.
+ * @see @ref setInnerConeAngle(), @ref setDirection(),
+ * @ref setOuterConeGain() @fn_al{Sourcef} with
+ * @def_al{CONE_OUTER_ANGLE}
+ */
+ Source& setOuterConeAngle(Deg angle) {
+ alSourcef(_id, AL_CONE_OUTER_ANGLE, Float(angle));
+ return *this;
+ }
+
+ /**
+ * @brief Set outer cone gain multiplier
+ * @return Reference to self (for method chaining)
+ *
+ * The factor with which the gain is multiplied outside the outer cone.
+ * Default is `0.0f`.
+ * @see @ref setGain(), @ref setOuterConeAngle(), @fn_al{Sourcef} with
+ * @def_al{CONE_OUTER_GAIN}
+ */
+ Source& setOuterConeGain(Float multiplier) {
+ alSourcef(_id, AL_CONE_OUTER_ANGLE, multiplier);
+ return *this;
+ }
+
+ /**
+ * @brief Set pitch
+ * @return Reference to self (for method chaining)
+ *
+ * Default is `1.0f`.
+ * @see @fn_al{Sourcef} with @def_al{PITCH}
+ */
+ Source& setPitch(Float pitch) {
+ alSourcef(_id, AL_PITCH, pitch);
+ return *this;
+ }
+
+ /*@}*/
+
+ /** @{ @name Buffer management */
+
+ /**
+ * @brief %Source type
+ *
+ * @see @ref type()
+ */
+ enum class Type: ALint {
+ Undetermined = AL_UNDETERMINED, /**< Undetermined (default) */
+ Static = AL_STATIC, /**< Static source */
+ Streaming = AL_STREAMING /**< Streaming source */
+ };
+
+ /**
+ * @brief Source type
+ *
+ * @see @ref setBuffer(), @fn_al{GetSourcei} with @def_al{SOURCE_TYPE}
+ */
+ Type type() const;
+
+ /**
+ * @brief Attach buffer
+ * @param buffer Buffer to attach or `nullptr`
+ * @return Reference to self (for method chaining)
+ *
+ * If an buffer is attached, changes source type to
+ * @ref Type "Type::Static", if detached, changes source type to
+ * @ref Type "Type::Undetermined". The buffer must be already filled
+ * with data.
+ * @see @ref type(), @fn_al{Sourcei} with @def_al{BUFFER}
+ */
+ Source& setBuffer(Buffer* buffer);
+
+ /*@}*/
+
+ /** @{ @name State management */
+
+ /**
+ * @brief %Source state
+ *
+ * @see @ref state(), @ref play(), @ref pause(), @ref stop(),
+ * @ref rewind()
+ */
+ enum class State: ALint {
+ Initial = AL_INITIAL, /**< Initial state (default) */
+ Playing = AL_PLAYING, /**< The source is playing */
+ Paused = AL_PAUSED, /**< The source is paused */
+ Stopped = AL_STOPPED /**< The source is stopped */
+ };
+
+ /**
+ * @brief Play more sources at once
+ *
+ * The operation is guaranteed to be done for all sources at the same
+ * time. `nullptr` is not allowed.
+ * @see @ref play(), @ref pause(std::initializer_list),
+ * @ref stop(std::initializer_list),
+ * @ref rewind(std::initializer_list),
+ * @fn_al{SourcePlayv}
+ */
+ static void play(std::initializer_list sources);
+ static void play(const std::vector& sources); /**< @overload */
+
+ /**
+ * @brief Pause more sources at once
+ *
+ * The operation is guaranteed to be done for all sources at the same
+ * time. `nullptr` is not allowed.
+ * @see @ref pause(), @ref play(std::initializer_list),
+ * @ref stop(std::initializer_list),
+ * @ref rewind(std::initializer_list),
+ * @fn_al{SourcePausev}
+ */
+ static void pause(std::initializer_list sources);
+ static void pause(const std::vector& sources); /**< @overload */
+
+ /**
+ * @brief Stop more sources at once
+ *
+ * The operation is guaranteed to be done for all sources at the same
+ * time. `nullptr` is not allowed.
+ * @see @ref stop(), @ref play(std::initializer_list),
+ * @ref pause(std::initializer_list),
+ * @ref rewind(std::initializer_list),
+ * @fn_al{SourceStopv}
+ */
+ static void stop(std::initializer_list sources);
+ static void stop(const std::vector& sources); /**< @overload */
+
+ /**
+ * @brief Rewind more sources at once
+ *
+ * The operation is guaranteed to be done for all sources at the same
+ * time. `nullptr` is not allowed.
+ * @see @ref rewind(), @ref play(std::initializer_list),
+ * @ref pause(std::initializer_list),
+ * @ref stop(std::initializer_list),
+ * @fn_al{SourceRewindv}
+ */
+ static void rewind(std::initializer_list sources);
+ static void rewind(const std::vector& sources); /**< @overload */
+
+ /**
+ * @brief State
+ *
+ * @see @ref play(), @ref pause(), @ref stop(), @ref rewind(),
+ * @fn_al{GetSourcei} with @def_al{SOURCE_STATE}
+ */
+ State state() const;
+
+ /**
+ * @brief Play
+ *
+ * @see @ref play(std::initializer_list), @ref state(),
+ * @ref pause(), @ref stop(), @ref rewind(), @fn_al{SourcePlay}
+ */
+ void play() { alSourcePlay(_id); }
+
+ /**
+ * @brief Pause
+ *
+ * @see @ref pause(std::initializer_list), @ref state(),
+ * @ref play(), @ref stop(), @ref rewind(), @fn_al{SourcePause}
+ */
+ void pause() { alSourcePause(_id); }
+
+ /**
+ * @brief Stop
+ *
+ * @see @ref stop(std::initializer_list), @ref state(),
+ * @ref play(), @ref pause(), @ref rewind(), @fn_al{SourceStop}
+ */
+ void stop() { alSourceStop(_id); }
+
+ /**
+ * @brief Rewind
+ *
+ * @see @ref rewind(std::initializer_list), @ref state(),
+ * @ref play(), @ref pause(), @ref stop(), @fn_al{SourceRewind}
+ */
+ void rewind() { alSourceRewind(_id); }
+
+ /**
+ * @brief Whether the source is looping
+ *
+ * @see @fn_al{GetSourcei} with @def_al{LOOPING}
+ */
+ bool isLooping() const;
+
+ /**
+ * @brief Set source looping
+ * @return Reference to self (for method chaining)
+ *
+ * Default is `false`.
+ * @see @fn_al{Sourcei} with @def_al{LOOPING}
+ */
+ Source& setLooping(bool loop) {
+ alSourcei(_id, AL_LOOPING, loop);
+ return *this;
+ }
+
+ /**
+ * @brief Offset in seconds
+ *
+ * @see @ref offsetInBytes(), @ref offsetInSamples(),
+ * @fn_al{GetSourcef} with @def_al{SEC_OFFSET}
+ */
+ Float offsetInSeconds() const;
+
+ /**
+ * @brief Set offset in seconds
+ * @return Reference to self (for method chaining)
+ *
+ * @see @ref setOffsetInBytes(), @ref setOffsetInSamples(),
+ * @fn_al{Sourcef} with @def_al{SEC_OFFSET}
+ */
+ Source& setOffsetInSeconds(Float offset) {
+ alSourcef(_id, AL_SEC_OFFSET, offset);
+ return *this;
+ }
+
+ /**
+ * @brief Offset in bytes
+ *
+ * @see @ref offsetInSeconds(), @ref offsetInSamples(),
+ * @fn_al{GetSourcei} with @def_al{BYTE_OFFSET}
+ */
+ Int offsetInBytes() const;
+
+ /**
+ * @brief Set offset in bytes
+ * @return Reference to self (for method chaining)
+ *
+ * @see @ref setOffsetInSeconds(), @ref setOffsetInSamples(),
+ * @fn_al{Sourcei} with @def_al{SEC_OFFSET}
+ */
+ Source& setOffsetInBytes(Int offset) {
+ alSourcei(_id, AL_BYTE_OFFSET, offset);
+ return *this;
+ }
+
+ /**
+ * @brief Offset in samples
+ *
+ * @see @ref offsetInSeconds(), @ref offsetInBytes(),
+ * @fn_al{GetSourcei} with @def_al{SAMPLE_OFFSET}
+ */
+ Int offsetInSamples() const;
+
+ /**
+ * @brief Set offset in samples
+ * @return Reference to self (for method chaining)
+ *
+ * @see @ref setOffsetInSeconds(), @ref setOffsetInBytes(),
+ * @fn_al{Sourcei} with @def_al{SEC_OFFSET}
+ */
+ Source& setOffsetInSamples(Int offset) {
+ alSourcei(_id, AL_SAMPLE_OFFSET, offset);
+ return *this;
+ }
+
+ /*@}*/
+
+ private:
+ ALuint _id;
+};
+
+/** @debugoperator{Magnum::Audio::Source} */
+Debug MAGNUM_AUDIO_EXPORT operator<<(Debug debug, Source::State value);
+
+inline Source::Source(Source&& other): _id(other._id) {
+ other._id = 0;
+}
+
+inline Source& Source::operator=(Source&& other) {
+ std::swap(_id, other._id);
+ return *this;
+}
+
+auto Source::state() const -> State {
+ ALint state;
+ alGetSourcei(_id, AL_SOURCE_STATE, &state);
+ return State(state);
+}
+
+inline bool Source::isLooping() const {
+ ALint looping;
+ alGetSourcei(_id, AL_LOOPING, &looping);
+ return looping;
+}
+
+inline Float Source::offsetInSeconds() const {
+ Float offset;
+ alGetSourcef(_id, AL_SEC_OFFSET, &offset);
+ return offset;
+}
+
+inline Int Source::offsetInBytes() const {
+ Int offset;
+ alGetSourcei(_id, AL_BYTE_OFFSET, &offset);
+ return offset;
+}
+
+inline Int Source::offsetInSamples() const {
+ Int offset;
+ alGetSourcei(_id, AL_SAMPLE_OFFSET, &offset);
+ return offset;
+}
+
+}}
+
+#endif
diff --git a/src/Audio/Test/AbstractImporterTest.cpp b/src/Audio/Test/AbstractImporterTest.cpp
new file mode 100644
index 000000000..ff479d654
--- /dev/null
+++ b/src/Audio/Test/AbstractImporterTest.cpp
@@ -0,0 +1,76 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+#include
+#include
+
+#include "Audio/AbstractImporter.h"
+
+#include "testConfigure.h"
+
+namespace Magnum { namespace Audio { namespace Test {
+
+class AbstractImporterTest: public TestSuite::Tester {
+ public:
+ explicit AbstractImporterTest();
+
+ void openFile();
+};
+
+AbstractImporterTest::AbstractImporterTest() {
+ addTests({&AbstractImporterTest::openFile});
+}
+
+void AbstractImporterTest::openFile() {
+ class DataImporter: public Audio::AbstractImporter {
+ public:
+ explicit DataImporter(): opened(false) {}
+
+ private:
+ Features doFeatures() const override { return Feature::OpenData; }
+ bool doIsOpened() const override { return opened; }
+ void doClose() override {}
+
+ void doOpenData(Containers::ArrayReference data) override {
+ opened = (data.size() == 1 && data[0] == 0xa5);
+ }
+
+ Buffer::Format doFormat() const override { return {}; }
+ UnsignedInt doFrequency() const override { return {}; }
+ Corrade::Containers::Array doData() override { return nullptr; }
+
+ bool opened;
+ };
+
+ /* doOpenFile() should call doOpenData() */
+ DataImporter importer;
+ CORRADE_VERIFY(!importer.isOpened());
+ importer.openFile(Utility::Directory::join(AUDIO_TEST_DIR, "file.bin"));
+ CORRADE_VERIFY(importer.isOpened());
+}
+
+}}}
+
+CORRADE_TEST_MAIN(Magnum::Audio::Test::AbstractImporterTest)
diff --git a/src/Audio/Test/BufferTest.cpp b/src/Audio/Test/BufferTest.cpp
new file mode 100644
index 000000000..56c6f2ba9
--- /dev/null
+++ b/src/Audio/Test/BufferTest.cpp
@@ -0,0 +1,51 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+#include
+
+#include "Audio/Buffer.h"
+
+namespace Magnum { namespace Audio { namespace Test {
+
+class BufferTest: public TestSuite::Tester {
+ public:
+ explicit BufferTest();
+
+ void debugFormat();
+};
+
+BufferTest::BufferTest() {
+ addTests({&BufferTest::debugFormat});
+}
+
+void BufferTest::debugFormat() {
+ std::ostringstream out;
+ Debug(&out) << Buffer::Format::Stereo16;
+ CORRADE_COMPARE(out.str(), "Audio::Buffer::Format::Stereo16\n");
+}
+
+}}}
+
+CORRADE_TEST_MAIN(Magnum::Audio::Test::BufferTest)
diff --git a/src/Audio/Test/CMakeLists.txt b/src/Audio/Test/CMakeLists.txt
new file mode 100644
index 000000000..3a42d1f27
--- /dev/null
+++ b/src/Audio/Test/CMakeLists.txt
@@ -0,0 +1,33 @@
+#
+# This file is part of Magnum.
+#
+# Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+#
+# 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.
+#
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testConfigure.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/testConfigure.h)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+corrade_add_test(AudioAbstractImporterTest AbstractImporterTest.cpp LIBRARIES MagnumAudio)
+corrade_add_test(AudioBufferTest BufferTest.cpp LIBRARIES MagnumAudio)
+corrade_add_test(AudioRendererTest RendererTest.cpp LIBRARIES MagnumAudio)
+corrade_add_test(AudioSourceTest SourceTest.cpp LIBRARIES MagnumAudio)
diff --git a/src/Audio/Test/RendererTest.cpp b/src/Audio/Test/RendererTest.cpp
new file mode 100644
index 000000000..9be69593d
--- /dev/null
+++ b/src/Audio/Test/RendererTest.cpp
@@ -0,0 +1,51 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+#include
+
+#include "Audio/Renderer.h"
+
+namespace Magnum { namespace Audio { namespace Test {
+
+class RendererTest: public TestSuite::Tester {
+ public:
+ explicit RendererTest();
+
+ void debugError();
+};
+
+RendererTest::RendererTest() {
+ addTests({&RendererTest::debugError});
+}
+
+void RendererTest::debugError() {
+ std::ostringstream out;
+ Debug(&out) << Renderer::Error::InvalidOperation;
+ CORRADE_COMPARE(out.str(), "Audio::Renderer::Error::InvalidOperation\n");
+}
+
+}}}
+
+CORRADE_TEST_MAIN(Magnum::Audio::Test::RendererTest)
diff --git a/src/Audio/Test/SourceTest.cpp b/src/Audio/Test/SourceTest.cpp
new file mode 100644
index 000000000..90424ce29
--- /dev/null
+++ b/src/Audio/Test/SourceTest.cpp
@@ -0,0 +1,51 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+#include
+
+#include "Audio/Source.h"
+
+namespace Magnum { namespace Audio { namespace Test {
+
+class SourceTest: public TestSuite::Tester {
+ public:
+ explicit SourceTest();
+
+ void debugState();
+};
+
+SourceTest::SourceTest() {
+ addTests({&SourceTest::debugState});
+}
+
+void SourceTest::debugState() {
+ std::ostringstream out;
+ Debug(&out) << Source::State::Playing;
+ CORRADE_COMPARE(out.str(), "Audio::Source::State::Playing\n");
+}
+
+}}}
+
+CORRADE_TEST_MAIN(Magnum::Audio::Test::SourceTest)
diff --git a/src/Audio/Test/file.bin b/src/Audio/Test/file.bin
new file mode 100644
index 000000000..dd6737691
--- /dev/null
+++ b/src/Audio/Test/file.bin
@@ -0,0 +1 @@
+¥
\ No newline at end of file
diff --git a/src/Audio/Test/testConfigure.h.cmake b/src/Audio/Test/testConfigure.h.cmake
new file mode 100644
index 000000000..29272db06
--- /dev/null
+++ b/src/Audio/Test/testConfigure.h.cmake
@@ -0,0 +1,25 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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.
+*/
+
+#define AUDIO_TEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
diff --git a/src/Audio/magnumAudioVisibility.h b/src/Audio/magnumAudioVisibility.h
new file mode 100644
index 000000000..e4a7c0f67
--- /dev/null
+++ b/src/Audio/magnumAudioVisibility.h
@@ -0,0 +1,35 @@
+#ifndef Magnum_Audio_magnumAudioVisibility_h
+#define Magnum_Audio_magnumAudioVisibility_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+
+#ifdef MagnumAudio_EXPORTS
+ #define MAGNUM_AUDIO_EXPORT CORRADE_VISIBILITY_EXPORT
+#else
+ #define MAGNUM_AUDIO_EXPORT CORRADE_VISIBILITY_IMPORT
+#endif
+
+#endif
diff --git a/src/Buffer.h b/src/Buffer.h
index 73163292e..65dbdf508 100644
--- a/src/Buffer.h
+++ b/src/Buffer.h
@@ -24,7 +24,7 @@
DEALINGS IN THE SOFTWARE.
*/
-/** @file
+/** @file /Buffer.h
* @brief Class Magnum::Buffer
*/
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b3cbcee62..566f39791 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -58,6 +58,7 @@ set(Magnum_SRCS
Image.cpp
ImageFormat.cpp
Mesh.cpp
+ MeshView.cpp
OpenGL.cpp
Query.cpp
Renderbuffer.cpp
@@ -117,6 +118,7 @@ set(Magnum_HEADERS
ImageReference.h
Magnum.h
Mesh.h
+ MeshView.h
OpenGL.h
Query.h
Renderbuffer.h
@@ -191,6 +193,10 @@ add_subdirectory(Math)
add_subdirectory(Platform)
add_subdirectory(Trade)
+if(WITH_AUDIO)
+ add_subdirectory(Audio)
+endif()
+
if(WITH_DEBUGTOOLS)
add_subdirectory(DebugTools)
endif()
@@ -236,5 +242,11 @@ if(BUILD_TESTS)
set_target_properties(MagnumTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
target_link_libraries(MagnumTestLib ${Magnum_LIBS})
+ # On Windows we need to install first and then run the tests to avoid "DLL
+ # not found" hell, thus we need to install this too
+ if(WIN32 AND NOT CMAKE_CROSSCOMPILING)
+ install(TARGETS MagnumMathTestLib MagnumTestLib DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
+ endif()
+
add_subdirectory(Test)
endif()
diff --git a/src/Context.h b/src/Context.h
index 50b7941f5..cf527da56 100644
--- a/src/Context.h
+++ b/src/Context.h
@@ -24,7 +24,7 @@
DEALINGS IN THE SOFTWARE.
*/
-/** @file
+/** @file /Context.h
* @brief Enum Magnum::Version, class Magnum::Context, Magnum::Extension, macro MAGNUM_ASSERT_VERSION_SUPPORTED(), MAGNUM_ASSERT_EXTENSION_SUPPORTED()
*/
diff --git a/src/DebugTools/CMakeLists.txt b/src/DebugTools/CMakeLists.txt
index 66546c172..d348e3b8b 100644
--- a/src/DebugTools/CMakeLists.txt
+++ b/src/DebugTools/CMakeLists.txt
@@ -33,6 +33,8 @@ set(MagnumDebugTools_SRCS
Implementation/AbstractShapeRenderer.cpp
Implementation/AxisAlignedBoxRenderer.cpp
Implementation/BoxRenderer.cpp
+ Implementation/CapsuleRenderer.cpp
+ Implementation/CylinderRenderer.cpp
Implementation/LineSegmentRenderer.cpp
Implementation/PointRenderer.cpp
Implementation/SphereRenderer.cpp)
diff --git a/src/DebugTools/Implementation/CapsuleRenderer.cpp b/src/DebugTools/Implementation/CapsuleRenderer.cpp
new file mode 100644
index 000000000..1cd1922bd
--- /dev/null
+++ b/src/DebugTools/Implementation/CapsuleRenderer.cpp
@@ -0,0 +1,116 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "CapsuleRenderer.h"
+
+#include "MeshView.h"
+#include "DebugTools/ResourceManager.h"
+#include "DebugTools/ShapeRenderer.h"
+#include "Primitives/Capsule.h"
+#include "Shapes/Capsule.h"
+#include "Shaders/Flat.h"
+#include "Trade/MeshData2D.h"
+#include "Trade/MeshData3D.h"
+
+#include "DebugTools/Implementation/CapsuleRendererTransformation.h"
+
+namespace Magnum { namespace DebugTools { namespace Implementation {
+
+AbstractCapsuleRenderer<2>::AbstractCapsuleRenderer(): AbstractShapeRenderer<2>("capsule2d", "capsule2d-vertices", "capsule2d-indices") {
+ constexpr UnsignedInt rings = 10;
+ if(!wireframeMesh) createResources(Primitives::Capsule2D::wireframe(rings, 1, 1.0f));
+
+ /* Bottom hemisphere */
+ if(!(bottom = ResourceManager::instance().get("capsule2d-bottom"))) {
+ auto view = new MeshView(wireframeMesh);
+ view->setIndexRange(0, rings*4, 0, rings*2+1);
+ ResourceManager::instance().set(bottom.key(), view, ResourceDataState::Final, ResourcePolicy::Manual);
+ }
+
+ /* Cylinder */
+ if(!(cylinder = ResourceManager::instance().get("capsule2d-cylinder"))) {
+ auto view = new MeshView(wireframeMesh);
+ view->setIndexRange(rings*4, 4, rings*2+1, rings*2+3);
+ ResourceManager::instance().set(cylinder.key(), view, ResourceDataState::Final, ResourcePolicy::Manual);
+ }
+
+ /* Top hemisphere */
+ if(!(top = ResourceManager::instance().get("capsule2d-top"))) {
+ auto view = new MeshView(wireframeMesh);
+ view->setIndexRange(rings*4+4, rings*4, rings*2+3, rings*4+4);
+ ResourceManager::instance().set(top.key(), view, ResourceDataState::Final, ResourcePolicy::Manual);
+ }
+}
+
+AbstractCapsuleRenderer<3>::AbstractCapsuleRenderer(): AbstractShapeRenderer<3>("capsule3d", "capsule3d-vertices", "capsule3d-indices") {
+ constexpr UnsignedInt rings = 10;
+ constexpr UnsignedInt segments = 40;
+ if(!wireframeMesh) createResources(Primitives::Capsule3D::wireframe(rings, 1, segments, 1.0f));
+
+ /* Bottom hemisphere */
+ if(!(bottom = ResourceManager::instance().get("capsule3d-bottom"))) {
+ auto view = new MeshView(wireframeMesh);
+ view->setIndexRange(0, rings*8, 0, rings*4+1);
+ ResourceManager::instance().set(bottom.key(), view, ResourceDataState::Final, ResourcePolicy::Manual);
+ }
+
+ /* Cylinder */
+ if(!(cylinder = ResourceManager::instance().get("capsule3d-cylinder"))) {
+ auto view = new MeshView(wireframeMesh);
+ view->setIndexRange(rings*8, segments*4+8, rings*4+1, rings*4+segments*2+5);
+ ResourceManager::instance().set(cylinder.key(), view, ResourceDataState::Final, ResourcePolicy::Manual);
+ }
+
+ /* Top */
+ if(!(top = ResourceManager::instance().get("capsule3d-top"))) {
+ auto view = new MeshView(wireframeMesh);
+ view->setIndexRange(rings*8+segments*4+8, rings*8, rings*4+segments*2+5, rings*8+segments*2+6);
+ ResourceManager::instance().set(top.key(), view, ResourceDataState::Final, ResourcePolicy::Manual);
+ }
+}
+
+template CapsuleRenderer::CapsuleRenderer(const Shapes::Implementation::AbstractShape& capsule): capsule(static_cast>&>(capsule).shape) {}
+
+template void CapsuleRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) {
+ std::array::MatrixType, 3> transformations = Implementation::capsuleRendererTransformation(capsule.a(), capsule.b(), capsule.radius());
+ AbstractShapeRenderer::wireframeShader->setColor(options->color())
+ .use();
+
+ /* Bottom */
+ AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*transformations[0]);
+ AbstractCapsuleRenderer::bottom->draw();
+
+ /* Cylinder */
+ AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*transformations[1]);
+ AbstractCapsuleRenderer::cylinder->draw();
+
+ /* Top */
+ AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*transformations[2]);
+ AbstractCapsuleRenderer::top->draw();
+}
+
+template class CapsuleRenderer<2>;
+template class CapsuleRenderer<3>;
+
+}}}
diff --git a/src/DebugTools/Implementation/CapsuleRenderer.h b/src/DebugTools/Implementation/CapsuleRenderer.h
new file mode 100644
index 000000000..d00c5e47f
--- /dev/null
+++ b/src/DebugTools/Implementation/CapsuleRenderer.h
@@ -0,0 +1,66 @@
+#ifndef Magnum_DebugTools_Implementation_CapsuleRenderer_h
+#define Magnum_DebugTools_Implementation_CapsuleRenderer_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "AbstractShapeRenderer.h"
+
+#include "Shapes/Shapes.h"
+
+#include "corradeCompatibility.h"
+
+namespace Magnum { namespace DebugTools { namespace Implementation {
+
+template class AbstractCapsuleRenderer;
+
+template<> class AbstractCapsuleRenderer<2>: public AbstractShapeRenderer<2> {
+ public:
+ explicit AbstractCapsuleRenderer();
+
+ protected:
+ Resource bottom, cylinder, top;
+};
+
+template<> class AbstractCapsuleRenderer<3>: public AbstractShapeRenderer<3> {
+ public:
+ explicit AbstractCapsuleRenderer();
+
+ protected:
+ Resource bottom, cylinder, top;
+};
+
+template class CapsuleRenderer: public AbstractCapsuleRenderer {
+ public:
+ explicit CapsuleRenderer(const Shapes::Implementation::AbstractShape& capsule);
+ CapsuleRenderer(const Shapes::Implementation::AbstractShape&&) = delete;
+
+ void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override;
+
+ private:
+ const Shapes::Capsule& capsule;
+};
+
+}}}
+
+#endif
diff --git a/src/DebugTools/Implementation/CapsuleRendererTransformation.h b/src/DebugTools/Implementation/CapsuleRendererTransformation.h
new file mode 100644
index 000000000..5f9271a67
--- /dev/null
+++ b/src/DebugTools/Implementation/CapsuleRendererTransformation.h
@@ -0,0 +1,106 @@
+#ifndef Magnum_DebugTools_Implementation_ForceRendererTransformation_h
+#define Magnum_DebugTools_Implementation_ForceRendererTransformation_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+
+#include "Math/Functions.h"
+#include "Math/Matrix3.h"
+#include "Math/Matrix4.h"
+#include "Magnum.h"
+#include "DimensionTraits.h"
+
+namespace Magnum { namespace DebugTools { namespace Implementation {
+
+template std::array::MatrixType, 3> capsuleRendererTransformation(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b, Float radius);
+
+template<> std::array capsuleRendererTransformation<2>(const Vector2& a, const Vector2& b, const Float radius) {
+ /* Vector from capsule center to top hemisphere center */
+ const Vector2 direction = 0.5f*(b - a);
+ const Float length = direction.length();
+
+ /* Capsule rotation and distance to caps after they are scaled to proper
+ radius (if nonzero cylinder length) */
+ Matrix3 rotation;
+ Vector2 capDistance;
+ if(length >= Math::TypeTraits::epsilon()) {
+ rotation.up() = direction/length;
+ rotation.right() = rotation.up().perpendicular();
+ CORRADE_INTERNAL_ASSERT(rotation.right().isNormalized());
+
+ capDistance = direction*(radius/length);
+ }
+
+ /* Scaling and translation of all parts */
+ const auto rotationScaling = rotation*Matrix3::scaling(Vector2(radius));
+ return {{
+ Matrix3::translation(a+capDistance)*rotationScaling,
+ Matrix3::translation(0.5f*(a + b))*rotation*Matrix3::scaling({radius, length}),
+ Matrix3::translation(b-capDistance)*rotationScaling
+ }};
+}
+
+template<> std::array capsuleRendererTransformation<3>(const Vector3& a, const Vector3& b, const Float radius) {
+ /* Vector from capsule center to top hemisphere center */
+ const Vector3 direction = 0.5f*(b - a);
+ const Float length = direction.length();
+
+ /* Capsule rotation and distance to caps after they are scaled to proper
+ radius (if nonzero cylinder length) */
+ Matrix4 rotation;
+ Vector3 capDistance;
+ if(length >= Math::TypeTraits::epsilon()) {
+ const Vector3 directionNormalized = direction/length;
+ const Float dot = Vector3::dot(directionNormalized, Vector3::zAxis());
+
+ /* Direction is parallel to Z axis, special rotation case */
+ if(Math::abs(dot) > 1.0f - Math::TypeTraits::epsilon()) {
+ rotation.up() = dot*Vector3::zAxis();
+ rotation.right() = Vector3::xAxis();
+ rotation.backward() = -dot*Vector3::yAxis();
+
+ /* Common case */
+ } else {
+ rotation.up() = directionNormalized;
+ rotation.right() = Vector3::cross(rotation.up(), Vector3::zAxis()).normalized();
+ rotation.backward() = Vector3::cross(rotation.right(), rotation.up());
+ CORRADE_INTERNAL_ASSERT(rotation.up().isNormalized() && rotation.backward().isNormalized());
+ }
+
+ capDistance = directionNormalized*radius;
+ }
+
+ /* Scaling and translation of all parts */
+ const auto rotationScaling = rotation*Matrix4::scaling(Vector3(radius));
+ return {{
+ Matrix4::translation(a+capDistance)*rotationScaling,
+ Matrix4::translation(0.5f*(a + b))*rotation*Matrix4::scaling({radius, length, radius}),
+ Matrix4::translation(b-capDistance)*rotationScaling
+ }};
+}
+
+}}}
+
+#endif
diff --git a/src/DebugTools/Implementation/CylinderRenderer.cpp b/src/DebugTools/Implementation/CylinderRenderer.cpp
new file mode 100644
index 000000000..f7cfbd1e2
--- /dev/null
+++ b/src/DebugTools/Implementation/CylinderRenderer.cpp
@@ -0,0 +1,61 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "CylinderRenderer.h"
+
+#include "Mesh.h"
+#include "DebugTools/ShapeRenderer.h"
+#include "Shapes/Cylinder.h"
+#include "Primitives/Cylinder.h"
+#include "Primitives/Square.h"
+#include "Shaders/Flat.h"
+#include "Trade/MeshData2D.h"
+#include "Trade/MeshData3D.h"
+
+#include "DebugTools/Implementation/CylinderRendererTransformation.h"
+
+namespace Magnum { namespace DebugTools { namespace Implementation {
+
+AbstractCylinderRenderer<2>::AbstractCylinderRenderer(): AbstractShapeRenderer<2>("cylinder2d", "cylinder2d-vertices", {}) {
+ if(!wireframeMesh) createResources(Primitives::Square::wireframe());
+}
+
+AbstractCylinderRenderer<3>::AbstractCylinderRenderer(): AbstractShapeRenderer<3>("cylinder3d", "cylinder3d-vertices", "cylinder3d-indices") {
+ if(!wireframeMesh) createResources(Primitives::Cylinder::wireframe(1, 40, 1.0f));
+}
+
+template CylinderRenderer::CylinderRenderer(const Shapes::Implementation::AbstractShape& cylinder): cylinder(static_cast>&>(cylinder).shape) {}
+
+template void CylinderRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) {
+ AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*
+ Implementation::cylinderRendererTransformation(cylinder.a(), cylinder.b(), cylinder.radius()))
+ .setColor(options->color())
+ .use();
+ AbstractShapeRenderer::wireframeMesh->draw();
+}
+
+template class CylinderRenderer<2>;
+template class CylinderRenderer<3>;
+
+}}}
diff --git a/src/DebugTools/Implementation/CylinderRenderer.h b/src/DebugTools/Implementation/CylinderRenderer.h
new file mode 100644
index 000000000..d5a511254
--- /dev/null
+++ b/src/DebugTools/Implementation/CylinderRenderer.h
@@ -0,0 +1,60 @@
+#ifndef Magnum_DebugTools_Implementation_CylinderRenderer_h
+#define Magnum_DebugTools_Implementation_CylinderRenderer_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "AbstractShapeRenderer.h"
+
+#include "Shapes/Shapes.h"
+
+#include "corradeCompatibility.h"
+
+namespace Magnum { namespace DebugTools { namespace Implementation {
+
+template class AbstractCylinderRenderer;
+
+template<> class AbstractCylinderRenderer<2>: public AbstractShapeRenderer<2> {
+ public:
+ explicit AbstractCylinderRenderer();
+};
+
+template<> class AbstractCylinderRenderer<3>: public AbstractShapeRenderer<3> {
+ public:
+ explicit AbstractCylinderRenderer();
+};
+
+template class CylinderRenderer: public AbstractCylinderRenderer {
+ public:
+ explicit CylinderRenderer(const Shapes::Implementation::AbstractShape& cylinder);
+ CylinderRenderer(const Shapes::Implementation::AbstractShape&&) = delete;
+
+ void draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) override;
+
+ private:
+ const Shapes::Cylinder& cylinder;
+};
+
+}}}
+
+#endif
diff --git a/src/DebugTools/Implementation/CylinderRendererTransformation.h b/src/DebugTools/Implementation/CylinderRendererTransformation.h
new file mode 100644
index 000000000..4caf8c5d6
--- /dev/null
+++ b/src/DebugTools/Implementation/CylinderRendererTransformation.h
@@ -0,0 +1,88 @@
+#ifndef Magnum_DebugTools_Implementation_ForceRendererTransformation_h
+#define Magnum_DebugTools_Implementation_ForceRendererTransformation_h
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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 "Math/Functions.h"
+#include "Math/Matrix3.h"
+#include "Math/Matrix4.h"
+#include "Magnum.h"
+#include "DimensionTraits.h"
+
+namespace Magnum { namespace DebugTools { namespace Implementation {
+
+template typename DimensionTraits::MatrixType cylinderRendererTransformation(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b, Float radius);
+
+template<> Matrix3 cylinderRendererTransformation<2>(const Vector2& a, const Vector2& b, const Float radius) {
+ /* Vector from cylinder center to top hemisphere center */
+ const Vector2 direction = 0.5f*(b - a);
+ const Float length = direction.length();
+
+ /* Capsule rotation and distance to caps after they are scaled to proper
+ radius (if nonzero cylinder length) */
+ Matrix3 rotation;
+ if(length >= Math::TypeTraits::epsilon()) {
+ rotation.up() = direction/length;
+ rotation.right() = rotation.up().perpendicular();
+ CORRADE_INTERNAL_ASSERT(rotation.right().isNormalized());
+ }
+
+ /* Scaling and translation */
+ return Matrix3::translation(0.5f*(a + b))*rotation*Matrix3::scaling({radius, length});
+}
+
+template<> Matrix4 cylinderRendererTransformation<3>(const Vector3& a, const Vector3& b, const Float radius) {
+ /* Vector from cylinder center to top hemisphere center */
+ const Vector3 direction = 0.5f*(b - a);
+ const Float length = direction.length();
+
+ /* Capsule rotation and distance to caps after they are scaled to proper
+ radius (if nonzero cylinder length) */
+ Matrix4 rotation;
+ if(length >= Math::TypeTraits::epsilon()) {
+ const Vector3 directionNormalized = direction/length;
+ const Float dot = Vector3::dot(directionNormalized, Vector3::zAxis());
+
+ /* Direction is parallel to Z axis, special rotation case */
+ if(Math::abs(dot) > 1.0f - Math::TypeTraits::epsilon()) {
+ rotation.up() = dot*Vector3::zAxis();
+ rotation.right() = Vector3::xAxis();
+ rotation.backward() = -dot*Vector3::yAxis();
+
+ /* Common case */
+ } else {
+ rotation.up() = directionNormalized;
+ rotation.right() = Vector3::cross(rotation.up(), Vector3::zAxis()).normalized();
+ rotation.backward() = Vector3::cross(rotation.right(), rotation.up());
+ CORRADE_INTERNAL_ASSERT(rotation.up().isNormalized() && rotation.backward().isNormalized());
+ }
+ }
+
+ /* Scaling and translation */
+ return Matrix4::translation(0.5f*(a + b))*rotation*Matrix4::scaling({radius, length, radius});
+}
+
+}}}
+
+#endif
diff --git a/src/DebugTools/Implementation/ForceRendererTransformation.h b/src/DebugTools/Implementation/ForceRendererTransformation.h
index 83879104c..8674cbafa 100644
--- a/src/DebugTools/Implementation/ForceRendererTransformation.h
+++ b/src/DebugTools/Implementation/ForceRendererTransformation.h
@@ -24,6 +24,7 @@
DEALINGS IN THE SOFTWARE.
*/
+#include "Math/Functions.h"
#include "Math/Matrix3.h"
#include "Math/Matrix4.h"
#include "Magnum.h"
@@ -34,7 +35,7 @@ namespace Magnum { namespace DebugTools { namespace Implementation {
template typename DimensionTraits::MatrixType forceRendererTransformation(const typename DimensionTraits::VectorType& forcePosition, const typename DimensionTraits::VectorType& force);
template<> inline Matrix3 forceRendererTransformation<2>(const Vector2& forcePosition, const Vector2& force) {
- return Matrix3::from({force, Vector2(-force.y(), force.x())}, forcePosition);
+ return Matrix3::from({force, force.perpendicular()}, forcePosition);
}
template<> Matrix4 forceRendererTransformation<3>(const Vector3& forcePosition, const Vector3& force) {
@@ -48,18 +49,15 @@ template<> Matrix4 forceRendererTransformation<3>(const Vector3& forcePosition,
const Float dot = Vector3::dot(force/forceLength, Vector3::xAxis());
/* Force is parallel to X axis, just scaling */
- if(dot > 1.0f - Math::TypeTraits::epsilon())
- return translation*Matrix4::scaling(Vector3(forceLength));
-
- /* Force is antiparallel to X axis, scaling inverted on X */
- if(-dot > 1.0f - Math::TypeTraits::epsilon())
- return translation*Matrix4::scaling({-forceLength, forceLength, forceLength});
+ if(Math::abs(dot) > 1.0f - Math::TypeTraits::epsilon())
+ return translation*Matrix4::scaling({Math::sign(dot)*forceLength, forceLength, forceLength});
/* Normal of plane going through force vector and X axis vector */
const Vector3 normal = Vector3::cross(Vector3::xAxis(), force).normalized();
/* Third base vector, orthogonal to force and normal */
- const Vector3 binormal = Vector3::cross(normal, force).normalized();
+ const Vector3 binormal = Vector3::cross(normal, force/forceLength);
+ CORRADE_INTERNAL_ASSERT(binormal.isNormalized());
/* Transformation matrix from scaled base vectors and translation vector */
return Matrix4::from({force, normal*forceLength, binormal*forceLength}, forcePosition);
diff --git a/src/DebugTools/Implementation/SphereRenderer.cpp b/src/DebugTools/Implementation/SphereRenderer.cpp
index 9a6815738..59362b226 100644
--- a/src/DebugTools/Implementation/SphereRenderer.cpp
+++ b/src/DebugTools/Implementation/SphereRenderer.cpp
@@ -40,7 +40,7 @@ AbstractSphereRenderer<2>::AbstractSphereRenderer(): AbstractShapeRenderer<2>("s
}
AbstractSphereRenderer<3>::AbstractSphereRenderer(): AbstractShapeRenderer<3>("sphere3d", "sphere3d-vertices", "sphere3d-indices") {
- if(!wireframeMesh) createResources(Primitives::UVSphere::wireframe(40, 20));
+ if(!wireframeMesh) createResources(Primitives::UVSphere::wireframe(20, 40));
}
template SphereRenderer::SphereRenderer(const Shapes::Implementation::AbstractShape& sphere): sphere(static_cast>&>(sphere).shape) {}
diff --git a/src/DebugTools/ResourceManager.cpp b/src/DebugTools/ResourceManager.cpp
index 204c28357..6b385af7d 100644
--- a/src/DebugTools/ResourceManager.cpp
+++ b/src/DebugTools/ResourceManager.cpp
@@ -28,13 +28,14 @@
#include "Buffer.h"
#include "Mesh.h"
+#include "MeshView.h"
#include "DebugTools/ForceRenderer.h"
#include "DebugTools/ObjectRenderer.h"
#include "DebugTools/ShapeRenderer.h"
namespace Magnum {
-template class ResourceManager;
+template class ResourceManager;
namespace DebugTools {
diff --git a/src/DebugTools/ResourceManager.h b/src/DebugTools/ResourceManager.h
index ccf907718..f5205e044 100644
--- a/src/DebugTools/ResourceManager.h
+++ b/src/DebugTools/ResourceManager.h
@@ -43,7 +43,9 @@
namespace Magnum {
-extern template ResourceManager MAGNUM_DEBUGTOOLS_EXPORT *& ResourceManager::internalInstance();
+/** @todo Do the listing in one place, not five thousand! */
+
+extern template ResourceManager MAGNUM_DEBUGTOOLS_EXPORT *& ResourceManager::internalInstance();
namespace DebugTools {
@@ -53,7 +55,7 @@ namespace DebugTools {
Stores various data used by debug renderers. See @ref debug-tools for more
information.
*/
-class MAGNUM_DEBUGTOOLS_EXPORT ResourceManager: public Magnum::ResourceManager {
+class MAGNUM_DEBUGTOOLS_EXPORT ResourceManager: public Magnum::ResourceManager {
public:
explicit ResourceManager();
~ResourceManager();
diff --git a/src/DebugTools/ShapeRenderer.cpp b/src/DebugTools/ShapeRenderer.cpp
index 91223c153..ee31c2626 100644
--- a/src/DebugTools/ShapeRenderer.cpp
+++ b/src/DebugTools/ShapeRenderer.cpp
@@ -31,6 +31,8 @@
#include "Implementation/AxisAlignedBoxRenderer.h"
#include "Implementation/BoxRenderer.h"
+#include "Implementation/CapsuleRenderer.h"
+#include "Implementation/CylinderRenderer.h"
#include "Implementation/LineSegmentRenderer.h"
#include "Implementation/PointRenderer.h"
#include "Implementation/SphereRenderer.h"
@@ -56,6 +58,12 @@ template<> void createDebugMesh(ShapeRenderer<2>& renderer, const Shapes::Implem
case Shapes::AbstractShape2D::Type::Sphere:
renderer.renderers.push_back(new Implementation::SphereRenderer<2>(shape));
break;
+ case Shapes::AbstractShape2D::Type::Capsule:
+ renderer.renderers.push_back(new Implementation::CapsuleRenderer<2>(shape));
+ break;
+ case Shapes::AbstractShape2D::Type::Cylinder:
+ renderer.renderers.push_back(new Implementation::CylinderRenderer<2>(shape));
+ break;
case Shapes::AbstractShape2D::Type::Composition: {
const Shapes::Composition2D& composition =
static_cast&>(shape).shape;
@@ -84,6 +92,12 @@ template<> void createDebugMesh(ShapeRenderer<3>& renderer, const Shapes::Implem
case Shapes::AbstractShape3D::Type::Sphere:
renderer.renderers.push_back(new Implementation::SphereRenderer<3>(shape));
break;
+ case Shapes::AbstractShape3D::Type::Capsule:
+ renderer.renderers.push_back(new Implementation::CapsuleRenderer<3>(shape));
+ break;
+ case Shapes::AbstractShape3D::Type::Cylinder:
+ renderer.renderers.push_back(new Implementation::CylinderRenderer<3>(shape));
+ break;
case Shapes::AbstractShape3D::Type::Composition: {
const Shapes::Composition3D& composition =
static_cast&>(shape).shape;
diff --git a/src/DebugTools/Test/CMakeLists.txt b/src/DebugTools/Test/CMakeLists.txt
index 1e945d0c0..35fca1640 100644
--- a/src/DebugTools/Test/CMakeLists.txt
+++ b/src/DebugTools/Test/CMakeLists.txt
@@ -22,5 +22,7 @@
# DEALINGS IN THE SOFTWARE.
#
+corrade_add_test(DebugToolsCapsuleRendererTest CapsuleRendererTest.cpp LIBRARIES MagnumMathTestLib)
+corrade_add_test(DebugToolsCylinderRendererTest CylinderRendererTest.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(DebugToolsForceRendererTest ForceRendererTest.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(DebugToolsLineSegmentRendererTest LineSegmentRendererTest.cpp LIBRARIES MagnumMathTestLib)
diff --git a/src/DebugTools/Test/CapsuleRendererTest.cpp b/src/DebugTools/Test/CapsuleRendererTest.cpp
new file mode 100644
index 000000000..4c0f7d762
--- /dev/null
+++ b/src/DebugTools/Test/CapsuleRendererTest.cpp
@@ -0,0 +1,177 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+
+#include "DebugTools/Implementation/CapsuleRendererTransformation.h"
+
+namespace Magnum { namespace DebugTools { namespace Test {
+
+class CapsuleRendererTest: public TestSuite::Tester {
+ public:
+ explicit CapsuleRendererTest();
+
+ void zeroLength2D();
+ void common2D();
+
+ void zeroLength3D();
+ void parallel3D();
+ void antiParallel3D();
+ void common3D();
+};
+
+CapsuleRendererTest::CapsuleRendererTest() {
+ addTests({&CapsuleRendererTest::zeroLength2D,
+ &CapsuleRendererTest::common2D,
+
+ &CapsuleRendererTest::zeroLength3D,
+ &CapsuleRendererTest::parallel3D,
+ &CapsuleRendererTest::antiParallel3D,
+ &CapsuleRendererTest::common3D});
+}
+
+void CapsuleRendererTest::zeroLength2D() {
+ const Vector2 a(0.5f, 3.0f);
+ std::array transformation = Implementation::capsuleRendererTransformation<2>(a, a, 3.5f);
+
+ const auto scaling = Math::Matrix<2, Float>::fromDiagonal(Vector2(3.5f));
+ CORRADE_COMPARE(transformation[0].rotationScaling(), scaling);
+ CORRADE_COMPARE(transformation[1].rotationScaling(), (Math::Matrix<2, Float>::fromDiagonal({3.5f, 0.0f})));
+ CORRADE_COMPARE(transformation[2].rotationScaling(), scaling);
+
+ CORRADE_COMPARE(transformation[0].translation(), a);
+ CORRADE_COMPARE(transformation[1].translation(), a);
+ CORRADE_COMPARE(transformation[2].translation(), a);
+}
+
+void CapsuleRendererTest::common2D() {
+ const Vector2 a(0.5f, 3.0f);
+ const Vector2 b(7.5f, -1.0f);
+ std::array transformation = Implementation::capsuleRendererTransformation<2>(a, b, 3.5f);
+
+ /* Vector from capsule center to top hemisphere center */
+ const Vector2 up(3.5f, -2.0f);
+ CORRADE_COMPARE(transformation[0].up(), up.resized(3.5f));
+ CORRADE_COMPARE(transformation[1].up(), up);
+ CORRADE_COMPARE(transformation[2].up(), up.resized(3.5f));
+
+ const auto right = Vector2(4.0f, 7.0f).resized(3.5f);
+ CORRADE_COMPARE(transformation[0].right(), right);
+ CORRADE_COMPARE(transformation[1].right(), right);
+ CORRADE_COMPARE(transformation[2].right(), right);
+
+ /* Orthogonality */
+ CORRADE_COMPARE(Vector2::dot(transformation[0].up(), transformation[0].right()), 0.0f);
+
+ const Vector2 capDistance = up.resized(3.5f);
+ CORRADE_COMPARE(transformation[0].translation(), a+capDistance);
+ CORRADE_COMPARE(transformation[1].translation(), 0.5f*(a + b));
+ CORRADE_COMPARE(transformation[2].translation(), b-capDistance);
+}
+
+void CapsuleRendererTest::zeroLength3D() {
+ const Vector3 a(0.5f, 3.0f, 7.0f);
+ std::array transformation = Implementation::capsuleRendererTransformation<3>(a, a, 3.5f);
+
+ const auto scaling = Math::Matrix<3, Float>::fromDiagonal(Vector3(3.5f));
+ CORRADE_COMPARE(transformation[0].rotationScaling(), scaling);
+ CORRADE_COMPARE(transformation[1].rotationScaling(), (Math::Matrix<3, Float>::fromDiagonal({3.5f, 0.0f, 3.5f})));
+ CORRADE_COMPARE(transformation[2].rotationScaling(), scaling);
+
+ CORRADE_COMPARE(transformation[0].translation(), a);
+ CORRADE_COMPARE(transformation[1].translation(), a);
+ CORRADE_COMPARE(transformation[2].translation(), a);
+}
+
+void CapsuleRendererTest::parallel3D() {
+ const Vector3 a(0.5f, 3.0f, 7.0f);
+ const Vector3 b(0.5f, 3.0f, 11.0f);
+ std::array transformation = Implementation::capsuleRendererTransformation<3>(a, b, 3.5f);
+
+ const auto rotation = Matrix4::rotationX(Deg(90.0f));
+ const auto scaling = (rotation*Matrix4::scaling(Vector3(3.5f))).rotationScaling();
+ CORRADE_COMPARE(transformation[0].rotationScaling(), scaling);
+ CORRADE_COMPARE(transformation[1].rotationScaling(),
+ (rotation*Matrix4::scaling({3.5f, 2.0f, 3.5f})).rotationScaling());
+ CORRADE_COMPARE(transformation[2].rotationScaling(), scaling);
+
+ const auto capDistance = Vector3::zAxis(3.5f);
+ CORRADE_COMPARE(transformation[0].translation(), a+capDistance);
+ CORRADE_COMPARE(transformation[1].translation(), a+Vector3::zAxis(2.0f));
+ CORRADE_COMPARE(transformation[2].translation(), b-capDistance);
+}
+
+void CapsuleRendererTest::antiParallel3D() {
+ const Vector3 a(0.5f, 3.0f, 7.0f);
+ const Vector3 b(0.5f, 3.0f, 3.0f);
+ std::array transformation = Implementation::capsuleRendererTransformation<3>(a, b, 3.5f);
+
+ const auto rotation = Matrix4::rotationX(-Deg(90.0f));
+ const auto rotationScaling = (rotation*Matrix4::scaling(Vector3(3.5f))).rotationScaling();
+ CORRADE_COMPARE(transformation[0].rotationScaling(), rotationScaling);
+ CORRADE_COMPARE(transformation[1].rotationScaling(),
+ (rotation*Matrix4::scaling({3.5f, 2.0f, 3.5f})).rotationScaling());
+ CORRADE_COMPARE(transformation[2].rotationScaling(), rotationScaling);
+
+ const auto capDistance = Vector3::zAxis(-3.5f);
+ CORRADE_COMPARE(transformation[0].translation(), a+capDistance);
+ CORRADE_COMPARE(transformation[1].translation(), a+Vector3::zAxis(-2.0f));
+ CORRADE_COMPARE(transformation[2].translation(), b-capDistance);
+}
+
+void CapsuleRendererTest::common3D() {
+ const Vector3 a(0.5f, 3.0f, 7.0f);
+ const Vector3 b(7.5f, -1.0f, 1.5f);
+ std::array transformation = Implementation::capsuleRendererTransformation<3>(a, b, 3.5f);
+
+ /* Vector from capsule center to top hemisphere center */
+ const Vector3 up(3.5f, -2.0f, -2.75f);
+ CORRADE_COMPARE(transformation[0].up(), up.resized(3.5f));
+ CORRADE_COMPARE(transformation[1].up(), up);
+ CORRADE_COMPARE(transformation[2].up(), up.resized(3.5f));
+
+ const auto right = Vector3(-2.0f, -3.5f, 0.0f).resized(3.5f);
+ CORRADE_COMPARE(transformation[0].right(), right);
+ CORRADE_COMPARE(transformation[1].right(), right);
+ CORRADE_COMPARE(transformation[2].right(), right);
+
+ const auto backward = Vector3(9.625f, -5.5f, 16.25f).resized(3.5f);
+ CORRADE_COMPARE(transformation[0].backward(), backward);
+ CORRADE_COMPARE(transformation[1].backward(), backward);
+ CORRADE_COMPARE(transformation[2].backward(), backward);
+
+ /* Orthogonality */
+ CORRADE_COMPARE(Vector3::dot(transformation[0].up(), transformation[0].right()), 0.0f);
+ CORRADE_COMPARE(Vector3::dot(transformation[0].up(), transformation[0].backward()), 0.0f);
+ CORRADE_COMPARE(Vector3::dot(transformation[0].right(), transformation[0].backward()), 0.0f);
+
+ const Vector3 capDistance = up.resized(3.5f);
+ CORRADE_COMPARE(transformation[0].translation(), a+capDistance);
+ CORRADE_COMPARE(transformation[1].translation(), 0.5f*(a + b));
+ CORRADE_COMPARE(transformation[2].translation(), b-capDistance);
+}
+
+}}}
+
+CORRADE_TEST_MAIN(Magnum::DebugTools::Test::CapsuleRendererTest)
diff --git a/src/DebugTools/Test/CylinderRendererTest.cpp b/src/DebugTools/Test/CylinderRendererTest.cpp
new file mode 100644
index 000000000..958003f96
--- /dev/null
+++ b/src/DebugTools/Test/CylinderRendererTest.cpp
@@ -0,0 +1,125 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 VladimÃr VondruÅ¡
+
+ 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
+
+#include "DebugTools/Implementation/CylinderRendererTransformation.h"
+
+namespace Magnum { namespace DebugTools { namespace Test {
+
+class CylinderRendererTest: public TestSuite::Tester {
+ public:
+ explicit CylinderRendererTest();
+
+ void zeroLength2D();
+ void common2D();
+
+ void zeroLength3D();
+ void parallel3D();
+ void antiParallel3D();
+ void common3D();
+};
+
+CylinderRendererTest::CylinderRendererTest() {
+ addTests({&CylinderRendererTest::zeroLength2D,
+ &CylinderRendererTest::common2D,
+
+ &CylinderRendererTest::zeroLength3D,
+ &CylinderRendererTest::parallel3D,
+ &CylinderRendererTest::antiParallel3D,
+ &CylinderRendererTest::common3D});
+}
+
+void CylinderRendererTest::zeroLength2D() {
+ const Vector2 a(0.5f, 3.0f);
+ const Matrix3 transformation = Implementation::cylinderRendererTransformation<2>(a, a, 3.5f);
+
+ CORRADE_COMPARE(transformation.rotationScaling(), (Math::Matrix<2, Float>::fromDiagonal({3.5f, 0.0f})));
+ CORRADE_COMPARE(transformation.translation(), a);
+}
+
+void CylinderRendererTest::common2D() {
+ const Vector2 a(0.5f, 3.0f);
+ const Vector2 b(7.5f, -1.0f);
+ const Matrix3 transformation = Implementation::cylinderRendererTransformation<2>(a, b, 3.5f);
+
+ /* Rotation + scaling, test orthogonality */
+ CORRADE_COMPARE(transformation.up(), Vector2(3.5f, -2.0f));
+ CORRADE_COMPARE(transformation.right(), Vector2(4.0f, 7.0f).resized(3.5f));
+ CORRADE_COMPARE(Vector2::dot(transformation.up(), transformation.right()), 0.0f);
+
+ CORRADE_COMPARE(transformation.translation(), 0.5f*(a + b));
+}
+
+void CylinderRendererTest::zeroLength3D() {
+ const Vector3 a(0.5f, 3.0f, 7.0f);
+ const Matrix4 transformation = Implementation::cylinderRendererTransformation<3>(a, a, 3.5f);
+
+ CORRADE_COMPARE(transformation.rotationScaling(), (Math::Matrix<3, Float>::fromDiagonal({3.5f, 0.0f, 3.5f})));
+ CORRADE_COMPARE(transformation.translation(), a);
+}
+
+void CylinderRendererTest::parallel3D() {
+ const Vector3 a(0.5f, 3.0f, 7.0f);
+ const Vector3 b(0.5f, 3.0f, 11.0f);
+ const Matrix4 transformation = Implementation::cylinderRendererTransformation<3>(a, b, 3.5f);
+
+ CORRADE_COMPARE(transformation.rotationScaling(),
+ (Matrix4::rotationX(Deg(90.0f))*Matrix4::scaling({3.5f, 2.0f, 3.5f})).rotationScaling());
+
+ CORRADE_COMPARE(transformation.translation(), a+Vector3::zAxis(2.0f));
+}
+
+void CylinderRendererTest::antiParallel3D() {
+ const Vector3 a(0.5f, 3.0f, 7.0f);
+ const Vector3 b(0.5f, 3.0f, 3.0f);
+ const Matrix4 transformation = Implementation::cylinderRendererTransformation<3>(a, b, 3.5f);
+
+ CORRADE_COMPARE(transformation.rotationScaling(),
+ (Matrix4::rotationX(-Deg(90.0f))*Matrix4::scaling({3.5f, 2.0f, 3.5f})).rotationScaling());
+
+ CORRADE_COMPARE(transformation.translation(), a+Vector3::zAxis(-2.0f));
+}
+
+void CylinderRendererTest::common3D() {
+ const Vector3 a(0.5f, 3.0f, 7.0f);
+ const Vector3 b(7.5f, -1.0f, 1.5f);
+ const Matrix4 transformation = Implementation::cylinderRendererTransformation<3>(a, b, 3.5f);
+
+ /* Rotation + scaling */
+ CORRADE_COMPARE(transformation.up(), Vector3(3.5f, -2.0f, -2.75f));
+ CORRADE_COMPARE(transformation.right(), Vector3(-2.0f, -3.5f, 0.0f).resized(3.5f));
+ CORRADE_COMPARE(transformation.backward(), Vector3(9.625f, -5.5f, 16.25f).resized(3.5f));
+
+ /* Orthogonality */
+ CORRADE_COMPARE(Vector3::dot(transformation.up(), transformation.right()), 0.0f);
+ CORRADE_COMPARE(Vector3::dot(transformation.up(), transformation.backward()), 0.0f);
+ CORRADE_COMPARE(Vector3::dot(transformation.right(), transformation.backward()), 0.0f);
+
+ CORRADE_COMPARE(transformation.translation(), 0.5f*(a + b));
+}
+
+}}}
+
+CORRADE_TEST_MAIN(Magnum::DebugTools::Test::CylinderRendererTest)
diff --git a/src/DebugTools/Test/ForceRendererTest.cpp b/src/DebugTools/Test/ForceRendererTest.cpp
index e02d3ce7d..d560e8e38 100644
--- a/src/DebugTools/Test/ForceRendererTest.cpp
+++ b/src/DebugTools/Test/ForceRendererTest.cpp
@@ -33,9 +33,7 @@ class ForceRendererTest: public TestSuite::Tester {
explicit ForceRendererTest();
void zero2D();
- void parallel2D();
- void antiParallel2D();
- void arbitrary2D();
+ void common2D();
void zero3D();
void parallel3D();
@@ -45,9 +43,7 @@ class ForceRendererTest: public TestSuite::Tester {
ForceRendererTest::ForceRendererTest() {
addTests({&ForceRendererTest::zero2D,
- &ForceRendererTest::parallel2D,
- &ForceRendererTest::antiParallel2D,
- &ForceRendererTest::arbitrary2D,
+ &ForceRendererTest::common2D,
&ForceRendererTest::zero3D,
&ForceRendererTest::parallel3D,
@@ -60,17 +56,7 @@ void ForceRendererTest::zero2D() {
Matrix3::translation({0.5f, -3.0f})*Matrix3::scaling(Vector2(0.0f)));
}
-void ForceRendererTest::parallel2D() {
- CORRADE_COMPARE(Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, Vector2::xAxis(2.5f)),
- Matrix3::translation({0.5f, -3.0f})*Matrix3::scaling(Vector2(2.5f)));
-}
-
-void ForceRendererTest::antiParallel2D() {
- CORRADE_COMPARE(Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, Vector2::xAxis(-2.5f)),
- Matrix3::translation({0.5f, -3.0f})*Matrix3::scaling(Vector2(-2.5f)));
-}
-
-void ForceRendererTest::arbitrary2D() {
+void ForceRendererTest::common2D() {
Vector2 force(2.7f, -11.5f);
Matrix3 m = Implementation::forceRendererTransformation<2>({0.5f, -3.0f}, force);
@@ -81,7 +67,7 @@ void ForceRendererTest::arbitrary2D() {
/* All vectors have the same length */
CORRADE_COMPARE(m.up().length(), force.length());
- /* All vectors are parallel */
+ /* All vectors are orthogonal */
CORRADE_COMPARE(Vector2::dot(m.right(), m.up()), 0.0f);
}
@@ -112,10 +98,11 @@ void ForceRendererTest::arbitrary3D() {
CORRADE_COMPARE(m.up().length(), force.length());
CORRADE_COMPARE(m.backward().length(), force.length());
- /* All vectors are parallel */
+ /* All vectors are orthogonal */
CORRADE_COMPARE(Vector3::dot(m.right(), m.up()), 0.0f);
CORRADE_COMPARE(Vector3::dot(m.right(), m.backward()), 0.0f);
- CORRADE_COMPARE(Vector3::dot(m.up(), m.backward()), 0.0f);
+ /** @todo This shouldn't be too different */
+ CORRADE_COMPARE(Vector3::dot(m.up(), m.backward()), -Math::TypeTraits::epsilon());
}
}}}}
diff --git a/src/Framebuffer.h b/src/Framebuffer.h
index 8f79517b7..3da23479c 100644
--- a/src/Framebuffer.h
+++ b/src/Framebuffer.h
@@ -161,7 +161,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @see attachRenderbuffer(), attachTexture1D(), attachTexture2D(),
* attachCubeMapTexture(), attachTexture3D()
*/
- class BufferAttachment {
+ class MAGNUM_EXPORT BufferAttachment {
public:
/** @brief Depth buffer */
static const BufferAttachment Depth;
diff --git a/src/Magnum.h b/src/Magnum.h
index c79918592..8aea39d19 100644
--- a/src/Magnum.h
+++ b/src/Magnum.h
@@ -392,6 +392,7 @@ typedef ImageReference<2> ImageReference2D;
typedef ImageReference<3> ImageReference3D;
class Mesh;
+class MeshView;
/* AbstractQuery is not used directly */
class PrimitiveQuery;
diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h
index c0c3510cf..07f2c204a 100644
--- a/src/Math/Matrix3.h
+++ b/src/Math/Matrix3.h
@@ -168,7 +168,7 @@ template class Matrix3: public Matrix<3, T> {
*
* Upper-left 2x2 part of the matrix.
* @see from(const Matrix<2, T>&, const Vector2&), rotation() const
- * rotationNormalized(), rotation(T),
+ * rotationNormalized(), @ref uniformScaling(), rotation(T),
* Matrix4::rotationScaling() const
*/
constexpr Matrix<2, T> rotationScaling() const {
@@ -181,7 +181,8 @@ template class Matrix3: public Matrix<3, T> {
*
* Similar to @ref rotationScaling(), but additionally checks that the
* base vectors are normalized.
- * @see rotation() const, @ref Matrix4::rotationNormalized()
+ * @see rotation() const, @ref uniformScaling(),
+ * @ref Matrix4::rotationNormalized()
* @todo assert also orthogonality or this is good enough?
*/
Matrix<2, T> rotationNormalized() const {
@@ -194,17 +195,47 @@ template class Matrix3: public Matrix<3, T> {
/**
* @brief 2D rotation part of the matrix
*
- * Normalized upper-left 2x2 part of the matrix.
- * @see rotationNormalized(), rotationScaling() const, rotation(T),
- * Matrix4::rotation() const
- * @todo assert uniform scaling (otherwise this would be garbage)
+ * Normalized upper-left 2x2 part of the matrix. Expects uniform
+ * scaling.
+ * @see rotationNormalized(), rotationScaling(), @ref uniformScaling(),
+ * rotation(T), Matrix4::rotation() const
*/
Matrix<2, T> rotation() const {
+ CORRADE_ASSERT(TypeTraits::equals((*this)[0].xy().dot(), (*this)[1].xy().dot()),
+ "Math::Matrix3::rotation(): the matrix doesn't have uniform scaling", {});
return {(*this)[0].xy().normalized(),
(*this)[1].xy().normalized()};
}
- /** @todo uniform scaling extraction */
+ /**
+ * @brief Uniform scaling part of the matrix, squared
+ *
+ * Squared length of vectors in upper-left 2x2 part of the matrix.
+ * Expects that the scaling is the same in all axes. Faster alternative
+ * to @ref uniformScaling(), because it doesn't compute the square
+ * root.
+ * @see @ref rotationScaling(), @ref rotation(),
+ * @ref rotationNormalized(), @ref scaling(const Vector2&),
+ * @ref Matrix4::uniformScaling()
+ */
+ T uniformScalingSquared() const {
+ const T scalingSquared = (*this)[0].xy().dot();
+ CORRADE_ASSERT(TypeTraits::equals((*this)[1].xy().dot(), scalingSquared),
+ "Math::Matrix3::uniformScaling(): the matrix doesn't have uniform scaling", {});
+ return scalingSquared;
+ }
+
+ /**
+ * @brief Uniform scaling part of the matrix
+ *
+ * Length of vectors in upper-left 2x2 part of the matrix. Expects that
+ * the scaling is the same in all axes. Use faster alternative
+ * @ref uniformScalingSquared() where possible.
+ * @see @ref rotationScaling(), @ref rotation(),
+ * @ref rotationNormalized(), @ref scaling(const Vector2&),
+ * @ref Matrix4::uniformScaling()
+ */
+ T uniformScaling() const { return std::sqrt(uniformScalingSquared()); }
/**
* @brief Right-pointing 2D vector
diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h
index 6e7fbe7f7..872cfffee 100644
--- a/src/Math/Matrix4.h
+++ b/src/Math/Matrix4.h
@@ -231,8 +231,8 @@ template class Matrix4: public Matrix<4, T> {
*
* Upper-left 3x3 part of the matrix.
* @see from(const Matrix<3, T>&, const Vector3&), rotation() const,
- * rotationNormalized(), rotation(T, const Vector3&),
- * Matrix3::rotationScaling() const
+ * rotationNormalized(), @ref uniformScaling(),
+ * rotation(T, const Vector3&), Matrix3::rotationScaling() const
*/
/* Not Matrix3, because it is for affine 2D transformations */
constexpr Matrix<3, T> rotationScaling() const {
@@ -246,7 +246,8 @@ template class Matrix4: public Matrix<4, T> {
*
* Similar to @ref rotationScaling(), but additionally checks that the
* base vectors are normalized.
- * @see rotation() const, @ref Matrix3::rotationNormalized()
+ * @see rotation() const, @ref uniformScaling(),
+ * @ref Matrix3::rotationNormalized()
* @todo assert also orthogonality or this is good enough?
*/
/* Not Matrix3, because it is for affine 2D transformations */
@@ -261,15 +262,39 @@ template class Matrix4: public Matrix<4, T> {
/**
* @brief 3D rotation part of the matrix
*
- * Normalized upper-left 3x3 part of the matrix.
+ * Normalized upper-left 3x3 part of the matrix. Expects uniform
+ * scaling.
* @see rotationNormalized(), rotationScaling() const,
- * rotation(T, const Vector3&), Matrix3::rotation() const
- * @todo assert uniform scaling (otherwise this would be garbage)
+ * @ref uniformScaling(), rotation(T, const Vector3&),
+ * Matrix3::rotation() const
*/
/* Not Matrix3, because it is for affine 2D transformations */
Matrix<3, T> rotation() const;
- /** @todo uniform scaling extraction */
+ /**
+ * @brief Uniform scaling part of the matrix, squared
+ *
+ * Squared length of vectors in upper-left 3x3 part of the matrix.
+ * Expects that the scaling is the same in all axes. Faster alternative
+ * to @ref uniformScaling(), because it doesn't compute the square
+ * root.
+ * @see @ref rotationScaling(), @ref rotation(),
+ * @ref rotationNormalized(), @ref scaling(const Vector3&),
+ * @ref Matrix3::uniformScaling()
+ */
+ T uniformScalingSquared() const;
+
+ /**
+ * @brief Uniform scaling part of the matrix
+ *
+ * Length of vectors in upper-left 3x3 part of the matrix. Expects that
+ * the scaling is the same in all axes. Use faster alternative
+ * @ref uniformScalingSquared() where possible.
+ * @see @ref rotationScaling(), @ref rotation(),
+ * @ref rotationNormalized(), @ref scaling(const Vector3&),
+ * @ref Matrix3::uniformScaling()
+ */
+ T uniformScaling() const { return std::sqrt(uniformScalingSquared()); }
/**
* @brief Right-pointing 3D vector
@@ -457,11 +482,22 @@ template Matrix4 Matrix4::perspectiveProjection(const Vector2&
}
template inline Matrix<3, T> Matrix4::rotation() const {
+ CORRADE_ASSERT(TypeTraits::equals((*this)[0].xyz().dot(), (*this)[1].xyz().dot()) &&
+ TypeTraits::equals((*this)[1].xyz().dot(), (*this)[2].xyz().dot()),
+ "Math::Matrix4::rotation(): the matrix doesn't have uniform scaling", {});
return {(*this)[0].xyz().normalized(),
(*this)[1].xyz().normalized(),
(*this)[2].xyz().normalized()};
}
+template T Matrix4::uniformScalingSquared() const {
+ const T scalingSquared = (*this)[0].xyz().dot();
+ CORRADE_ASSERT(TypeTraits::equals((*this)[1].xyz().dot(), scalingSquared) &&
+ TypeTraits::equals((*this)[2].xyz().dot(), scalingSquared),
+ "Math::Matrix4::uniformScaling(): the matrix doesn't have uniform scaling", {});
+ return scalingSquared;
+}
+
template Matrix4 Matrix4::invertedRigid() const {
CORRADE_ASSERT(isRigidTransformation(),
"Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation", {});
diff --git a/src/Math/Test/Matrix3Test.cpp b/src/Math/Test/Matrix3Test.cpp
index 6daafea13..778f78e3a 100644
--- a/src/Math/Test/Matrix3Test.cpp
+++ b/src/Math/Test/Matrix3Test.cpp
@@ -78,6 +78,7 @@ class Matrix3Test: public Corrade::TestSuite::Tester {
void rotationScalingPart();
void rotationNormalizedPart();
void rotationPart();
+ void uniformScalingPart();
void vectorParts();
void invertedRigid();
void transform();
@@ -113,6 +114,7 @@ Matrix3Test::Matrix3Test() {
&Matrix3Test::rotationScalingPart,
&Matrix3Test::rotationNormalizedPart,
&Matrix3Test::rotationPart,
+ &Matrix3Test::uniformScalingPart,
&Matrix3Test::vectorParts,
&Matrix3Test::invertedRigid,
&Matrix3Test::transform,
@@ -322,21 +324,32 @@ void Matrix3Test::rotationPart() {
CORRADE_COMPARE(rotationTranslationPart, expectedRotationPart);
/* Test uniform scaling */
- Matrix3 rotationScaling = rotation*Matrix3::scaling(Vector2(9.0f));
+ Matrix3 rotationScaling = rotation*Matrix3::scaling(Vector2(3.0f));
Matrix2 rotationScalingPart = rotationScaling.rotation();
CORRADE_COMPARE(rotationScalingPart.determinant(), 1.0f);
CORRADE_COMPARE(rotationScalingPart*rotationScalingPart.transposed(), Matrix2());
CORRADE_COMPARE(rotationScalingPart, expectedRotationPart);
/* Fails on non-uniform scaling */
- {
- CORRADE_EXPECT_FAIL("Assertion on uniform scaling is not implemented yet.");
- std::ostringstream o;
- Error::setOutput(&o);
- Matrix3 rotationScaling2 = rotation*Matrix3::scaling(Vector2::yScale(3.5f));
- CORRADE_COMPARE(o.str(), "Math::Matrix3::rotation(): the matrix doesn't have uniform scaling\n");
- CORRADE_COMPARE(rotationScaling2, Matrix3(Matrix3::Zero));
- }
+ std::ostringstream o;
+ Error::setOutput(&o);
+ Matrix2 rotationScaling2 = (rotation*Matrix3::scaling(Vector2::yScale(3.5f))).rotation();
+ CORRADE_COMPARE(o.str(), "Math::Matrix3::rotation(): the matrix doesn't have uniform scaling\n");
+ CORRADE_COMPARE(rotationScaling2, Matrix2());
+}
+
+void Matrix3Test::uniformScalingPart() {
+ const Matrix3 rotation = Matrix3::rotation(Deg(-74.0f));
+
+ /* Test uniform scaling */
+ CORRADE_COMPARE((rotation*Matrix3::scaling(Vector2(3.0f))).uniformScaling(), 3.0f);
+
+ /* Fails on non-uniform scaling */
+ std::ostringstream o;
+ Error::setOutput(&o);
+ const Float nonUniformScaling = (rotation*Matrix3::scaling(Vector2::yScale(3.0f))).uniformScaling();
+ CORRADE_COMPARE(o.str(), "Math::Matrix3::uniformScaling(): the matrix doesn't have uniform scaling\n");
+ CORRADE_COMPARE(nonUniformScaling, 0.0f);
}
void Matrix3Test::vectorParts() {
diff --git a/src/Math/Test/Matrix4Test.cpp b/src/Math/Test/Matrix4Test.cpp
index c311b6c24..0ccfbc13f 100644
--- a/src/Math/Test/Matrix4Test.cpp
+++ b/src/Math/Test/Matrix4Test.cpp
@@ -85,6 +85,7 @@ class Matrix4Test: public Corrade::TestSuite::Tester {
void rotationScalingPart();
void rotationNormalizedPart();
void rotationPart();
+ void uniformScalingPart();
void vectorParts();
void invertedRigid();
void transform();
@@ -125,6 +126,7 @@ Matrix4Test::Matrix4Test() {
&Matrix4Test::rotationScalingPart,
&Matrix4Test::rotationNormalizedPart,
&Matrix4Test::rotationPart,
+ &Matrix4Test::uniformScalingPart,
&Matrix4Test::vectorParts,
&Matrix4Test::invertedRigid,
&Matrix4Test::transform,
@@ -408,21 +410,32 @@ void Matrix4Test::rotationPart() {
CORRADE_COMPARE(rotationTranslationPart, expectedRotationPart);
/* Test uniform scaling */
- Matrix4 rotationScaling = rotation*Matrix4::scaling(Vector3(9.0f));
+ Matrix4 rotationScaling = rotation*Matrix4::scaling(Vector3(3.0f));
Matrix3 rotationScalingPart = rotationScaling.rotation();
CORRADE_COMPARE(rotationScalingPart.determinant(), 1.0f);
CORRADE_COMPARE(rotationScalingPart*rotationScalingPart.transposed(), Matrix3());
CORRADE_COMPARE(rotationScalingPart, expectedRotationPart);
/* Fails on non-uniform scaling */
- {
- CORRADE_EXPECT_FAIL("Assertion on uniform scaling is not implemented yet.");
- std::ostringstream o;
- Error::setOutput(&o);
- Matrix4 rotationScaling2 = rotation*Matrix4::scaling(Vector3::yScale(3.5f));
- CORRADE_COMPARE(o.str(), "Math::Matrix4::rotation(): the matrix doesn't have uniform scaling\n");
- CORRADE_COMPARE(rotationScaling2, Matrix4(Matrix4::Zero));
- }
+ std::ostringstream o;
+ Error::setOutput(&o);
+ Matrix3 rotationScaling2 = (rotation*Matrix4::scaling(Vector3::yScale(3.5f))).rotation();
+ CORRADE_COMPARE(o.str(), "Math::Matrix4::rotation(): the matrix doesn't have uniform scaling\n");
+ CORRADE_COMPARE(rotationScaling2, Matrix3());
+}
+
+void Matrix4Test::uniformScalingPart() {
+ const Matrix4 rotation = Matrix4::rotation(Deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized());
+
+ /* Test uniform scaling */
+ CORRADE_COMPARE((rotation*Matrix4::scaling(Vector3(3.0f))).uniformScaling(), 3.0f);
+
+ /* Fails on non-uniform scaling */
+ std::ostringstream o;
+ Error::setOutput(&o);
+ const Float nonUniformScaling = (rotation*Matrix4::scaling(Vector3::yScale(3.0f))).uniformScaling();
+ CORRADE_COMPARE(o.str(), "Math::Matrix4::uniformScaling(): the matrix doesn't have uniform scaling\n");
+ CORRADE_COMPARE(nonUniformScaling, 0.0f);
}
void Matrix4Test::vectorParts() {
diff --git a/src/Math/instantiation.cpp b/src/Math/instantiation.cpp
index dcaaaa601..1bf7f918b 100644
--- a/src/Math/instantiation.cpp
+++ b/src/Math/instantiation.cpp
@@ -105,6 +105,46 @@ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Quate
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Quaternion&);
#endif
+/* Check proper size of GL types */
+static_assert(sizeof(Vector<2, Float>) == 8, "Improper size of 2-element Float vector");
+static_assert(sizeof(Vector<3, Float>) == 12, "Improper size of 3-element Float vector");
+static_assert(sizeof(Vector<4, Float>) == 16, "Improper size of 4-element Float vector");
+static_assert(sizeof(Vector<2, Int>) == 8, "Improper size of 2-element Int vector");
+static_assert(sizeof(Vector<3, Int>) == 12, "Improper size of 3-element Int vector");
+static_assert(sizeof(Vector<4, Int>) == 16, "Improper size of 4-element Int vector");
+static_assert(sizeof(Vector<2, UnsignedInt>) == 8, "Improper size of 2-element UnsignedInt vector");
+static_assert(sizeof(Vector<3, UnsignedInt>) == 12, "Improper size of 3-element UnsignedInt vector");
+static_assert(sizeof(Vector<4, UnsignedInt>) == 16, "Improper size of 4-element UnsignedInt vector");
+#ifndef MAGNUM_TARGET_GLES
+static_assert(sizeof(Vector<2, Double>) == 16, "Improper size of 2-element Double vector");
+static_assert(sizeof(Vector<3, Double>) == 24, "Improper size of 3-element Double vector");
+static_assert(sizeof(Vector<4, Double>) == 32, "Improper size of 4-element Double vector");
+#endif
+
+static_assert(sizeof(RectangularMatrix<2, 2, Float>) == 16, "Improper size of 2x2 Float matrix");
+static_assert(sizeof(RectangularMatrix<3, 3, Float>) == 36, "Improper size of 3x3 Float matrix");
+static_assert(sizeof(RectangularMatrix<4, 4, Float>) == 64, "Improper size of 4x4 Float matrix");
+#ifndef MAGNUM_TARGET_GLES
+static_assert(sizeof(RectangularMatrix<2, 2, Double>) == 32, "Improper size of 2x2 Double matrix");
+static_assert(sizeof(RectangularMatrix<3, 3, Double>) == 72, "Improper size of 3x3 Double matrix");
+static_assert(sizeof(RectangularMatrix<4, 4, Double>) == 128, "Improper size of 4x4 Double matrix");
+#endif
+
+static_assert(sizeof(RectangularMatrix<2, 3, Float>) == 24, "Improper size of 2x3 Float matrix");
+static_assert(sizeof(RectangularMatrix<3, 2, Float>) == 24, "Improper size of 3x2 Float matrix");
+static_assert(sizeof(RectangularMatrix<2, 4, Float>) == 32, "Improper size of 2x4 Float matrix");
+static_assert(sizeof(RectangularMatrix<4, 2, Float>) == 32, "Improper size of 4x2 Float matrix");
+static_assert(sizeof(RectangularMatrix<3, 4, Float>) == 48, "Improper size of 3x4 Float matrix");
+static_assert(sizeof(RectangularMatrix<4, 3, Float>) == 48, "Improper size of 4x3 Float matrix");
+#ifndef MAGNUM_TARGET_GLES
+static_assert(sizeof(RectangularMatrix<2, 3, Double>) == 48, "Improper size of 2x3 Double matrix");
+static_assert(sizeof(RectangularMatrix<3, 2, Double>) == 48, "Improper size of 3x2 Double matrix");
+static_assert(sizeof(RectangularMatrix<2, 4, Double>) == 64, "Improper size of 2x4 Double matrix");
+static_assert(sizeof(RectangularMatrix<4, 2, Double>) == 64, "Improper size of 4x2 Double matrix");
+static_assert(sizeof(RectangularMatrix<3, 4, Double>) == 96, "Improper size of 3x4 Double matrix");
+static_assert(sizeof(RectangularMatrix<4, 3, Double>) == 96, "Improper size of 4x3 Double matrix");
+#endif
+
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, Float>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, Float>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 4, Float>&);
diff --git a/src/Mesh.cpp b/src/Mesh.cpp
index ceb74ebae..176e30f97 100644
--- a/src/Mesh.cpp
+++ b/src/Mesh.cpp
@@ -60,9 +60,9 @@ std::size_t Mesh::indexSize(IndexType type) {
Mesh::Mesh(Primitive primitive): _primitive(primitive), _vertexCount(0), _indexCount(0)
#ifndef MAGNUM_TARGET_GLES2
- , indexStart(0), indexEnd(0)
+ , _indexStart(0), _indexEnd(0)
#endif
- , indexOffset(0), indexType(IndexType::UnsignedInt), indexBuffer(nullptr)
+ , _indexOffset(0), _indexType(IndexType::UnsignedInt), _indexBuffer(nullptr)
{
(this->*createImplementation)();
}
@@ -70,49 +70,49 @@ Mesh::Mesh(Primitive primitive): _primitive(primitive), _vertexCount(0), _indexC
Mesh::~Mesh() {
/* Remove current vao from the state */
GLuint& current = Context::current()->state().mesh->currentVAO;
- if(current == vao) current = 0;
+ if(current == _id) current = 0;
(this->*destroyImplementation)();
}
-Mesh::Mesh(Mesh&& other): vao(other.vao), _primitive(other._primitive), _vertexCount(other._vertexCount), _indexCount(other._indexCount)
+Mesh::Mesh(Mesh&& other): _id(other._id), _primitive(other._primitive), _vertexCount(other._vertexCount), _indexCount(other._indexCount)
#ifndef MAGNUM_TARGET_GLES2
- , indexStart(other.indexStart), indexEnd(other.indexEnd)
+ , _indexStart(other._indexStart), _indexEnd(other._indexEnd)
#endif
- , indexOffset(other.indexOffset), indexType(other.indexType), indexBuffer(other.indexBuffer), attributes(std::move(other.attributes))
+ , _indexOffset(other._indexOffset), _indexType(other._indexType), _indexBuffer(other._indexBuffer), _attributes(std::move(other._attributes))
#ifndef MAGNUM_TARGET_GLES2
- , integerAttributes(std::move(other.integerAttributes))
+ , _integerAttributes(std::move(other._integerAttributes))
#ifndef MAGNUM_TARGET_GLES
- , longAttributes(std::move(other.longAttributes))
+ , _longAttributes(std::move(other._longAttributes))
#endif
#endif
{
- other.vao = 0;
+ other._id = 0;
}
Mesh& Mesh::operator=(Mesh&& other) {
(this->*destroyImplementation)();
- vao = other.vao;
+ _id = other._id;
_primitive = other._primitive;
_vertexCount = other._vertexCount;
_indexCount = other._indexCount;
#ifndef MAGNUM_TARGET_GLES2
- indexStart = other.indexStart;
- indexEnd = other.indexEnd;
+ _indexStart = other._indexStart;
+ _indexEnd = other._indexEnd;
#endif
- indexOffset = other.indexOffset;
- indexType = other.indexType;
- indexBuffer = other.indexBuffer;
- attributes = std::move(other.attributes);
+ _indexOffset = other._indexOffset;
+ _indexType = other._indexType;
+ _indexBuffer = other._indexBuffer;
+ _attributes = std::move(other._attributes);
#ifndef MAGNUM_TARGET_GLES2
- integerAttributes = std::move(other.integerAttributes);
+ _integerAttributes = std::move(other._integerAttributes);
#ifndef MAGNUM_TARGET_GLES
- longAttributes = std::move(other.longAttributes);
+ _longAttributes = std::move(other._longAttributes);
#endif
#endif
- other.vao = 0;
+ other._id = 0;
return *this;
}
@@ -120,14 +120,14 @@ Mesh& Mesh::operator=(Mesh&& other) {
Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end) {
#ifdef CORRADE_TARGET_NACL
CORRADE_ASSERT(buffer.targetHint() == Buffer::Target::ElementArray,
- "Mesh::setIndexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::ElementArray << "but got" << buffer.targetHint(), this);
+ "Mesh::setIndexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::ElementArray << "but got" << buffer.targetHint(), *this);
#endif
- indexOffset = offset;
- indexType = type;
+ _indexOffset = offset;
+ _indexType = type;
#ifndef MAGNUM_TARGET_GLES2
- indexStart = start;
- indexEnd = end;
+ _indexStart = start;
+ _indexEnd = end;
#else
static_cast(start);
static_cast(end);
@@ -136,25 +136,25 @@ Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, Unsi
return *this;
}
-void Mesh::draw() {
+void Mesh::drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset, Int indexCount, Int indexStart, Int indexEnd) {
/* Nothing to draw */
- if(!_vertexCount && !_indexCount) return;
+ if(!vertexCount && !indexCount) return;
(this->*bindImplementation)();
/* Non-indexed mesh */
- if(!_indexCount)
- glDrawArrays(static_cast