Hazel game engine (030) abstraction of vertex and index buffers

If there are errors in the code, terminology, etc. in the text, please correct me

Article directory

  • foreword
  • project related
    • Code additions and modifications
    • Effect

Foreword

  • of this program

    For the generationvertex buffer and index buffer of OpenGL, the original code is abstracted into classes.

    There are rendering codes for creating opengl, vertex buffers, and index buffers in the application. If these OpenGL functions are not included in the application, these operations need to be encapsulated into classes.

  • How to design classes

    Start with the API form you want to use

    VertexBuffer m_VertexBuffer = new VertexBuffer(vertices, sizeof(vertices));
    // Complete the creation of vertex buffer objects, binding, and sending data from the CPU to the GPU in the m_VertexArray constructor
    
  • Rendering interface design

    Since there can be multiple rendering graphics APIs: OpenGL, DX, if the engine supports two rendering graphics APIs, which one needs to be designed and selected

    • If selected at compile time

      Disadvantages: If you change the rendering object, you need to recompile the engine, and you cannot switch at runtime

    • If selecting at runtime

      Disadvantage: Both rendering-related objs must be compiled at compile time

      Advantages: can dynamically switch

      How to implement: Using the dynamic characteristics of C++, the base class pointer points to the subclass object to realize dynamic polymorphism

  • The class diagram for determining the rendering interface at runtime: taking vertex buffer objects and index buffer objects as examples

    Please add a picture description

    Interpretation:

    For example: VertexBuffer has a static Create function, returns VertexBuffer*, and calls return new OpenGLVertexBuffer or DirectxVertexBuffer according to the choice of different rendering graphics API, the base class pointer points to the subclass object, C++ dynamic polymorphism. (However, later chapters will use macro definitions to determine which rendering graphics API to choose at compile time)

Project related

Code addition and modification

  • Application

     private:
    std::unique_ptr<Window> m_Window;
    ImGuiLayer* m_ImGuiLayer;
    bool m_Running = true;
    LayerStack m_LayerStack;
    
    unsigned int m_VertexArray;
    std::unique_ptr<Shader> m_Shader;
    std::unique_ptr<VertexBuffer> m_VertexBuffer;
    std::unique_ptr<IndexBuffer> m_IndexBuffer;
    
    ......
    // Render a triangle using OpenGL functions
    // vertex data
    float vertices[3 * 3] = {<!-- -->
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f, 0.5f, 0.0f
    };
    unsigned int indices[3] = {<!-- --> 0, 1, 2 }; // index data
    
    // 0. Generate vertex array object VAO, vertex buffer object VBO, index buffer object EBO/
    glGenVertexArrays(1, &m_VertexArray);
    // 1. Bind the vertex array object
    glBindVertexArray(m_VertexArray);
    
    // 2.1 Vertex buffer
    m_VertexBuffer.reset(VertexBuffer::Create(vertices, sizeof(vertices))); // here
    
    // 2.2 Set the vertex attribute pointer to explain the layout of the vertex attributes in the vertex buffer
    glEnableVertexAttribArray(0);//Open glsl's layout = 0 input
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
    
    // 3. Index buffer
    m_IndexBuffer.reset(IndexBuffer::Create(indices, sizeof(indices) / sizeof(uint32_t))); // here
    ?…
    
  • Renderer

    #pragma once
    namespace Hazel {<!-- -->
    enum class RendererAPI
    {<!-- -->
    None = 0, OpenGL = 1
    };
    class Renderer{<!-- -->
    public:
    inline static RendererAPI GetAPI() {<!-- --> return s_RendererAPI; }
    private:
    static RendererAPI s_RendererAPI;
    };
    }
    
    #include "hzpch.h"
    #include "Renderer.h"
    namespace Hazel {<!-- -->
    RendererAPI Renderer::s_RendererAPI = RendererAPI::OpenGL;
    }
    
  • Add the VertexBuffer and IndexBuffer classes to be placed in the Buffer file

    #pragma once
    namespace Hazel {<!-- -->
    class VertexBuffer{<!-- -->
    public:
    virtual ~VertexBuffer(){<!-- -->}
    virtual void Bind() const = 0;
    virtual void Unbind() const = 0;
    static VertexBuffer* Create(float* vertices, uint32_t size);
    };
    class IndexBuffer {<!-- -->
    public:
    virtual ~IndexBuffer() {<!-- -->}
    virtual void Bind() const = 0;
    virtual void Unbind() const = 0;
    virtual uint32_t GetCount() const = 0;
    static IndexBuffer* Create(uint32_t* indices, uint32_t size);
    };
    }
    
    #include "hzpch.h"
    #include "Buffer.h"
    // Create different ones according to different platforms. . .
    #include "Renderer.h"
    #include "Platform/OpenGL/OpenGLBuffer.h"
    namespace Hazel {<!-- -->
    VertexBuffer* VertexBuffer::Create(float* vertices, uint32_t size){<!-- -->
    switch (Renderer::GetAPI()) {<!-- -->
    case RendererAPI::None: HZ_CORE_ASSERT(false, "RendererAPI:None is currently not supported!"); return nullptr;
    case RendererAPI::OpenGL: return new OpenGLVertexBuffer(vertices, size);
    }
    HZ_CORE_ASSERT(false, "Unknown RendererAPI!");
    return nullptr;
    }
    IndexBuffer* IndexBuffer::Create(uint32_t* indices, uint32_t size){<!-- -->
    switch (Renderer::GetAPI()) {<!-- -->
    case RendererAPI::None: HZ_CORE_ASSERT(false, "RendererAPI:None is currently not supported!"); return nullptr;
    case RendererAPI::OpenGL: return new OpenGLIndexBuffer(indices, size);
    }
    HZ_CORE_ASSERT(false, "Unknown RendererAPI!");
    return nullptr;
    }
    }
    
  • OpenGLBuffer

    #pragma once
    #include "Hazel/Renderer/Buffer.h"
    namespace Hazel {<!-- -->
    class OpenGLVertexBuffer : public VertexBuffer{<!-- -->
    public:
    OpenGLVertexBuffer(float* vertices, uint32_t size);
    virtual ~OpenGLVertexBuffer();
    
    virtual void Bind() const;
    virtual void Unbind() const;
    private:
    uint32_t m_RendererID;
    };
    class OpenGLIndexBuffer : public IndexBuffer{<!-- -->
    public:
    OpenGLIndexBuffer(uint32_t* indices, uint32_t count);
    virtual ~OpenGLIndexBuffer();
    virtual void Bind() const;
    virtual void Unbind() const;
    virtual uint32_t GetCount() const {<!-- --> return m_Count; }
    private:
    uint32_t m_RendererID;
    uint32_t m_Count;
    };
    }
    
    #include "hzpch.h"
    #include "OpenGLBuffer.h"
    #include <glad/glad.h>
    namespace Hazel {<!-- -->
    //VertexBuffer/
    OpenGLVertexBuffer::OpenGLVertexBuffer(float* vertices, uint32_t size){<!-- -->
    // 1. Create a vertex buffer object
    glCreateBuffers(1, &m_RendererID);
    // 2. Bind the vertex buffer object
    glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
    // 3. Copy the vertex data of our CPU to the GPU vertex buffer for use by OpenGL
    glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
    }
    OpenGLVertexBuffer::~OpenGLVertexBuffer(){<!-- -->
    glDeleteBuffers(1, &m_RendererID);
    }
    void OpenGLVertexBuffer::Bind() const{<!-- -->
    glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
    }
    void OpenGLVertexBuffer::Unbind() const{<!-- -->
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
    // IndexBuffer //
    OpenGLIndexBuffer::OpenGLIndexBuffer(uint32_t* indices, uint32_t count)
    : m_Count(count){<!-- -->
    // 1. Create a vertex buffer object
    glCreateBuffers(1, &m_RendererID);
    // 2. Bind the vertex buffer object
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
    // 3. Copy the index data of our CPU to the GPU index buffer for use by OpenGL
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(uint32_t), indices, GL_STATIC_DRAW);
    }
    OpenGLIndexBuffer::~OpenGLIndexBuffer(){<!-- -->
    glDeleteBuffers(1, &m_RendererID);
    }
    void OpenGLIndexBuffer::Bind() const{<!-- -->
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
    }
    void OpenGLIndexBuffer::Unbind() const{<!-- -->
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    }
    }
    

Effect

Unchanged, it proves that the abstract vertex buffer and index buffer class are successful

Please add picture description