首页 > 代码库 > GLSL程序对象的C++封装

GLSL程序对象的C++封装

      在OpenGL的shader编程中,最常用的可能就是程序对象了,GLSL的程序对象的创建、加载shader等步骤都是固定的,如果每次都写同样的代码,觉得十分浪费时间,所以现在就将我在Shader学习过程中自己封装的GLSLProgram类奉献出来供大家参考:


头文件如下:

/*
 * GLSLProgram.h
 *
 *  Created
 *      Author: zhouxuguang
 */

#ifndef GLSLPROGRAM_H_
#define GLSLPROGRAM_H_

#include "GLPrecompile.h"

class GLSLProgram {
public:
    GLSLProgram();
    
	GLSLProgram(const char* pVertexSource, const char* pFragmentSource);
    
	~GLSLProgram();
    
    void InitWithShader(const char* pVertexSource, const char* pFragmentSource);
    
    //编译和连接程序
    void LinkProgram();

	//加载二进制shader程序
	void LoadProgramBinary( const char * fileName, GLenum format );

	//使用程序对象
	void Use();

	//使用固定管线
	void UseFixedFunction();

	//绑定属性变量
	void BindAttribLocation (unsigned int index, const char *name);
    
    void BindFragDataLocation(unsigned int index , const char *name);

	//获得属性变量
	GLint GetAttributeLocation(const char* attrName);

	//获得指定Uniform变量的位置
	GLint GetUniformLocation( const char* uniName);

	GLint GetUniformBlockIndex( const char* uniName);

	//设置属性变量的值
	//void	 SetAttributeVariable( char *, int );
	void SetAttributeVariable( const char *, float );
	void SetAttributeVariable( const char *, float, float, float );
	void SetAttributeVariable( const char *, float[3] );

	//设置uniform变量的值
	void SetUniformVariable( const char *, int );
	void SetUniformVariable( const char *, float );
	void SetUniformVariable( const char *, float, float, float );
	void SetUniformVariable( const char *, float[3] );

	void SetUniformMatrix2f(const char* name,int count, bool transpose, const float *value);
	void SetUniformMatrix3f(const char* name,int count, bool transpose, const float *value);
	void SetUniformMatrix4f(const char* name,int count, bool transpose, const float *value);

	void GetActiveUniformBlockiv(const char* uniName, GLenum pname, GLint *params);

	void GetUniformIndices ( GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);

	void GetActiveUniformsiv ( GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
    
    //加载shader
    static GLuint LoadShader(GLenum shaderType, const char* pSource);
    
    static bool LoadShaderFile(const char* pShaderFile,std::string &shaderString);

private:
	GLuint mProgram;		//程序对象
    GLuint mVertexShader;      //顶点shader
    GLuint mFragmentShader;     //片段shader

	std::map<const char *, int>	mAttributeLocs;	//attribute属性变量的map
	std::map<const char *, int> mUniformLocs;	//Uniform变量的map
};

#endif /* GLSLPROGRAM_H_ */


实现文件如下:

/*
 * GLSLProgram.cpp
 *
 *  Created on: 
 *      Author: zhouxuguang
 */

#include "GLSLProgram.h"

GLuint GLSLProgram::LoadShader(GLenum shaderType, const char* pSource) {
    GLuint shader = glCreateShader(shaderType);
    if (shader) {
        glShaderSource(shader, 1, &pSource, NULL);
        glCompileShader(shader);
        GLint compiled = 0;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
        if (!compiled) {
            GLint infoLen = 0;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen) {
                char* buf = (char*) malloc(infoLen);
                if (buf != NULL) {
                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
                    //LOGE("Could not compile shader %d:\n%s\n",shaderType, buf);
                    free(buf);
                }
                glDeleteShader(shader);
                shader = 0;
            }
        }
    }
    return shader;
}

bool GLSLProgram::LoadShaderFile(const char *pShaderFile,std::string &shaderString)
{
    FILE *fpin = fopen( pShaderFile, "rb" );
    if( fpin == NULL )
    {
        return false;
    }
    fseek( fpin, 0, SEEK_END );
    long length = (long)ftell( fpin );
    char *buffer = new char[ length ];
    rewind( fpin );
    fread( buffer, length, 1, fpin );
    fclose( fpin );
    
    shaderString = buffer;
    delete []buffer;
    return true;
}

GLSLProgram::GLSLProgram():mVertexShader(0),mFragmentShader(0),mProgram(0)
{
}

GLSLProgram::GLSLProgram(const char* pVertexSource, const char* pFragmentSource)
{
    InitWithShader(pVertexSource,pFragmentSource);
}

GLSLProgram::~GLSLProgram()
{
    if (mProgram)
    {
        glDetachShader(mProgram, mVertexShader);
        glDetachShader(mProgram, mFragmentShader);
        glDeleteShader(mVertexShader);
        mVertexShader = 0;
        glDeleteShader(mFragmentShader);
        mFragmentShader = 0;
        
        glDeleteProgram(mProgram);
        mProgram = 0;
    }
}

void GLSLProgram::InitWithShader(const char *pVertexSource, const char *pFragmentSource)
{
    mVertexShader = GLSLProgram::LoadShader(GL_VERTEX_SHADER, pVertexSource);
    if (!mVertexShader) {
        return;
    }
    
    mFragmentShader = GLSLProgram::LoadShader(GL_FRAGMENT_SHADER, pFragmentSource);
    if (!mFragmentShader) {
        return;
    }
    
    mProgram = glCreateProgram();
}

void GLSLProgram::LinkProgram()
{
    if (mProgram) {
        glAttachShader(mProgram, mVertexShader);
        glAttachShader(mProgram, mFragmentShader);
        glLinkProgram(mProgram);
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
        if (linkStatus != GL_TRUE) {
            GLint bufLength = 0;
            glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &bufLength);
            if (bufLength) {
                char* buf = (char*) malloc(bufLength);
                if (buf) {
                    glGetProgramInfoLog(mProgram, bufLength, NULL, buf);
                    free(buf);
                }
            }
            glDeleteProgram(mProgram);
            mProgram = 0;
        }
    }
}

void GLSLProgram::LoadProgramBinary(const char * fileName, GLenum format)
{
	FILE *fpin = fopen( fileName, "rb" );
	if( fpin == NULL )
	{
		fprintf( stderr, "Cannot open input GLSL binary file ‘%s‘\n", fileName );
		return;
	}
	fseek( fpin, 0, SEEK_END );
	GLint length = (GLint)ftell( fpin );
	GLubyte *buffer = new GLubyte[ length ];
	rewind( fpin );
	fread( buffer, length, 1, fpin );
	fclose( fpin );

	glProgramBinary( this->mProgram, format, buffer, length );
	delete [] buffer;

	GLint   success;
	glGetProgramiv( this->mProgram, GL_LINK_STATUS, &success );

	if( !success )
	{
		fprintf( stderr, "Did not successfully load the GLSL binary file ‘%s‘\n", fileName );
		return;
	}
}

void GLSLProgram::Use()
{
	glUseProgram(mProgram);
}

void GLSLProgram::UseFixedFunction()
{
	glUseProgram(0);
}

void GLSLProgram::BindAttribLocation (unsigned int index, const char *name)
{
	glBindAttribLocation(mProgram,(GLuint)index,(const GLchar*)name);
}

void GLSLProgram::BindFragDataLocation(unsigned int index, const char *name)
{
    //只有桌面版本支持
}

GLint GLSLProgram::GetAttributeLocation(const char* attrName)
{
	std::map<const char *, int>::iterator iter = mAttributeLocs.find(attrName);
	if(iter == mAttributeLocs.end())
	{
		mAttributeLocs[attrName] = glGetAttribLocation(mProgram, attrName);
	}
	return mAttributeLocs[attrName];
}

GLint GLSLProgram::GetUniformLocation(const char* uniName)
{
	std::map<const char*, int>::iterator iter = mUniformLocs.find(uniName);
	if(iter == mUniformLocs.end())
	{
		mUniformLocs[uniName] = glGetUniformLocation(mProgram, uniName);
	}
	return mUniformLocs[uniName];
}

GLint GLSLProgram::GetUniformBlockIndex(const char* uniName)
{
	return glGetUniformBlockIndex(mProgram, uniName);
}

//void GLSLProgram::SetAttributeVariable( char* name, int val )
//{
//	int loc;
//	if( ( loc = GetAttributeLocation( name ) )  >= 0 )
//	{
//		this->Use();
//		glVertexAttrib1i( loc, val );
//	}
//};

void GLSLProgram::SetAttributeVariable( const char* name, float val )
{
	int loc;
	if( ( loc = GetAttributeLocation( name ) )  >= 0 )
	{
		this->Use();
		glVertexAttrib1f( loc, val );
	}
};

void GLSLProgram::SetAttributeVariable( const char* name, float val0, float val1, float val2 )
{
	int loc;
	if( ( loc = GetAttributeLocation( name ) )  >= 0 )
	{
		this->Use();
		glVertexAttrib3f( loc, val0, val1, val2 );
	}
};

void GLSLProgram::SetAttributeVariable( const char* name, float vals[3] )
{
	int loc;
	if( ( loc = GetAttributeLocation( name ) )  >= 0 )
	{
		this->Use();
		glVertexAttrib3fv( loc, vals );
	}
};

void GLSLProgram::SetUniformVariable( const char* name, int val )
{
	int loc;
	if( ( loc = GetUniformLocation( name ) )  >= 0 )
	{
		this->Use();
		glUniform1i( loc, val );
	}
};


void GLSLProgram::SetUniformVariable( const char* name, float val )
{
	int loc;
	if( ( loc = GetUniformLocation( name ) )  >= 0 )
	{
		this->Use();
		glUniform1f( loc, val );
	}
};

void GLSLProgram::SetUniformVariable( const char* name, float val0, float val1, float val2 )
{
	int loc;
	if( ( loc = GetUniformLocation( name ) )  >= 0 )
	{
		this->Use();
		glUniform3f( loc, val0, val1, val2 );
	}
};

void GLSLProgram::SetUniformVariable( const char* name, float vals[3] )
{
	int loc;

	if( ( loc = GetUniformLocation( name ) )  >= 0 )
	{
		this->Use();
		glUniform3fv( loc, 3, vals );
	}
};

void GLSLProgram::SetUniformMatrix2f(const char* name ,int count, bool transpose, const float *value)
{
	int loc;

	if( ( loc = GetUniformLocation( name ) )  >= 0 )
	{
		this->Use();
		glUniformMatrix2fv( loc, count, transpose, value );
	}
}

void GLSLProgram::SetUniformMatrix3f(const char* name ,int count, bool transpose, const float *value)
{
	int loc;

	if( ( loc = GetUniformLocation( name ) )  >= 0 )
	{
		this->Use();
		glUniformMatrix3fv( loc, count, transpose, value );
	}
}

void GLSLProgram::SetUniformMatrix4f(const char* name ,int count, bool transpose, const float *value)
{
	int loc;

	if( ( loc = GetUniformLocation( name ) )  >= 0 )
	{
		this->Use();
		glUniformMatrix4fv( loc, count, transpose, value );
	}
}

void GLSLProgram::GetActiveUniformBlockiv(const char* uniName, GLenum pname, GLint *params)
{
	int loc;
	if ( (loc = GetUniformBlockIndex(uniName)) >= 0)
	{
		this->Use();
		glGetActiveUniformBlockiv(mProgram,loc,pname,params);
	}
}

void GLSLProgram::GetUniformIndices(GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices)
{
	glGetUniformIndices(mProgram,uniformCount,uniformNames,uniformIndices);
}

void GLSLProgram::GetActiveUniformsiv(GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params)
{
	glGetActiveUniformsiv(mProgram,uniformCount,uniformIndices,pname,params);
}

这里还引入了一个头文件,其实就是在不同平台上引入相应的头文件,头文件内容如下:

//
//  GLPrecompile.h
//  GLUtilBox
//
//  Created by zhouxuguang .
//  Copyright © 2016年 zhouxuguang. All rights reserved.
//

#ifndef GLPrecompile_hpp
#define GLPrecompile_hpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <string>
#include <vector>
#include <map>

#ifdef __ANDROID__

#include <GLES/gl.h>
#include <GLES2/gl2.h>
#include <GLES3/gl3.h>

#elif defined(__IOS__)

#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>

#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>

#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>

#endif

#endif /* GLPrecompile_hpp */

希望对大家有用 ,桌面版本的OpenGL头文件没有处理,大家有需要也可以根据自己需要改一下就OK

GLSL程序对象的C++封装