mirror of https://github.com/mosra/magnum.git
5 changed files with 609 additions and 0 deletions
@ -0,0 +1,114 @@
|
||||
/*
|
||||
Copyright © 2010 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
This file is part of Magnum. |
||||
|
||||
Magnum is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU Lesser General Public License version 3 |
||||
only, as published by the Free Software Foundation. |
||||
|
||||
Magnum is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License version 3 for more details. |
||||
*/ |
||||
|
||||
#include "AbstractShaderProgram.h" |
||||
|
||||
#include <iostream> |
||||
#include <fstream> |
||||
|
||||
#define LINKER_MESSAGE_MAX_LENGTH 1024 |
||||
|
||||
using namespace std; |
||||
|
||||
namespace Magnum { |
||||
|
||||
AbstractShaderProgram::LogLevel AbstractShaderProgram::_logLevel = AbstractShaderProgram::Errors; |
||||
|
||||
AbstractShaderProgram::AbstractShaderProgram(): state(Initialized) { |
||||
program = glCreateProgram(); |
||||
} |
||||
|
||||
AbstractShaderProgram::~AbstractShaderProgram() { |
||||
if(program) glDeleteProgram(program); |
||||
} |
||||
|
||||
bool AbstractShaderProgram::use() { |
||||
if(state != Linked) return false; |
||||
|
||||
glUseProgram(program); |
||||
return true; |
||||
} |
||||
|
||||
bool AbstractShaderProgram::loadShader(Shader* shader) { |
||||
if(!shader) return false; |
||||
|
||||
GLuint _shader = shader->compile(); |
||||
if(!_shader) return false; |
||||
|
||||
glAttachShader(program, _shader); |
||||
return true; |
||||
} |
||||
|
||||
bool AbstractShaderProgram::bindAttribute(GLuint location, const string& name) { |
||||
/* Check whether given id already exists */ |
||||
if(attributes.find(location) != attributes.end()) return false; |
||||
|
||||
/* Check whether given name already exists */ |
||||
for(map<GLuint, string>::const_iterator it = attributes.begin(); it != attributes.end(); ++it) |
||||
if(it->second == name) return false; |
||||
|
||||
attributes.insert(pair<GLuint, string>(location, name)); |
||||
return true; |
||||
} |
||||
|
||||
void AbstractShaderProgram::link() { |
||||
/* Already compiled or failed, exit */ |
||||
if(state != Initialized) return; |
||||
|
||||
/* Set state to failed if anything goes wrong */ |
||||
state = Failed; |
||||
|
||||
/* Bind attributes to specified locations */ |
||||
for(map<GLuint, string>::const_iterator it = attributes.begin(); it != attributes.end(); ++it) |
||||
glBindAttribLocation(program, it->first, it->second.c_str()); |
||||
|
||||
/* Link shader program */ |
||||
glLinkProgram(program); |
||||
|
||||
/* Check link status */ |
||||
GLint status; |
||||
glGetProgramiv(program, GL_LINK_STATUS, &status); |
||||
|
||||
/* Display errors or warnings */ |
||||
if((status == GL_FALSE && _logLevel != None) || _logLevel == Warnings) { |
||||
/* Get message */ |
||||
char message[LINKER_MESSAGE_MAX_LENGTH]; |
||||
glGetProgramInfoLog(program, LINKER_MESSAGE_MAX_LENGTH, 0, message); |
||||
|
||||
/* Show error log and delete shader */ |
||||
if(status == GL_FALSE) { |
||||
cerr << "Shader program failed to link. Error message:" << endl |
||||
<< message << endl; |
||||
|
||||
/* Or just warnings, if there are any */ |
||||
} else if(message[0] != 0) { |
||||
cerr << "Shader program was linked with the following warnings:" << endl |
||||
<< message << endl; |
||||
} |
||||
} |
||||
|
||||
if(status == GL_FALSE) { |
||||
glDeleteProgram(program); |
||||
program = 0; |
||||
state = Failed; |
||||
} else state = Linked; |
||||
} |
||||
|
||||
GLint AbstractShaderProgram::uniformLocation(const std::string& name) { |
||||
if(state != Linked) return -1; |
||||
return glGetUniformLocation(program, name.c_str()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,190 @@
|
||||
#ifndef Magnum_AbstractShaderProgram_h |
||||
#define Magnum_AbstractShaderProgram_h |
||||
/*
|
||||
Copyright © 2010 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
This file is part of Magnum. |
||||
|
||||
Magnum is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU Lesser General Public License version 3 |
||||
only, as published by the Free Software Foundation. |
||||
|
||||
Magnum is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License version 3 for more details. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Class Magnum::AbstractShaderProgram |
||||
*/ |
||||
|
||||
#include <string> |
||||
#include <map> |
||||
|
||||
#include "Magnum.h" |
||||
#include "Shader.h" |
||||
|
||||
namespace Magnum { |
||||
|
||||
/**
|
||||
@brief Base class for shaders |
||||
|
||||
This class is designed to be used via subclassing. Subclasses define these |
||||
functions and properties: |
||||
- @b Constructor, which loads particular shaders, links the program, binds |
||||
attribute locations and gets uniform locations. |
||||
- <strong>Attribute location</strong> enum with indexes where the particular |
||||
attribute is bound, for example: |
||||
@code |
||||
enum Attribute { |
||||
VertexCoordinates = 1, |
||||
Color = 2, |
||||
TextureCoordinates = 3, |
||||
Normal = 4 |
||||
}; |
||||
@endcode |
||||
See also bindAttribute(). |
||||
- <strong>Uniform binding functions</strong>, which set shader uniforms with |
||||
setUniform() and setUniformArray() functions. Example: |
||||
@code |
||||
void setProjectionMatrixUniform(const Matrix4& matrix); |
||||
@endcode |
||||
|
||||
Basic workflow with AbstractShaderProgram subclasses is: instancing the class |
||||
(once at the beginning), then in every frame calling use(), binding uniforms |
||||
and assigning vertex buffers to given attribute locations. |
||||
*/ |
||||
class AbstractShaderProgram { |
||||
DISABLE_COPY(AbstractShaderProgram) |
||||
|
||||
public: |
||||
/** @brief Logging level */ |
||||
enum LogLevel { |
||||
None, /**< @brief Don't display anything */ |
||||
Errors, /**< @brief Display only errors */ |
||||
Warnings /**< @brief Display only errors and warnings */ |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Log level |
||||
* |
||||
* Log level for displaying compilation messages. Default is Errors. |
||||
*/ |
||||
inline static LogLevel logLevel() { return _logLevel; } |
||||
|
||||
/** @brief Set log level */ |
||||
inline static void setLogLevel(LogLevel level) { _logLevel = level; } |
||||
|
||||
/** @brief Default constructor */ |
||||
AbstractShaderProgram(); |
||||
|
||||
/**
|
||||
* @brief Destructor |
||||
* |
||||
* Deletes the shader program. |
||||
*/ |
||||
~AbstractShaderProgram(); |
||||
|
||||
/**
|
||||
* @brief Use shader |
||||
* @return False if the program wasn't successfully linked, true |
||||
* otherwise. |
||||
*/ |
||||
bool use(); |
||||
|
||||
protected: |
||||
/**
|
||||
* @brief Load shader |
||||
* @return False if the shader wasn't successfully compiled, true |
||||
* otherwise. |
||||
* |
||||
* Compiles the shader, if it is not already, and prepares it for |
||||
* linking. |
||||
* @note The shader should be deleted by caller after linking. |
||||
*/ |
||||
bool loadShader(Shader* shader); |
||||
|
||||
/**
|
||||
* @brief Bind attribute to given location |
||||
* @param location Location |
||||
* @param name Attribute name |
||||
* @return False if the location or name is already bound, true |
||||
* otherwise. |
||||
* |
||||
* Binds attribute to the location which can be used later when binding |
||||
* vertex buffers. |
||||
* @note This function should be called between loadShader() calls |
||||
* and link(). |
||||
*/ |
||||
bool bindAttribute(GLuint location, const std::string& name); |
||||
|
||||
/**
|
||||
* @brief Link the shader |
||||
* |
||||
* Binds previously specified attributes to given indexes and links the |
||||
* shader program together. |
||||
*/ |
||||
void link(); |
||||
|
||||
/**
|
||||
* @brief Get uniform location |
||||
* @param name Uniform name |
||||
* |
||||
* @note This function should be called after link(). |
||||
*/ |
||||
GLint uniformLocation(const std::string& name); |
||||
|
||||
/**
|
||||
* @brief Set uniform value |
||||
* @param location Uniform location (see uniformLocation()) |
||||
* @param value Value |
||||
* |
||||
* @attention This function doesn't check whether this shader is in use! |
||||
*/ |
||||
inline void setUniform(GLint location, GLint value) { |
||||
glUniform1i(location, value); |
||||
} |
||||
|
||||
/** @copydoc setUniform(GLint, GLint) */ |
||||
void setUniform(GLint location, GLuint value) { |
||||
glUniform1ui(location, value); |
||||
} |
||||
|
||||
/** @copydoc setUniform(GLint, GLint) */ |
||||
void setUniform(GLint location, GLfloat value) { |
||||
glUniform1f(location, value); |
||||
} |
||||
|
||||
/** @copydoc setUniform(GLint, GLint) */ |
||||
void setUniform(GLint location, const Vector3& value) { |
||||
glUniform3fv(location, 1, value.data()); |
||||
} |
||||
|
||||
/** @copydoc setUniform(GLint, GLint) */ |
||||
void setUniform(GLint location, const Vector4& value) { |
||||
glUniform4fv(location, 1, value.data()); |
||||
} |
||||
|
||||
/** @copydoc setUniform(GLint, GLint) */ |
||||
void setUniform(GLint location, const Matrix4& value) { |
||||
glUniformMatrix4fv(location, 1, GL_FALSE, value.data()); |
||||
} |
||||
|
||||
private: |
||||
enum State { |
||||
Initialized, |
||||
Linked, |
||||
Failed |
||||
}; |
||||
|
||||
static LogLevel _logLevel; |
||||
|
||||
GLuint program; |
||||
State state; |
||||
std::map<GLuint, std::string> attributes; |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif |
||||
@ -0,0 +1,112 @@
|
||||
/*
|
||||
Copyright © 2010 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
This file is part of Magnum. |
||||
|
||||
Magnum is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU Lesser General Public License version 3 |
||||
only, as published by the Free Software Foundation. |
||||
|
||||
Magnum is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License version 3 for more details. |
||||
*/ |
||||
|
||||
#include "Shader.h" |
||||
|
||||
#include <iostream> |
||||
#include <fstream> |
||||
|
||||
#define COMPILER_MESSAGE_MAX_LENGTH 1024 |
||||
|
||||
using namespace std; |
||||
|
||||
namespace Magnum { |
||||
|
||||
Shader::LogLevel Shader::_logLevel = Shader::Errors; |
||||
|
||||
bool Shader::addFile(const std::string& filename) { |
||||
/* Open file */ |
||||
ifstream file(filename.c_str()); |
||||
if(!file.good()) { |
||||
file.close(); |
||||
|
||||
cerr << "Shader file " << filename << " cannot be opened." << endl; |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/* Get size of shader and initialize buffer */ |
||||
file.seekg(0, ios::end); |
||||
size_t size = file.tellg(); |
||||
char* source = new char[size+1]; |
||||
source[size] = '\0'; |
||||
|
||||
/* Read data, close */ |
||||
file.seekg(0, ios::beg); |
||||
file.read(source, size); |
||||
file.close(); |
||||
|
||||
/* Add to sources and free the buffer */ |
||||
addSource(source); |
||||
delete source; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
GLuint Shader::compile() { |
||||
/* Already compiled, return */ |
||||
if(_state != Initialized) return shader; |
||||
|
||||
/* Array of sources */ |
||||
const GLchar** _sources = new const GLchar*[sources.size()]; |
||||
for(size_t i = 0; i != sources.size(); ++i) |
||||
_sources[i] = static_cast<const GLchar*>(sources[i].c_str()); |
||||
|
||||
/* Create shader and set its source */ |
||||
shader = glCreateShader(_type); |
||||
glShaderSource(shader, 1, _sources, 0); |
||||
|
||||
/* Compile shader */ |
||||
glCompileShader(shader); |
||||
delete _sources; |
||||
|
||||
/* Check compilation status */ |
||||
GLint status; |
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status); |
||||
|
||||
/* Display errors or warnings */ |
||||
if((status == GL_FALSE && _logLevel != None) || _logLevel == Warnings) { |
||||
/* Get message */ |
||||
char message[COMPILER_MESSAGE_MAX_LENGTH]; |
||||
glGetShaderInfoLog(shader, COMPILER_MESSAGE_MAX_LENGTH, 0, message); |
||||
|
||||
if(status == GL_FALSE || message[0] != 0) switch(_type) { |
||||
case Vertex: cerr << "Vertex"; break; |
||||
case Geometry: cerr << "Geometry"; break; |
||||
case Fragment: cerr << "Fragment"; break; |
||||
} |
||||
|
||||
/* Show error log and delete shader */ |
||||
if(status == GL_FALSE) { |
||||
cerr << " shader failed to compile. Error message:" << endl |
||||
<< message << endl; |
||||
|
||||
/* Or just warnings, if there are any */ |
||||
} else if(message[0] != 0) { |
||||
cerr << " shader was compiled with the following warnings:" << endl |
||||
<< message << endl; |
||||
} |
||||
} |
||||
|
||||
if(status == GL_FALSE) { |
||||
glDeleteShader(shader); |
||||
shader = 0; |
||||
_state = Failed; |
||||
} else _state = Compiled; |
||||
|
||||
return shader; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,191 @@
|
||||
#ifndef Magnum_Shader_h |
||||
#define Magnum_Shader_h |
||||
/*
|
||||
Copyright © 2010 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
This file is part of Magnum. |
||||
|
||||
Magnum is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU Lesser General Public License version 3 |
||||
only, as published by the Free Software Foundation. |
||||
|
||||
Magnum is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License version 3 for more details. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Class Magnum::Shader |
||||
*/ |
||||
|
||||
#include "Magnum.h" |
||||
|
||||
#include <vector> |
||||
#include <string> |
||||
|
||||
namespace Magnum { |
||||
|
||||
/**
|
||||
* @brief Shader |
||||
* |
||||
* Allows loading and compiling the shader from file or directly from source |
||||
* string. Compiled shaders are then passed to AbstractShaderProgram subclasses |
||||
* for linking and usage. |
||||
*/ |
||||
class Shader { |
||||
DISABLE_COPY(Shader) |
||||
|
||||
public: |
||||
/** @brief Logging level */ |
||||
enum LogLevel { |
||||
None, /**< @brief Don't display anything */ |
||||
Errors, /**< @brief Display only errors */ |
||||
Warnings /**< @brief Display only errors and warnings */ |
||||
}; |
||||
|
||||
/** @brief Shader type */ |
||||
enum Type { |
||||
Vertex = GL_VERTEX_SHADER, /**< @brief Vertex shader */ |
||||
Geometry = GL_GEOMETRY_SHADER, /**< @brief Geometry shader */ |
||||
Fragment = GL_FRAGMENT_SHADER /**< @brief Fragment shader */ |
||||
}; |
||||
|
||||
/** @brief Shader state */ |
||||
enum State { |
||||
Initialized, /**< @brief Shader sloaded */ |
||||
Compiled, /**< @brief Shader is compiled */ |
||||
Failed /**< @brief Compilation failed */ |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Log level |
||||
* |
||||
* Log level for displaying compilation messages. |
||||
*/ |
||||
inline static LogLevel logLevel() { return _logLevel; } |
||||
|
||||
/** @brief Set log level */ |
||||
inline static void setLogLevel(LogLevel level) { _logLevel = level; } |
||||
|
||||
/**
|
||||
* @brief Load shader from source |
||||
* @param type Shader type |
||||
* @param source Shader source |
||||
* @return Pointer to compiled shader |
||||
* |
||||
* Loads the shader from one source. Shorthand for |
||||
* @code |
||||
* Shader* s = new Shader(type); |
||||
* s->addData(data); |
||||
* @endcode |
||||
* Note that it is also possible to compile shader from more than one |
||||
* source. |
||||
*/ |
||||
inline static Shader* fromData(Type type, const std::string& source) { |
||||
Shader* s = new Shader(type); |
||||
s->addSource(source); |
||||
return s; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Load shader from file |
||||
* @param type Shader type |
||||
* @param filename Source filename |
||||
* @return Pointer to compiled shader or zero, if file cannot be opened. |
||||
* |
||||
* Loads the shader from from one file. Shorthand for |
||||
* @code |
||||
* Shader* s = new Shader(type); |
||||
* if(!s->addFile(filename)) delete s; |
||||
* @endcode |
||||
* Note that it is also possible to compile shader from more than one |
||||
* source. |
||||
*/ |
||||
inline static Shader* fromFile(Type type, const char* filename) { |
||||
Shader* s = new Shader(type); |
||||
if(!s->addFile(filename)) { |
||||
delete s; |
||||
return 0; |
||||
} |
||||
|
||||
return s; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Constructor |
||||
* |
||||
* Creates empty shader. Sources can be added with addData() or addFile(). |
||||
* @see fromData(), fromFile() |
||||
*/ |
||||
inline Shader(Type type): _type(type), _state(Initialized), shader(0) {} |
||||
|
||||
/**
|
||||
* @brief Destructor |
||||
* |
||||
* If the shader is compiled, deletes it. |
||||
*/ |
||||
inline ~Shader() { if(shader) glDeleteShader(shader); } |
||||
|
||||
/**
|
||||
* @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 Add shader source |
||||
* @param source String with shader source |
||||
* |
||||
* If the shader is not compiled already, adds given |
||||
* source to source list. Note that it is possible to compile source |
||||
* from more than one source. |
||||
* @see addFile() |
||||
*/ |
||||
inline void addSource(const std::string& source) { |
||||
if(_state == Initialized) sources.push_back(source); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Add source file |
||||
* @param filename Name of source file to read from |
||||
* @return False if reading the file fails, true otherwise. |
||||
* |
||||
* @see addSource() |
||||
*/ |
||||
bool 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 logLevel(), state() |
||||
*/ |
||||
GLuint compile(); |
||||
|
||||
private: |
||||
static LogLevel _logLevel; |
||||
|
||||
Type _type; |
||||
State _state; |
||||
|
||||
std::vector<std::string> sources; |
||||
|
||||
GLuint shader; |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif |
||||
Loading…
Reference in new issue