You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lunarium_OLD/src/renderer/shader.cpp

215 lines
6.9 KiB
C++

/******************************************************************************
* File - shader.cpp
* Author - Joey Pollack
* Date - 2022/08/04 (y/m/d)
* Mod Date - 2022/08/04 (y/m/d)
* Description - opengl shader system
******************************************************************************/
#include "shader.h"
#include <utils/logger.h>
#include <glad/gl.h>
#include <string>
namespace lunarium
{
Shader::Shader(const char* vert_source, const char* geo_source, const char* frag_source)
: mGLID(0)
{
// Validate parameters
if (!vert_source)
{
Logger::Error(LogCategory::GRAPHICS, "Failed to create Shader - vert_source can not be nullptr!");
return;
}
if (!frag_source)
{
Logger::Error(LogCategory::GRAPHICS, "Failed to create Shader - vert_source can not be nullptr!");
return;
}
// Compile source code
u32 vert_id = CompileSource(vert_source, GL_VERTEX_SHADER);
u32 geo_id = (geo_source ? CompileSource(geo_source, GL_GEOMETRY_SHADER) : 0 );
u32 frag_id = CompileSource(frag_source, GL_FRAGMENT_SHADER);
// Validate compilation
if (vert_id < 1 || frag_id < 1)
{
// Free any succesfully compiled shader sources
if (vert_id > 0) glDeleteShader(vert_id);
if (geo_id > 0) glDeleteShader(geo_id);
if (frag_id > 0) glDeleteShader(frag_id);
Logger::Error(LogCategory::GRAPHICS, "Failed to create shader program");
return;
}
// Link shader program
mGLID = glCreateProgram();
glAttachShader(mGLID, vert_id);
if (geo_id > 0) glAttachShader(mGLID, geo_id);
glAttachShader(mGLID, frag_id);
glLinkProgram(mGLID);
// check for linking errors
int success;
const int buffer_size = 512;
char info_log[buffer_size];
glGetProgramiv(mGLID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(mGLID, 512, NULL, info_log);
Logger::Error(LogCategory::GRAPHICS, "Failed to link shader program: %s", info_log);
glDeleteProgram(mGLID);
mGLID = 0;
}
// Clean up
if (vert_id > 0) glDeleteShader(vert_id);
if (geo_id > 0) glDeleteShader(geo_id);
if (frag_id > 0) glDeleteShader(frag_id);
}
Shader::~Shader()
{
if (IsValid())
{
glDeleteProgram(mGLID);
mGLID = 0;
}
}
bool Shader::IsValid() const
{
return mGLID > 0;
}
void Shader::Use() const
{
glUseProgram(mGLID);
}
OpRes Shader::GetAllUniforms(std::vector<Uniform>& uniforms)
{
uniforms.clear();
GLint size; // size of the variable
GLenum type; // type of the variable (float, vec3 or mat4, etc)
const GLsizei buffer_size = 16; // maximum name length
GLchar name[buffer_size]; // variable name in GLSL
GLsizei length; // name length
int count = -1;
glGetProgramiv(mGLID, GL_ACTIVE_UNIFORMS, &count);
Logger::Debug(LogCategory::GRAPHICS, "Active Uniforms for shader %n: %n", mGLID, count);
for (int i = 0; i < count; i++)
{
glGetActiveUniform(mGLID, (GLuint)i, buffer_size, &length, &size, &type, name);
u32 location = glGetUniformLocation(mGLID, name);
Logger::Debug(LogCategory::GRAPHICS, "Uniform #%n Type: %u Name: %s Location: %n", i, type, name, location);
Uniform u;
u.Location = location;
u.Type = GLToUniformType(type);
u.Name = std::string(name);
uniforms.push_back(u);
}
return OpRes::OK();
}
void Shader::GetUniformLocation(Uniform& uniform)
{
uniform.Location = glGetUniformLocation(mGLID, uniform.Name.c_str());
}
OpRes Shader::SetUniform(Uniform& uniform, void* values)
{
if (uniform.Location == -1)
{
GetUniformLocation(uniform);
if (uniform.Location == -1)
{
return OpRes::Fail("Could not find location for uniform: %s", uniform.Name.c_str());
}
}
switch (uniform.Type)
{
case UniformType::F1: glUniform1fv(uniform.Location, 1, (GLfloat*)values); break;
case UniformType::F2: glUniform2fv(uniform.Location, 1, (GLfloat*)values); break;
case UniformType::F3: glUniform3fv(uniform.Location, 1, (GLfloat*)values); break;
case UniformType::F4: glUniform4fv(uniform.Location, 1, (GLfloat*)values); break;
case UniformType::I1: glUniform1iv(uniform.Location, 1, (GLint*)values); break;
case UniformType::I2: glUniform2iv(uniform.Location, 1, (GLint*)values); break;
case UniformType::I3: glUniform3iv(uniform.Location, 1, (GLint*)values); break;
case UniformType::I4: glUniform4iv(uniform.Location, 1, (GLint*)values); break;
case UniformType::FMAT3: glUniformMatrix3fv(uniform.Location, 1, GL_FALSE, (GLfloat*)values); break;
case UniformType::FMAT4: glUniformMatrix4fv(uniform.Location, 1, GL_FALSE, (GLfloat*)values); break;
default: return OpRes::Fail("Can not set uniform value - Unknown type");
}
return OpRes::OK();
}
u32 Shader::CompileSource(const char* source, u32 source_type)
{
u32 id = glCreateShader(source_type);
glShaderSource(id, 1, &source, NULL);
glCompileShader(id);
int success;
const int buffer_size = 512;
char info_log[buffer_size];
glGetShaderiv(id, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(id, buffer_size, NULL, info_log);
std::string type = "";
switch (source_type)
{
case GL_VERTEX_SHADER: type = "Vertex"; break;
case GL_GEOMETRY_SHADER: type = "Geometry"; break;
case GL_FRAGMENT_SHADER: type = "Fragment"; break;
}
Logger::Error(LogCategory::GRAPHICS, "Failed to compile %s shader source: %s", type.c_str(), info_log);
return 0;
}
return id;
}
UniformType Shader::GLToUniformType(u32 type)
{
switch (type)
{
case GL_FLOAT: return UniformType::F1;
case GL_FLOAT_VEC2: return UniformType::F2;
case GL_FLOAT_VEC3: return UniformType::F3;
case GL_FLOAT_VEC4: return UniformType::F4;
case GL_INT: return UniformType::I1;
case GL_INT_VEC2: return UniformType::I2;
case GL_INT_VEC3: return UniformType::I3;
case GL_INT_VEC4: return UniformType::I4;
case GL_FLOAT_MAT3: return UniformType::FMAT3;
case GL_FLOAT_MAT4: return UniformType::FMAT4;
}
Logger::Warn(LogCategory::GRAPHICS, "Can not convert GL uniform type - Unknown type: %u", type);
return UniformType::UNKNOWN;
}
}