From 007360a9c8891ea2396f327d3cf7490eefb921bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 6 Jun 2021 18:40:07 +0200 Subject: [PATCH] GL,Shaders: allow draw() and friends to be chained. It had a point originally, but with the new multidraw workflows it's just annoying. --- doc/changelog.dox | 9 +++++ doc/snippets/MagnumGL.cpp | 25 +++++++++++- src/Magnum/GL/AbstractShaderProgram.cpp | 40 +++++++++++--------- src/Magnum/GL/AbstractShaderProgram.h | 43 +++++++++++++-------- src/Magnum/Shaders/DistanceFieldVectorGL.h | 22 +++++++++++ src/Magnum/Shaders/FlatGL.h | 22 +++++++++++ src/Magnum/Shaders/MeshVisualizerGL.h | 44 ++++++++++++++++++++++ src/Magnum/Shaders/PhongGL.h | 22 +++++++++++ src/Magnum/Shaders/VectorGL.h | 22 +++++++++++ src/Magnum/Shaders/VertexColorGL.h | 22 +++++++++++ 10 files changed, 236 insertions(+), 35 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index b0b55502b..2cb5cfe4b 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -228,6 +228,15 @@ See also: @subsubsection changelog-latest-changes-gl GL library +- @ref GL::AbstractShaderProgram::draw(), + @relativeref{GL::AbstractShaderProgram,drawTransformFeedback()} and + @relativeref{GL::AbstractShaderProgram,dispatchCompute()} APIs now return + a reference to self and all subclasses in @ref Shaders return a subclass + reference from these. The functions used to @cpp void @ce as that made more + sense in the classic workflow where a large set of uniforms had to be set + prior to every draw, however with the new multidraw workflows that's no + longer the case and the inability to chain draw calls proved to be + annoying. - The @ref GL::Context class got significantly optimized in terms of compile time, header size and runtime as well, significantly reducing the amount of allocations done at startup. diff --git a/doc/snippets/MagnumGL.cpp b/doc/snippets/MagnumGL.cpp index a17f87d98..1a4baa4ea 100644 --- a/doc/snippets/MagnumGL.cpp +++ b/doc/snippets/MagnumGL.cpp @@ -269,11 +269,32 @@ enum: UnsignedInt { /* [AbstractShaderProgram-output-attributes] */ #if !defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) -/* [AbstractShaderProgram-hide-irrelevant] */ +/* [AbstractShaderProgram-return-hide-irrelevant] */ +public: + MyShader& draw(GL::Mesh& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MyShader& draw(GL::Mesh&& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MyShader& draw(GL::MeshView& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MyShader& draw(GL::MeshView&& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + /* Omit these if the shader is not ready for multidraw */ + MyShader& draw(Containers::ArrayView> meshes) { + return static_cast(GL::AbstractShaderProgram::draw(meshes)); + } + MyShader& draw(std::initializer_list> meshes) { + return static_cast(GL::AbstractShaderProgram::draw(meshes)); + } + private: using GL::AbstractShaderProgram::drawTransformFeedback; using GL::AbstractShaderProgram::dispatchCompute; -/* [AbstractShaderProgram-hide-irrelevant] */ +/* [AbstractShaderProgram-return-hide-irrelevant] */ public: #endif diff --git a/src/Magnum/GL/AbstractShaderProgram.cpp b/src/Magnum/GL/AbstractShaderProgram.cpp index 05685f68e..06603814a 100644 --- a/src/Magnum/GL/AbstractShaderProgram.cpp +++ b/src/Magnum/GL/AbstractShaderProgram.cpp @@ -350,11 +350,11 @@ std::pair AbstractShaderProgram::validate() { return {success, std::move(message)}; } -void AbstractShaderProgram::draw(Mesh& mesh) { - CORRADE_ASSERT(mesh._countSet, "GL::AbstractShaderProgram::draw(): Mesh::setCount() was never called, probably a mistake?", ); +AbstractShaderProgram& AbstractShaderProgram::draw(Mesh& mesh) { + CORRADE_ASSERT(mesh._countSet, "GL::AbstractShaderProgram::draw(): Mesh::setCount() was never called, probably a mistake?", *this); /* Nothing to draw, exit without touching any state */ - if(!mesh._count || !mesh._instanceCount) return; + if(!mesh._count || !mesh._instanceCount) return *this; use(); @@ -363,13 +363,14 @@ void AbstractShaderProgram::draw(Mesh& mesh) { #else mesh.drawInternal(mesh._count, mesh._baseVertex, mesh._instanceCount, mesh._indexOffset); #endif + return *this; } -void AbstractShaderProgram::draw(MeshView& mesh) { - CORRADE_ASSERT(mesh._countSet, "GL::AbstractShaderProgram::draw(): MeshView::setCount() was never called, probably a mistake?", ); +AbstractShaderProgram& AbstractShaderProgram::draw(MeshView& mesh) { + CORRADE_ASSERT(mesh._countSet, "GL::AbstractShaderProgram::draw(): MeshView::setCount() was never called, probably a mistake?", *this); /* Nothing to draw, exit without touching any state */ - if(!mesh._count || !mesh._instanceCount) return; + if(!mesh._count || !mesh._instanceCount) return *this; use(); @@ -378,17 +379,18 @@ void AbstractShaderProgram::draw(MeshView& mesh) { #else mesh._original->drawInternal(mesh._count, mesh._baseVertex, mesh._instanceCount, mesh._indexOffset); #endif + return *this; } -void AbstractShaderProgram::draw(Containers::ArrayView> meshes) { - if(meshes.empty()) return; +AbstractShaderProgram& AbstractShaderProgram::draw(Containers::ArrayView> meshes) { + if(meshes.empty()) return *this; use(); #ifndef CORRADE_NO_ASSERT const Mesh* original = &*meshes.front()->_original; for(std::size_t i = 0; i != meshes.size(); ++i) - CORRADE_ASSERT(&*meshes[i]->_original == original, "GL::AbstractShaderProgram::draw(): all meshes must be views of the same original mesh, expected" << original << "but got" << &*meshes[i]->_original << "at index" << i, ); + CORRADE_ASSERT(&*meshes[i]->_original == original, "GL::AbstractShaderProgram::draw(): all meshes must be views of the same original mesh, expected" << original << "but got" << &*meshes[i]->_original << "at index" << i, *this); #endif #ifndef MAGNUM_TARGET_GLES @@ -396,34 +398,38 @@ void AbstractShaderProgram::draw(Containers::ArrayView> meshes) { - draw(Containers::arrayView(meshes)); +AbstractShaderProgram& AbstractShaderProgram::draw(std::initializer_list> meshes) { + return draw(Containers::arrayView(meshes)); } #ifndef MAGNUM_TARGET_GLES -void AbstractShaderProgram::drawTransformFeedback(Mesh& mesh, TransformFeedback& xfb, UnsignedInt stream) { +AbstractShaderProgram& AbstractShaderProgram::drawTransformFeedback(Mesh& mesh, TransformFeedback& xfb, UnsignedInt stream) { /* Nothing to draw, exit without touching any state */ - if(!mesh._instanceCount) return; + if(!mesh._instanceCount) return *this; use(); mesh.drawInternal(xfb, stream, mesh._instanceCount); + return *this; } -void AbstractShaderProgram::drawTransformFeedback(MeshView& mesh, TransformFeedback& xfb, UnsignedInt stream) { - /* Nothing to draw, exit without touching any state */ - if(!mesh._instanceCount) return; +AbstractShaderProgram& AbstractShaderProgram::drawTransformFeedback(MeshView& mesh, TransformFeedback& xfb, UnsignedInt stream) { + /* If nothing to draw, exit without touching any state */ + if(mesh._instanceCount) return *this; use(); mesh._original->drawInternal(xfb, stream, mesh._instanceCount); + return *this; } #endif #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) -void AbstractShaderProgram::dispatchCompute(const Vector3ui& workgroupCount) { +AbstractShaderProgram& AbstractShaderProgram::dispatchCompute(const Vector3ui& workgroupCount) { use(); glDispatchCompute(workgroupCount.x(), workgroupCount.y(), workgroupCount.z()); + return *this; } #endif diff --git a/src/Magnum/GL/AbstractShaderProgram.h b/src/Magnum/GL/AbstractShaderProgram.h index fe54fae93..101dc46d2 100644 --- a/src/Magnum/GL/AbstractShaderProgram.h +++ b/src/Magnum/GL/AbstractShaderProgram.h @@ -87,12 +87,14 @@ functions and properties: @snippet MagnumGL.cpp AbstractShaderProgram-xfb -
  • And optionally, **hiding irrelevant draw/dispatch functions** to prevent - users from accidentally calling @ref draw() on compute shaders, - @ref drawTransformFeedback() on shaders that don't have transform feedback - or @ref dispatchCompute() on shaders that aren't compute. For example: - - @snippet MagnumGL.cpp AbstractShaderProgram-hide-irrelevant +
  • And optionally, **return derived type from relevant draw/dispatch functions** + to make it possible for users to easily chain draw calls, and on the other + hand **hide the irrelevant APIs** to prevent users from accidentally + calling @ref draw() on compute shaders, @ref drawTransformFeedback() on + shaders that don't have transform feedback or @ref dispatchCompute() on + shaders that aren't compute. For example: + + @snippet MagnumGL.cpp AbstractShaderProgram-return-hide-irrelevant @subsection GL-AbstractShaderProgram-attribute-location Binding attribute and fragment data location @@ -751,7 +753,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { /** * @brief Draw a mesh - * @param mesh Mesh to draw + * @return Reference to self (for method chaining) * @m_since{2020,06} * * Expects that @p mesh is compatible with this shader and is fully set @@ -794,16 +796,19 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @requires_gl Specifying base vertex for indexed meshes is not * available in OpenGL ES or WebGL. */ - void draw(Mesh& mesh); + AbstractShaderProgram& draw(Mesh& mesh); /** * @overload * @m_since{2020,06} */ - void draw(Mesh&& mesh) { draw(mesh); } + AbstractShaderProgram& draw(Mesh&& mesh) { + return draw(mesh); + } /** * @brief Draw a mesh view + * @return Reference to self (for method chaining) * @m_since{2020,06} * * See @ref draw(Mesh&) for more information. @@ -828,16 +833,19 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @requires_gl Specifying base vertex for indexed meshes is not * available in OpenGL ES or WebGL. */ - void draw(MeshView& mesh); + AbstractShaderProgram& draw(MeshView& mesh); /** * @overload * @m_since{2020,06} */ - void draw(MeshView&& mesh) { draw(mesh); } + AbstractShaderProgram& draw(MeshView&& mesh) { + return draw(mesh); + } /** * @brief Draw multiple meshes at once + * @return Reference to self (for method chaining) * @m_since{2020,06} * * On OpenGL ES, if neither @gl_extension{EXT,multi_draw_arrays} nor @@ -872,13 +880,13 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * if the mesh is indexed and @ref MeshView::baseVertex() is not * `0` */ - void draw(Containers::ArrayView> meshes); + AbstractShaderProgram& draw(Containers::ArrayView> meshes); /** * @overload * @m_since{2020,06} */ - void draw(std::initializer_list> meshes); + AbstractShaderProgram& draw(std::initializer_list> meshes); #ifndef MAGNUM_TARGET_GLES /** @@ -886,6 +894,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @param mesh Mesh to draw * @param xfb Transform feedback to use for vertex count * @param stream Transform feedback stream ID + * @return Reference to self (for method chaining) * @m_since{2020,06} * * Expects that @p mesh is compatible with this shader, is fully set up @@ -911,10 +920,11 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @requires_gl42 Extension @gl_extension{ARB,transform_feedback_instanced} * if @ref Mesh::instanceCount() is more than `1` */ - void drawTransformFeedback(Mesh& mesh, TransformFeedback& xfb, UnsignedInt stream = 0); + AbstractShaderProgram& drawTransformFeedback(Mesh& mesh, TransformFeedback& xfb, UnsignedInt stream = 0); /** * @brief Draw a mesh view with vertices coming out of transform feedback + * @return Reference to self (for method chaining) * @m_since{2020,06} * * Everything set by @ref MeshView::setCount(), @@ -931,13 +941,14 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @requires_gl42 Extension @gl_extension{ARB,transform_feedback_instanced} * if @ref MeshView::instanceCount() is more than `1` */ - void drawTransformFeedback(MeshView& mesh, TransformFeedback& xfb, UnsignedInt stream = 0); + AbstractShaderProgram& drawTransformFeedback(MeshView& mesh, TransformFeedback& xfb, UnsignedInt stream = 0); #endif #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) /** * @brief Dispatch compute * @param workgroupCount Workgroup count in given dimension + * @return Reference to self (for method chaining) * * Valid only on programs with compute shader attached. * @see @fn_gl{DispatchCompute} @@ -946,7 +957,7 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * and older. * @requires_gles Compute shaders are not available in WebGL. */ - void dispatchCompute(const Vector3ui& workgroupCount); + AbstractShaderProgram& dispatchCompute(const Vector3ui& workgroupCount); #endif protected: diff --git a/src/Magnum/Shaders/DistanceFieldVectorGL.h b/src/Magnum/Shaders/DistanceFieldVectorGL.h index ffd3a40fe..abd2e926c 100644 --- a/src/Magnum/Shaders/DistanceFieldVectorGL.h +++ b/src/Magnum/Shaders/DistanceFieldVectorGL.h @@ -531,6 +531,28 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector * @} */ + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + DistanceFieldVectorGL& draw(GL::Mesh& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + DistanceFieldVectorGL& draw(GL::Mesh&& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + DistanceFieldVectorGL& draw(GL::MeshView& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + DistanceFieldVectorGL& draw(GL::MeshView&& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + DistanceFieldVectorGL& draw(Containers::ArrayView> meshes) { + return static_cast&>(GL::AbstractShaderProgram::draw(meshes)); + } + DistanceFieldVectorGL& draw(std::initializer_list> meshes) { + return static_cast&>(GL::AbstractShaderProgram::draw(meshes)); + } + #endif + private: /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Shaders/FlatGL.h b/src/Magnum/Shaders/FlatGL.h index 5230d5d8d..d57785615 100644 --- a/src/Magnum/Shaders/FlatGL.h +++ b/src/Magnum/Shaders/FlatGL.h @@ -860,6 +860,28 @@ template class MAGNUM_SHADERS_EXPORT FlatGL: public GL:: * @} */ + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + FlatGL& draw(GL::Mesh& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + FlatGL& draw(GL::Mesh&& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + FlatGL& draw(GL::MeshView& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + FlatGL& draw(GL::MeshView&& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + FlatGL& draw(Containers::ArrayView> meshes) { + return static_cast&>(GL::AbstractShaderProgram::draw(meshes)); + } + FlatGL& draw(std::initializer_list> meshes) { + return static_cast&>(GL::AbstractShaderProgram::draw(meshes)); + } + #endif + private: /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Shaders/MeshVisualizerGL.h b/src/Magnum/Shaders/MeshVisualizerGL.h index d96773057..fccf0cd88 100644 --- a/src/Magnum/Shaders/MeshVisualizerGL.h +++ b/src/Magnum/Shaders/MeshVisualizerGL.h @@ -595,6 +595,28 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua * @} */ + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + MeshVisualizerGL2D& draw(GL::Mesh& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MeshVisualizerGL2D& draw(GL::Mesh&& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MeshVisualizerGL2D& draw(GL::MeshView& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MeshVisualizerGL2D& draw(GL::MeshView&& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MeshVisualizerGL2D& draw(Containers::ArrayView> meshes) { + return static_cast(GL::AbstractShaderProgram::draw(meshes)); + } + MeshVisualizerGL2D& draw(std::initializer_list> meshes) { + return static_cast(GL::AbstractShaderProgram::draw(meshes)); + } + #endif + private: Int _transformationProjectionMatrixUniform{6}; }; @@ -1574,6 +1596,28 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua * @} */ + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + MeshVisualizerGL3D& draw(GL::Mesh& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MeshVisualizerGL3D& draw(GL::Mesh&& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MeshVisualizerGL3D& draw(GL::MeshView& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MeshVisualizerGL3D& draw(GL::MeshView&& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + MeshVisualizerGL3D& draw(Containers::ArrayView> meshes) { + return static_cast(GL::AbstractShaderProgram::draw(meshes)); + } + MeshVisualizerGL3D& draw(std::initializer_list> meshes) { + return static_cast(GL::AbstractShaderProgram::draw(meshes)); + } + #endif + private: Int _transformationMatrixUniform{6}, _projectionMatrixUniform{7}; diff --git a/src/Magnum/Shaders/PhongGL.h b/src/Magnum/Shaders/PhongGL.h index c04ef613e..9c34a3b2d 100644 --- a/src/Magnum/Shaders/PhongGL.h +++ b/src/Magnum/Shaders/PhongGL.h @@ -1561,6 +1561,28 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram { * @} */ + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + PhongGL& draw(GL::Mesh& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + PhongGL& draw(GL::Mesh&& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + PhongGL& draw(GL::MeshView& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + PhongGL& draw(GL::MeshView&& mesh) { + return static_cast(GL::AbstractShaderProgram::draw(mesh)); + } + PhongGL& draw(Containers::ArrayView> meshes) { + return static_cast(GL::AbstractShaderProgram::draw(meshes)); + } + PhongGL& draw(std::initializer_list> meshes) { + return static_cast(GL::AbstractShaderProgram::draw(meshes)); + } + #endif + private: /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Shaders/VectorGL.h b/src/Magnum/Shaders/VectorGL.h index 51068ad54..977ec4a26 100644 --- a/src/Magnum/Shaders/VectorGL.h +++ b/src/Magnum/Shaders/VectorGL.h @@ -483,6 +483,28 @@ template class MAGNUM_SHADERS_EXPORT VectorGL: public GL * @} */ + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + VectorGL& draw(GL::Mesh& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + VectorGL& draw(GL::Mesh&& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + VectorGL& draw(GL::MeshView& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + VectorGL& draw(GL::MeshView&& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + VectorGL& draw(Containers::ArrayView> meshes) { + return static_cast&>(GL::AbstractShaderProgram::draw(meshes)); + } + VectorGL& draw(std::initializer_list> meshes) { + return static_cast&>(GL::AbstractShaderProgram::draw(meshes)); + } + #endif + private: /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Shaders/VertexColorGL.h b/src/Magnum/Shaders/VertexColorGL.h index c13e29f76..4379062cd 100644 --- a/src/Magnum/Shaders/VertexColorGL.h +++ b/src/Magnum/Shaders/VertexColorGL.h @@ -341,6 +341,28 @@ template class MAGNUM_SHADERS_EXPORT VertexColorGL: publ */ #endif + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + VertexColorGL& draw(GL::Mesh& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + VertexColorGL& draw(GL::Mesh&& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + VertexColorGL& draw(GL::MeshView& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + VertexColorGL& draw(GL::MeshView&& mesh) { + return static_cast&>(GL::AbstractShaderProgram::draw(mesh)); + } + VertexColorGL& draw(Containers::ArrayView> meshes) { + return static_cast&>(GL::AbstractShaderProgram::draw(meshes)); + } + VertexColorGL& draw(std::initializer_list> meshes) { + return static_cast&>(GL::AbstractShaderProgram::draw(meshes)); + } + #endif + private: /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES