您当前的位置: 首页 >  ar

Jave.Lin

暂无认证

  • 2浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

LearnGL - 04 - VAO 探究

Jave.Lin 发布时间:2020-06-11 00:21:40 ,浏览量:2

文章目录
  • VAO 结构
  • GL LIKE 测试项目
    • gl_like.h
    • gl_like_gv.h
    • gl_like.cpp
    • Main.cpp
    • 运行效果
LearnGL - 学习笔记目录

本人才疏学浅,如有什么错误,望不吝指出。

上一篇:LearnGL - 03 - DrawQuad - VBO/EBO,学会了如何使用 EBO/IBO 画一个四边形。

这一篇:我将使用C++写个类似 OpenGL 在使用 VAO 期间的功能:

VAO 结构

VAO的结果差不多就如下图: 在这里插入图片描述

GL LIKE 测试项目

我模仿 OpenGL 一部分的 API 编写了测试项目:

gl_like.h
// gl_like.h
// jave.lin - 测试模仿 opengl 的规范,没有参考 opengl specification 规范,只是自己的理解
// 不做过多的封装,只为简单的理解结束结构,大致的功能
//(什么 private fields, public getter/setter都不封装),实际项目时是不能这么封装的
#ifndef _GL_LIKE__H_
#define _GL_LIKE__H_
#include
#include
#include

// 获取地址类型对象指针
#define GET_POINSTER_BY_VALUE(type, addressValue) ((type)((void*)addressValue))
// 获取指针对象地址值
#define GET_ADDRESS_VALUE(address) ((uint)address);

//
// symbol constants - 符号常量,参考 glad 的定义
//
#define GL_ARRAY_BUFFER                         0x8892
#define GL_ELEMENT_ARRAY_BUFFER                 0x8893
#define GL_STATIC_DRAW                          0x88E4

#define GL_BYTE                                 0x1400
#define GL_UNSIGNED_BYTE                        0x1401
#define GL_SHORT                                0x1402
#define GL_UNSIGNED_SHORT                       0x1403
#define GL_INT                                  0x1404
#define GL_UNSIGNED_INT                         0x1405
#define GL_FLOAT                                0x1406

#define GL_POINTS                               0x0000
#define GL_LINES                                0x0001
#define GL_LINE_LOOP                            0x0002
#define GL_LINE_STRIP                           0x0003
#define GL_TRIANGLES                            0x0004
#define GL_TRIANGLE_STRIP                       0x0005
#define GL_TRIANGLE_FAN                         0x0006
//
// custom symbol constants - 符号常量,自定义的,暂时还没有看到的参考资料
//
#define GL_MAX_NUM_OF_VAO                       4096
#define GL_MAX_NUM_OF_VBO                       4096

#define GL_TRUE                                 1
#define GL_FALSE                                0

#define GL_INVALIDATED_CONTEXT                  1
#define GL_OUT_BO_MAX_COUNT                     2
#define GL_CREATE_FAILURE                       3
#define GL_CONTEXT_NOT_NULL                     4
#define GL_BINDING_UN_HANDLE_BUFF_TYPE          5
#define GL_SET_BUFF_VALUES_BUFF_NULL            6

    //
    // declaretion - empty - 空定义
    //

    //
    // typdef - 参考 glad 的 typedef 别名(C++中的话,使用using会更好,因为支持template,但typedef一直到c会更好)
    //
    typedef unsigned int GLenum;
    typedef unsigned char GLboolean;
    typedef unsigned int GLbitfield;
    typedef void GLvoid;
    typedef signed char GLbyte;
    typedef unsigned char GLubyte;
    typedef signed short GLshort;
    typedef unsigned short GLushort;
    typedef int GLint;
    typedef unsigned int GLuint;
    typedef int GLclampx;
    typedef int GLsizei;
    typedef float GLfloat;
    typedef float GLclampf;
    typedef double GLdouble;
    typedef double GLclampd;
    typedef void* GLeglClientBufferEXT;
    typedef void* GLeglImageOES;
    typedef char GLchar;
    typedef char GLcharARB;
    typedef signed   long  int GLsizeiptr;

    typedef GLbyte* _buffer_t;
    typedef GLubyte* _ubuffer_T;


    //
    // declaretion - sold
    //

    class _BuffObject {
    public:
        _ubuffer_T data = NULL;
        GLsizei size = 0;
        GLsizei capacity = 0;
        ~_BuffObject();
    };
    class BufferObject {                            // 缓存对象
    public:
        _BuffObject* buf = NULL;
        ~BufferObject();
    };
    
    class VertexAttributeFormat {
    public:
        GLuint index = -1;                          // location 索引
        GLint numOfComponent = 0;                   // 分量的数量
        GLenum typeOfComponent = 0;                 // 分量的类型
        GLboolean normalized = 0;                   // 分量值是否归一化
        GLsizei stride = 0;                         // 顶点属性所在数据数组的每个分段大小
        void* pointer = 0;                          // 在对应分段的字节偏移
        GLuint setupToVBO = 0;                      // 安装到vbo
        ~VertexAttributeFormat();
    }; 
    class VertexArrayObject {                       // VAO
    public:
        BufferObject* vbo = NULL;                   // VBO 指针
        BufferObject* ebo = NULL;                   // EBO 指针
        std::vector* vafs = NULL; // VBO 格式(规范)
        std::vector* vafs_enabled = NULL;   // 启用的 VBO 格式
        VertexArrayObject();
        ~VertexArrayObject();
    };
    class Context {
    public:
        GLuint major = 0;
        GLuint minor = 0;

        VertexArrayObject* bindingVAO = NULL;           // 绑定之后的VAO
        VertexArrayObject* defalultVAO = NULL;          // 未绑定的VAO

        std::vector* VAOs = NULL;   // 已申请的所有 VAO 对象
        std::vector* BOs = NULL;         // 已申请的所有 BO 对象
        Context();
        ~Context();
        inline VertexArrayObject* GetUsingVAO() const;  // 获取当前用的VAO
    };

    //
    // function - others
    //
    void Terminate();
    void MakeCurrentContext(GLuint context);
    void CheckBuffType(GLenum buffType);
    void Error(const GLuint ec, const GLchar* msg);
    GLboolean CreateContext(GLuint major, GLuint minor, GLuint* context);

    void glGenVertexArrays(GLsizei n, GLuint* arrays);
    void glDeleteVertexArrays(GLsizei n, GLuint* arrays);
    void glBindVertexArray(GLuint array);

    void glGenBuffers(GLsizei n, GLuint* buffers);
    void glDeleteBuffers(GLsizei n, GLuint* buffers);
    void glBindBuffer(GLenum target, GLuint buffer);
    void glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage);

    void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
    void glEnableVertexAttribArray(GLuint index);
    void glDisableVertexAttribArray(GLuint index);

    void glDrawArrays(GLenum mode, GLint first, GLsizei count);
    void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);

#endif // #ifndef _GL_LIKE__H_
gl_like_gv.h
// gl_like_gv.h
// jave.lin - global variables
#include"gl_like.h"

#ifndef _GL_LIKE_GV__H_
#define _GL_LIKE_GV__H_

Context* currentContext = NULL;
GLint errorCode = 0;
GLchar* errorMsg = NULL;

#endif
gl_like.cpp
// gl_like.cpp
// jave.lin - 定义以及实现
// 实现不一定是按 OpenGL 来的,都只是自己看了一些官方文档了解功能后,而编写的功能
// 所以会出现,只实现了部分的功能,会之不对的功能
#include
#include
#include
#include"gl_like_gv.h"
#include"gl_like.h"

extern Context* currentContext;
extern GLint errorCode;
extern GLchar* errorMsg;

//
// function - definition
//

/* 	暂时没用上,这时对 glVertexAttribPointer 是的 normalized 来确定要不要归一化数据额类型的,
	需要再传入(复制)到 GPU 前就得处理的归一化
// jave.lin : 这是处理数据类型归一化到单精度的过程
// 有符号数据类型归一化处理
template
inline GLfloat Normalized_signed(DataType value) {
    // jave.lin : 对应 Katex 是: f = \frac{c}{2^b-1}
    return (GLfloat)((value) / (std::pow(2, sizeof(DataType) * 8 - 1)));
}
// 无符号数据类型归一化处理
template
inline GLfloat Normalized_unsigned(DataType value) {
    // jave.lin : 对应 Katex 是: f = \frac{2c + 1}{2^b-1}
    return (GLfloat)((value * 2 + 1) / (std::pow(2, sizeof(DataType) * 8 - 1)));
}
*/

void PrintVertex(GLuint vertexID, VertexAttributeFormat* format, _ubuffer_T buffer) {
    std::cout
        begin();
        std::vector::iterator end_va0 = this->VAOs->end();
        for (; begin_vao != end_va0; begin_vao++) {
            delete* begin_vao;
        }
        this->VAOs->clear();
        this->VAOs = NULL;
    }

    if (this->BOs != NULL) {
        std::vector::iterator begin_vbo = this->BOs->begin();
        std::vector::iterator end_vb0 = this->BOs->end();
        for (; begin_vbo != end_vb0; begin_vbo++) {
            delete* begin_vbo;
        }
        this->BOs->clear();
        this->BOs = NULL;
    }

    if (this->defalultVAO != NULL) {
        delete this->defalultVAO;
        this->defalultVAO = NULL;
    }
    this->bindingVAO = NULL;
} // ~Context
void Terminate() {
    if (currentContext != NULL) {
        delete currentContext;
        currentContext = NULL;
    }
} // Terminater
void MakeCurrentContext(GLuint context) {
    currentContext = (Context*)((void*)context);
} // MakeCurrentContext
void CheckBuffType(GLenum buffType) {
    switch (buffType)
    {
    case GL_ARRAY_BUFFER:           // VBO
        break;
    case GL_ELEMENT_ARRAY_BUFFER:   // EBO
        break;
    default:
        GLchar str[512];
        sprintf_s(str, "binding unhandle buffer type : %d", buffType);
        Error(GL_BINDING_UN_HANDLE_BUFF_TYPE, (const GLchar*)str);
        break;
    } // end switch
} // end CheckBuffType
void Error(const GLuint ec, const GLchar* msg) {
    errorCode = ec;
    if (errorMsg == NULL) {
        errorMsg = (GLchar*)malloc(512);
    }
    strcpy_s(errorMsg, 512, msg);
    throw msg;
} // end Error
GLboolean CreateContext(GLuint major, GLuint minor, GLuint* context) {
    if (currentContext != NULL) {
        Error(GL_CONTEXT_NOT_NULL, (const GLchar*)"context not null");
        return GL_FALSE;
    }

    Context* p = new Context();

    *context = (GLuint) (p);
    if (p == NULL) {
        Error(GL_CREATE_FAILURE, (const GLchar*)"create context failure");
        return GL_FALSE;
    }

    p->major = major;
    p->minor = minor;
    return GL_TRUE;
} // end CreateContext

//
// gllike api
//

void glGenVertexArrays(GLsizei n, GLuint* arrays) {
    *arrays = 0;
    if (currentContext == NULL) {
        Error(GL_INVALIDATED_CONTEXT, (const GLchar*)"context == null");
        return;
    }
    if ((currentContext->VAOs->size() + n) >= GL_MAX_NUM_OF_VAO) {
        Error(GL_OUT_BO_MAX_COUNT, (const GLchar*)"out of vao buffer object max count");
        return;
    }
    for (size_t i = 0; i VAOs->push_back(vao);
        }
    }
} // end glGenVertexArrays
void glDeleteVertexArrays(GLsizei n, GLuint* arrays) {
    for (size_t i = 0; i VAOs->begin();
        std::vector::const_iterator end = currentContext->VAOs->end();
        for (; begin != end; begin++) {
            if (*begin == p) {
                currentContext->VAOs->erase(begin);
                break;
            }
        }
        delete p;
        *(arrays + i) = 0;
    }
} // end glDeleteVertexArrays
void glBindVertexArray(GLuint array) {
    currentContext->bindingVAO = (VertexArrayObject*)array;
    currentContext->defalultVAO->vbo = NULL;
    currentContext->defalultVAO->ebo = NULL;
    if (currentContext->defalultVAO->vafs != NULL) {
        std::vector::const_iterator begin_vaf, end_vaf;
        begin_vaf = currentContext->defalultVAO->vafs->begin();
        end_vaf = currentContext->defalultVAO->vafs->end();
        for (; begin_vaf != end_vaf; begin_vaf++) {
            delete *begin_vaf;
        }
        currentContext->defalultVAO->vafs->clear();
    }
    if (currentContext->defalultVAO->vafs_enabled != NULL) {
        currentContext->defalultVAO->vafs_enabled->clear();
    }
} // end glBindVertexArray

void glGenBuffers(GLsizei n, GLuint* buffers) {
    *buffers = 0;
    if (currentContext == NULL) {
        Error(GL_INVALIDATED_CONTEXT, (const GLchar*)"context == null");
        return;
    }
    if ((currentContext->BOs->size() + n) >= GL_MAX_NUM_OF_VBO) {
        Error(GL_OUT_BO_MAX_COUNT, (const GLchar*)"out of bo buffer object max count");
        return;
    }
    for (size_t i = 0; i BOs->push_back(vbo);
        }
    }
} // glGenBuffers
void glDeleteBuffers(GLsizei n, GLuint* buffers) {
    for (size_t i = 0; i BOs->begin();
        std::vector::const_iterator end = currentContext->BOs->end();
        for (; begin != end; begin++) {
            if (*begin == p) {
                currentContext->BOs->erase(begin);
                break;
            }
        }
        delete p;
        *(buffers + i) = 0;
    }
} // glDeleteBuffers
void glBindBuffer(GLenum target, GLuint buffer) {
    CheckBuffType(target);
    switch (target)
    {
    case GL_ARRAY_BUFFER:           // VBO
        currentContext->GetUsingVAO()->vbo = (BufferObject*)(buffer);
        break;
    case GL_ELEMENT_ARRAY_BUFFER:   // EBO
        currentContext->GetUsingVAO()->ebo = (BufferObject*)(buffer);
        break;
    default:
        throw "un handle glBindBuffer target type";
        break;
    }
} // glBindBuffer
void glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
    CheckBuffType(target);

    // usage 参数不使用,因为这个与硬件加速相关
    GLboolean validated = true;
    _BuffObject** buffObj = NULL;

    // 目前只对两种缓存类型做处理
    switch (target)
    {
    case GL_ARRAY_BUFFER:           // VBO
        buffObj = &(currentContext->GetUsingVAO()->vbo->buf);
        break;
    case GL_ELEMENT_ARRAY_BUFFER:   // EBO
        buffObj = &(currentContext->GetUsingVAO()->ebo->buf);
        break;
    default:
        validated = false;
        GLchar str[512];
        sprintf_s(str, "binding unhandle buffer type : %d", target);
        Error(GL_BINDING_UN_HANDLE_BUFF_TYPE, (const GLchar*)str);
        break;
    } // end switch
    if (validated) {
        if (*buffObj == NULL) {
            *buffObj = new _BuffObject();
        }
        if ((*buffObj)->size data == NULL) {
                (*buffObj)->data = (_ubuffer_T)malloc(size);
            }
            else {
                (*buffObj)->data = (_ubuffer_T)realloc((void*)((*buffObj)->data), size);
            }
            (*buffObj)->capacity = size;
        }
        (*buffObj)->size = size;
        memcpy((*buffObj)->data, data, size);
    }
} // end glBufferData
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) {
    std::vector* pVec = currentContext->GetUsingVAO()->vafs;
    std::vector::const_iterator begin = pVec->begin();
    std::vector::const_iterator end = pVec->end();
    bool found = false;
    VertexAttributeFormat* p = NULL;
    for (; begin != end; begin++) {
        p = *begin;
        if (p->index == index) {                    // 先看看目前有无重复设置的
            found = true;                           // 有重复的
            break;
        }
    }
    if (!found) {                                   // 没有重复的,则新建一个
        p = new VertexAttributeFormat;
        p->index = index;
        pVec->push_back(p);
    }
    if (pVec->size() > 128) {                        // 假装最多只能有 128 个 vertex attribute
        GLchar str[512];
        sprintf_s(str, "glVertexAttribPointer number of vertex attribute more than 128");
        throw str;
    }
    p->numOfComponent = size;
    p->typeOfComponent = type;
    p->normalized = normalized;
    p->stride = stride;
    p->pointer = (void*)pointer;
    p->setupToVBO = (GLuint)((void*)currentContext->GetUsingVAO()->vbo); // 记录安装时的 VBO 是哪个
} // end glVertexAttribPointer
void glEnableVertexAttribArray(GLuint index) {
    std::vector* pVec = currentContext->GetUsingVAO()->vafs_enabled;    // 启用 attribute 的数据记录
    std::vector::const_iterator begin = pVec->begin();
    std::vector::const_iterator end = pVec->end();
    VertexAttributeFormat* p = NULL;
    bool found = false;
    for (; begin != end; begin++) {
        if ((*begin) == index) {                                                // 如果本身是启用的,则不添加
            found = true;
            break;
        }
    }
    if (found == false) {                                                       // 如果没有启用,则添加
        pVec->push_back(index);
    }
} // end glEnableVertexAttribArray
void glDisableVertexAttribArray(GLuint index) {
    std::vector* pVec = currentContext->GetUsingVAO()->vafs_enabled;
    std::vector::const_iterator begin = pVec->begin();
    std::vector::const_iterator end = pVec->end();
    VertexAttributeFormat* p = NULL;
    for (; begin != end; begin++) {
        if ((*begin) == index) {
            pVec->erase(begin);                                                 // 找到启用的 attribute 索引,就删除
            break;
        }
    }
} // end glDisableVertexAttribArray

void glDrawArrays(GLenum mode, GLint first, GLsizei count) {
    if (mode == GL_TRIANGLES) {                                                 // 目前只支持三角形
        std::cout end();                           // 顶点规范的启用索引数组

        end_vaf = vao->vafs->end();

        // 遍历顶点数
        for (size_t i = 0; i vafs_enabled->begin();
            for (; begin_enabled_index != end_enabled_index; begin_enabled_index++) {
                GLboolean found = false;
                // 查找属性索引对应的格式(规范)
                begin_vaf = vao->vafs->begin();
                for (; begin_vaf != end_vaf; begin_vaf++) {
                    if ((*begin_vaf)->index == *begin_enabled_index) {
                        found = true;
                        break;
                    }
                }
                // 如果找不到启用的 attribute,则报错(OpenGL 这里会使用 静态的顶点属性,这里就不实现了,直接报错)
                if (!found) {
                    GLchar str[512];
                    sprintf_s(str, "glDrawArrays mode is triangle, but not found attribute loation : %d", *begin_enabled_index);
                    throw str;
                }
                // 取格式(规范)中绑定的 VBO
                BufferObject* vbo = (BufferObject*)((*begin_vaf)->setupToVBO);
                // 取 VBO 中的数据
                _ubuffer_T buffer = (vbo->buf->data);
                // 取顶点的偏移,按 stride 来偏移
                // 这里为了测试 VAO 整体应用,只打印一下数据即可
                // 其实也可以再写个 C++ 版本的软渲染器来替换这里的打印也是可以的
                GLuint offset = ((GLuint)((*begin_vaf)->stride)) * i;
                PrintVertex(i, *begin_vaf, buffer + offset);
            }
        }
    }
    else {
        GLchar str[512];
        sprintf_s(str, "unhandle glDrawArrays mode : %d", mode);
        throw str;
    }
} // end glDrawArrays
void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
    if (mode == GL_TRIANGLES) {                                                 // 目前只支持三角形
        std::cout vafs_enabled->end();

        end_vaf = vao->vafs->end();

        if (type != GL_UNSIGNED_INT) {
            GLchar str[512];
            sprintf_s(str, "glDrawElements unhandle type : %d", type);
            throw str;
        }

        GLuint* indexBuffer = (GLuint*)(ebo->buf->data + (GLuint)indices);      // 真正的索引缓存数据

        // 根据索引遍历顶点数
        for (size_t i = 0; i vafs_enabled->begin();
            for (; begin_enabled_index != end_enabled_index; begin_enabled_index++) {
                GLboolean found = false;
                // 查找属性索引对应的格式(规范)
                begin_vaf = vao->vafs->begin();
                for (; begin_vaf != end_vaf; begin_vaf++) {
                    if ((*begin_vaf)->index == *begin_enabled_index) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    GLchar str[512];
                    sprintf_s(str, "glDrawElements mode is triangle, but not found attribute loation : %d", *begin_enabled_index);
                    throw str;
                }
                // 取格式(规范)中绑定的 VBO
                BufferObject* vbo = (BufferObject*)((*begin_vaf)->setupToVBO);
                // 取 VBO 中的数据
                _ubuffer_T buffer = (vbo->buf->data);
                // 取顶点的偏移,按 stride 来偏移
                // 这里为了测试 VAO 整体应用,只打印一下数据即可
                // 其实也可以再写个 C++ 版本的软渲染器来替换这里的打印也是可以的
                GLuint offset = ((GLuint)((*begin_vaf)->stride)) * vertexIndex; // 使用索引值来偏移 VBO 数据
                PrintVertex(i, *begin_vaf, buffer + offset);
            }
        }
    }
    else {
        GLchar str[512];
        sprintf_s(str, "unhandle glDrawElements mode : %d", mode);
        throw str;
    }
} // end glDrawElements
Main.cpp
// Main.cpp
// jave.lin - 测试自己写的 gllike,目前为了测试 VAO/VBO/EBO 等接口的使用
#include
#include
#include"gl_like.h"

extern Context* currentContext;
extern GLint errorCode;
extern GLchar* errorMsg;

void PrintGlobalError() {
	GLchar errorCodeMeans[512] = { 0 };
	switch (errorCode)
	{
	case GL_INVALIDATED_CONTEXT:			strcpy_s(errorCodeMeans, 512, "Invalidated context"); break;
	case GL_OUT_BO_MAX_COUNT:				strcpy_s(errorCodeMeans, 512, "Out of buffer object max count"); break;
	case GL_CREATE_FAILURE:					strcpy_s(errorCodeMeans, 512, "Create / alloc failure"); break;
	case GL_CONTEXT_NOT_NULL:				strcpy_s(errorCodeMeans, 512, "Context not null"); break;
	case GL_BINDING_UN_HANDLE_BUFF_TYPE:	strcpy_s(errorCodeMeans, 512, "Binding unhandle buffer type"); break;
	case GL_SET_BUFF_VALUES_BUFF_NULL:		strcpy_s(errorCodeMeans, 512, "Buffer is NULL, while Setting buffer"); break;
	default:
		break;
	}
	if (errorCode != 0) {
		std::cout             
关注
打赏
1664331872
查看更多评论
0.0788s