2
\$\begingroup\$

I've tried to create a small OpenGL abstraction layer.

I've tried to favor composition over inheritance but somehow it added extra complexity to my code. I probably overused it.

shader.h

#ifndef SHADER_H
#define SHADER_H
#include "filereader.h"
#include <string>
#include <iostream>
#include <GL/glew.h>
#include <memory>

class HandleInterface {
    protected:
        GLuint handle_;
    public:
        virtual void SetHandle( GLuint )=0;
        virtual ~HandleInterface() {}
        virtual GLuint GetHandle() const=0;
};

class BaseHandle : public HandleInterface {

    public:
        virtual void SetHandle( GLuint i ) {
            handle_ = i;
        }
        virtual GLuint GetHandle() const {
            return handle_;
        }
};

class Handle {
        std::unique_ptr<HandleInterface> handle_;
    protected:
        virtual void SetHandle( GLuint i );
    public:
        Handle();
        Handle( std::unique_ptr<HandleInterface> handle_ptr );
        virtual void SetHandleInterface( std::unique_ptr<HandleInterface> handle_ptr );
        virtual GLuint GetHandle() const;
};

class ShaderInterface  {
    public:
        virtual ~ShaderInterface() {}
        virtual void SetShaderSourceFromFile( std::string path ) = 0;
        virtual void SetShaderSourceFromString( std::string source ) = 0;
        virtual void CreateShader() = 0;
        virtual GLenum GetShadertype() = 0;
};

class BaseShader : public Handle ,public ShaderInterface {
        std::string shader_source_;
    public:
        ~BaseShader() {
            glDeleteShader( GetHandle() );
        }
        virtual void SetShaderSourceFromFile( std::string path );
        virtual void SetShaderSourceFromString( std::string source );
        virtual void CreateShader();

};
class VertexShader : public BaseShader {
    public:
        GLenum GetShadertype() {
            return GL_VERTEX_SHADER;
        }
};
class FragmentShader : public BaseShader {
    public:
        GLenum GetShadertype() {
            return GL_FRAGMENT_SHADER;
        }
};
class ComputeShader : public BaseShader {
    public:
        GLenum GetShadertype() {
            return GL_COMPUTE_SHADER;
        }
};
class TesselationControlShader : public BaseShader {
    public:
        GLenum GetShadertype() {
            return GL_TESS_CONTROL_SHADER;
        }
};

class TesselationEvaluationShader : public BaseShader {
    public:
        GLenum GetShadertype() {
            return GL_TESS_EVALUATION_SHADER;
        }
};

class ShaderProgramInterface {
    public:
        virtual void AttachShader( const BaseShader &s ) = 0;
        virtual void Link() = 0;
        virtual void Use() = 0;
};

class ShaderProgram : public Handle , public ShaderProgramInterface {
    public:
        ShaderProgram();
        void AttachShader( const BaseShader &s );
        void Link();
        void Use();
};

class VertexBufferInterface {
    public:
        virtual ~VertexBufferInterface() {}
        virtual void bind( GLenum ) = 0;
        virtual void setBufferData( GLenum,GLsizeiptr,const GLvoid*,GLenum )= 0;
};
class VertexBuffer : public Handle, public VertexBufferInterface {
    public:

        VertexBuffer();
        ~VertexBuffer() {}
        void bind( GLenum );
        void setBufferType( GLenum );
        void setBufferData(GLenum target, GLsizeiptr size, const GLvoid*data, GLenum usage );

};

#endif // SHADER_H

shader.cpp

#include "shader.h"
/*#############################
  Base
##############################*/
GLuint Handle::GetHandle() const {
    return handle_->GetHandle();
}
void Handle::SetHandle( GLuint i ) {
    handle_->SetHandle( i );
}
void Handle::SetHandleInterface( std::unique_ptr<HandleInterface> handle_ptr ) {
    handle_ = std::move( handle_ptr );
}

Handle::Handle( std::unique_ptr<HandleInterface> handle_ptr ) {
    SetHandleInterface( std::move( handle_ptr ) );
}
Handle::Handle()
    : Handle( std::unique_ptr<HandleInterface>( new BaseHandle() ) ) {
}
/*#############################
  BaseShader
##############################*/
void BaseShader::CreateShader() {
    SetHandle( glCreateShader( GetShadertype() ) );

    GLint length[1];
    length[0] = BaseShader::shader_source_.size();
    const GLchar* p[1];
    p[0] = BaseShader::shader_source_.c_str();
    glShaderSource( BaseShader::GetHandle(),1,p,length );
    glCompileShader( GetHandle() );
    GLint success;
    glGetShaderiv( GetHandle(), GL_COMPILE_STATUS, &success );
    if ( !success ) {
        // todo throw something?
    }

}
void BaseShader::SetShaderSourceFromFile( std::string path ) {
    FileReader fileReader( path );
    BaseShader::shader_source_ = fileReader.get();
}

void BaseShader::SetShaderSourceFromString( std::string source ) {
    BaseShader::shader_source_ = source;
}


/*#############################
  ShaderProgram
##############################*/

void ShaderProgram::AttachShader( const BaseShader &s ) {
    glAttachShader( ShaderProgram::GetHandle(), s.GetHandle() );
}
void ShaderProgram::Use() {
    glUseProgram( GetHandle() );
}
void ShaderProgram::Link() {
    glLinkProgram( GetHandle() );
}
ShaderProgram::ShaderProgram() {
    Handle();
    SetHandle( glCreateProgram() );
}

/*#############################
  VertexBuffer
##############################*/
void VertexBuffer::bind( GLenum buffertype ) {
    glBindBuffer( buffertype, GetHandle() );
}
VertexBuffer::VertexBuffer() {
    GLuint handle;
    glGenBuffers( 1,&handle );
    SetHandle( handle );
}
void VertexBuffer::setBufferData(GLenum target, GLsizeiptr s,const GLvoid * data, GLenum usage ) {
    glBufferData( target, s, data, usage );
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Drop all the interface classes. It really only makes sense to have them if you are going to implement them multiple times. But you don't. It just increases the complexity of your code for no gain.

BaseHandler does nothing more than hold a GLuint. So its a useless class. It doesn't add anything. Just have Handle hold the GLuint.

        virtual void SetShaderSourceFromFile( std::string path );
        virtual void SetShaderSourceFromString( std::string source );

Don't set static parameters, that's just asking for trouble. Pass any needed parameter to the correct method.

        virtual void CreateShader();

Use a constructor, its for creating objects.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.