#include "pch.h" #include "log.h" #include "shader.h" std::map ShaderManager::m_shaders; Shader* ShaderManager::m_current; bool Shader::create(const char* vertex, const char* fragment) { GLint status; static char infolog[4096]; int infolen; const GLchar* source; auto vs = glCreateShader(GL_VERTEX_SHADER); if (!vs) { return false; } source = vertex; glShaderSource(vs, 1, &source, nullptr); glCompileShader(vs); glGetShaderiv(vs, GL_COMPILE_STATUS, &status); glGetShaderInfoLog(vs, sizeof(infolog), &infolen, infolog); if (infolen > 0) LOG("VERTEX SHADER:\n%s", infolog); if (status == 0) { glDeleteShader(vs); return false; } auto fs = glCreateShader(GL_FRAGMENT_SHADER); if (!fs) { glDeleteShader(vs); return false; } source = fragment; glShaderSource(fs, 1, &source, nullptr); glCompileShader(fs); glGetShaderiv(fs, GL_COMPILE_STATUS, &status); glGetShaderInfoLog(fs, sizeof(infolog), &infolen, infolog); if (infolen > 0) LOG("FRAGMENT SHADER:\n%s", infolog); if (status == 0) { glDeleteShader(vs); glDeleteShader(fs); return false; } auto ps = glCreateProgram(); if (!ps) { glDeleteShader(vs); glDeleteShader(fs); return false; } glAttachShader(ps, vs); glAttachShader(ps, fs); glDeleteShader(vs); glDeleteShader(fs); glLinkProgram(ps); if (glGetAttribLocation(ps, "pos") != -1) glBindAttribLocation(ps, 0, "pos"); if (glGetAttribLocation(ps, "uvs") != -1) glBindAttribLocation(ps, 1, "uvs"); if (glGetAttribLocation(ps, "uvs2") != -1) glBindAttribLocation(ps, 2, "uvs2"); if (glGetAttribLocation(ps, "col") != -1) glBindAttribLocation(ps, 3, "col"); if (glGetAttribLocation(ps, "nor") != -1) glBindAttribLocation(ps, 3, "nor"); glLinkProgram(ps); glGetProgramiv(ps, GL_LINK_STATUS, &status); glGetProgramInfoLog(ps, sizeof(infolog), &infolen, infolog); if (infolen > 0) LOG("LINK SHADER:\n%s", infolog); if (status == 0) { glDeleteProgram(ps); return false; } // Parse shader uniforms { GLint count; GLint size; // size of the variable GLenum type; // type of the variable (float, vec3 or mat4, etc) const GLsizei bufSize = 16; // maximum name length GLchar name[bufSize]; // variable name in GLSL GLsizei length; // name length glGetProgramiv(ps, GL_ACTIVE_UNIFORMS, &count); for (int i = 0; i < count; i++) { glGetActiveUniform(ps, (GLuint)i, bufSize, &length, &size, &type, name); m_umap[(kShaderUniform)const_hash(name)] = glGetUniformLocation(ps, name); //printf("Uniform #%d Type: %u Name: %s Loc: %d\n", i, type, name, glGetUniformLocation(ps, name)); } } prog = ps; return true; } void Shader::use() { glUseProgram(prog); } void Shader::u_vec4(kShaderUniform id, const glm::vec4& v) { if (m_umap.count(id) == 0) LOG("UNIFORM vec4 %d NOT FOUND in shader %d", (int)id, (int)name) else glUniform4fv(m_umap[id], 1, glm::value_ptr(v)); } void Shader::u_vec3(kShaderUniform id, const glm::vec3& v) { if (m_umap.count(id) == 0) LOG("UNIFORM vec3 %d NOT FOUND in shader %d", (int)id, (int)name) else glUniform3fv(m_umap[id], 1, glm::value_ptr(v)); } void Shader::u_vec2(kShaderUniform id, const glm::vec2& v) { if (m_umap.count(id) == 0) LOG("UNIFORM vec2 %d NOT FOUND in shader %d", (int)id, (int)name) else glUniform2fv(m_umap[id], 1, glm::value_ptr(v)); } void Shader::u_mat4(kShaderUniform id, const glm::mat4& m) { if (m_umap.count(id) == 0) LOG("UNIFORM mat4 %d NOT FOUND in shader %d", (int)id, (int)name) else glUniformMatrix4fv(m_umap[id], 1, GL_FALSE, glm::value_ptr(m)); } void Shader::u_int(kShaderUniform id, int i) { if (m_umap.count(id) == 0) LOG("UNIFORM int %d NOT FOUND in shader %d", (int)id, (int)name) else glUniform1i(m_umap[id], i); } void Shader::u_float(kShaderUniform id, float f) { if (m_umap.count(id) == 0) LOG("UNIFORM float %d NOT FOUND in shader %d", (int)id, (int)name) else glUniform1f(m_umap[id], f); } GLint Shader::GetAttribLocation(const char* name) { return glGetAttribLocation(prog, name); } bool ShaderManager::create(kShader id, const char* vertex, const char* fragment) { m_shaders[id].name = id; return m_shaders[id].create(vertex, fragment); } void ShaderManager::use(kShader id) { m_current = &m_shaders[id]; m_current->use(); } void ShaderManager::use(const char* name) { m_current = &m_shaders[(kShader)const_hash(name)]; m_current->use(); } void ShaderManager::u_vec4(kShaderUniform id, const glm::vec4& v) { m_current->u_vec4(id, v); } void ShaderManager::u_vec3(kShaderUniform id, const glm::vec3& v) { m_current->u_vec3(id, v); } void ShaderManager::u_vec2(kShaderUniform id, const glm::vec2& v) { m_current->u_vec2(id, v); } void ShaderManager::u_mat4(kShaderUniform id, const glm::mat4& m) { m_current->u_mat4(id, m); } void ShaderManager::u_int(kShaderUniform id, int i) { m_current->u_int(id, i); } Shader* ShaderManager::get(kShader id) { auto it = m_shaders.find(id); return (it == m_shaders.end()) ? nullptr : &it->second; } void ShaderManager::u_float(kShaderUniform id, float f) { m_current->u_float(id, f); } void ShaderManager::invalidate() { m_shaders.clear(); }