GLSL程序对象的C++封装

Posted 周旭光

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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++封装的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中为 GLSL 片段着色器实现 iGlobalTime?

OpenGL GLSL 统一缓冲区对象

我的OpenGL学习进阶之旅如何抽取着色器代码到assets目录下的GLSL文件,以及如何通过Java或者C++代码来加载着GLSL文件?

从 GLSL 着色器中获取常量

从 C++ 运行 GLSL 着色器(尚未编译)的最快捷方式是啥?

C++封装向量-线性表