7#include <glm/gtc/type_ptr.hpp>
9#include <smk/Shader.hpp>
17extern bool g_khr_parallel_shader;
21const std::string kShaderHeader =
24 "precision mediump float;\n"
25 "precision mediump int;\n"
26 "precision mediump sampler2DArray;\n";
43 std::ifstream file(filename);
45 std::istreambuf_iterator<char>()),
61 std::vector<char> buffer;
62 for (
const auto& c : kShaderHeader) {
65 for (
const auto& c : content) {
68 buffer.push_back(
'\0');
69 return Shader(buffer, type);
78Shader::Shader() =
default;
79Shader::Shader(
const std::vector<char>& content, GLenum type) {
81 id_ = glCreateShader(type);
83 std::cerr <<
"[Error] Impossible to create a new Shader" << std::endl;
84 throw std::runtime_error(
"[Error] Impossible to create a new Shader");
88 const char* shaderText(&content[0]);
89 glShaderSource(id_, 1, (
const GLchar**)&shaderText,
nullptr);
101 if (g_khr_parallel_shader) {
102 GLint completion_status = {};
103 glGetShaderiv(id_, GL_COMPLETION_STATUS_KHR, &completion_status);
104 return completion_status == GL_TRUE;
107 std::cerr <<
"Used bad path" << std::endl;
114 GLint compile_status = {};
115 glGetShaderiv(id_, GL_COMPILE_STATUS, &compile_status);
116 if (compile_status == GL_TRUE) {
121 glGetShaderiv(id_, GL_INFO_LOG_LENGTH, &logsize);
123 std::vector<char> log(logsize + 1);
124 glGetShaderInfoLog(id_, logsize, &logsize, log.data());
126 std::cout <<
"[Error] compilation error: " << std::endl;
127 std::cout << log.data() << std::endl;
136Shader::Shader(
const Shader& other)
noexcept {
137 this->operator=(other);
140Shader::Shader(Shader&& other)
noexcept {
141 this->operator=(std::move(other));
144Shader& Shader::operator=(
const Shader& other)
noexcept {
145 if (
this == &other) {
153 if (!other.ref_count_) {
154 other.ref_count_ =
new int(1);
158 ref_count_ = other.ref_count_;
164Shader& Shader::operator=(Shader&& other)
noexcept {
165 std::swap(id_, other.id_);
166 std::swap(ref_count_, other.ref_count_);
170void Shader::Release() {
178 int* ref_count =
nullptr;
180 std::swap(ref_count_, ref_count);
197struct ShaderProgram::Impl {
207 Impl(
const Impl&) =
delete;
208 Impl(Impl&&) =
delete;
209 Impl& operator=(
const Impl&) =
delete;
210 Impl& operator=(Impl&&) =
delete;
212 std::map<std::string, GLint> uniforms;
226 impl_->id = glCreateProgram();
228 std::cerr <<
"[Error] Impossible to create a new Shader" << std::endl;
232 glAttachShader(
id(), shader.
id());
244bool ShaderProgram::IsReady()
const {
245 if (g_khr_parallel_shader) {
246 GLint completion_status = {};
247 std::cerr << GL_COMPLETION_STATUS_KHR << std::endl;
248 std::cerr <<
id() << std::endl;
249 glGetProgramiv(
id(), GL_COMPLETION_STATUS_KHR, &completion_status);
250 return completion_status == GL_TRUE;
256bool ShaderProgram::LinkStatus()
const {
258 glGetProgramiv(
id(), GL_LINK_STATUS, &result);
259 if (result == GL_TRUE) {
263 std::cout <<
"[Error] linkage error" << std::endl;
266 glGetProgramiv(
id(), GL_INFO_LOG_LENGTH, &logsize);
268 std::vector<char> log(logsize);
269 glGetProgramInfoLog(
id(), logsize, &logsize, log.data());
271 std::cout << log.data() << std::endl;
279 auto it = impl_->uniforms.find(name);
280 if (it == impl_->uniforms.end()) {
282 GLint r = glGetUniformLocation(
id(), name.c_str());
284 if (r == GL_INVALID_OPERATION || r < 0) {
285 std::cerr <<
"[Error] Uniform " << name <<
" doesn't exist in program"
289 impl_->uniforms[name] = r;
297GLint ShaderProgram::operator[](
const std::string& name) {
305 GLint attrib = glGetAttribLocation(
id(), name.c_str());
306 if (attrib == GL_INVALID_OPERATION || attrib < 0) {
307 std::cerr <<
"[Error] Attribute " << name <<
" doesn't exist in program"
338 glEnableVertexAttribArray(loc);
339 glVertexAttribPointer(loc, size, type, normalize, stride,
340 reinterpret_cast<void*
>(offset));
349 GLboolean normalize)
const {
350 SetAttribute(name, size, stride, offset, normalize, GL_FLOAT);
368 GLuint offset)
const {
369 SetAttribute(name, size, stride, offset,
false, GL_FLOAT);
381 glUniform3f(
Uniform(name), x, y, z);
388 glUniform3fv(
Uniform(name), 1, value_ptr(v));
395 glUniform4fv(
Uniform(name), 1, value_ptr(v));
402 glUniformMatrix4fv(
Uniform(name), 1, GL_FALSE, value_ptr(m));
409 glUniformMatrix3fv(
Uniform(name), 1, GL_FALSE, value_ptr(m));
416 glUniform1f(
Uniform(name), val);
423 glUniform1i(
Uniform(name), val);
445bool ShaderProgram::operator==(
const ShaderProgram& rhs)
const {
446 return impl_ == rhs.impl_;
449bool ShaderProgram::operator!=(
const ShaderProgram& rhs)
const {
450 return impl_ != rhs.impl_;
453ShaderProgram::~ShaderProgram() =
default;
455ShaderProgram::ShaderProgram(const ShaderProgram&) = default;
456ShaderProgram& ShaderProgram::operator=(ShaderProgram&&) noexcept = default;
457ShaderProgram& ShaderProgram::operator=(const ShaderProgram&) = default;
A shader program is a set of shader (for instance vertex shader + pixel shader) defining the renderin...
GLint Attribute(const std::string &name) const
Return the GPU attribute id.
void SetAttribute(const std::string &name, GLint size, GLsizei stride, GLuint offset, GLboolean normalize, GLenum type) const
Set an OpenGL attribute properties.
ShaderProgram()
The constructor. The ShaderProgram is initially invalid. You need to call AddShader and Link before b...
GLint Uniform(const std::string &name)
Return the uniform ID.
void SetUniform(const std::string &name, float x, float y, float z)
Assign shader vec3 uniform.
void Unuse() const
Unbind the ShaderProgram.
void AddShader(const Shader &shader)
Add a Shader to the program list. This must called multiple time for each shader components before ca...
GLuint id() const
The GPU id to the ShaderProgram.
void Use() const
Bind the ShaderProgram. Future draw will use it. This unbind any previously bound ShaderProgram.
void Link() const
Add a Shader to the program list.
A Shader is a little program that rest on the GPU. They are run on a specific section of the graphic ...
bool CompileStatus() const
Wait until the Shader to be ready.
static Shader FromFile(const std::string &filename, GLenum type)
Load a shader from a file.
GLuint id() const
The GPU shader id.
static Shader FromString(const std::string &content, GLenum type)
Load a shader from a std::string.
bool IsReady() const
Check the status of a Shader. Linking shader is an asynchronous process. Using the shader can causes ...