Browse Source

Reworked and cleaned up shader classes.

Removed unneeded member variables, removed wrong assertions and wrong
documentation (most of the state they were fobidding is actually valid).
Retrieving shader log with full length, properly printing non-error
messages to debug output.

Each shader must now be compiled explicitly using compile(), which is
slightly better for the user as it is possible to check compile status
instead of having it weirdly hidden inside attachShader(). link() now
also returns linking status.
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
6904b38b13
  1. 56
      src/AbstractShaderProgram.cpp
  2. 73
      src/AbstractShaderProgram.h
  3. 124
      src/Shader.cpp
  4. 54
      src/Shader.h
  5. 20
      src/Shaders/DistanceFieldVector.cpp
  6. 20
      src/Shaders/Flat.cpp
  7. 26
      src/Shaders/MeshVisualizer.cpp
  8. 20
      src/Shaders/Phong.cpp
  9. 20
      src/Shaders/Vector.cpp
  10. 20
      src/Shaders/VertexColor.cpp
  11. 20
      src/TextureTools/DistanceField.cpp

56
src/AbstractShaderProgram.cpp

@ -30,8 +30,6 @@
#include "Implementation/ShaderProgramState.h" #include "Implementation/ShaderProgramState.h"
#include "Implementation/State.h" #include "Implementation/State.h"
#define LINKER_MESSAGE_MAX_LENGTH 1024
namespace Magnum { namespace Magnum {
AbstractShaderProgram::Uniform1fvImplementation AbstractShaderProgram::uniform1fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; AbstractShaderProgram::Uniform1fvImplementation AbstractShaderProgram::uniform1fvImplementation = &AbstractShaderProgram::uniformImplementationDefault;
@ -88,67 +86,58 @@ Int AbstractShaderProgram::maxSupportedVertexAttributeCount() {
return value; return value;
} }
AbstractShaderProgram::AbstractShaderProgram(): _id(glCreateProgram()) {}
AbstractShaderProgram::~AbstractShaderProgram() { AbstractShaderProgram::~AbstractShaderProgram() {
/* Remove current usage from the state */ /* Remove current usage from the state */
GLuint& current = Context::current()->state()->shaderProgram->current; GLuint& current = Context::current()->state()->shaderProgram->current;
if(current == _id) current = 0; if(current == _id) current = 0;
glDeleteProgram(_id); if(_id) glDeleteProgram(_id);
} }
bool AbstractShaderProgram::use() { void AbstractShaderProgram::use() {
if(state != Linked) return false;
/* Use only if the program isn't already in use */ /* Use only if the program isn't already in use */
GLuint& current = Context::current()->state()->shaderProgram->current; GLuint& current = Context::current()->state()->shaderProgram->current;
if(current != _id) glUseProgram(current = _id); if(current != _id) glUseProgram(current = _id);
return true;
} }
bool AbstractShaderProgram::attachShader(Shader& shader) { void AbstractShaderProgram::attachShader(Shader& shader) {
GLuint _shader = shader.compile(); glAttachShader(_id, shader.id());
if(!_shader) return false;
glAttachShader(_id, _shader);
return true;
} }
void AbstractShaderProgram::bindAttributeLocation(UnsignedInt location, const std::string& name) { 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()); glBindAttribLocation(_id, location, name.c_str());
} }
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void AbstractShaderProgram::bindFragmentDataLocation(UnsignedInt location, const std::string& name) { 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()); glBindFragDataLocation(_id, location, name.c_str());
} }
void AbstractShaderProgram::bindFragmentDataLocationIndexed(UnsignedInt location, UnsignedInt index, const std::string& name) { 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()); glBindFragDataLocationIndexed(_id, location, index, name.c_str());
} }
#endif #endif
void AbstractShaderProgram::link() { bool AbstractShaderProgram::link() {
/* Already compiled or failed, exit */
if(state != Initialized) return;
/* Link shader program */ /* Link shader program */
glLinkProgram(_id); glLinkProgram(_id);
/* Check link status */ /* Check link status */
GLint status; GLint success, logLength;
glGetProgramiv(_id, GL_LINK_STATUS, &status); glGetProgramiv(_id, GL_LINK_STATUS, &success);
glGetProgramiv(_id, GL_INFO_LOG_LENGTH, &logLength);
/* Display errors or warnings */
char message[LINKER_MESSAGE_MAX_LENGTH]; /* Error or warning message. The string is returned null-terminated, scrap
glGetProgramInfoLog(_id, LINKER_MESSAGE_MAX_LENGTH, nullptr, message); 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 */ /* Show error log and delete shader */
if(status == GL_FALSE) { if(!success) {
Error out; Error out;
out.setFlag(Debug::NewLineAtTheEnd, false); out.setFlag(Debug::NewLineAtTheEnd, false);
out.setFlag(Debug::SpaceAfterEachValue, false); out.setFlag(Debug::SpaceAfterEachValue, false);
@ -156,7 +145,7 @@ void AbstractShaderProgram::link() {
<< message; << message;
/* Or just warnings, if there are any */ /* Or just warnings, if there are any */
} else if(message[0] != 0) { } else if(!message.empty()) {
Debug out; Debug out;
out.setFlag(Debug::NewLineAtTheEnd, false); out.setFlag(Debug::NewLineAtTheEnd, false);
out.setFlag(Debug::SpaceAfterEachValue, false); out.setFlag(Debug::SpaceAfterEachValue, false);
@ -164,13 +153,10 @@ void AbstractShaderProgram::link() {
<< message; << message;
} }
state = status == GL_FALSE ? Failed : Linked; return success;
} }
Int AbstractShaderProgram::uniformLocation(const std::string& name) { 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()); GLint location = glGetUniformLocation(_id, name.c_str());
if(location == -1) if(location == -1)
Warning() << "AbstractShaderProgram: location of uniform \'" + name + "\' cannot be retrieved!"; Warning() << "AbstractShaderProgram: location of uniform \'" + name + "\' cannot be retrieved!";

73
src/AbstractShaderProgram.h

@ -35,8 +35,6 @@
#include "OpenGL.h" #include "OpenGL.h"
#include "magnumVisibility.h" #include "magnumVisibility.h"
/** @todo early asserts (no bool returns?) */
namespace Magnum { namespace Magnum {
namespace Implementation { namespace Implementation {
@ -84,12 +82,19 @@ Int TransformationUniform = 0,
gets uniform locations, for example: gets uniform locations, for example:
@code @code
MyShader() { MyShader() {
// Load shaders from file and attach them to the program // Load shaders, compile them and attach them to the program
attachShader(Shader(Version::GL430, Shader::Type::Vertex).attachFile("PhongShader.vert")); Shader vert(Version::GL430, Shader::Type::Vertex);
attachShader(Shader(Version::GL430, Shader::Type::Fragment).attachFile("PhongShader.frag")); vert.attachFile("PhongShader.vert");
CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile());
// Link attachShader(vert);
link();
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 @endcode
- **Uniform setting functions**, which will provide public interface for - **Uniform setting functions**, which will provide public interface for
@ -521,9 +526,7 @@ class MAGNUM_EXPORT AbstractShaderProgram {
* Creates one OpenGL shader program. * Creates one OpenGL shader program.
* @see @fn_gl{CreateProgram} * @see @fn_gl{CreateProgram}
*/ */
inline explicit AbstractShaderProgram(): state(Initialized) { explicit AbstractShaderProgram();
_id = glCreateProgram();
}
/** /**
* @brief Destructor * @brief Destructor
@ -535,12 +538,10 @@ class MAGNUM_EXPORT AbstractShaderProgram {
/** /**
* @brief Use shader for rendering * @brief Use shader for rendering
* @return False if the program wasn't successfully linked, true
* otherwise.
* *
* @see @fn_gl{UseProgram} * @see @fn_gl{UseProgram}
*/ */
bool use(); void use();
protected: protected:
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
@ -548,8 +549,6 @@ class MAGNUM_EXPORT AbstractShaderProgram {
* @brief Allow retrieving program binary * @brief Allow retrieving program binary
* *
* Initially disabled. * 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} * @see @fn_gl{ProgramParameter} with @def_gl{PROGRAM_BINARY_RETRIEVABLE_HINT}
* @requires_gl41 %Extension @extension{ARB,get_program_binary} * @requires_gl41 %Extension @extension{ARB,get_program_binary}
* @requires_gles30 Always allowed in OpenGL ES 2.0. * @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 * @brief Allow the program to be bound to individual pipeline stages
* *
* Initially disabled. * Initially disabled.
* @note This function should be called after attachShader() calls and
* before link().
* @see @fn_gl{ProgramParameter} with @def_gl{PROGRAM_SEPARABLE} * @see @fn_gl{ProgramParameter} with @def_gl{PROGRAM_SEPARABLE}
* @requires_gl41 %Extension @extension{ARB,separate_shader_objects} * @requires_gl41 %Extension @extension{ARB,separate_shader_objects}
* @requires_es_extension %Extension @es_extension{EXT,separate_shader_objects} * @requires_es_extension %Extension @es_extension{EXT,separate_shader_objects}
@ -579,20 +576,11 @@ class MAGNUM_EXPORT AbstractShaderProgram {
} }
/** /**
* @brief Load shader * @brief Attach shader
* @return False if the shader wasn't successfully compiled, true
* otherwise.
* *
* Compiles the shader, if it is not already, and prepares it for * @fn_gl{AttachShader}
* linking.
* @see Shader::compile(), @fn_gl{AttachShader}
*/ */
bool attachShader(Shader& shader); void attachShader(Shader& shader);
/** @overload */
inline bool attachShader(Shader&& shader) {
return attachShader(shader);
}
/** /**
* @brief Bind attribute to given location * @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 * Binds attribute to location which is used later for binding vertex
* buffers. * buffers.
* @note This function should be called after attachShader() calls and
* before link().
* @deprecated Preferred usage is to specify attribute location * @deprecated Preferred usage is to specify attribute location
* explicitly in the shader instead of using this function. See * explicitly in the shader instead of using this function. See
* @ref AbstractShaderProgram-attribute-location "class documentation" * @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 * Binds fragment data to location which is used later for framebuffer
* operations. See also Framebuffer::BlendFunction for more * operations. See also Framebuffer::BlendFunction for more
* information about using color input index. * 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 * @deprecated Preferred usage is to specify attribute location
* explicitly in the shader instead of using this function. See * explicitly in the shader instead of using this function. See
* @ref AbstractShaderProgram-attribute-location "class documentation" * @ref AbstractShaderProgram-attribute-location "class documentation"
@ -652,18 +636,19 @@ class MAGNUM_EXPORT AbstractShaderProgram {
/** /**
* @brief Link the shader * @brief Link the shader
* *
* Binds previously specified attributes to given indexes and links the * Returns `false` if linking failed, `true` otherwise. Compiler
* shader program together. * 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 * @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 * @brief Get uniform location
* @param name Uniform name * @param name Uniform name
* *
* @note This function should be called after link().
* @deprecated Preferred usage is to specify uniform location * @deprecated Preferred usage is to specify uniform location
* explicitly in the shader instead of using this function. See * explicitly in the shader instead of using this function. See
* @ref AbstractShaderProgram-uniform-location "class documentation" * @ref AbstractShaderProgram-uniform-location "class documentation"
@ -717,8 +702,7 @@ class MAGNUM_EXPORT AbstractShaderProgram {
* @extension{EXT,direct_state_access} is available, the shader is * @extension{EXT,direct_state_access} is available, the shader is
* marked for use before the operation. * marked for use before the operation.
* @see setUniform(Int, const T&), @fn_gl{UseProgram}, @fn_gl{Uniform} * @see setUniform(Int, const T&), @fn_gl{UseProgram}, @fn_gl{Uniform}
* or `glProgramUniform()` from * or @fn_gl{ProgramUniform}/@fn_gl_extension{ProgramUniform,EXT,direct_state_access}.
* @extension{ARB,separate_shader_objects}/@extension{EXT,direct_state_access}.
*/ */
inline void setUniform(Int location, UnsignedInt count, const Float* values) { inline void setUniform(Int location, UnsignedInt count, const Float* values) {
(this->*uniform1fvImplementation)(location, count, values); (this->*uniform1fvImplementation)(location, count, values);
@ -984,12 +968,6 @@ class MAGNUM_EXPORT AbstractShaderProgram {
#endif #endif
private: private:
enum State {
Initialized,
Linked,
Failed
};
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
typedef void(AbstractShaderProgram::*Uniform1fvImplementation)(GLint, GLsizei, const GLfloat*); typedef void(AbstractShaderProgram::*Uniform1fvImplementation)(GLint, GLsizei, const GLfloat*);
@ -1155,7 +1133,6 @@ class MAGNUM_EXPORT AbstractShaderProgram {
#endif #endif
GLuint _id; GLuint _id;
State state;
}; };
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT

124
src/Shader.cpp

@ -27,8 +27,6 @@
#include <fstream> #include <fstream>
#include <Utility/Assert.h> #include <Utility/Assert.h>
#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 */ /* libgles-omap3-dev_4.03.00.02-r15.6 on BeagleBoard/Ångström linux 2011.3 doesn't have GLchar */
#ifdef MAGNUM_TARGET_GLES #ifdef MAGNUM_TARGET_GLES
typedef char GLchar; typedef char GLchar;
@ -36,8 +34,27 @@ typedef char GLchar;
namespace Magnum { namespace Magnum {
Shader::Shader(Version version, Type type): _type(type), _state(State::Initialized), shader(0) { namespace {
shader = glCreateShader(static_cast<GLenum>(_type));
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<GLenum>(_type));
switch(version) { switch(version) {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
@ -62,32 +79,34 @@ Shader::Shader(Version version, Type type): _type(type), _state(State::Initializ
CORRADE_ASSERT_UNREACHABLE(); CORRADE_ASSERT_UNREACHABLE();
} }
Shader::Shader(Shader&& other): _type(other._type), _state(other._state), sources(std::move(other.sources)), shader(other.shader) { Shader::Shader(Shader&& other): _type(other._type), _id(other._id), sources(std::move(other.sources)) {
other.shader = 0; other._id = 0;
}
Shader::~Shader() {
if(_id) glDeleteShader(_id);
} }
Shader& Shader::operator=(Shader&& other) { Shader& Shader::operator=(Shader&& other) {
glDeleteShader(shader); glDeleteShader(_id);
_type = other._type; _type = other._type;
_state = other._state;
sources = std::move(other.sources); sources = std::move(other.sources);
shader = other.shader; _id = other._id;
other.shader = 0; other._id = 0;
return *this; return *this;
} }
Shader& Shader::addSource(std::string source) { Shader& Shader::addSource(std::string source) {
if(source.empty()) return *this; if(!source.empty()) {
if(_state == State::Initialized) {
/* Fix line numbers, so line 41 of third added file is marked as 3(41). /* Fix line numbers, so line 41 of third added file is marked as 3(41).
Source 0 is the #version string added in constructor. */ Source 0 is the #version string added in constructor. */
sources.push_back("#line 1 " + std::to_string(sources.size()) + '\n'); sources.push_back("#line 1 " + std::to_string(sources.size()) + '\n');
sources.push_back(std::move(source)); sources.push_back(std::move(source));
} }
return *this; return *this;
} }
@ -111,9 +130,8 @@ Shader& Shader::addFile(const std::string& filename) {
return *this; return *this;
} }
GLuint Shader::compile() { bool Shader::compile() {
/* Already compiled, return */ CORRADE_ASSERT(sources.size() > 1, "Shader::compile(): no files added", false);
if(_state != State::Initialized) return shader;
/* Array of sources */ /* Array of sources */
const GLchar** _sources = new const GLchar*[sources.size()]; const GLchar** _sources = new const GLchar*[sources.size()];
@ -121,57 +139,45 @@ GLuint Shader::compile() {
_sources[i] = static_cast<const GLchar*>(sources[i].c_str()); _sources[i] = static_cast<const GLchar*>(sources[i].c_str());
/* Create shader and set its source */ /* Create shader and set its source */
glShaderSource(shader, sources.size(), _sources, nullptr); glShaderSource(_id, sources.size(), _sources, nullptr);
/* Compile shader */ /* Compile shader */
glCompileShader(shader); glCompileShader(_id);
delete _sources; delete _sources;
/* Check compilation status */ /* Check compilation status */
GLint status; GLint success, logLength;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status); glGetShaderiv(_id, GL_COMPILE_STATUS, &success);
glGetShaderiv(_id, GL_INFO_LOG_LENGTH, &logLength);
/* Display errors or warnings */
char message[COMPILER_MESSAGE_MAX_LENGTH]; /* Error or warning message. The string is returned null-terminated, scrap
glGetShaderInfoLog(shader, COMPILER_MESSAGE_MAX_LENGTH, nullptr, message); the \0 at the end afterwards */
std::string message(logLength, '\0');
if(status == GL_FALSE || message[0] != 0) { if(!message.empty()) {
Error err; glGetShaderInfoLog(_id, message.size(), nullptr, &message[0]);
err << "Shader:"; message.resize(logLength-1);
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;
}
} }
if(status == GL_FALSE) { /* Show error log */
_state = State::Failed; if(!success) {
return 0; Error out;
} else { out.setFlag(Debug::NewLineAtTheEnd, false);
_state = State::Compiled; out.setFlag(Debug::SpaceAfterEachValue, false);
return shader; 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;
} }
} }

54
src/Shader.h

@ -41,8 +41,7 @@ namespace Magnum {
/** /**
@brief %Shader @brief %Shader
Allows loading and compiling the shader from file or directly from source See AbstractShaderProgram for more information.
string. See AbstractShaderProgram for more information.
*/ */
class MAGNUM_EXPORT Shader { class MAGNUM_EXPORT Shader {
Shader(const Shader&) = delete; Shader(const Shader&) = delete;
@ -86,13 +85,6 @@ class MAGNUM_EXPORT Shader {
Fragment = GL_FRAGMENT_SHADER /**< Fragment 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 * @brief Constructor
* @param version Target version * @param version Target version
@ -110,7 +102,7 @@ class MAGNUM_EXPORT Shader {
* Deletes associated OpenGL shader. * Deletes associated OpenGL shader.
* @see @fn_gl{DeleteShader} * @see @fn_gl{DeleteShader}
*/ */
inline ~Shader() { if(shader) glDeleteShader(shader); } ~Shader();
/** @brief Move constructor */ /** @brief Move constructor */
Shader(Shader&& other); Shader(Shader&& other);
@ -118,28 +110,17 @@ class MAGNUM_EXPORT Shader {
/** @brief Move assignment operator */ /** @brief Move assignment operator */
Shader& operator=(Shader&& other); Shader& operator=(Shader&& other);
/** /** @brief OpenGL shader ID */
* @brief %Shader type inline GLuint id() const { return _id; }
*
* Set in constructor.
*/
inline Type type() const { return _type; }
/**
* @brief Compilation state
*
* Changes after calling compile().
*/
inline State state() const { return _state; }
/** /**
* @brief Add shader source * @brief Add shader source
* @param source String with shader source * @param source String with shader source
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* *
* If the shader is not compiled already, adds given source to source * Adds given source to source list, preceeded with @c \#line directive
* list. Note that it is possible to compile shader from more than * marking first line of the source as `n(1)` where n is number of
* one source. If passed string is empty, the function does nothing. * added source. If passed string is empty, the function does nothing.
* @see addFile() * @see addFile()
*/ */
Shader& addSource(std::string source); Shader& addSource(std::string source);
@ -149,32 +130,27 @@ class MAGNUM_EXPORT Shader {
* @param filename Name of source file to read from * @param filename Name of source file to read from
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* *
* The file must exist and must be readable. * The file must exist and must be readable. Calls addSource() with
* @see addSource() * the contents.
*/ */
Shader& addFile(const std::string& filename); Shader& addFile(const std::string& filename);
/** /**
* @brief Compile shader * @brief Compile shader
* @return Compiled shader or 0 if compilation failed.
* *
* If the shader has any sources present and hasn't been compiled * Returns `false` if compilation failed, `true` otherwise. Compiler
* before, it tries to compile it. If compilation fails or no sources * message (if any) is printed to error output.
* are present, returns 0. If the shader was compiled already, returns * @see @fn_gl{ShaderSource}, @fn_gl{CompileShader}, @fn_gl{GetShader}
* already existing shader. * with @def_gl{COMPILE_STATUS} and @def_gl{INFO_LOG_LENGTH},
* @see state(), @fn_gl{ShaderSource}, @fn_gl{CompileShader},
* @fn_gl{GetShader} with @def_gl{COMPILE_STATUS},
* @fn_gl{GetShaderInfoLog} * @fn_gl{GetShaderInfoLog}
*/ */
GLuint compile(); bool compile();
private: private:
Type _type; Type _type;
State _state; GLuint _id;
std::vector<std::string> sources; std::vector<std::string> sources;
GLuint shader;
}; };
} }

20
src/Shaders/DistanceFieldVector.cpp

@ -47,13 +47,17 @@ template<UnsignedInt dimensions> DistanceFieldVector<dimensions>::DistanceFieldV
Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200});
#endif #endif
AbstractShaderProgram::attachShader(Shader(v, Shader::Type::Vertex) Shader frag(v, Shader::Type::Vertex);
.addSource(rs.get("compatibility.glsl")) frag.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get(vertexShaderName<dimensions>()))); .addSource(rs.get(vertexShaderName<dimensions>()));
CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile());
AbstractShaderProgram::attachShader(Shader(v, Shader::Type::Fragment) AbstractShaderProgram::attachShader(frag);
.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get("DistanceFieldVector.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 #ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() || if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() ||
@ -66,7 +70,7 @@ template<UnsignedInt dimensions> DistanceFieldVector<dimensions>::DistanceFieldV
AbstractShaderProgram::bindAttributeLocation(AbstractVector<dimensions>::TextureCoordinates::Location, "textureCoordinates"); AbstractShaderProgram::bindAttributeLocation(AbstractVector<dimensions>::TextureCoordinates::Location, "textureCoordinates");
} }
AbstractShaderProgram::link(); CORRADE_INTERNAL_ASSERT_OUTPUT(AbstractShaderProgram::link());
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>()) if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>())

20
src/Shaders/Flat.cpp

@ -46,13 +46,17 @@ template<UnsignedInt dimensions> Flat<dimensions>::Flat(): transformationProject
Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200});
#endif #endif
attachShader(Shader(v, Shader::Type::Vertex) Shader frag(v, Shader::Type::Vertex);
.addSource(rs.get("compatibility.glsl")) frag.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get(vertexShaderName<dimensions>()))); .addSource(rs.get(vertexShaderName<dimensions>()));
CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile());
attachShader(Shader(v, Shader::Type::Fragment) attachShader(frag);
.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get("Flat.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 #ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() || if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() ||
@ -64,7 +68,7 @@ template<UnsignedInt dimensions> Flat<dimensions>::Flat(): transformationProject
bindAttributeLocation(Position::Location, "position"); bindAttributeLocation(Position::Location, "position");
} }
link(); CORRADE_INTERNAL_ASSERT_OUTPUT(link());
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>()) if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>())

26
src/Shaders/MeshVisualizer.cpp

@ -39,19 +39,27 @@ MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationP
Corrade::Utility::Resource rs("MagnumShaders"); Corrade::Utility::Resource rs("MagnumShaders");
attachShader(Shader(Version::GL330, Shader::Type::Vertex) Shader vert(Version::GL330, Shader::Type::Vertex);
.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") vert.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "")
.addSource(rs.get("compatibility.glsl")) .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) if(flags & Flag::Wireframe) {
.addSource(rs.get("compatibility.glsl")) Shader geom(Version::GL330, Shader::Type::Geometry);
.addSource(rs.get("MeshVisualizer.geom"))); 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) Shader frag(Version::GL330, Shader::Type::Fragment);
.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") frag.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "")
.addSource(rs.get("compatibility.glsl")) .addSource(rs.get("compatibility.glsl"))
.addSource(rs.get("MeshVisualizer.frag"))); .addSource(rs.get("MeshVisualizer.frag"));
CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile());
attachShader(frag);
link(); link();
} }

20
src/Shaders/Phong.cpp

@ -40,13 +40,17 @@ Phong::Phong(): transformationMatrixUniform(0), projectionMatrixUniform(1), norm
Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200});
#endif #endif
attachShader(Shader(v, Shader::Type::Vertex) Shader vert(v, Shader::Type::Vertex);
.addSource(rs.get("compatibility.glsl")) vert.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get("Phong.vert"))); .addSource(rs.get("Phong.vert"));
CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile());
attachShader(Shader(v, Shader::Type::Fragment) attachShader(vert);
.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get("Phong.frag"))); 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 #ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() || if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() ||
@ -59,7 +63,7 @@ Phong::Phong(): transformationMatrixUniform(0), projectionMatrixUniform(1), norm
bindAttributeLocation(Normal::Location, "normal"); bindAttributeLocation(Normal::Location, "normal");
} }
link(); CORRADE_INTERNAL_ASSERT_OUTPUT(link());
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>()) if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>())

20
src/Shaders/Vector.cpp

@ -47,13 +47,17 @@ template<UnsignedInt dimensions> Vector<dimensions>::Vector(): transformationPro
Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200});
#endif #endif
AbstractShaderProgram::attachShader(Shader(v, Shader::Type::Vertex) Shader vert(v, Shader::Type::Vertex);
.addSource(rs.get("compatibility.glsl")) vert.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get(vertexShaderName<dimensions>()))); .addSource(rs.get(vertexShaderName<dimensions>()));
CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile());
AbstractShaderProgram::attachShader(Shader(v, Shader::Type::Fragment) AbstractShaderProgram::attachShader(vert);
.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get("Vector.frag"))); 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 #ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() || if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() ||
@ -66,7 +70,7 @@ template<UnsignedInt dimensions> Vector<dimensions>::Vector(): transformationPro
AbstractShaderProgram::bindAttributeLocation(AbstractVector<dimensions>::TextureCoordinates::Location, "textureCoordinates"); AbstractShaderProgram::bindAttributeLocation(AbstractVector<dimensions>::TextureCoordinates::Location, "textureCoordinates");
} }
AbstractShaderProgram::link(); CORRADE_INTERNAL_ASSERT_OUTPUT(AbstractShaderProgram::link());
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>()) if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>())

20
src/Shaders/VertexColor.cpp

@ -46,13 +46,17 @@ template<UnsignedInt dimensions> VertexColor<dimensions>::VertexColor(): transfo
Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200});
#endif #endif
attachShader(Shader(v, Shader::Type::Vertex) Shader vert(v, Shader::Type::Vertex);
.addSource(rs.get("compatibility.glsl")) vert.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get(vertexShaderName<dimensions>()))); .addSource(rs.get(vertexShaderName<dimensions>()));
CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile());
attachShader(Shader(v, Shader::Type::Fragment) attachShader(vert);
.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get("VertexColor.frag"))); 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 #ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() || if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>() ||
@ -65,7 +69,7 @@ template<UnsignedInt dimensions> VertexColor<dimensions>::VertexColor(): transfo
bindAttributeLocation(Color::Location, "color"); bindAttributeLocation(Color::Location, "color");
} }
link(); CORRADE_INTERNAL_ASSERT_OUTPUT(link());
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>()) if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_uniform_location>())

20
src/TextureTools/DistanceField.cpp

@ -70,14 +70,18 @@ DistanceFieldShader::DistanceFieldShader() {
Corrade::Utility::Resource rs("MagnumTextureTools"); Corrade::Utility::Resource rs("MagnumTextureTools");
attachShader(Shader(Version::GL330, Shader::Type::Vertex) Shader vert(Version::GL330, Shader::Type::Vertex);
.addSource(rs.get("DistanceFieldShader.vert"))); vert.addSource(rs.get("DistanceFieldShader.vert"));
CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile());
attachShader(Shader(Version::GL330, Shader::Type::Fragment) attachShader(vert);
.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get("DistanceFieldShader.frag"))); Shader frag(Version::GL330, Shader::Type::Fragment);
frag.addSource(rs.get("compatibility.glsl"))
link(); .addSource(rs.get("DistanceFieldShader.frag"));
CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile());
attachShader(frag);
CORRADE_INTERNAL_ASSERT_OUTPUT(link());
} }
} }

Loading…
Cancel
Save