From 5bb358e05d32b451ca8ee538f5c930cf8a86420f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 4 Jun 2018 16:08:42 +0200 Subject: [PATCH] Audio: cleaned up the scene graph implementation. * De-inlined most of the code * Reduced includes in headers * Formatting * Global variables don't need to be exposed publicly --- src/Magnum/Audio/CMakeLists.txt | 4 +- src/Magnum/Audio/Listener.cpp | 56 +++++++----- src/Magnum/Audio/Listener.h | 54 +++-------- src/Magnum/Audio/Playable.cpp | 84 +++++++++++++++++ src/Magnum/Audio/Playable.h | 81 +++++------------ src/Magnum/Audio/PlayableGroup.cpp | 109 +++++++++++++++++++++++ src/Magnum/Audio/PlayableGroup.h | 90 ++++--------------- src/Magnum/Audio/Renderer.h | 1 - src/Magnum/Audio/Test/ListenerALTest.cpp | 3 +- src/Magnum/Audio/Test/PlayableALTest.cpp | 1 + 10 files changed, 284 insertions(+), 199 deletions(-) create mode 100644 src/Magnum/Audio/Playable.cpp create mode 100644 src/Magnum/Audio/PlayableGroup.cpp diff --git a/src/Magnum/Audio/CMakeLists.txt b/src/Magnum/Audio/CMakeLists.txt index efca7c237..74d438353 100644 --- a/src/Magnum/Audio/CMakeLists.txt +++ b/src/Magnum/Audio/CMakeLists.txt @@ -58,7 +58,9 @@ if(WITH_SCENEGRAPH) PlayableGroup.h) list(APPEND MagnumAudio_SRCS - Listener.cpp) + Listener.cpp + Playable.cpp + PlayableGroup.cpp) endif() # Audio library diff --git a/src/Magnum/Audio/Listener.cpp b/src/Magnum/Audio/Listener.cpp index 0bb9cbcfa..59eef5ace 100644 --- a/src/Magnum/Audio/Listener.cpp +++ b/src/Magnum/Audio/Listener.cpp @@ -24,21 +24,19 @@ DEALINGS IN THE SOFTWARE. */ -#include "Magnum/Audio/Listener.h" +#include "Listener.h" + #include "Magnum/Audio/Playable.h" #include "Magnum/Audio/PlayableGroup.h" - +#include "Magnum/Audio/Renderer.h" +#include "Magnum/Math/Matrix3.h" namespace Magnum { namespace Audio { -using namespace SceneGraph; - -namespace Implementation { - void* activeListener = nullptr; -} - namespace { +void* activeListener = nullptr; + /* Create a Matrix4 from a Matrix3/Matrix4 */ inline Matrix4 padMatrix4(const Matrix3& m) { return Matrix4{Vector4::pad(m[0]), Vector4::pad(m[1]), Vector4::pad(m[2]), Vector4{}}; @@ -50,31 +48,33 @@ inline Matrix4 padMatrix4(const Matrix4& m) { } +template Listener::Listener(SceneGraph::AbstractObject& object): SceneGraph::AbstractFeature(object), _gain{1.0f} { + SceneGraph::AbstractFeature::setCachedTransformations(SceneGraph::CachedTransformation::Absolute); +} + +template Listener::~Listener() = default; + template void Listener::clean(const MatrixTypeFor& absoluteTransformationMatrix) { - if(!isActive()) { - /* Only clean if this Listener is active */ - return; - } + /* Only clean if this Listener is active */ + if(!isActive()) return; - Renderer::setListenerPosition(soundTransformation().transformVector(Vector3::pad(absoluteTransformationMatrix.translation()))); + Renderer::setListenerPosition(_soundTransformation.transformVector(Vector3::pad(absoluteTransformationMatrix.translation()))); - const Vector3 fwd = soundTransformation().transformVector(-padMatrix4(absoluteTransformationMatrix).backward()); - const Vector3 up = soundTransformation().transformVector(padMatrix4(absoluteTransformationMatrix).up()); + const Vector3 fwd = _soundTransformation.transformVector(-padMatrix4(absoluteTransformationMatrix).backward()); + const Vector3 up = _soundTransformation.transformVector(padMatrix4(absoluteTransformationMatrix).up()); Renderer::setListenerOrientation(fwd, up); - Renderer::setListenerGain(_gain); /** @todo velocity */ } template void Listener::update(std::initializer_list>> groups) { - /* Check if active listener just changed to this */ - if(this != Implementation::activeListener) { + if(this != activeListener) { /* Ensure that clean() is called also when switching between (clean) listeners */ - Implementation::activeListener = this; + activeListener = this; this->object().setDirty(); /* Listener gain needs to be updated only when active listener changed @@ -84,17 +84,27 @@ template void Listener::update(std::initiali /* Add all objects of the Playables in the PlayableGroups to a vector to later setClean() */ - std::vector>> objects; + std::vector>> objects; objects.push_back(this->object()); - for(PlayableGroup& group : groups) { - for(UnsignedInt i = 0; i < group.size(); ++i) { + for(PlayableGroup& group: groups) { + for(std::size_t i = 0; i != group.size(); ++i) { objects.push_back(group[i].object()); } } /* Use the more performant way to set multiple objects clean */ - AbstractObject::setClean(objects); + SceneGraph::AbstractObject::setClean(objects); +} + +template Listener& Listener::setGain(const Float gain) { + _gain = gain; + if(isActive()) Renderer::setListenerGain(_gain); + return *this; +} + +template bool Listener::isActive() const { + return this == activeListener; } /* On non-MinGW Windows the instantiations are already marked with extern diff --git a/src/Magnum/Audio/Listener.h b/src/Magnum/Audio/Listener.h index f658cf571..b463a5eef 100644 --- a/src/Magnum/Audio/Listener.h +++ b/src/Magnum/Audio/Listener.h @@ -30,26 +30,13 @@ * @brief Class @ref Magnum::Audio::Listener, @ref Magnum::Audio::Listener2D, @ref Magnum::Audio::Listener3D */ -#include -#include - -#include -#include -#include -#include -#include - -#include "Magnum/Audio/Renderer.h" -#include "Magnum/Audio/PlayableGroup.h" +#include "Magnum/Audio/Audio.h" +#include "Magnum/Audio/visibility.h" +#include "Magnum/Math/Matrix4.h" +#include "Magnum/SceneGraph/AbstractFeature.h" namespace Magnum { namespace Audio { -namespace Implementation { - /* Pointer to the currently active listener. Should never be dereferenced, - since may be null at any given time. */ - extern MAGNUM_AUDIO_EXPORT void* activeListener; -} - /** @brief Listener @@ -109,11 +96,8 @@ a certain world scale. In the later case you might want to instead consider @see @ref Audio::Renderer, @ref Playable, @ref PlayableGroup */ -template class Listener: public SceneGraph::AbstractFeature { - friend class ActiveListenerHolder; - +template class Listener: public SceneGraph::AbstractFeature { public: - /** * @brief Constructor * @param object Object this listener belongs to @@ -124,12 +108,9 @@ template class Listener: public SceneGraph::AbstractFea * affected by @p object or via @ref Listener::setSoundTransformation(). * @see @ref setGain() */ - explicit Listener(SceneGraph::AbstractObject& object): - SceneGraph::AbstractFeature(object), - _gain{1.0f} - { - SceneGraph::AbstractFeature::setCachedTransformations(SceneGraph::CachedTransformation::Absolute); - } + explicit Listener(SceneGraph::AbstractObject& object); + + ~Listener(); /** @brief Sound transformation */ const Matrix4& soundTransformation() const { @@ -160,36 +141,25 @@ template class Listener: public SceneGraph::AbstractFea void update(std::initializer_list>> groups); /** @brief Listener gain */ - Float gain() const { - return _gain; - } + Float gain() const { return _gain; } /** * @brief Set listener gain * @param gain Gain * @return Reference to self (for method chaining) */ - Listener& setGain(Float gain) { - _gain = gain; - if(isActive()) { - Renderer::setListenerGain(_gain); - } - return *this; - } + Listener& setGain(Float gain); /** @brief Whether this listener is the active listener */ - bool isActive() const { - return this == Implementation::activeListener; - } + bool isActive() const; private: - virtual void clean(const MatrixTypeFor& absoluteTransformationMatrix) override; + MAGNUM_AUDIO_LOCAL void clean(const MatrixTypeFor& absoluteTransformationMatrix) override; Matrix4 _soundTransformation; Float _gain; }; - /** * @brief Listener for two dimensional float scenes * diff --git a/src/Magnum/Audio/Playable.cpp b/src/Magnum/Audio/Playable.cpp new file mode 100644 index 000000000..38337c4bc --- /dev/null +++ b/src/Magnum/Audio/Playable.cpp @@ -0,0 +1,84 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + Copyright © 2015 Jonathan Hale + + 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 "Playable.h" + +#include "Magnum/Audio/PlayableGroup.h" +#include "Magnum/Math/Matrix3.h" +#include "Magnum/Math/Matrix4.h" + +namespace Magnum { namespace Audio { + +template Playable::Playable(SceneGraph::AbstractObject& object, PlayableGroup* group): SceneGraph::AbstractGroupedFeature, Float>(object, group), _fwd{}, _gain{1.0f} { + SceneGraph::AbstractFeature::setCachedTransformations(SceneGraph::CachedTransformation::Absolute); + _fwd[dimensions - 1] = -1; +} + +template Playable::~Playable() = default; + +template Playable& Playable::setGain(const Float gain) { + _gain = gain; + cleanGain(); + return *this; +} + +template void Playable::clean(const MatrixTypeFor& absoluteTransformationMatrix) { + Vector3 position = Vector3::pad(absoluteTransformationMatrix.translation()); + if(playables()) + position = playables()->soundTransformation().transformVector(position); + + _source.setPosition(position); + _source.setDirection(Vector3::pad(absoluteTransformationMatrix.rotation()*_fwd)); + + /** @todo velocity */ +} + +template PlayableGroup* Playable::playables() { + return static_cast*>(this->group()); +} + +template const PlayableGroup* Playable::playables() const { + return static_cast*>(this->group()); +} + +template void Playable::cleanGain() { + _source.setGain(playables() ? _gain*playables()->gain() : _gain); +} + +/* On non-MinGW Windows the instantiations are already marked with extern + template */ +#if !defined(CORRADE_TARGET_WINDOWS) || defined(__MINGW32__) +#define MAGNUM_AUDIO_EXPORT_HPP MAGNUM_AUDIO_EXPORT +#else +#define MAGNUM_AUDIO_EXPORT_HPP +#endif + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_AUDIO_EXPORT_HPP Playable<2>; +template class MAGNUM_AUDIO_EXPORT_HPP Playable<3>; +#endif + +}} diff --git a/src/Magnum/Audio/Playable.h b/src/Magnum/Audio/Playable.h index 2ecc1fd3d..1683ddac3 100644 --- a/src/Magnum/Audio/Playable.h +++ b/src/Magnum/Audio/Playable.h @@ -30,16 +30,9 @@ * @brief Class @ref Magnum::Audio::Playable, typedef @ref Magnum::Audio::Playable2D, @ref Magnum::Audio::Playable3D */ -#include -#include - -#include -#include -#include - -#include "Magnum/Audio/PlayableGroup.h" #include "Magnum/Audio/Source.h" -#include "Magnum/Audio/visibility.h" +#include "Magnum/Math/Vector3.h" +#include "Magnum/SceneGraph/AbstractGroupedFeature.h" namespace Magnum { namespace Audio { @@ -76,10 +69,7 @@ To manage multiple Playables at once, use @ref PlayableGroup. @see @ref Source, @ref PlayableGroup, @ref Listener */ template class Playable: public SceneGraph::AbstractGroupedFeature, Float> { - friend PlayableGroup; - public: - /** * @brief Constructor * @param object Object this playable belongs to @@ -92,25 +82,15 @@ template class Playable: public SceneGraph::AbstractGrou * @ref PlayableGroup::setSoundTransformation(). * @see @ref setGain(), @ref PlayableGroup::add() */ - explicit Playable(SceneGraph::AbstractObject& object, PlayableGroup* group = nullptr): - SceneGraph::AbstractGroupedFeature, Float>(object, group), - _fwd(0.0f), - _gain(1.0f), - _source() - { - SceneGraph::AbstractFeature::setCachedTransformations(SceneGraph::CachedTransformation::Absolute); - _fwd[dimensions - 1] = -1; - } + explicit Playable(SceneGraph::AbstractObject& object, PlayableGroup* group = nullptr); + + ~Playable(); /** @brief Source which is managed by this feature */ - Source& source() { - return _source; - } + Source& source() { return _source; } /** @brief Gain */ - Float gain() const { - return _gain; - } + Float gain() const { return _gain; } /** * @brief Set gain of the playable and source respecting the PlayableGroups gain @@ -120,46 +100,26 @@ template class Playable: public SceneGraph::AbstractGrou * Default for the playables gain is @cpp 1.0f @ce. * @see @ref PlayableGroup::setGain(), @ref Source::setGain() */ - Playable& setGain(const Float gain) { - _gain = gain; - cleanGain(); - return *this; - } + Playable& setGain(const Float gain); /** * @brief Group containing this playable * * If the playable doesn't belong to any group, returns @cpp nullptr @ce. */ - PlayableGroup* playables() { - return static_cast*>(this->group()); - } + PlayableGroup* playables(); - const PlayableGroup* playables() const { /**< @overload */ - return static_cast*>(this->group()); - } + const PlayableGroup* playables() const; /**< @overload */ private: - void clean(const MatrixTypeFor& absoluteTransformationMatrix) override { - Vector3 position = Vector3::pad(absoluteTransformationMatrix.translation(), 0); - if(playables()) { - position = playables()->soundTransformation().transformVector(position); - } - _source.setPosition(position); - _source.setDirection(Vector3::pad(absoluteTransformationMatrix.rotation()*_fwd)); - - /** @todo velocity */ - } - - /* Update the gain of the underlying source to reflect changes in _group and/or _gain. - Called in Playable::setGain() and PlayableGroup::setGain() */ - void cleanGain() { - if(playables()) { - _source.setGain(_gain*playables()->gain()); - } else { - _source.setGain(_gain); - } - } + friend PlayableGroup; + + MAGNUM_AUDIO_LOCAL void clean(const MatrixTypeFor& absoluteTransformationMatrix) override; + + /* Updates the gain of the underlying source to reflect changes in + _group and/or _gain. Called from setGain() and + PlayableGroup::setGain() */ + MAGNUM_AUDIO_LOCAL void cleanGain(); VectorTypeFor _fwd; Float _gain; @@ -180,6 +140,11 @@ typedef Playable<2> Playable2D; */ typedef Playable<3> Playable3D; +#if defined(CORRADE_TARGET_WINDOWS) && !defined(__MINGW32__) +extern template class MAGNUM_AUDIO_EXPORT Playable<2>; +extern template class MAGNUM_AUDIO_EXPORT Playable<3>; +#endif + }} #endif diff --git a/src/Magnum/Audio/PlayableGroup.cpp b/src/Magnum/Audio/PlayableGroup.cpp new file mode 100644 index 000000000..ec3ca5022 --- /dev/null +++ b/src/Magnum/Audio/PlayableGroup.cpp @@ -0,0 +1,109 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + Copyright © 2015 Jonathan Hale + + 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 "PlayableGroup.h" + +#include "Magnum/Audio/Playable.h" +#include "Magnum/Audio/Source.h" +#include "Magnum/SceneGraph/AbstractObject.h" + +namespace Magnum { namespace Audio { + +namespace { + +template std::vector> sources(PlayableGroup& group) { + std::vector> srcs; + srcs.reserve(group.size()); + for(std::size_t i = 0; i != group.size(); ++i) + srcs.push_back(group[i].source()); + return srcs; +} + +} + +template PlayableGroup::PlayableGroup(): SceneGraph::FeatureGroup, Float>(), _gain{1.0f} {} + +template PlayableGroup::~PlayableGroup() = default; + +template PlayableGroup& PlayableGroup::play() { + Source::play(sources(*this)); + return *this; +} + +template PlayableGroup& PlayableGroup::pause() { + Source::pause(sources(*this)); + return *this; +} + +template PlayableGroup& PlayableGroup::stop() { + Source::stop(sources(*this)); + return *this; +} + +template PlayableGroup& PlayableGroup::setGain(const Float gain) { + _gain = gain; + for(UnsignedInt i = 0; i < this->size(); ++i) + (*this)[i].cleanGain(); + + return *this; +} + +template PlayableGroup& PlayableGroup::setSoundTransformation(const Matrix4& matrix) { + _soundTransform = matrix; + + /* I cannot come up with a use case for which the sound transformation + would be set frequently, so we are setting objects dirty whether the + matrix changed or not. */ + for(UnsignedInt i = 0; i < this->size(); ++i) + (*this)[i].object().setDirty(); + + return *this; +} + +template void PlayableGroup::setClean() { + std::vector>> objects; + objects.reserve(this->size()); + + for(UnsignedInt i = 0; i < this->size(); ++i) + objects.push_back((*this)[i].object()); + + SceneGraph::AbstractObject::setClean(objects); +} + +/* On non-MinGW Windows the instantiations are already marked with extern + template */ +#if !defined(CORRADE_TARGET_WINDOWS) || defined(__MINGW32__) +#define MAGNUM_AUDIO_EXPORT_HPP MAGNUM_AUDIO_EXPORT +#else +#define MAGNUM_AUDIO_EXPORT_HPP +#endif + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_AUDIO_EXPORT_HPP PlayableGroup<2>; +template class MAGNUM_AUDIO_EXPORT_HPP PlayableGroup<3>; +#endif + +}} diff --git a/src/Magnum/Audio/PlayableGroup.h b/src/Magnum/Audio/PlayableGroup.h index 91ea5cb4c..0b2038628 100644 --- a/src/Magnum/Audio/PlayableGroup.h +++ b/src/Magnum/Audio/PlayableGroup.h @@ -30,18 +30,11 @@ * @brief Class @ref Magnum::Audio::PlayableGroup, typedef @ref Magnum::Audio::PlayableGroup2D, @ref Magnum::Audio::PlayableGroup3D */ -#include -#include -#include - -#include -#include -#include - +#include "Magnum/Magnum.h" #include "Magnum/Audio/Audio.h" -#include "Magnum/Audio/Playable.h" -#include "Magnum/Audio/Source.h" #include "Magnum/Audio/visibility.h" +#include "Magnum/Math/Matrix4.h" +#include "Magnum/SceneGraph/FeatureGroup.h" namespace Magnum { namespace Audio { @@ -78,50 +71,34 @@ For two dimensional scenes simply replace `3D` with `2D`. When using a @see @ref Playable, @ref SceneGraph::FeatureGroup, @ref Listener */ template class PlayableGroup: public SceneGraph::FeatureGroup, Float> { - friend Playable; - public: + explicit PlayableGroup(); - /** @brief Constructor */ - explicit PlayableGroup(): - SceneGraph::FeatureGroup, Float>(), - _gain{1.0f} - {} + ~PlayableGroup(); /** * @brief Play all sound sources in this group * @return Reference to self (for method chaining) * @see @ref Source::play() */ - PlayableGroup& play() { - Source::play(sources()); - return *this; - } + PlayableGroup& play(); /** * @brief Pause all sound sources in this group * @return Reference to self (for method chaining) * @see @ref Source::pause() */ - PlayableGroup& pause() { - Source::stop(sources()); - return *this; - } + PlayableGroup& pause(); /** * @brief Stop all sound sources in this group * @return Reference to self (for method chaining) * @see @ref Source::stop() */ - PlayableGroup& stop() { - Source::stop(sources()); - return *this; - } + PlayableGroup& stop(); /** @brief Gain */ - Float gain() const { - return _gain; - } + Float gain() const { return _gain; } /** * @brief Set gain for all sound sources of Playables in this group @@ -133,18 +110,10 @@ template class PlayableGroup: public SceneGraph::Feature * @cpp sourceGain = playableGain*groupGain @ce. Default of the groups * gain is @cpp 1.0f @ce. */ - PlayableGroup& setGain(const Float gain) { - _gain = gain; - for(UnsignedInt i = 0; i < this->size(); ++i) - (*this)[i].cleanGain(); - - return *this; - } + PlayableGroup& setGain(const Float gain); /** @brief Sound transformation */ - const Matrix4& soundTransformation() const { - return _soundTransform; - } + const Matrix4& soundTransformation() const { return _soundTransform; } /** * @brief Set transformation of the sounds in this group @@ -159,42 +128,12 @@ template class PlayableGroup: public SceneGraph::Feature void setClean(); private: - - /* @brief Sources of all Playables in this group */ - std::vector> sources() { - std::vector> srcs; - srcs.reserve(this->size()); - for(UnsignedInt i = 0; i < this->size(); ++i) - srcs.push_back((*this)[i].source()); - return srcs; - } + friend Playable; Matrix4 _soundTransform; Float _gain; }; -template inline PlayableGroup& PlayableGroup::setSoundTransformation(const Matrix4& matrix) { - _soundTransform = matrix; - - /* I cannot come up with a use case for which the sound - transformation would be set frequently, so we are setting - objects dirty whether the matrix changed or not. */ - for(UnsignedInt i = 0; i < this->size(); ++i) - (*this)[i].object().setDirty(); - - return *this; -} - -template inline void PlayableGroup::setClean() { - std::vector>> objects; - objects.reserve(this->size()); - - for(UnsignedInt i = 0; i < this->size(); ++i) - objects.push_back((*this)[i].object()); - - SceneGraph::AbstractObject::setClean(objects); -} - /** * @brief Playable group for two dimensional float scenes * @@ -209,6 +148,11 @@ typedef PlayableGroup<2> PlayableGroup2D; */ typedef PlayableGroup<3> PlayableGroup3D; +#if defined(CORRADE_TARGET_WINDOWS) && !defined(__MINGW32__) +extern template class MAGNUM_AUDIO_EXPORT PlayableGroup<2>; +extern template class MAGNUM_AUDIO_EXPORT PlayableGroup<3>; +#endif + }} #endif diff --git a/src/Magnum/Audio/Renderer.h b/src/Magnum/Audio/Renderer.h index 5963d06a6..61335485f 100644 --- a/src/Magnum/Audio/Renderer.h +++ b/src/Magnum/Audio/Renderer.h @@ -30,7 +30,6 @@ */ #include - #include #include "Magnum/Magnum.h" diff --git a/src/Magnum/Audio/Test/ListenerALTest.cpp b/src/Magnum/Audio/Test/ListenerALTest.cpp index 47d18f675..4887ee087 100644 --- a/src/Magnum/Audio/Test/ListenerALTest.cpp +++ b/src/Magnum/Audio/Test/ListenerALTest.cpp @@ -26,10 +26,11 @@ #include -#include "Magnum/Audio/Playable.h" #include "Magnum/Audio/Context.h" #include "Magnum/Audio/Listener.h" +#include "Magnum/Audio/Playable.h" #include "Magnum/Audio/PlayableGroup.h" +#include "Magnum/Audio/Renderer.h" #include "Magnum/SceneGraph/Scene.h" #include "Magnum/SceneGraph/Object.h" #include "Magnum/SceneGraph/MatrixTransformation2D.h" diff --git a/src/Magnum/Audio/Test/PlayableALTest.cpp b/src/Magnum/Audio/Test/PlayableALTest.cpp index e6c073e45..f675c300c 100644 --- a/src/Magnum/Audio/Test/PlayableALTest.cpp +++ b/src/Magnum/Audio/Test/PlayableALTest.cpp @@ -28,6 +28,7 @@ #include "Magnum/Audio/Context.h" #include "Magnum/Audio/Playable.h" +#include "Magnum/Audio/PlayableGroup.h" #include "Magnum/SceneGraph/Scene.h" #include "Magnum/SceneGraph/Object.h" #include "Magnum/SceneGraph/MatrixTransformation3D.h"