GL01-11: OpenGL总结性封装

本文是总结性C++面向对象封装,文件动态加载,数据动态添加,颜色动态添加,纹理动态添加。主要封装3大块:
  1. 上下文环境封装()
  2. 数据(顶点、颜色与纹理)加载封装;
  3. 着色器的编译与连接封装
  4. 测试文件


  • 文件清单
文件名 说名
gl_env.h 环境头文件
gl_env.cpp 环境实现文件
gl_data.h 数据头文件
gl_data.cpp 数据实现文件
gl_shader.h 着色器头文件
gl_shader.cpp 着色器实现文件
gl05_multi_texture.cpp 调用测试文件

  • 编译命令行
    g++ -omain gl05_multi_texture.cpp gl_env.cpp gl_data.cpp gl_shader.cpp -lglfw -lglew -framework opengl

一、准备

1. 图片

  • bird.png图片
  • texture.png图片

2. 图像加载库

  • stb_image.h,可以网络搜索下载

3. GLSL脚本

  脚本放在目录glsl_script下。

  • 顶点着色器脚本glsl05_v_multi_texture.glsl
#version 410 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec4 aColor;
layout (location = 2) in vec2 aCoord;

out vec4 vColor;
out vec2 vCoord;
void main(){
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
    vColor = aColor;
    vCoord = aCoord;
}
  • 片着色器脚本glsl05_f_multi_texture.glsl
#version 410 core
in vec4 vColor;
in vec2 vCoord;
uniform sampler2D sTexture_bird;
uniform sampler2D sTexture_texture;
out vec4 FragColor;
void main(){
    FragColor = mix(texture(sTexture_bird, vCoord), texture(sTexture_texture, vCoord), 0.5) * vColor;
}

环境封装

头文件gl_env.h

#ifndef GL_ENV_H
#define GL_ENV_H
#include 
#include                          // 该include之前必须先 #include 

typedef void (*render_callback)();              // 回调绘制函数

struct GL_Env {
    ///////////////////////////////////////////////////
    GLFWwindow* win;
    ///////////////////////////////////////////////////
    void context(const char* title);            // 初始化OpenGL上下文,使用GLFW框架
    void opengl();                              // 加载OpenGL
    void destroy();                             // 释放环境
    void run(render_callback render_cb);        // 开始绘制
};
#endif

实现文件gl_env.cpp

#include "gl_env.h"


void GL_Env::context(const char* title){
   if(!glfwInit()){
        return;                             // 给异常转移处理,这里暂时不处理
    }
    // 设置提示
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    win = glfwCreateWindow(600,400, title, NULL, NULL);
    if(!win){
        return;                             // 给异常转移处理,这里暂时不处理
    }
    glfwMakeContextCurrent(win);
}          
void GL_Env::opengl(){
    if(glewInit() != GLEW_OK){   
        return;                             // 留给异常转移处理,这里暂时不处理
    }
}
void GL_Env::destroy(){
    glfwTerminate();
}
void GL_Env::run(render_callback render_cb){
    GLdouble oldTime = glfwGetTime();
    while(!glfwWindowShouldClose(win)){
        if(glfwGetTime() - oldTime > 0.1){
            render_cb();                    // 绘制函数回调
            glfwSwapBuffers(win);
            oldTime = glfwGetTime();
        }
        glfwPollEvents();                   // 无阻塞消息处理
    }
}

数据封装

头文件gl_data.h

#ifndef GL_DATA_H
#define GL_DATA_H

#include 

struct GL_Data{
    ///////////////////////////////////////////////////
    GLuint vertexArrayID;                // 数据缓冲
    GLushort texture_channel[8];
    int id;
    /**
     * 实际定点数组可以多个,然后实现切换,这里只创建一个
     */
    GL_Data();
    ///////////////////////////////////////////////////
    void initVertextArrays();       // 初始化定点数组
    void addData(                   // 传送数据到shader
        const GLfloat *data,        // 数据
        GLsizeiptr size,            // 数据缓冲长度
        GLuint index,               // shader中参数位置
        GLint num);                 // 单位数据个数
    void updateIndex(               // 对定点数据进行索引
        const GLuint *data,         // 定点数组
        GLsizeiptr size);           // 数组大小
    ///////////////////////////////////////////////////
    void addTexture(const char *fileName,int *width, int *height, int *depth);
    ///////////////////////////////////////////////////
    void open();
    void close();
};
#endif

实现文件gl_data.cpp

#include "gl_data.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

GL_Data::GL_Data(){
    id = 0;
    texture_channel[0] = GL_TEXTURE0;
    texture_channel[1] = GL_TEXTURE1;
    texture_channel[2] = GL_TEXTURE2;
    texture_channel[3] = GL_TEXTURE3;
    texture_channel[4] = GL_TEXTURE4;
    texture_channel[5] = GL_TEXTURE5;
    texture_channel[6] = GL_TEXTURE6;
    texture_channel[7] = GL_TEXTURE7;
}

void GL_Data::initVertextArrays(){
    glGenVertexArrays(1, &vertexArrayID); 
}
void GL_Data::open(){
    glBindVertexArray(vertexArrayID);
}
void GL_Data::close(){
    glBindVertexArray(0);
}
void GL_Data::addData(const GLfloat *data, GLsizeiptr size, GLuint index, GLint num){
    // 先激活vertexArrayID
    GL_Data::open(); 
    // 对数据进行缓冲
    GLuint bufferID;
    glGenBuffers(1, &bufferID);
    glBindBuffer(GL_ARRAY_BUFFER, bufferID);
    glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
    // 完成拷贝后,释放缓冲
    // glDeleteBuffers(1, &bufferID);    // 不能删除,数据还需要使用
    // 顶点属性
    glVertexAttribPointer(index, num, GL_FLOAT, GL_FALSE, 0, NULL);  
    glEnableVertexAttribArray(index); 
    GL_Data::close();   // 停止vertexArrayID的激活  
}

void GL_Data::updateIndex(const GLuint *data, GLsizeiptr size){
    GLuint indexID;
    glGenBuffers(1, &indexID);
    GL_Data::open();                                        // 注意开始定点数组
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); 
    GL_Data::close(); 
}

void GL_Data::addTexture(const char *fileName, int *width, int *height, int *depth){
    GLuint textureID;
    glGenTextures(1, &textureID);
    glActiveTexture(texture_channel[id]);
    glBindTexture(GL_TEXTURE_2D, textureID); 
    // 加载图像
    unsigned char *data = stbi_load(fileName, width, height, depth, 0);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, *width, *height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);  // 生成类型为2D的纹理映射
    // 释放图像
    stbi_image_free(data);
    id ++;
}

着色器封装

头文件gl_shader.h

#ifndef GL_SHADER_H
#define GL_SHADER_H

#include 

struct GL_Shader{
    ///////////////////////////////////////////////////
    GLuint programID;
    ///////////////////////////////////////////////////
    void initProgram();
    void compileShaderFromFile(const char* fileName, GLenum shaderType);            // 加载编译脚本
    void compileShaderFromString(const char* scriptString, GLenum shaderType);      // 加载编译脚本
    void link();                                                                    // 连接脚本为Shader程序

    void setUniform_1i(const char *name, GLint index);
    ///////////////////////////////////////////////////
    void open();
    void close();
};
#endif 

实现文件gl_shader.cpp

#include "gl_shader.h"
#include       // 文件流
#include       // 字符串缓冲流

void GL_Shader::initProgram(){
    programID = glCreateProgram();
}
void GL_Shader::open(){
    glUseProgram(programID);
}
void GL_Shader::close(){
    glUseProgram(0);
}
void GL_Shader::compileShaderFromFile(const char* fileName, GLenum shaderType){
    // 打开文件
    std::ifstream  fShader(fileName);
    // 读取数据到缓冲
    std::stringstream bufferScript;
    bufferScript << fShader.rdbuf();
    // 从缓冲转为字符串对象
    std::string strScript = bufferScript.str();
    // 把字符串对象转为C字符数组
    const char *scriptCode = strScript.c_str();
    // 编译
    GL_Shader::compileShaderFromString(scriptCode, shaderType);

}
void GL_Shader::compileShaderFromString(const char* scriptString, GLenum shaderType){
    GLuint shader;
    shader = glCreateShader(shaderType);
    glShaderSource(shader, 1, &scriptString, NULL);
    glCompileShader(shader);
    glAttachShader(programID, shader);
    glDeleteShader(shader);
}
void GL_Shader::link(){
    GL_Shader::open();
    glLinkProgram(programID);
    GL_Shader::close();
}
void GL_Shader::setUniform_1i(const char *name, GLint index){
    GL_Shader::open();
    GLint location = glGetUniformLocation(programID, name);
    glUniform1i(location, index);  // 设置纹理对象为索引为0,
    GL_Shader::close();
}

测试代码gl05_multi_texture.cpp

#include "gl_env.h"
#include "gl_data.h"
#include "gl_shader.h"
#include 

// 环境
GL_Env env;
// 定点数组
GL_Data data;
// 着色器
GL_Shader shader;

void render();

int main(int argc, const char** argv) {

    env.context("Shader框架总结");
    env.opengl();
    ///////////////////////////////////////////////////

    data.initVertextArrays();
    GLfloat vertices[] = {  // 平面三角形
        -0.5f, -0.5f, 0.0f, 
         0.5f, -0.5f, 0.0f, 
         0.0f,  0.5f, 0.0f  
    }; 
    data.addData(vertices, sizeof(vertices), 0, 3);     // 开启Shader第一个参数位置,顶点3个一组。
    GLuint indices[] = {0, 1, 2};
    data.updateIndex(indices,sizeof(indices));
    GLfloat colors[] ={   // 三角形三个定点对应的颜色
        1.0f, 0.0f, 0.0f, 1.0f,
        0.0f, 1.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f, 1.0f
    };
    data.addData(colors, sizeof(colors), 1, 4); 
    GLfloat coords[] ={   // 三角形三个定点对应的纹理
        1.0f, 0.0f,
        0.0f, 1.0f,
        0.0f, 0.0f
    };
    data.addData(coords, sizeof(coords), 2, 2); 
    int w, h, d;
    data.addTexture("bird.png", &w, &h, &d);
    std::cout << w << "," << h << "," << d << std::endl;
    data.addTexture("texture.png", &w, &h, &d);
    std::cout << w << "," << h << "," << d << std::endl;
    ///////////////////////////////////////////////////
    shader.initProgram();
    shader.compileShaderFromFile("./glsl_script/glsl05_v_multi_texture.glsl", GL_VERTEX_SHADER);
    shader.compileShaderFromFile("./glsl_script/glsl05_f_multi_texture.glsl", GL_FRAGMENT_SHADER);
    shader.link();
    shader.setUniform_1i("sTexture_bird", 0);
    shader.setUniform_1i("sTexture_texture", 1);
    // 加载纹理
    ///////////////////////////////////////////////////
    env.run(render);
    env.destroy();
    return 0;
}
void render(){
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    data.open();        // 开启顶点
    shader.open();
    // glDrawArrays(GL_TRIANGLES, 0, 3);  // 绘制三角形 
    glDrawElements(GL_TRIANGLES,3, GL_UNSIGNED_INT, 0);

    shader.close();
    data.close();       // 关闭顶点
}
// g++ -omain  gl05_multi_texture.cpp gl_env.cpp gl_data.cpp gl_shader.cpp  -lglfw  -lglew  -framework opengl

  • 测试运行效果


    运行效果

你可能感兴趣的:(GL01-11: OpenGL总结性封装)