用模板化的替代品替换OpenGL glUniform函数

时间:2018-02-21 12:44:17

标签: c++ templates opengl

我正在关注一个OpenGL教程,在我现在的位置,它会教你编写一个Shader类。但是,有一些我不喜欢的东西,即允许你设置统一值的函数。本教程提供以下内容:

void Shader::setBool(const std::string &name, bool value) const
{         
    glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); 
}
void Shader::setInt(const std::string &name, int value) const
{ 
    glUniform1i(glGetUniformLocation(ID, name.c_str()), value); 
}
void Shader::setFloat(const std::string &name, float value) const
{ 
    glUniform1f(glGetUniformLocation(ID, name.c_str()), value); 
} 

当我看到这个时,我的第一次尝试是:“必须做得更好,我认为模板可以帮助我”。所以我开始研究它,直到我有以下Shader类:

class Shader
{
public:
    Shader();
    Shader(std::string const& vertex_path, std::string const& fragment_path);

    //Activates the shader
    void use();

    using size_type = unsigned int;

    //Uniform utility functions
    template<typename T>
    void setUniform(std::string const& name, T const& v0) const
    {
        using RemovedRefCV = std::remove_cv_t<std::remove_reference_t<T>>;
        if constexpr (Traits::IsValidType<RemovedRefCV> >())
        {
            auto location = glGetUniformLocation(name);

            if constexpr(std::is_same_v<RemovedRefCV, int>)
            {
                glUniform1i(location, v0);
            }
            else if constexpr (std::is_same_v<RemovedRefCV, unsigned int>)
            {
                glUniform1ui(location, v0);
            }
            else if constexpr (std::is_same_v<RemovedRefCV, float>)
            {
                glUniform1f(location, v0);
            }
        }
        else
        {
            static_assert(false, "Shader::set<std::string const& name, T v0>: Type T must be int, unsigned int or float");
        }
    }

    template<typename T>
    void setUniform(std::string const& name, T const& v0, T const& v1) const
    {
        using RemovedRefCV = std::remove_cv_t<std::remove_reference_t<T>>;
        if constexpr (Traits::IsValidType<RemovedRefCV> > ())
        {
            auto location = glGetUniformLocation(name);

            if constexpr(std::is_same_v<RemovedRefCV, int>)
            {
                glUniform2i(location, v0, v1);
            }
            else if constexpr (std::is_same_v<RemovedRefCV, unsigned int>)
            {
                glUniform2ui(location, v0, v1);
            }
            else if constexpr (std::is_same_v<RemovedRefCV, float>)
            {
                glUniform2f(location, v0, v1);
            }
        }
        else
        {
            static_assert(false, "Shader::set<std::string const& name, T v0, T v1>: Type T must be int, unsigned int or float");
        }
    }

    template<typename T>
    void setUniform(std::string const& name, T const& v0, T const& v1, T const& v2) const
    {
        using RemovedRefCV = std::remove_cv_t<std::remove_reference_t<T>>;
        if constexpr (Traits::IsValidType<RemovedRefCV> > ())
        {
            auto location = glGetUniformLocation(name);

            if constexpr(std::is_same_v<RemovedRefCV, int>)
            {
                glUniform3i(location, v0, v1, v2);
            }
            else if constexpr (std::is_same_v<RemovedRefCV, unsigned int>)
            {
                glUniform3ui(location, v0, v1, v2);
            }
            else if constexpr (std::is_same_v<RemovedRefCV, float>)
            {
                glUniform3f(location, v0, v1, v2);
            }
        }
        else
        {
            static_assert(false, "Shader::set<std::string const& name, T v0, T v1, T v2>: Type T must be int, unsigned int or float");
        }
    }

    template<typename T>
    void setUniform(std::string const& name, T const& v0, T const& v1, T const& v2, T const& v3) const
    {
        using RemovedRefCV = std::remove_cv_t<std::remove_reference_t<T>>;
        if constexpr (Traits::IsValidType<RemovedRefCV> > ())
        {
            auto location = glGetUniformLocation(name);

            if constexpr(std::is_same_v<RemovedRefCV, int>)
            {
                glUniform4i(location, v0, v1, v2, v3);
            }
            else if constexpr (std::is_same_v<RemovedRefCV, unsigned int>)
            {
                glUniform4ui(location, v0, v1, v2, v3);
            }
            else if constexpr (std::is_same_v<RemovedRefCV, float>)
            {
                glUniform4f(location, v0, v1, v2, v3);
            }
        }
        else
        {
            static_assert(false, "Shader::set<std::string const& name, T v0, T v1, T v2, T v3>: Type T must be int, unsigned int or float");
        }
    }

    template<typename T>
    void setUniform(std::string const& name, size_type count, const T* v) const
    {

    }

private:
    GLuint ID;
    bool loaded;

    class Traits
    {
    private:
        template<typename T, typename = std::void_t<>>
        struct IsValidTypeHelper : std::false_type
        {

        };

        template<typename T>
        struct IsValidTypeHelper<T, std::enable_if_t<std::is_same_v<decltype(T), float> ||
            std::is_same_v<decltype(T), int> ||
            std::is_same_v<decltype(T), unsigned int>
        >
        >
            : std::true_type {};

        template<typename T>
        struct IsValidTypeT : IsValidTypeHelper<T>::type {};

    public:
        template<typename T> using IsValidType = typename IsValidTypeT<T>::type;
    };
};

正如您所看到的,我已经为向量创建了一个重载,但我不确定如何实现它,因为我想尝试使用我的Shader :: setUniform()替换尽可能多的glUniform***()调用功能尽可能。我查看过this个问题,但它没有完全解决我正在寻找的问题。

0 个答案:

没有答案