|
|
|
|
/******************************************************************************
|
|
|
|
|
* 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, int num_uniforms)
|
|
|
|
|
{
|
|
|
|
|
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, num_uniforms, (GLfloat*)values); break;
|
|
|
|
|
case UniformType::F2: glUniform2fv(uniform.Location, num_uniforms, (GLfloat*)values); break;
|
|
|
|
|
case UniformType::F3: glUniform3fv(uniform.Location, num_uniforms, (GLfloat*)values); break;
|
|
|
|
|
case UniformType::F4: glUniform4fv(uniform.Location, num_uniforms, (GLfloat*)values); break;
|
|
|
|
|
|
|
|
|
|
case UniformType::I1: glUniform1iv(uniform.Location, num_uniforms, (GLint*)values); break;
|
|
|
|
|
case UniformType::I2: glUniform2iv(uniform.Location, num_uniforms, (GLint*)values); break;
|
|
|
|
|
case UniformType::I3: glUniform3iv(uniform.Location, num_uniforms, (GLint*)values); break;
|
|
|
|
|
case UniformType::I4: glUniform4iv(uniform.Location, num_uniforms, (GLint*)values); break;
|
|
|
|
|
|
|
|
|
|
case UniformType::FMAT3: glUniformMatrix3fv(uniform.Location, num_uniforms, GL_FALSE, (GLfloat*)values); break;
|
|
|
|
|
case UniformType::FMAT4: glUniformMatrix4fv(uniform.Location, num_uniforms, GL_FALSE, (GLfloat*)values); break;
|
|
|
|
|
|
|
|
|
|
default: return OpRes::Fail("Can not set uniform value - Unknown type");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int error = glGetError();
|
|
|
|
|
if (error > 0)
|
|
|
|
|
{
|
|
|
|
|
Logger::Error(LogCategory::GRAPHICS, "Error setting uniform - Name: %s error code: %d", uniform.Name.c_str(), error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|