LearnGL - 04 - VAO 探究


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<string.h>
#include<stdlib.h>
#include<vector>

// 获取地址类型对象指针
#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<VertexAttributeFormat*>* vafs = NULL; // VBO 格式(规范)
        std::vector<GLuint>* 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<VertexArrayObject*>* VAOs = NULL;   // 已申请的所有 VAO 对象
        std::vector<BufferObject*>* 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<iostream>
#include<string.h>
#include<math.h>
#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<typename DataType>
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<typename DataType>
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
        << "VertexID:" << vertexID
        << " Location:" << format->index
        << " NumOfComponent:" << format->numOfComponent
        << " TypeOfComponent:" << format->typeOfComponent
        << " Normalized:" << (format->normalized == GL_TRUE ? "true" : "false")
        << " Strid:" << format->stride
        << " Pointer(Offset):" << ((GLuint)format->pointer)
        << "\n";

    if (format->typeOfComponent == GL_FLOAT) {
        GLuint offset = (GLuint)format->pointer;
        GLfloat* pointer = (GLfloat*)(buffer + offset);
        std::cout << (format->numOfComponent == 1 ? "float" : "vec") << format->numOfComponent << "( ";
        for (size_t i = 0; i < format->numOfComponent; i++) {
            std::cout << *(pointer + i) << (i == (format->numOfComponent - 1) ? " " : ", ");
        }
        std::cout << ")";
    }
    else {
        GLchar str[512];
        sprintf_s(str, "PrintVertex Error, type of component unhandle : %d", format->typeOfComponent);
        throw str;
    }

    std::cout << "\n";
} // PrintVertex

//
// api function - definition
//
inline VertexArrayObject* Context::GetUsingVAO() const {
    // 如果没有绑定 VAO,就使用默认的 VAO
    return this->bindingVAO ? this->bindingVAO : this->defalultVAO;
} // Context::GetUsingVAO


//
// construct function - definition
//
VertexArrayObject::VertexArrayObject() {
    this->vafs = new std::vector<VertexAttributeFormat*>;
    this->vafs_enabled = new std::vector<GLuint>();
} // VertexArrayObject
Context::Context() {
    this->defalultVAO = new VertexArrayObject;
    this->VAOs = new std::vector<VertexArrayObject*>;
    this->BOs = new std::vector<BufferObject*>;
} // Context
//
// destruct function - definition
//
_BuffObject::~_BuffObject() {
    if (this->data != NULL) free(this->data);
    this->data = NULL;
} // ~_BuffObject
BufferObject::~BufferObject() {
    if (this->buf != NULL) delete this->buf;
    this->buf = NULL;
} // ~BufferObject
VertexArrayObject::~VertexArrayObject() {
    this->vbo = NULL;
    this->ebo = NULL;

    if (this->vafs != NULL) {
        std::vector<VertexAttributeFormat*>::iterator begin = this->vafs->begin();
        std::vector<VertexAttributeFormat*>::iterator end = this->vafs->end();
        for (; begin != end; begin++) {
            delete* begin;
        }
        this->vafs->clear();
        this->vafs = NULL;
    }

    if (this->vafs_enabled != NULL) {
        this->vafs_enabled->clear();
        this->vafs_enabled = NULL;
    }
} // VertexArrayObject
VertexAttributeFormat::~VertexAttributeFormat() {
    this->pointer = NULL;
} // ~VertexAttributeFormat
Context::~Context() {
    if (this->VAOs != NULL) {
        std::vector<VertexArrayObject*>::iterator begin_vao = this->VAOs->begin();
        std::vector<VertexArrayObject*>::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<BufferObject*>::iterator begin_vbo = this->BOs->begin();
        std::vector<BufferObject*>::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 < n; i++) {
        // glGenVertexArrays 只生成空数据的指针 VAO 对象
        VertexArrayObject* vao = new VertexArrayObject;
        *(arrays + i) = (GLuint)((void*)(vao));
        if (*(arrays + i) == 0) {
            Error(GL_CREATE_FAILURE, (const GLchar*)"gen vao buffer failure");
            return;
        }
        else {
            currentContext->VAOs->push_back(vao);
        }
    }
} // end glGenVertexArrays
void glDeleteVertexArrays(GLsizei n, GLuint* arrays) {
    for (size_t i = 0; i < n; i++) {
        VertexArrayObject* p = (VertexArrayObject*)(*(arrays + i));
        std::vector<VertexArrayObject*>::const_iterator begin = currentContext->VAOs->begin();
        std::vector<VertexArrayObject*>::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<VertexAttributeFormat*>::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 < n; i++) {
        // glGenBuffers 只生成空数据的指针 VBO 对象
        BufferObject* vbo = new BufferObject;
        *(buffers + i) = (GLuint)((void*)(vbo));
        if (*(buffers + i) == 0) {
            Error(GL_CREATE_FAILURE, (const GLchar*)"gen bo buffer failure");
            return;
        }
        else {
            currentContext->BOs->push_back(vbo);
        }
    }
} // glGenBuffers
void glDeleteBuffers(GLsizei n, GLuint* buffers) {
    for (size_t i = 0; i < n; i++) {
        BufferObject* p = (BufferObject*)(*(buffers + i));
        std::vector<BufferObject*>::const_iterator begin = currentContext->BOs->begin();
        std::vector<BufferObject*>::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 < size) {
            if ((*buffObj)->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<VertexAttributeFormat*>* pVec = currentContext->GetUsingVAO()->vafs;
    std::vector<VertexAttributeFormat*>::const_iterator begin = pVec->begin();
    std::vector<VertexAttributeFormat*>::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<GLuint>* pVec = currentContext->GetUsingVAO()->vafs_enabled;    // 启用 attribute 的数据记录
    std::vector<GLuint>::const_iterator begin = pVec->begin();
    std::vector<GLuint>::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<GLuint>* pVec = currentContext->GetUsingVAO()->vafs_enabled;
    std::vector<GLuint>::const_iterator begin = pVec->begin();
    std::vector<GLuint>::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 << "glDrawArray mode : GL_TRIANGLES\n";
        if (count <= 0 || count % 3 != 0) {                                     // 如果绘制的索引数量不是 3 的倍数,则报错
            GLchar str[512];
            sprintf_s(str, "glDrawArrays mode is triangle, but 'count' not the times of three : %d", count);
            throw str;
        }

        VertexArrayObject* vao;
        std::vector<GLuint>::const_iterator begin_enabled_index, end_enabled_index;
        std::vector<VertexAttributeFormat*>::const_iterator begin_vaf, end_vaf;

        vao = currentContext->GetUsingVAO();                                    // 使用的 VAO

        end_enabled_index = vao->vafs_enabled->end();                           // 顶点规范的启用索引数组

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

        // 遍历顶点数
        for (size_t i = 0; i < count; i ++) {
            // 遍历属性索引
            begin_enabled_index = vao->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 << "glDrawElements mode : GL_TRIANGLES\n";
        if (count <= 0 || count % 3 != 0) {                                     // 如果绘制的索引数量不是 3 的倍数,则报错
            GLchar str[512];
            sprintf_s(str, "glDrawElements mode is triangle, but 'count' not the times of three : %d", count);
            throw str;
        }

        VertexArrayObject* vao;
        BufferObject* ebo;
        GLuint vertexIndex;
        std::vector<GLuint>::const_iterator begin_enabled_index, end_enabled_index;
        std::vector<VertexAttributeFormat*>::const_iterator begin_vaf, end_vaf;

        vao = currentContext->GetUsingVAO();
        ebo = vao->ebo;

        end_enabled_index = vao->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 < count; i++) {
            // 获取 EBO 中的索引值
            vertexIndex = *(indexBuffer + i);
            // 遍历属性索引
            begin_enabled_index = vao->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<iostream>
#include<string.h>
#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 << "Error Code : " << errorCode << ", Mean : " << errorCodeMeans << ", Message : " << (errorMsg == NULL ? "" : errorMsg) << "\n";
	}
}

void testDrawTriangleByOnlyVBO_2FloatComponent() {
	GLuint vbo;
	// 生成 VBO
	glGenBuffers(1, &vbo);
	if (vbo == 0) {
		std::cout << "Generate VBO Buffer Failure : " << vbo << "\n";
		exit(EXIT_FAILURE);
	}
	// 顶点
	GLfloat vertices[9] = {
		-0.5f, -0.5f,
		+0.5f, -0.5f,
		+0.0f, +0.5f,
	};
	// 绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	// 设置 VBO 数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	// 设置 0 索引顶点属性 VBO 格式
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, (GLsizei)sizeof(GLfloat) * 2, 0);
	// 启用 0 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(0);
	// 绘制 VBO 内容
	glDrawArrays(GL_TRIANGLES, 0, 3);

	// 禁用 0 索引顶点属性 VBO 格式
	glDisableVertexAttribArray(0);
	// 取消绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	// 删除 VBO
	glDeleteBuffers(1, &vbo);
} // testDrawTriangleByOnlyVBO

void testDrawTriangleByOnlyVBO() {
	GLuint vbo;
	// 生成 VBO
	glGenBuffers(1, &vbo);
	if (vbo == 0) {
		std::cout << "Generate VBO Buffer Failure : " << vbo << "\n";
		exit(EXIT_FAILURE);
	}
	// 顶点
	GLfloat vertices[9] = {
		-0.5f, -0.5f, +0.0f,
		+0.5f, -0.5f, +0.0f,
		+0.0f, +0.5f, +0.0f,
	};
	// 绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	// 设置 VBO 数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	// 设置 0 索引顶点属性 VBO 格式
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, (GLsizei)sizeof(GLfloat) * 3, 0);
	// 启用 0 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(0);
	// 绘制 VBO 内容
	glDrawArrays(GL_TRIANGLES, 0, 3);

	// 禁用 0 索引顶点属性 VBO 格式
	glDisableVertexAttribArray(0);
	// 取消绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	// 删除 VBO
	glDeleteBuffers(1, &vbo);
} // testDrawTriangleByOnlyVBO

void testDrawQuadByOnlyVBO() {
	GLuint vbo;
	// 生成 VBO
	glGenBuffers(1, &vbo);
	if (vbo == 0) {
		std::cout << "Generate VBO Buffer Failure : " << vbo << "\n";
		exit(EXIT_FAILURE);
	}
	// 顶点
	GLfloat vertices[18] = {
		-0.5f, -0.5f, +0.0f,
		+0.5f, -0.5f, +0.0f,
		-0.5f, +0.5f, +0.0f,

		+0.5f, -0.5f, +0.0f,
		+0.5f, +0.5f, +0.0f,
		-0.5f, +0.5f, +0.0f,
	};
	// 绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	// 设置 VBO 数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	// 设置 0 索引顶点属性 VBO 格式
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, (GLsizei)sizeof(GLfloat) * 3, 0);
	// 启用 0 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(0);
	// 绘制 VBO 内容
	glDrawArrays(GL_TRIANGLES, 0, 6);

	// 禁用 0 索引顶点属性 VBO 格式
	glDisableVertexAttribArray(0);
	// 取消绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	// 删除 VBO
	glDeleteBuffers(1, &vbo);
} // testDrawQuadByOnlyVBO

void testDrawQuadByOnlyVBO_2Attribute_Pos_Col_inSingleVBO() {
	GLuint vbo;
	// 生成 VBO
	glGenBuffers(1, &vbo);
	if (vbo == 0) {
		std::cout << "Generate VBO Buffer Failure : " << vbo << "\n";
		exit(EXIT_FAILURE);
	}
	// 顶点
	GLfloat vertices[36] = {
		// x	y	  z			r	  g		b
		-0.5f, -0.5f, +0.0f,	1.0f, 0.0f, 0.0f,
		+0.5f, -0.5f, +0.0f,	0.0f, 1.0f, 0.0f,
		-0.5f, +0.5f, +0.0f,	0.0f, 0.0f, 1.0f,

		+0.5f, -0.5f, +0.0f,	0.0f, 1.0f, 0.0f,
		+0.5f, +0.5f, +0.0f,	1.0f, 1.0f, 0.0f,
		-0.5f, +0.5f, +0.0f,	0.0f, 0.0f, 1.0f,
	};
	// 绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	// 设置 VBO 数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	// 设置 0 索引顶点属性 VBO 格式
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, (GLsizei)sizeof(GLfloat) * 6, 0);
	// 设置 1 索引顶点属性 VBO 格式
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, (GLsizei)sizeof(GLfloat) * 6, (const void*)(sizeof(GLfloat) * 3));
	// 启用 0 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(0);
	// 启用 1 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(1);
	// 绘制 VBO 内容
	glDrawArrays(GL_TRIANGLES, 0, 6);

	// 禁用 0 索引顶点属性 VBO 格式
	glDisableVertexAttribArray(0);
	// 禁用 1 索引顶点属性 VBO 格式
	glDisableVertexAttribArray(1);
	// 取消绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	// 删除 VBO
	glDeleteBuffers(1, &vbo);
} // testDrawQuadByOnlyVBO

void testDrawQuadByOnlyVBO_2Attribute_Pos_Col_TwoVBO() {
	GLuint vbo[2];
	// 生成 VBO
	glGenBuffers(2, vbo);
	if (vbo[0] == 0 || vbo[1] == 0) {
		std::cout << "Generate VBO Buffer Failure : [0]=" << vbo[0] << "[1]=" << vbo[1] << "\n";
		exit(EXIT_FAILURE);
	}
	// 顶点
	GLfloat vertices[18] = {
		// x	y	  z		
		-0.5f, -0.5f, +0.0f,
		+0.5f, -0.5f, +0.0f,
		-0.5f, +0.5f, +0.0f,

		+0.5f, -0.5f, +0.0f,
		+0.5f, +0.5f, +0.0f,
		-0.5f, +0.5f, +0.0f,
	};
	// 颜色
	GLfloat colors[18] = {
		//r	  g		b
		1.0f, 0.0f, 0.0f,
		0.0f, 1.0f, 0.0f,
		0.0f, 0.0f, 1.0f,

		0.0f, 1.0f, 0.0f,
		1.0f, 1.0f, 0.0f,
		0.0f, 0.0f, 1.0f,
	};
	// 绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	// 设置 VBO 数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	// 设置 0 索引顶点属性 VBO 格式
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, (GLsizei)sizeof(GLfloat) * 3, 0);
	// 启用 0 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	// 设置 VBO 数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
	// 设置 0 索引顶点属性 VBO 格式
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, (GLsizei)sizeof(GLfloat) * 3, 0);
	// 启用 0 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(1);
	
	// 绘制 VBO 内容
	glDrawArrays(GL_TRIANGLES, 0, 6);

	// 禁用 0 索引顶点属性 VBO 格式
	glDisableVertexAttribArray(0);
	// 禁用 1 索引顶点属性 VBO 格式
	glDisableVertexAttribArray(1);
	// 取消绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	// 删除 VBO
	glDeleteBuffers(2, vbo);
} // testDrawQuadByOnlyVBO

void testVAO_VBO_EBO_vertex_single_buff() {
	GLuint vao;
	// 生成 VAO
	glGenVertexArrays(1, &vao);
	if (vao == 0) {
		std::cout << "Generate VAO Buffer Failure : " << vao << "\n";
		exit(EXIT_FAILURE);
	}
	GLuint vbo;
	// 生成 VBO
	glGenBuffers(1, &vbo);
	if (vbo == 0) {
		std::cout << "Generate VBO Buffer Failure : " << vbo << "\n";
		exit(EXIT_FAILURE);
	}
	GLuint ebo;
	// 生成 EBO
	glGenBuffers(1, &ebo);
	if (ebo == 0) {
		std::cout << "Generate EBO Buffer Failure : " << ebo << "\n";
		exit(EXIT_FAILURE);
	}
	// 顶点
	GLfloat vertices[24] = {
		// x	y	  z			r	  g		b
		-0.5f, -0.5f, +0.0f,	1.0f, 0.0f, 0.0f,
		+0.5f, -0.5f, +0.0f,	0.0f, 1.0f, 0.0f,
		+0.5f, +0.5f, +0.0f,	0.0f, 0.0f, 1.0f,
		-0.5f, +0.5f, +0.0f,	1.0f, 1.0f, 0.0f,
	};
	// 索引
	GLuint indices[] = {
		0, 1, 3,
		1, 2, 3
	};

	// 绑定 VAO
	glBindVertexArray(vao);

	// 绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	// 设置 VBO 数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	// 绑定 EBO
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
	// 设置 EBO 数据
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	// 设置 0 索引顶点属性 VBO 格式
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, (GLsizei)sizeof(GLfloat) * 6, 0);
	// 设置 1 索引顶点属性 VBO 格式
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, (GLsizei)sizeof(GLfloat) * 6, (void*)(sizeof(GLfloat) * 3));

	// 启用 0 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(0);
	// 启用 1 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(1);

	// 绘制 EBO 内容,当前我们绑定了 VAO 的,所以使用的是 VAO 内的 EBO
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

	// 禁用 0 索引顶点属性 VBO 格式
	glDisableVertexAttribArray(0);
	// 禁用 1 索引顶点属性 VBO 格式
	glDisableVertexAttribArray(1);
	// 取消绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	// 取消绑定 EBO
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	// 取消绑定 VAO
	glBindVertexArray(0);
	// 删除 EBO
	glDeleteBuffers(1, &ebo);
	// 删除 VBO
	glDeleteBuffers(1, &vbo);
	// 删除 VAO
	glDeleteVertexArrays(1, &vao);
}

void testMultiVAO() {
	GLuint vao[2];
	// 生成 VAO
	glGenVertexArrays(2, vao);
	if (vao[0] == 0 || vao[1] == 0) {
		std::cout << "Generate VAO Buffer Failure : [0]=" << vao[0] << " [1]=" << vao[1] << "\n";
		exit(EXIT_FAILURE);
	}
	GLuint vbo[2];
	// 生成 VBO
	glGenBuffers(2, vbo);
	if (vbo[0] == 0 || vbo[1] == 0) {
		std::cout << "Generate VBO Buffer Failure : [0]=" << vbo[0] << " [1]=" << vbo[1] << "\n";
		exit(EXIT_FAILURE);
	}
	GLuint ebo[2];
	// 生成 EBO
	glGenBuffers(2, ebo);
	if (ebo[0] == 0 || ebo[1] == 0) {
		std::cout << "Generate EBO Buffer Failure : [0]=" << ebo[0] << " [1]=" << ebo[1] << "\n";
		exit(EXIT_FAILURE);
	}

	//
	// 第一个 VAO 的设置
	//
	// 顶点
	GLfloat vertices_0[24] = {
		// x	y	  z			r	  g		b
		-0.5f, -0.5f, +0.0f,	1.0f, 0.0f, 0.0f,
		+0.5f, -0.5f, +0.0f,	0.0f, 1.0f, 0.0f,
		+0.5f, +0.5f, +0.0f,	0.0f, 0.0f, 1.0f,
		-0.5f, +0.5f, +0.0f,	1.0f, 1.0f, 0.0f,
	};
	// 索引
	GLuint indices_0[] = {
		0, 1, 3,
		1, 2, 3
	};

	// 绑定 VAO[0]
	glBindVertexArray(vao[0]);

	// 绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	// 设置 VBO 数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_0), vertices_0, GL_STATIC_DRAW);

	// 绑定 EBO
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
	// 设置 EBO 数据
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices_0), indices_0, GL_STATIC_DRAW);

	// 设置 0 索引顶点属性 VBO 格式
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, (GLsizei)sizeof(GLfloat) * 6, 0);
	// 设置 1 索引顶点属性 VBO 格式
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, (GLsizei)sizeof(GLfloat) * 6, (void*)(sizeof(GLfloat) * 3));

	// 启用 0 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(0);
	// 启用 1 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(1);

	//
	// 第二个 VAO 的设置
	//
	// 顶点
	GLfloat vertices_1[18] = {
		// x	y	  z			r	  g		b
		-0.5f, -0.5f, +0.0f,	1.0f, 0.0f, 0.0f,
		+0.5f, -0.5f, +0.0f,	0.0f, 1.0f, 0.0f,
		+0.5f, +0.5f, +0.0f,	0.0f, 0.0f, 1.0f,
	};
	// 索引
	GLuint indices_1[] = {
		0, 1, 2
	};

	// 绑定 VAO[0]
	glBindVertexArray(vao[1]);

	// 绑定 VBO
	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	// 设置 VBO 数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_1), vertices_1, GL_STATIC_DRAW);

	// 绑定 EBO
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[1]);
	// 设置 EBO 数据
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices_1), indices_1, GL_STATIC_DRAW);

	// 设置 0 索引顶点属性 VBO 格式
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, (GLsizei)sizeof(GLfloat) * 6, 0);
	// 设置 1 索引顶点属性 VBO 格式
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, (GLsizei)sizeof(GLfloat) * 6, (void*)(sizeof(GLfloat) * 3));

	// 启用 0 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(0);
	// 启用 1 索引顶点属性 VBO 格式
	glEnableVertexAttribArray(1);

	//
	// 开始绘制
	//
	// 绘制第一个 VAO
	glBindVertexArray(vao[0]);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
	// 绘制第二个 VAO
	glBindVertexArray(vao[1]);
	glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);

	// 取消绑定 VAO
	glBindVertexArray(0);
	// 删除 EBO
	glDeleteBuffers(2, ebo);
	// 删除 VBO
	glDeleteBuffers(2, vbo);
	// 删除 VAO
	glDeleteVertexArrays(2, vao);
}

int main() {

	GLuint context;

	if (!CreateContext(4, 6, &context)) {
		std::cout << "Create Context Failure\n";
		exit(EXIT_FAILURE);
	}
	
	MakeCurrentContext(context);
	
	std::cout << " === Testing [testDrawTriangleByOnlyVBO_2FloatComponent] START ===\n";
	testDrawTriangleByOnlyVBO_2FloatComponent();
	std::cout << " === Testing [testDrawTriangleByOnlyVBO_2FloatComponent] END ===\n\n";

	std::cout << " === Testing [testDrawTriangleByOnlyVBO] START ===\n";
	testDrawTriangleByOnlyVBO();
	std::cout << " === Testing [testDrawTriangleByOnlyVBO] END ===\n\n";

	std::cout << " === Testing [testDrawQuadByOnlyVBO] START ===\n";
	testDrawQuadByOnlyVBO();
	std::cout << " === Testing [testDrawQuadByOnlyVBO] END ===\n\n";

	std::cout << " === Testing [testDrawQuadByOnlyVBO_2Attribute_Pos_Col_inSingleVBO] START ===\n";
	testDrawQuadByOnlyVBO_2Attribute_Pos_Col_inSingleVBO();
	std::cout << " === Testing [testDrawQuadByOnlyVBO_2Attribute_Pos_Col_inSingleVBO] END ===\n\n";

	std::cout << " === Testing [testDrawQuadByOnlyVBO_2Attribute_Pos_Col_TwoVBO] START ===\n";
	testDrawQuadByOnlyVBO_2Attribute_Pos_Col_TwoVBO();
	std::cout << " === Testing [testDrawQuadByOnlyVBO_2Attribute_Pos_Col_TwoVBO] END ===\n\n";

	std::cout << " === Testing [testVAO_VBO_EBO_vertex_single_buff] START ===\n";
	testVAO_VBO_EBO_vertex_single_buff();
	std::cout << " === Testing [testVAO_VBO_EBO_vertex_single_buff] END ===\n\n";

	std::cout << " === Testing [testMultiVAO] START ===\n";
	testMultiVAO();
	std::cout << " === Testing [testMultiVAO] END ===\n\n";

	// 实现分开的 VBO

	Terminate();

	PrintGlobalError();
	
	return 0;
}

运行效果

 === Testing [testDrawTriangleByOnlyVBO_2FloatComponent] START ===
glDrawArray mode : GL_TRIANGLES
VertexID:0 Location:0 NumOfComponent:2 TypeOfComponent:5126 Normalized:false Strid:8 Pointer(Offset):0
vec2( -0.5, -0.5 )
VertexID:1 Location:0 NumOfComponent:2 TypeOfComponent:5126 Normalized:false Strid:8 Pointer(Offset):0
vec2( 0.5, -0.5 )
VertexID:2 Location:0 NumOfComponent:2 TypeOfComponent:5126 Normalized:false Strid:8 Pointer(Offset):0
vec2( 0, 0.5 )
 === Testing [testDrawTriangleByOnlyVBO_2FloatComponent] END ===

 === Testing [testDrawTriangleByOnlyVBO] START ===
glDrawArray mode : GL_TRIANGLES
VertexID:0 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( -0.5, -0.5, 0 )
VertexID:1 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:2 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0, 0.5, 0 )
 === Testing [testDrawTriangleByOnlyVBO] END ===

 === Testing [testDrawQuadByOnlyVBO] START ===
glDrawArray mode : GL_TRIANGLES
VertexID:0 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( -0.5, -0.5, 0 )
VertexID:1 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:2 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( -0.5, 0.5, 0 )
VertexID:3 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:4 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0.5, 0.5, 0 )
VertexID:5 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( -0.5, 0.5, 0 )
 === Testing [testDrawQuadByOnlyVBO] END ===

 === Testing [testDrawQuadByOnlyVBO_2Attribute_Pos_Col_inSingleVBO] START ===
glDrawArray mode : GL_TRIANGLES
VertexID:0 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):0
vec3( -0.5, -0.5, 0 )
VertexID:0 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):12
vec3( 1, 0, 0 )
VertexID:1 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:1 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):12
vec3( 0, 1, 0 )
VertexID:2 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):0
vec3( -0.5, 0.5, 0 )
VertexID:2 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):12
vec3( 0, 0, 1 )
VertexID:3 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:3 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):12
vec3( 0, 1, 0 )
VertexID:4 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):0
vec3( 0.5, 0.5, 0 )
VertexID:4 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):12
vec3( 1, 1, 0 )
VertexID:5 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):0
vec3( -0.5, 0.5, 0 )
VertexID:5 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:24 Pointer(Offset):12
vec3( 0, 0, 1 )
 === Testing [testDrawQuadByOnlyVBO_2Attribute_Pos_Col_inSingleVBO] END ===

 === Testing [testDrawQuadByOnlyVBO_2Attribute_Pos_Col_TwoVBO] START ===
glDrawArray mode : GL_TRIANGLES
VertexID:0 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( -0.5, -0.5, 0 )
VertexID:0 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 1, 0, 0 )
VertexID:1 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:1 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0, 1, 0 )
VertexID:2 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( -0.5, 0.5, 0 )
VertexID:2 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0, 0, 1 )
VertexID:3 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:3 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0, 1, 0 )
VertexID:4 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0.5, 0.5, 0 )
VertexID:4 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 1, 1, 0 )
VertexID:5 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( -0.5, 0.5, 0 )
VertexID:5 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:false Strid:12 Pointer(Offset):0
vec3( 0, 0, 1 )
 === Testing [testDrawQuadByOnlyVBO_2Attribute_Pos_Col_TwoVBO] END ===

 === Testing [testVAO_VBO_EBO_vertex_single_buff] START ===
glDrawElements mode : GL_TRIANGLES
VertexID:0 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( -0.5, -0.5, 0 )
VertexID:0 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 1, 0, 0 )
VertexID:1 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:1 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 0, 1, 0 )
VertexID:2 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( -0.5, 0.5, 0 )
VertexID:2 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 1, 1, 0 )
VertexID:3 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:3 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 0, 1, 0 )
VertexID:4 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( 0.5, 0.5, 0 )
VertexID:4 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 0, 0, 1 )
VertexID:5 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( -0.5, 0.5, 0 )
VertexID:5 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 1, 1, 0 )
 === Testing [testVAO_VBO_EBO_vertex_single_buff] END ===

 === Testing [testMultiVAO] START ===
glDrawElements mode : GL_TRIANGLES
VertexID:0 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( -0.5, -0.5, 0 )
VertexID:0 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 1, 0, 0 )
VertexID:1 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:1 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 0, 1, 0 )
VertexID:2 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( -0.5, 0.5, 0 )
VertexID:2 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 1, 1, 0 )
VertexID:3 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:3 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 0, 1, 0 )
VertexID:4 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( 0.5, 0.5, 0 )
VertexID:4 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 0, 0, 1 )
VertexID:5 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( -0.5, 0.5, 0 )
VertexID:5 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 1, 1, 0 )
glDrawElements mode : GL_TRIANGLES
VertexID:0 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( -0.5, -0.5, 0 )
VertexID:0 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 1, 0, 0 )
VertexID:1 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( 0.5, -0.5, 0 )
VertexID:1 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 0, 1, 0 )
VertexID:2 Location:0 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):0
vec3( 0.5, 0.5, 0 )
VertexID:2 Location:1 NumOfComponent:3 TypeOfComponent:5126 Normalized:true Strid:24 Pointer(Offset):12
vec3( 0, 0, 1 )
 === Testing [testMultiVAO] END ===
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值