diff --git a/src/AbstractShaderProgram.cpp b/src/AbstractShaderProgram.cpp index 628b471ba..5ecce8aac 100644 --- a/src/AbstractShaderProgram.cpp +++ b/src/AbstractShaderProgram.cpp @@ -30,8 +30,6 @@ #include "Implementation/ShaderProgramState.h" #include "Implementation/State.h" -#define LINKER_MESSAGE_MAX_LENGTH 1024 - namespace Magnum { AbstractShaderProgram::Uniform1fvImplementation AbstractShaderProgram::uniform1fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; @@ -88,67 +86,58 @@ Int AbstractShaderProgram::maxSupportedVertexAttributeCount() { return value; } +AbstractShaderProgram::AbstractShaderProgram(): _id(glCreateProgram()) {} + AbstractShaderProgram::~AbstractShaderProgram() { /* Remove current usage from the state */ GLuint& current = Context::current()->state()->shaderProgram->current; if(current == _id) current = 0; - glDeleteProgram(_id); + if(_id) glDeleteProgram(_id); } -bool AbstractShaderProgram::use() { - if(state != Linked) return false; - +void AbstractShaderProgram::use() { /* Use only if the program isn't already in use */ GLuint& current = Context::current()->state()->shaderProgram->current; if(current != _id) glUseProgram(current = _id); - return true; } -bool AbstractShaderProgram::attachShader(Shader& shader) { - GLuint _shader = shader.compile(); - if(!_shader) return false; - - glAttachShader(_id, _shader); - return true; +void AbstractShaderProgram::attachShader(Shader& shader) { + glAttachShader(_id, shader.id()); } void AbstractShaderProgram::bindAttributeLocation(UnsignedInt location, const std::string& name) { - CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: attribute cannot be bound after linking.", ); - glBindAttribLocation(_id, location, name.c_str()); } #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::bindFragmentDataLocation(UnsignedInt location, const std::string& name) { - CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", ); - glBindFragDataLocation(_id, location, name.c_str()); } void AbstractShaderProgram::bindFragmentDataLocationIndexed(UnsignedInt location, UnsignedInt index, const std::string& name) { - CORRADE_ASSERT(state == Initialized, "AbstractShaderProgram: fragment data location cannot be bound after linking.", ); - glBindFragDataLocationIndexed(_id, location, index, name.c_str()); } #endif -void AbstractShaderProgram::link() { - /* Already compiled or failed, exit */ - if(state != Initialized) return; - +bool AbstractShaderProgram::link() { /* Link shader program */ glLinkProgram(_id); /* Check link status */ - GLint status; - glGetProgramiv(_id, GL_LINK_STATUS, &status); - - /* Display errors or warnings */ - char message[LINKER_MESSAGE_MAX_LENGTH]; - glGetProgramInfoLog(_id, LINKER_MESSAGE_MAX_LENGTH, nullptr, message); + GLint success, logLength; + glGetProgramiv(_id, GL_LINK_STATUS, &success); + glGetProgramiv(_id, GL_INFO_LOG_LENGTH, &logLength); + + /* Error or warning message. The string is returned null-terminated, scrap + the \0 at the end afterwards */ + std::string message(logLength, '\n'); + if(!message.empty()) { + glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]); + message.resize(logLength-1); + } /* Show error log and delete shader */ - if(status == GL_FALSE) { + if(!success) { Error out; out.setFlag(Debug::NewLineAtTheEnd, false); out.setFlag(Debug::SpaceAfterEachValue, false); @@ -156,7 +145,7 @@ void AbstractShaderProgram::link() { << message; /* Or just warnings, if there are any */ - } else if(message[0] != 0) { + } else if(!message.empty()) { Debug out; out.setFlag(Debug::NewLineAtTheEnd, false); out.setFlag(Debug::SpaceAfterEachValue, false); @@ -164,13 +153,10 @@ void AbstractShaderProgram::link() { << message; } - state = status == GL_FALSE ? Failed : Linked; + return success; } Int AbstractShaderProgram::uniformLocation(const std::string& name) { - /** @todo What if linking just failed (not programmer error?) */ - CORRADE_ASSERT(state == Linked, "AbstractShaderProgram: uniform location cannot be retrieved before linking.", -1); - GLint location = glGetUniformLocation(_id, name.c_str()); if(location == -1) Warning() << "AbstractShaderProgram: location of uniform \'" + name + "\' cannot be retrieved!"; diff --git a/src/AbstractShaderProgram.h b/src/AbstractShaderProgram.h index 72136ea37..3d2843f2a 100644 --- a/src/AbstractShaderProgram.h +++ b/src/AbstractShaderProgram.h @@ -35,8 +35,6 @@ #include "OpenGL.h" #include "magnumVisibility.h" -/** @todo early asserts (no bool returns?) */ - namespace Magnum { namespace Implementation { @@ -84,12 +82,19 @@ Int TransformationUniform = 0, gets uniform locations, for example: @code MyShader() { - // Load shaders from file and attach them to the program - attachShader(Shader(Version::GL430, Shader::Type::Vertex).attachFile("PhongShader.vert")); - attachShader(Shader(Version::GL430, Shader::Type::Fragment).attachFile("PhongShader.frag")); - - // Link - link(); + // Load shaders, compile them and attach them to the program + Shader vert(Version::GL430, Shader::Type::Vertex); + vert.attachFile("PhongShader.vert"); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); + + Shader frag(Version::GL430, Shader::Type::Fragment); + frag.attachFile("PhongShader.vert"); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); + + // Link the program together + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } @endcode - **Uniform setting functions**, which will provide public interface for @@ -521,9 +526,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * Creates one OpenGL shader program. * @see @fn_gl{CreateProgram} */ - inline explicit AbstractShaderProgram(): state(Initialized) { - _id = glCreateProgram(); - } + explicit AbstractShaderProgram(); /** * @brief Destructor @@ -535,12 +538,10 @@ class MAGNUM_EXPORT AbstractShaderProgram { /** * @brief Use shader for rendering - * @return False if the program wasn't successfully linked, true - * otherwise. * * @see @fn_gl{UseProgram} */ - bool use(); + void use(); protected: #ifndef MAGNUM_TARGET_GLES2 @@ -548,8 +549,6 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @brief Allow retrieving program binary * * Initially disabled. - * @note This function should be called after attachShader() calls and - * before link(). * @see @fn_gl{ProgramParameter} with @def_gl{PROGRAM_BINARY_RETRIEVABLE_HINT} * @requires_gl41 %Extension @extension{ARB,get_program_binary} * @requires_gles30 Always allowed in OpenGL ES 2.0. @@ -563,8 +562,6 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @brief Allow the program to be bound to individual pipeline stages * * Initially disabled. - * @note This function should be called after attachShader() calls and - * before link(). * @see @fn_gl{ProgramParameter} with @def_gl{PROGRAM_SEPARABLE} * @requires_gl41 %Extension @extension{ARB,separate_shader_objects} * @requires_es_extension %Extension @es_extension{EXT,separate_shader_objects} @@ -579,20 +576,11 @@ class MAGNUM_EXPORT AbstractShaderProgram { } /** - * @brief Load shader - * @return False if the shader wasn't successfully compiled, true - * otherwise. + * @brief Attach shader * - * Compiles the shader, if it is not already, and prepares it for - * linking. - * @see Shader::compile(), @fn_gl{AttachShader} + * @fn_gl{AttachShader} */ - bool attachShader(Shader& shader); - - /** @overload */ - inline bool attachShader(Shader&& shader) { - return attachShader(shader); - } + void attachShader(Shader& shader); /** * @brief Bind attribute to given location @@ -601,8 +589,6 @@ class MAGNUM_EXPORT AbstractShaderProgram { * * Binds attribute to location which is used later for binding vertex * buffers. - * @note This function should be called after attachShader() calls and - * before link(). * @deprecated Preferred usage is to specify attribute location * explicitly in the shader instead of using this function. See * @ref AbstractShaderProgram-attribute-location "class documentation" @@ -621,8 +607,6 @@ class MAGNUM_EXPORT AbstractShaderProgram { * Binds fragment data to location which is used later for framebuffer * operations. See also Framebuffer::BlendFunction for more * information about using color input index. - * @note This function should be called after attachShader() calls and - * before link(). * @deprecated Preferred usage is to specify attribute location * explicitly in the shader instead of using this function. See * @ref AbstractShaderProgram-attribute-location "class documentation" @@ -652,18 +636,19 @@ class MAGNUM_EXPORT AbstractShaderProgram { /** * @brief Link the shader * - * Binds previously specified attributes to given indexes and links the - * shader program together. + * Returns `false` if linking failed, `true` otherwise. Compiler + * message (if any) is printed to error output. All attached shaders + * must be explicitly compiled with Shader::compile() before linking. * @see @fn_gl{LinkProgram}, @fn_gl{GetProgram} with - * @def_gl{LINK_STATUS}, @fn_gl{GetProgramInfoLog} + * @def_gl{LINK_STATUS} and @def_gl{INFO_LOG_LENGTH}, + * @fn_gl{GetProgramInfoLog} */ - void link(); + bool link(); /** * @brief Get uniform location * @param name Uniform name * - * @note This function should be called after link(). * @deprecated Preferred usage is to specify uniform location * explicitly in the shader instead of using this function. See * @ref AbstractShaderProgram-uniform-location "class documentation" @@ -717,8 +702,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * @extension{EXT,direct_state_access} is available, the shader is * marked for use before the operation. * @see setUniform(Int, const T&), @fn_gl{UseProgram}, @fn_gl{Uniform} - * or `glProgramUniform()` from - * @extension{ARB,separate_shader_objects}/@extension{EXT,direct_state_access}. + * or @fn_gl{ProgramUniform}/@fn_gl_extension{ProgramUniform,EXT,direct_state_access}. */ inline void setUniform(Int location, UnsignedInt count, const Float* values) { (this->*uniform1fvImplementation)(location, count, values); @@ -984,12 +968,6 @@ class MAGNUM_EXPORT AbstractShaderProgram { #endif private: - enum State { - Initialized, - Linked, - Failed - }; - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); typedef void(AbstractShaderProgram::*Uniform1fvImplementation)(GLint, GLsizei, const GLfloat*); @@ -1155,7 +1133,6 @@ class MAGNUM_EXPORT AbstractShaderProgram { #endif GLuint _id; - State state; }; #ifdef DOXYGEN_GENERATING_OUTPUT diff --git a/src/Shader.cpp b/src/Shader.cpp index 385728853..4b6ee9c1b 100644 --- a/src/Shader.cpp +++ b/src/Shader.cpp @@ -27,8 +27,6 @@ #include #include -#define COMPILER_MESSAGE_MAX_LENGTH 1024 - /* libgles-omap3-dev_4.03.00.02-r15.6 on BeagleBoard/Ångström linux 2011.3 doesn't have GLchar */ #ifdef MAGNUM_TARGET_GLES typedef char GLchar; @@ -36,8 +34,27 @@ typedef char GLchar; namespace Magnum { -Shader::Shader(Version version, Type type): _type(type), _state(State::Initialized), shader(0) { - shader = glCreateShader(static_cast(_type)); +namespace { + +std::string shaderName(const Shader::Type type) { + switch(type) { + case Shader::Type::Vertex: return "vertex"; + #ifndef MAGNUM_TARGET_GLES + case Shader::Type::Geometry: return "geometry"; + case Shader::Type::TessellationControl: return "tessellation control"; + case Shader::Type::TessellationEvaluation: return "tessellation evaluation"; + case Shader::Type::Compute: return "compute"; + #endif + case Shader::Type::Fragment: return "fragment"; + } + + CORRADE_ASSERT_UNREACHABLE(); +} + +} + +Shader::Shader(const Version version, const Type type): _type(type), _id(0) { + _id = glCreateShader(static_cast(_type)); switch(version) { #ifndef MAGNUM_TARGET_GLES @@ -62,32 +79,34 @@ Shader::Shader(Version version, Type type): _type(type), _state(State::Initializ CORRADE_ASSERT_UNREACHABLE(); } -Shader::Shader(Shader&& other): _type(other._type), _state(other._state), sources(std::move(other.sources)), shader(other.shader) { - other.shader = 0; +Shader::Shader(Shader&& other): _type(other._type), _id(other._id), sources(std::move(other.sources)) { + other._id = 0; +} + +Shader::~Shader() { + if(_id) glDeleteShader(_id); } Shader& Shader::operator=(Shader&& other) { - glDeleteShader(shader); + glDeleteShader(_id); _type = other._type; - _state = other._state; sources = std::move(other.sources); - shader = other.shader; + _id = other._id; - other.shader = 0; + other._id = 0; return *this; } Shader& Shader::addSource(std::string source) { - if(source.empty()) return *this; - - if(_state == State::Initialized) { + if(!source.empty()) { /* Fix line numbers, so line 41 of third added file is marked as 3(41). Source 0 is the #version string added in constructor. */ sources.push_back("#line 1 " + std::to_string(sources.size()) + '\n'); sources.push_back(std::move(source)); } + return *this; } @@ -111,9 +130,8 @@ Shader& Shader::addFile(const std::string& filename) { return *this; } -GLuint Shader::compile() { - /* Already compiled, return */ - if(_state != State::Initialized) return shader; +bool Shader::compile() { + CORRADE_ASSERT(sources.size() > 1, "Shader::compile(): no files added", false); /* Array of sources */ const GLchar** _sources = new const GLchar*[sources.size()]; @@ -121,57 +139,45 @@ GLuint Shader::compile() { _sources[i] = static_cast(sources[i].c_str()); /* Create shader and set its source */ - glShaderSource(shader, sources.size(), _sources, nullptr); + glShaderSource(_id, sources.size(), _sources, nullptr); /* Compile shader */ - glCompileShader(shader); + glCompileShader(_id); delete _sources; /* Check compilation status */ - GLint status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - - /* Display errors or warnings */ - char message[COMPILER_MESSAGE_MAX_LENGTH]; - glGetShaderInfoLog(shader, COMPILER_MESSAGE_MAX_LENGTH, nullptr, message); - - if(status == GL_FALSE || message[0] != 0) { - Error err; - err << "Shader:"; - - switch(_type) { - case Type::Vertex: err << "vertex"; break; - #ifndef MAGNUM_TARGET_GLES - case Type::Geometry: err << "geometry"; break; - case Type::TessellationControl: err << "tessellation control"; break; - case Type::TessellationEvaluation: err << "tessellation evaluation"; break; - case Type::Compute: err << "compute"; break; - #endif - case Type::Fragment: err << "fragment"; break; - } - - err.setFlag(Debug::NewLineAtTheEnd, false); - err.setFlag(Debug::SpaceAfterEachValue, false); - - /* Show error log and delete shader */ - if(status == GL_FALSE) { - err << " shader failed to compile with the following message:\n" - << message; - - /* Or just warnings, if there are any */ - } else if(message[0] != 0) { - err << " shader was successfully compiled with the following message:\n" - << message; - } + GLint success, logLength; + glGetShaderiv(_id, GL_COMPILE_STATUS, &success); + glGetShaderiv(_id, GL_INFO_LOG_LENGTH, &logLength); + + /* Error or warning message. The string is returned null-terminated, scrap + the \0 at the end afterwards */ + std::string message(logLength, '\0'); + if(!message.empty()) { + glGetShaderInfoLog(_id, message.size(), nullptr, &message[0]); + message.resize(logLength-1); } - if(status == GL_FALSE) { - _state = State::Failed; - return 0; - } else { - _state = State::Compiled; - return shader; + /* Show error log */ + if(!success) { + Error out; + out.setFlag(Debug::NewLineAtTheEnd, false); + out.setFlag(Debug::SpaceAfterEachValue, false); + out << "Shader:" << shaderName(_type) + << " shader failed to compile with the following message:\n" + << message; + + /* Or just message, if any */ + } else if(!message.empty()) { + Error out; + out.setFlag(Debug::NewLineAtTheEnd, false); + out.setFlag(Debug::SpaceAfterEachValue, false); + out << "Shader:" << shaderName(_type) + << " shader was successfully compiled with the following message:\n" + << message; } + + return success; } } diff --git a/src/Shader.h b/src/Shader.h index 9bcc2101f..0e885f1d6 100644 --- a/src/Shader.h +++ b/src/Shader.h @@ -41,8 +41,7 @@ namespace Magnum { /** @brief %Shader -Allows loading and compiling the shader from file or directly from source -string. See AbstractShaderProgram for more information. +See AbstractShaderProgram for more information. */ class MAGNUM_EXPORT Shader { Shader(const Shader&) = delete; @@ -86,13 +85,6 @@ class MAGNUM_EXPORT Shader { Fragment = GL_FRAGMENT_SHADER /**< Fragment shader */ }; - /** @brief %Shader state */ - enum class State { - Initialized, /**< %Shader is loaded */ - Compiled, /**< %Shader is compiled */ - Failed /**< Compilation failed */ - }; - /** * @brief Constructor * @param version Target version @@ -110,7 +102,7 @@ class MAGNUM_EXPORT Shader { * Deletes associated OpenGL shader. * @see @fn_gl{DeleteShader} */ - inline ~Shader() { if(shader) glDeleteShader(shader); } + ~Shader(); /** @brief Move constructor */ Shader(Shader&& other); @@ -118,28 +110,17 @@ class MAGNUM_EXPORT Shader { /** @brief Move assignment operator */ Shader& operator=(Shader&& other); - /** - * @brief %Shader type - * - * Set in constructor. - */ - inline Type type() const { return _type; } - - /** - * @brief Compilation state - * - * Changes after calling compile(). - */ - inline State state() const { return _state; } + /** @brief OpenGL shader ID */ + inline GLuint id() const { return _id; } /** * @brief Add shader source * @param source String with shader source * @return Reference to self (for method chaining) * - * If the shader is not compiled already, adds given source to source - * list. Note that it is possible to compile shader from more than - * one source. If passed string is empty, the function does nothing. + * Adds given source to source list, preceeded with @c \#line directive + * marking first line of the source as `n(1)` where n is number of + * added source. If passed string is empty, the function does nothing. * @see addFile() */ Shader& addSource(std::string source); @@ -149,32 +130,27 @@ class MAGNUM_EXPORT Shader { * @param filename Name of source file to read from * @return Reference to self (for method chaining) * - * The file must exist and must be readable. - * @see addSource() + * The file must exist and must be readable. Calls addSource() with + * the contents. */ Shader& addFile(const std::string& filename); /** * @brief Compile shader - * @return Compiled shader or 0 if compilation failed. * - * If the shader has any sources present and hasn't been compiled - * before, it tries to compile it. If compilation fails or no sources - * are present, returns 0. If the shader was compiled already, returns - * already existing shader. - * @see state(), @fn_gl{ShaderSource}, @fn_gl{CompileShader}, - * @fn_gl{GetShader} with @def_gl{COMPILE_STATUS}, + * Returns `false` if compilation failed, `true` otherwise. Compiler + * message (if any) is printed to error output. + * @see @fn_gl{ShaderSource}, @fn_gl{CompileShader}, @fn_gl{GetShader} + * with @def_gl{COMPILE_STATUS} and @def_gl{INFO_LOG_LENGTH}, * @fn_gl{GetShaderInfoLog} */ - GLuint compile(); + bool compile(); private: Type _type; - State _state; + GLuint _id; std::vector sources; - - GLuint shader; }; } diff --git a/src/Shaders/DistanceFieldVector.cpp b/src/Shaders/DistanceFieldVector.cpp index 09b140cea..b7b78b171 100644 --- a/src/Shaders/DistanceFieldVector.cpp +++ b/src/Shaders/DistanceFieldVector.cpp @@ -47,13 +47,17 @@ template DistanceFieldVector::DistanceFieldV Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); #endif - AbstractShaderProgram::attachShader(Shader(v, Shader::Type::Vertex) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get(vertexShaderName()))); - - AbstractShaderProgram::attachShader(Shader(v, Shader::Type::Fragment) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get("DistanceFieldVector.frag"))); + Shader frag(v, Shader::Type::Vertex); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get(vertexShaderName())); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + AbstractShaderProgram::attachShader(frag); + + Shader vert(v, Shader::Type::Fragment); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("DistanceFieldVector.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + AbstractShaderProgram::attachShader(vert); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported() || @@ -66,7 +70,7 @@ template DistanceFieldVector::DistanceFieldV AbstractShaderProgram::bindAttributeLocation(AbstractVector::TextureCoordinates::Location, "textureCoordinates"); } - AbstractShaderProgram::link(); + CORRADE_INTERNAL_ASSERT_OUTPUT(AbstractShaderProgram::link()); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) diff --git a/src/Shaders/Flat.cpp b/src/Shaders/Flat.cpp index 69d1371c2..fdcb3fc6a 100644 --- a/src/Shaders/Flat.cpp +++ b/src/Shaders/Flat.cpp @@ -46,13 +46,17 @@ template Flat::Flat(): transformationProject Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); #endif - attachShader(Shader(v, Shader::Type::Vertex) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get(vertexShaderName()))); - - attachShader(Shader(v, Shader::Type::Fragment) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get("Flat.frag"))); + Shader frag(v, Shader::Type::Vertex); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get(vertexShaderName())); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); + + Shader vert(v, Shader::Type::Fragment); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("Flat.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported() || @@ -64,7 +68,7 @@ template Flat::Flat(): transformationProject bindAttributeLocation(Position::Location, "position"); } - link(); + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) diff --git a/src/Shaders/MeshVisualizer.cpp b/src/Shaders/MeshVisualizer.cpp index 0e44ee489..95316b973 100644 --- a/src/Shaders/MeshVisualizer.cpp +++ b/src/Shaders/MeshVisualizer.cpp @@ -39,19 +39,27 @@ MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationP Corrade::Utility::Resource rs("MagnumShaders"); - attachShader(Shader(Version::GL330, Shader::Type::Vertex) - .addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") + Shader vert(Version::GL330, Shader::Type::Vertex); + vert.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get("MeshVisualizer.vert"))); + .addSource(rs.get("MeshVisualizer.vert")); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); - if(flags & Flag::Wireframe) attachShader(Shader(Version::GL330, Shader::Type::Geometry) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get("MeshVisualizer.geom"))); + if(flags & Flag::Wireframe) { + Shader geom(Version::GL330, Shader::Type::Geometry); + geom.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("MeshVisualizer.geom")); + CORRADE_INTERNAL_ASSERT_OUTPUT(geom.compile()); + attachShader(geom); + } - attachShader(Shader(Version::GL330, Shader::Type::Fragment) - .addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") + Shader frag(Version::GL330, Shader::Type::Fragment); + frag.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get("MeshVisualizer.frag"))); + .addSource(rs.get("MeshVisualizer.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); link(); } diff --git a/src/Shaders/Phong.cpp b/src/Shaders/Phong.cpp index b57723910..3b5df96d4 100644 --- a/src/Shaders/Phong.cpp +++ b/src/Shaders/Phong.cpp @@ -40,13 +40,17 @@ Phong::Phong(): transformationMatrixUniform(0), projectionMatrixUniform(1), norm Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); #endif - attachShader(Shader(v, Shader::Type::Vertex) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get("Phong.vert"))); - - attachShader(Shader(v, Shader::Type::Fragment) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get("Phong.frag"))); + Shader vert(v, Shader::Type::Vertex); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("Phong.vert")); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); + + Shader frag(v, Shader::Type::Fragment); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("Phong.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported() || @@ -59,7 +63,7 @@ Phong::Phong(): transformationMatrixUniform(0), projectionMatrixUniform(1), norm bindAttributeLocation(Normal::Location, "normal"); } - link(); + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) diff --git a/src/Shaders/Vector.cpp b/src/Shaders/Vector.cpp index 48b3463cc..69b47713a 100644 --- a/src/Shaders/Vector.cpp +++ b/src/Shaders/Vector.cpp @@ -47,13 +47,17 @@ template Vector::Vector(): transformationPro Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); #endif - AbstractShaderProgram::attachShader(Shader(v, Shader::Type::Vertex) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get(vertexShaderName()))); - - AbstractShaderProgram::attachShader(Shader(v, Shader::Type::Fragment) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get("Vector.frag"))); + Shader vert(v, Shader::Type::Vertex); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get(vertexShaderName())); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + AbstractShaderProgram::attachShader(vert); + + Shader frag(v, Shader::Type::Fragment); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("Vector.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + AbstractShaderProgram::attachShader(frag); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported() || @@ -66,7 +70,7 @@ template Vector::Vector(): transformationPro AbstractShaderProgram::bindAttributeLocation(AbstractVector::TextureCoordinates::Location, "textureCoordinates"); } - AbstractShaderProgram::link(); + CORRADE_INTERNAL_ASSERT_OUTPUT(AbstractShaderProgram::link()); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) diff --git a/src/Shaders/VertexColor.cpp b/src/Shaders/VertexColor.cpp index 910285f3d..0890137ca 100644 --- a/src/Shaders/VertexColor.cpp +++ b/src/Shaders/VertexColor.cpp @@ -46,13 +46,17 @@ template VertexColor::VertexColor(): transfo Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); #endif - attachShader(Shader(v, Shader::Type::Vertex) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get(vertexShaderName()))); - - attachShader(Shader(v, Shader::Type::Fragment) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get("VertexColor.frag"))); + Shader vert(v, Shader::Type::Vertex); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get(vertexShaderName())); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); + + Shader frag(v, Shader::Type::Fragment); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("VertexColor.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported() || @@ -65,7 +69,7 @@ template VertexColor::VertexColor(): transfo bindAttributeLocation(Color::Location, "color"); } - link(); + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) diff --git a/src/TextureTools/DistanceField.cpp b/src/TextureTools/DistanceField.cpp index c7f593cfb..ca9765007 100644 --- a/src/TextureTools/DistanceField.cpp +++ b/src/TextureTools/DistanceField.cpp @@ -70,14 +70,18 @@ DistanceFieldShader::DistanceFieldShader() { Corrade::Utility::Resource rs("MagnumTextureTools"); - attachShader(Shader(Version::GL330, Shader::Type::Vertex) - .addSource(rs.get("DistanceFieldShader.vert"))); - - attachShader(Shader(Version::GL330, Shader::Type::Fragment) - .addSource(rs.get("compatibility.glsl")) - .addSource(rs.get("DistanceFieldShader.frag"))); - - link(); + Shader vert(Version::GL330, Shader::Type::Vertex); + vert.addSource(rs.get("DistanceFieldShader.vert")); + CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + attachShader(vert); + + Shader frag(Version::GL330, Shader::Type::Fragment); + frag.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("DistanceFieldShader.frag")); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); + + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); } }