← Back to file list Raw

src/CShaderGL.cpp

#include "CShaderGL.h"
#include "CEngine.h"
#include "U_Log.h"
#include <fstream>
#include <sstream>
#include "GL/glew.h"
#include <iterator>
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtx/quaternion.hpp"
#include "glm/gtc/type_ptr.hpp"
CShaderGL::CShaderGL() { }
CShaderGL::CShaderGL(const std::string& vertex_path, const std::string& frag_path, const std::string& geom_path)
{
LoadFromFile(vertex_path, frag_path, geom_path);
}
void CShaderGL::SetProperty(const std::string& name, const std::string& value)
{
for (Property& prop : Properties)
{
if (prop.Name == name)
{
prop.Value = value;
return;
}
}
Properties.push_back({ name, value });
}
void CShaderGL::DeleteProperty(const std::string& name)
{
for (int i = 0; i < Properties.size(); i++)
{
if (Properties.at(i).Name == name)
{
Properties.erase(Properties.begin() + i);
return;
}
}
}
void CShaderGL::ReloadShadersProperties()
{
std::string vertCode = OriginalVertexShader, fragCode = OriginalFragmentShader, geomCode = OriginalGeometryShader;
if (!fragCode.empty()) { usingFrag = true; }
if (!geomCode.empty()) { usingGeom = true; }
std::string propString;
for (Property& prop : Properties)
{
propString += "#define " + prop.Name + " " + prop.Value + "\r\n";
}
std::string toFind = "#version 430\r\n";
size_t index = vertCode.find(toFind);
vertCode.insert(index + toFind.length(), propString);
if (usingFrag)
{
std::string toFind = "#version 430\r\n";
size_t index = fragCode.find(toFind);
fragCode.insert(index + toFind.length(), propString);
}
if (usingGeom)
{
std::string toFind = "#version 430\r\n";
size_t index = geomCode.find(toFind);
geomCode.insert(index + toFind.length(), propString);
}
Compile(vertCode, fragCode, geomCode);
}
void CShaderGL::SetDefaultShaderProperties()
{
}
void CShaderGL::LoadFromFile(const std::string& vertex_path, const std::string& frag_path, const std::string& geom_path)
{
if (!frag_path.empty()) { usingFrag = true; }
if (!geom_path.empty()) { usingGeom = true; }
vertPath = vertex_path;
fragPath = frag_path;
geomPath = geom_path;
std::string vertCode, fragCode, geomCode;
std::ifstream vertStream, fragStream, geomStream;
std::string propString;
for (Property& prop : Properties)
{
propString += "#define " + prop.Name + " " + prop.Value + "\r\n";
}
vertStream.open(vertex_path);
if (vertStream.is_open())
{
std::stringstream vertStringStream;
vertStringStream << vertStream.rdbuf();
vertStream.close();
vertCode = vertStringStream.str();
OriginalVertexShader = vertCode;
std::string toFind = "#version 430\r\n";
size_t index = vertCode.find(toFind);
vertCode.insert(index + toFind.length(), propString);
if (vertex_path == "resources\\shaders\\default.vs")
{
std::ofstream fstr;
fstr.open("vs.txt");
fstr << vertCode;
fstr.close();
}
}
if (usingFrag)
{
fragStream.open(frag_path);
if (fragStream.is_open())
{
std::stringstream fragStringStream;
fragStringStream << fragStream.rdbuf();
fragStream.close();
fragCode = fragStringStream.str();
OriginalFragmentShader = fragCode;
std::string toFind = "#version 430\r\n";
size_t index = fragCode.find(toFind);
fragCode.insert(index + toFind.length(), propString);
if (vertex_path == "resources\\shaders\\default.vs")
{
std::ofstream fstr;
fstr.open("fs.txt");
fstr << fragCode;
fstr.close();
}
}
}
if (usingGeom)
{
geomStream.open(geom_path);
if (geomStream.is_open())
{
std::stringstream geomStringStream;
geomStringStream << geomStream.rdbuf();
geomStream.close();
geomCode = geomStringStream.str();
OriginalGeometryShader = geomCode;
std::string toFind = "#version 430\r\n";
size_t index = geomCode.find(toFind);
geomCode.insert(index + toFind.length(), propString);
}
}
Compile(vertCode, fragCode, geomCode);
}
void CShaderGL::Compile(const std::string& vertCode, const std::string& fragCode, const std::string& geomCode)
{
if (Compiled) { DestructProgram(); Compiled = false; }
unsigned int vertex, fragment, geometry;
int success;
char infoLog[512];
const char* vertcode = vertCode.c_str();
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vertcode, NULL);
glCompileShader(vertex);
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
Log::Errln("Can't compile vertex shader \"" + vertPath + "\":\n" + std::string(infoLog));
std::ofstream fstr;
fstr.open("errordvs.txt");
fstr << vertCode;
fstr.close();
}
else
{
Log::Outln("Vertex shader compiled");
}
if (usingFrag)
{
const char* fragcode = fragCode.c_str();
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fragcode, NULL);
glCompileShader(fragment);
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
Log::Errln("Can't compile fragment shader \"" + fragPath + "\":\n" + std::string(infoLog));
std::ofstream fstr;
fstr.open("errordfs.txt");
fstr << fragCode;
fstr.close();
}
else
{
Log::Outln("Fragment shader compiled");
}
}
if (usingGeom)
{
const char* geomcode = geomCode.c_str();
geometry = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(geometry, 1, &geomcode, NULL);
glCompileShader(geometry);
glGetShaderiv(geometry, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(geometry, 512, NULL, infoLog);
Log::Errln("Can't compile geometry shader \"" + geomPath + "\":\n" + std::string(infoLog));
}
else
{
Log::Outln("Geometry shader compiled");
}
}
ID = glCreateProgram();
glAttachShader(ID, vertex);
if (usingFrag) { glAttachShader(ID, fragment); }
if (usingGeom) { glAttachShader(ID, geometry); }
glLinkProgram(ID);
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(ID, 512, NULL, infoLog);
Log::Errln("Can't link shader:\n" + std::string(infoLog));
}
else
{
Compiled = true;
Log::Outln("Shader linked");
}
glDeleteShader(vertex);
if (usingFrag) { glDeleteShader(fragment); }
if (usingGeom) { glDeleteShader(geometry); }
}
CShaderGL::~CShaderGL()
{
DestructProgram();
}
unsigned int CShaderGL::GetShaderID() { return ID; }
void CShaderGL::DestructProgram()
{
glDeleteProgram(ID);
}
void CShaderGL::Bind()
{
glUseProgram(ID);
}
void CShaderGL::UnbindAll()
{
glUseProgram(0);
}
int CShaderGL::GetUniformLocation(const std::string& name)
{
for (Uniform& u : Uniforms)
{
if (u.Name == name)
{
return u.Location;
}
}
int loc = glGetUniformLocation(ID, name.c_str());
if (loc != -1)
{
Log::Instance() << "Found uniform \"" << name << "\"\n";
Uniforms.push_back({ name, loc });
}
return loc;
}
int CShaderGL::GetUniformBlockLocation(const std::string& name)
{
for (Uniform& u : Uniforms)
{
if (u.Name == name)
{
return u.Location;
}
}
int loc = glGetUniformBlockIndex(ID, name.c_str());
if (loc != -1)
{
Uniforms.push_back({ name, loc });
}
return loc;
}
void CShaderGL::setUniform(const std::string& name, float x)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform1f(loc, x);
}
}
void CShaderGL::setUniform(const std::string& name, int x)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform1i(loc, x);
}
}
void CShaderGL::setUniformLegacyTextureID(const std::string& name, int x)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform1i(loc, x);
}
}
void CShaderGL::setUniform(const std::string& name, unsigned int x)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform1ui(loc, x);
}
}
void CShaderGL::setUniform(const std::string& name, bool x)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform1i(loc, static_cast<int>(x));
}
}
void CShaderGL::setUniform(const std::string& name, const glm::vec2& v)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform2f(loc, v.x, v.y);
}
}
void CShaderGL::setUniform(const std::string& name, const glm::vec3& v)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform3f(loc, v.x, v.y, v.z);
}
}
void CShaderGL::setUniform(const std::string& name, const glm::vec4& v)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform4f(loc, v.x, v.y, v.z, v.w);
}
}
void CShaderGL::setUniform(const std::string& name, const glm::ivec2& v)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform2i(loc, v.x, v.y);
}
}
void CShaderGL::setUniform(const std::string& name, const glm::ivec3& v)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform3i(loc, v.x, v.y, v.z);
}
}
void CShaderGL::setUniform(const std::string& name, const glm::ivec4& v)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform4i(loc, v.x, v.y, v.z, v.w);
}
}
void CShaderGL::setUniform(const std::string& name, const glm::uvec2& v)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform2ui(loc, v.x, v.y);
}
}
void CShaderGL::setUniform(const std::string& name, const glm::uvec3& v)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform3ui(loc, v.x, v.y, v.z);
}
}
void CShaderGL::setUniform(const std::string& name, const glm::uvec4& v)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform4ui(loc, v.x, v.y, v.z, v.w);
}
}
void CShaderGL::setUniform(const std::string& name, const glm::mat3& matrix)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniformMatrix3fv(loc, 1, GL_FALSE, glm::value_ptr(matrix));
}
}
void CShaderGL::setUniform(const std::string& name, const glm::mat4& matrix)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(matrix));
}
}
void CShaderGL::setTextureHandleUniform(const std::string& name, std::uint64_t handle)
{
int loc = GetUniformLocation(name);
if (loc != -1)
{
glUniform2ui(loc, reinterpret_cast<unsigned int*>(&handle)[0], reinterpret_cast<unsigned int*>(&handle)[1]);
}
}
void CShaderGL::setUniformBuffer(const std::string& name, GLuint id, GLuint binding)
{
int loc = GetUniformBlockLocation(name);
//Game.Console.Print("loc of \"" + name + "\" is " + std::to_string(loc) + " and id is " + std::to_string(id));
if (loc != -1)
{
glUniformBlockBinding(ID, loc, binding);
glBindBufferBase(GL_UNIFORM_BUFFER, binding, id);
}
}
int CShaderGL::getUboLayoutSize(const std::string& name)
{
GLint blockSize;
glGetActiveUniformBlockiv(ID, GetUniformBlockLocation(name), GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
return blockSize;
}
std::vector<GLuint> CShaderGL::getUboLayoutIndices(const std::string& name, std::vector<std::string> names)
{
char** result = new char* [names.size()];
for (int index = 0; index < names.size(); index++)
{
result[index] = const_cast<char*>(names[index].c_str());
}
std::vector<GLuint> ret = getUboLayoutIndices(name, const_cast<const char**>(result), names.size());
delete[] result;
return ret;
}
std::vector<int> CShaderGL::getUboLayoutOffsets(const std::string& name, std::vector<GLuint> indices)
{
return getUboLayoutOffsets(name, indices.data(), indices.size());
}
std::vector<GLuint> CShaderGL::getUboLayoutIndices(const std::string& name, const char** names, size_t count)
{
GLuint* indices = new GLuint[count];
glGetUniformIndices(ID, count, names, indices);
std::vector<GLuint> ret;
ret.assign(indices, indices + count);
delete[] indices;
return ret;
}
std::vector<int> CShaderGL::getUboLayoutOffsets(const std::string& name, const GLuint* indices, size_t count)
{
GLint* offset = new GLint[count];
glGetActiveUniformsiv(ID, count, indices, GL_UNIFORM_OFFSET, offset);
std::vector<GLint> ret;
ret.assign(offset, offset + count);
delete[] offset;
return ret;
}