通过状态机模式,实现VBO/VAO/EBO的绑定/解绑/数据更新

gpu.h

添加mCurrentVBO与mCurrentEBO、mCurrentVAO 这些绑定的状态参数
添加bindBuffer(bufferType指定绑定ARRAY_BUFFER跟顶点属性相关的VBO还是ELEMENT_ARRAY_BUIFFER与顶点索引相关的EBO)
添加bufferData(更新bufferType绑定的数据)
对于VAO,添加genVertexArrray、deleteVertexArray、bindVertyexArray、vertexAttributePointer

#pragma once
#include "../global/base.h"
#include "frameBuffer.h"
#include "../application/application.h"
#include "../math/math.h"
#include "dataStructures.h"
#include "bufferObject.h"
#include "vao.h"

#define sgl GPU::getInstance()

/*
* class GPU:
* 模拟GPU的绘图行为以及算法等
*/
class GPU {
public:
static GPU* getInstance();
GPU();

~GPU();

//接受外界传入的bmp对应的内存指针以及窗体的宽/高
void initSurface(const uint32_t& width, const uint32_t& height, void* buffer = nullptr);

//清除画布内容
void clear();

//打印状态机
void printVAO(const uint32_t& vaoID);

uint32_t genBuffer();
void deleteBuffer(const uint32_t& bufferID);
void bindBuffer(const uint32_t& bufferType, const uint32_t& bufferID);
void bufferData(const uint32_t& bufferType, size_t dataSize, void* data);

uint32_t genVertexArray();
void deleteVertexArray(const uint32_t& vaoID);
void bindVertexArray(const uint32_t& vaoID);
//用来设置当前编号binding的数据的属性
void vertexAttributePointer(
const uint32_t& binding,
const uint32_t& itemSize,
const uint32_t& stride,
const uint32_t& offset);

private:
static GPU* mInstance;
FrameBuffer* mFrameBuffer{ nullptr };

//VBO相关/EBO也存在内部
uint32_t mCurrentVBO{ 0 };
uint32_t mCurrentEBO{ 0 };
uint32_t mBufferCounter{ 0 };
std::map<uint32_t, BufferObject*> mBufferMap;

//VAO相关
uint32_t mCurrentVAO{ 0 };
uint32_t mVaoCounter{ 0 };
std::map<uint32_t, VertexArrayObject*> mVaoMap;
};

gpu.cpp

#include "gpu.h"
#include "raster.h"

GPU* GPU::mInstance = nullptr;
GPU* GPU::getInstance() {
if (!mInstance) {
mInstance = new GPU();
}

return mInstance;
}

GPU::GPU() {}

GPU::~GPU() {
if (mFrameBuffer) {
delete mFrameBuffer;
}

for (auto iter : mBufferMap) {
delete iter.second;
}
mBufferMap.clear();

for (auto iter : mVaoMap) {
delete iter.second;
}
mVaoMap.clear();
}

void GPU::initSurface(const uint32_t& width, const uint32_t& height, void* buffer) {
mFrameBuffer = new FrameBuffer(width, height, buffer);
}

void GPU::clear() {
size_t pixelSize = mFrameBuffer->mWidth * mFrameBuffer->mHeight;
std::fill_n(mFrameBuffer->mColorBuffer, pixelSize, RGBA(0, 0, 0, 0));
}

void GPU::printVAO(const uint32_t& vaoID) {
auto iter = mVaoMap.find(vaoID);
if (iter != mVaoMap.end()) {
iter->second->print();
}
}

uint32_t GPU::genBuffer() {
mBufferCounter++;
mBufferMap.insert(std::make_pair(mBufferCounter, new BufferObject()));

return mBufferCounter;
}

void GPU::deleteBuffer(const uint32_t& bufferID) {
auto iter = mBufferMap.find(bufferID);
if (iter != mBufferMap.end()) {
delete iter->second;
}
else {
return;
}

mBufferMap.erase(iter);
}

void GPU::bindBuffer(const uint32_t& bufferType, const uint32_t& bufferID) {
if (bufferType == ARRAY_BUFFER) {
mCurrentVBO = bufferID;
}
else if (bufferType == ELEMENT_ARRAY_BUFFER) {
mCurrentEBO = bufferID;
}
}

void GPU::bufferData(const uint32_t& bufferType, size_t dataSize, void* data) {
uint32_t bufferID = 0;
if (bufferType == ARRAY_BUFFER) {
bufferID = mCurrentVBO;
}
else if (bufferType == ELEMENT_ARRAY_BUFFER) {
bufferID = mCurrentEBO;
}
else {
assert(false);
}

auto iter = mBufferMap.find(bufferID);
if (iter == mBufferMap.end()) {
assert(false);
}

BufferObject* bufferObject = iter->second;
bufferObject->setBufferData(dataSize, data);
}

uint32_t GPU::genVertexArray() {
mVaoCounter++;
mVaoMap.insert(std::make_pair(mVaoCounter, new VertexArrayObject()));

return mVaoCounter;
}

void GPU::deleteVertexArray(const uint32_t& vaoID) {
auto iter = mVaoMap.find(vaoID);
if (iter != mVaoMap.end()) {
delete iter->second;
}
else {
return;
}

mVaoMap.erase(iter);
}

void GPU::bindVertexArray(const uint32_t& vaoID) {
mCurrentVAO = vaoID;
}

void GPU::vertexAttributePointer(
const uint32_t& binding,
const uint32_t& itemSize,
const uint32_t& stride,
const uint32_t& offset)
{
auto iter = mVaoMap.find(mCurrentVAO);
if (iter == mVaoMap.end()) {
assert(false);
}

auto vao = iter->second;
vao->set(binding, mCurrentVBO, itemSize, stride, offset);
}

使用例子:

uint32_t WIDTH = 800;
uint32_t HEIGHT = 600;


void render() {
sgl->clear();
}

//三个属性对应vbo
uint32_t positionVbo = 0;
uint32_t colorVbo = 0;
uint32_t uvVbo = 0;

//三角形的indices
uint32_t ebo = 0;

//本三角形专属vao
uint32_t vao = 0;

void prepare() {
float positions[] = {
-0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
};

float 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,
};

float uvs[] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
};

uint32_t indices[] = { 0, 1, 2 };

//生成indices对应ebo
ebo = sgl->genBuffer();
sgl->bindBuffer(ELEMENT_ARRAY_BUFFER, ebo);
sgl->bufferData(ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * 3, indices);
sgl->bindBuffer(ELEMENT_ARRAY_BUFFER, 0);

//生成vao并且绑定
vao = sgl->genVertexArray();
sgl->bindVertexArray(vao);

//生成每个vbo,绑定后,设置属性ID及读取参数
auto positionVbo = sgl->genBuffer();
sgl->bindBuffer(ARRAY_BUFFER, positionVbo);
sgl->bufferData(ARRAY_BUFFER, sizeof(float) * 9, positions);
sgl->vertexAttributePointer(0, 3, 3 * sizeof(float), 0);

auto colorVbo = sgl->genBuffer();
sgl->bindBuffer(ARRAY_BUFFER, colorVbo);
sgl->bufferData(ARRAY_BUFFER, sizeof(float) * 12, colors);
sgl->vertexAttributePointer(1, 4, 4 * sizeof(float), 0);

auto uvVbo = sgl->genBuffer();
sgl->bindBuffer(ARRAY_BUFFER, uvVbo);
sgl->bufferData(ARRAY_BUFFER, sizeof(float) * 6, uvs);
sgl->vertexAttributePointer(2, 2, 2 * sizeof(float), 0);

sgl->bindBuffer(ARRAY_BUFFER, 0);
sgl->bindVertexArray(0);

sgl->printVAO(vao);
}

int APIENTRY wWinMain(
_In_ HINSTANCE hInstance, //本应用程序实例句柄,唯一指代当前程序
_In_opt_ HINSTANCE hPrevInstance, //本程序前一个实例,一般是null
_In_ LPWSTR lpCmdLine, //应用程序运行参数
_In_ int nCmdShow) //窗口如何显示(最大化、最小化、隐藏),不需理会
{
if (!app->initApplication(hInstance, WIDTH, HEIGHT)) {
return -1;
}

//将bmp指向的内存配置到sgl当中
sgl->initSurface(app->getWidth(), app->getHeight(), app->getCanvas());

prepare();

bool alive = true;
while (alive) {
alive = app->peekMessage();
render();
app->show();
}

return 0;
}