Skip to content

File Shaders.cpp

File List > render > Shaders.cpp

Go to the documentation of this file

#include "Shaders.h"

std::string const Shaders::shader_type[4] = { "Vertex Shader", "Fragment Shader", "Compute Shader", "Geometry Shader" };

void Shaders::ShaderUnit::_del()
{
    glDeleteShader(sh_ID);
    sh_ID = 0;
}

void Shaders::ShaderUnit::_copyInfo(const ShaderUnit& unit)
{
    sh_type = unit.sh_type;
    sh_name = unit.sh_name;
    sh_ID = unit.sh_ID;
    sh_code = unit.sh_code;
}

void Shaders::ShaderUnit::_resetID(GLuint ID)
{
    if (ID > 0 && ID != sh_ID)
        _del();
    sh_ID = ID;
}

Shaders::ShaderUnit::ShaderUnit(const ShaderUnit& unit)
{
    _resetID(unit.sh_ID);
    _copyInfo(unit);

    if (unit.sh_struct)
        sh_struct = unit.sh_struct;
}

Shaders::ShaderUnit::ShaderUnit(ShaderUnit&& unit) noexcept
{
    _resetID(unit.sh_ID);
    _copyInfo(unit);
    unit.sh_ID = 0;

    if (unit.sh_struct)
        sh_struct = std::move(unit.sh_struct);
}

Shaders::ShaderUnit::ShaderUnit(ShaderType type, std::string name)
    :sh_type(type), sh_name(name)
{}

Shaders::ShaderUnit::~ShaderUnit()
{
    if (sh_ID != 0)
        _del();
}

Shaders::ShaderUnit& Shaders::ShaderUnit::operator=(ShaderUnit&& unit) noexcept
{
    _resetID(unit.sh_ID);
    _copyInfo(unit);
    unit.sh_ID = 0;

    if (unit.sh_struct)
        sh_struct = std::move(unit.sh_struct);

    return *this;
}

Shaders::ShaderUnit& Shaders::ShaderUnit::operator=(const ShaderUnit& unit)
{
    _resetID(unit.sh_ID);
    _copyInfo(unit);

    if (unit.sh_struct)
        sh_struct = unit.sh_struct;

    return *this;
}

std::size_t Shaders::ShaderUnit::hash_fn::operator()(const ShaderUnit& inp) const
{
    static std::hash<std::string> hasher;
    return hasher(inp.sh_name + std::to_string(inp.sh_type));
}

std::string Shaders::folder_root = "res/shaders/";
std::vector<std::string> Shaders::file_type = { ".vert", ".frag", ".comp", ".geom" };

GLuint Shaders::CompileShaderCode(ShaderType _type, const std::string& source) {

    const auto [name, fname, glname] = Shaders::ParseShaderType(_type);

    GLuint id = glCreateShader(glname);
    const char* src = source.c_str(); //传入指针,需要保证指向source(shader代码)的内存一直存在

    glShaderSource(id, 1, &src, nullptr);

    //std::cout << id << std::endl;
    glCompileShader(id);

    //delete src;
    int status = 0;
    glGetShaderiv(id, GL_COMPILE_STATUS, &status);

    if (!status) {
        int length;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        std::string message;
        message.resize(length);

        glGetShaderInfoLog(id, length, &length, message.data());
        std::cout << name + " error\n";
        std::cout << message << "\n";
        printf(source.c_str());
        glDeleteShader(id);
        return -1;
    }
#ifdef _DEBUG
    else
        std::cout << name << " is complied successfully!\n";
#endif
    //delete src;
    return id;
}

std::string Shaders::ReadShaderFile(ShaderType _type, const std::string& name)
{
    std::string file_name = name.find(Shaders::folder_root) == std::string::npos ? Shaders::folder_root + name : name;

    if (Shaders::ParseFileEXT(file_name) == NONE_SHADER)
        file_name += Shaders::file_type[_type];

    std::ifstream File(file_name);
    std::stringstream Stream;

    Stream << File.rdbuf();

    File.close();

    return Stream.str();
}

Shaders::Shaders(const Shaders& shader)
{
    _resetProgramID(shader.GetProgramID());
}

Shaders::Shaders(Shaders&& shader) noexcept
{
    _resetProgramID(shader.GetProgramID());
    shader.program_id = 0;
}

Shaders::~Shaders()
{

}

Shaders& Shaders::operator=(Shaders&& shader) noexcept
{
    _resetProgramID(shader.GetProgramID());
    shader.program_id = 0;

    return *this;
}

Shaders& Shaders::operator=(const Shaders& shader)
{
    _resetProgramID(shader.GetProgramID());

    return *this;
}

void Shaders::_del()
{
    glDeleteProgram(program_id);
    program_id = 0;
}

Shaders::ShaderConstInfo Shaders::ParseShaderType(ShaderType _type)
{
    switch (_type)
    {
    case VERTEX_SHADER:
        return { Shaders::shader_type[_type], ".vert", GL_VERTEX_SHADER};
    case FRAGMENT_SHADER:
        return { Shaders::shader_type[_type], ".frag", GL_FRAGMENT_SHADER };
    case COMPUTE_SHADER:
        return { Shaders::shader_type[_type], ".comp", GL_COMPUTE_SHADER };
    case GEOMETRY_SHADER:
        return { Shaders::shader_type[_type], ".geom", GL_GEOMETRY_SHADER };
    default:
        return { "/", "/", GL_NONE };
    }
}

ShaderType Shaders::ParseFileEXT(std::string path)
{
    for (int i = 0; auto & ext : Shaders::file_type) {
        if (path.find(ext) != std::string::npos)
            return ShaderType(i);
        i++;
    }

    return NONE_SHADER;
}




void Shaders::UseShader() const
{
    glUseProgram(program_id);
}

void Shaders::UnuseShader() const
{
    glUseProgram(0);
}

GLuint Shaders::getVarID(const char* name) const
{
    //std::cout << program_id << "\n";
    if (_uniforms_cache.find(name) != _uniforms_cache.end())
        return _uniforms_cache[name];

    this->UseShader();
    int id = glGetUniformLocation(program_id, name);

#ifdef _DEBUG
    if (id == -1)std::cout << name << " do not exist!" << std::endl;
#endif

    _uniforms_cache[name] = id;
    return glGetUniformLocation(program_id, name);
}

void Shaders::SetValue(const std::string& name, int v0, int v1, int v2, int v3)
{
    int id = getVarID(name.c_str());
    glUniform4i(id, v0, v1, v2, v3);
}

void Shaders::SetValue(const std::string& name, int v0, int v1, int v2)
{
    int id = getVarID(name.c_str());
    glUniform3i(id, v0, v1, v2);
}

void Shaders::SetValue(const std::string& name, float v0, float v1)
{
    int id = getVarID(name.c_str());
    glUniform2f(id, v0, v1);
}

void Shaders::SetValue(const std::string& name, float v0, float v1, float v2)
{
    int id = getVarID(name.c_str());
    glUniform3f(id, v0, v1, v2);
}

void Shaders::SetValue(const std::string& name, float v0, float v1, float v2, float v3)
{
    int id = getVarID(name.c_str());
    glUniform4f(id, v0, v1, v2, v3);
}

void Shaders::SetValue(const std::string& name, const glm::mat4& projection)
{
    int id = getVarID(name.c_str());
    glUniformMatrix4fv(id, 1, GL_FALSE, &projection[0][0]);
}

void Shaders::SetValue(const std::string& name, float v0)
{
    int id = getVarID(name.c_str());
    glUniform1f(id, v0);
}

void Shaders::SetValue(const std::string& name, int v0)
{
    int id = getVarID(name.c_str());
    glUniform1i(id, v0);
}

void Shaders::SetValue(const std::string& name, bool v0)
{
    int id = getVarID(name.c_str());
    glUniform1i(id, v0);
}

void Shaders::SetValue(const std::string& name, const GLuint& v0)
{
    int id = getVarID(name.c_str());
    glUniform1i(id, v0);
}

void Shaders::SetValue(const std::string& name, const glm::vec2& vec2)
{
    SetValue(name, vec2[0], vec2[1]);
}

void Shaders::SetValue(const std::string& name, const glm::vec3& vec3)
{
    SetValue(name, vec3[0], vec3[1], vec3[2]);
}

void Shaders::SetValue(const std::string& name, const glm::vec4& vec4)
{
    SetValue(name, vec4[0], vec4[1], vec4[2], vec4[3]);
}

void Shaders::SetValue(const std::string& name, GLsizei count, const float* va0, ArrayType TYPE)
{
    int id = getVarID(name.c_str());
    switch (TYPE)
    {
    case NULL_ARRAY:

        break;
    case VEC1_ARRAY:
        glUniform1fv(id, count, va0);
        break;
    case VEC2_ARRAY:
        glUniform2fv(id, count * 2, va0);
        break;
    case VEC3_ARRAY:
        glUniform3fv(id, count * 3, va0);
        break;
    case VEC4_ARRAY:
        glUniform4fv(id, count * 4, va0);
        break;
    case MAT4_ARRAY:
        glUniform4fv(id, count * 4, va0);
        break;
    default:
        break;
    }
}

void Shaders::SetValue(const std::string& name, GLsizei count, const int* va0, ArrayType TYPE)
{
    int id = getVarID(name.c_str());
    switch (TYPE)
    {
    case NULL_ARRAY:

        break;
    case VEC1_ARRAY:
        glUniform1iv(id, count, va0);
        break;
    case VEC2_ARRAY:
        glUniform2iv(id, count * 2, va0);
        break;
    case VEC3_ARRAY:
        glUniform3iv(id, count * 3, va0);
        break;
    case VEC4_ARRAY:
        glUniform4iv(id, count * 4, va0);
        break;
    case MAT4_ARRAY:
        glUniform4iv(id, count * 4, va0);
        break;
    default:
        break;
    }
}

void Shaders::SetValue(const std::string& name, GLsizei count, const GLuint* va0, ArrayType TYPE)
{
    int id = getVarID(name.c_str());
    switch (TYPE)
    {
    case NULL_ARRAY:

        break;
    case VEC1_ARRAY:
        glUniform1uiv(id, count, va0);
        break;
    case VEC2_ARRAY:
        glUniform2uiv(id, count * 2, va0);
        break;
    case VEC3_ARRAY:
        glUniform3uiv(id, count * 3, va0);
        break;
    case VEC4_ARRAY:
        glUniform4uiv(id, count * 4, va0);
        break;
    case MAT4_ARRAY:
        glUniform4uiv(id, count * 4, va0);
        break;
    default:
        break;
    }
}

void Shaders::SetValue(const std::string& name, ArrayUni arr)
{
    SetValue(name, arr.size, arr.data, arr.type);
}

void Shaders::SetValue(const std::string& name, GLsizei count, const glm::mat4* va0)
{
    int id = getVarID(name.c_str());
    glUniformMatrix4fv(id, count, GL_FALSE, (GLfloat*)va0);
}