#include "CVertexBuffer.h" #include "CVertexArrayManager.h" #include CVertexBuffer::CVertexBuffer() { mBuffered = false; SetVertexDesc(ePosition | eNormal | eTex0 | eTex1 | eTex2 | eTex3 | eTex4 | eTex5 | eTex6 | eTex7); } CVertexBuffer::CVertexBuffer(EVertexDescription Desc) { mBuffered = false; SetVertexDesc(Desc); } CVertexBuffer::~CVertexBuffer() { CVertexArrayManager::DeleteAllArraysForVBO(this); if (mBuffered) glDeleteBuffers(12, mAttribBuffers); } u16 CVertexBuffer::AddVertex(const CVertex& Vert) { if (mPositions.size() == 0xFFFF) throw std::overflow_error("VBO contains too many vertices"); if (mVtxDesc & ePosition) mPositions.push_back(Vert.Position); if (mVtxDesc & eNormal) mNormals.push_back(Vert.Normal); if (mVtxDesc & eColor0) mColors[0].push_back(Vert.Color[0]); if (mVtxDesc & eColor1) mColors[1].push_back(Vert.Color[1]); for (u32 iTex = 0; iTex < 8; iTex++) if (mVtxDesc & (eTex0 << (iTex * 2))) mTexCoords[iTex].push_back(Vert.Tex[iTex]); for (u32 iMtx = 0; iMtx < 8; iMtx++) if (mVtxDesc & (ePosMtx << iMtx)) mTexCoords[iMtx].push_back(Vert.MatrixIndices[iMtx]); return (mPositions.size() - 1); } u16 CVertexBuffer::AddIfUnique(const CVertex& Vert, u16 Start) { if (Start < mPositions.size()) { for (u16 iVert = Start; iVert < mPositions.size(); iVert++) { // I use a bool because "continue" doesn't work properly within the iTex loop bool Unique = false; if (mVtxDesc & ePosition) if (Vert.Position != mPositions[iVert]) Unique = true; if ((!Unique) && (mVtxDesc & eNormal)) if (Vert.Normal != mNormals[iVert]) Unique = true; if ((!Unique) && (mVtxDesc & eColor0)) if (Vert.Color[0] != mColors[0][iVert]) Unique = true; if ((!Unique) && (mVtxDesc & eColor1)) if (Vert.Color[1] != mColors[1][iVert]) Unique = true; if (!Unique) for (u32 iTex = 0; iTex < 8; iTex++) if ((mVtxDesc & (eTex0 << (iTex * 2)))) if (Vert.Tex[iTex] != mTexCoords[iTex][iVert]) { Unique = true; break; } if (!Unique) return iVert; } } return AddVertex(Vert); } void CVertexBuffer::Reserve(u16 size) { u32 ReserveSize = mPositions.size() + size; if (mVtxDesc & ePosition) mPositions.reserve(ReserveSize); if (mVtxDesc & eNormal) mNormals.reserve(ReserveSize); if (mVtxDesc & eColor0) mColors[0].reserve(ReserveSize); if (mVtxDesc & eColor1) mColors[1].reserve(ReserveSize); for (u32 iTex = 0; iTex < 8; iTex++) if (mVtxDesc & (eTex0 << (iTex * 2))) mTexCoords[iTex].reserve(ReserveSize); } void CVertexBuffer::Clear() { if (mBuffered) glDeleteBuffers(12, mAttribBuffers); mBuffered = false; mPositions.clear(); mNormals.clear(); mColors[0].clear(); mColors[1].clear(); for (u32 iTex = 0; iTex < 8; iTex++) mTexCoords[iTex].clear(); } void CVertexBuffer::Buffer() { // Make sure we don't end up with two buffers for the same data... if (mBuffered) { glDeleteBuffers(12, mAttribBuffers); mBuffered = false; } // Generate buffers glGenBuffers(12, mAttribBuffers); for (u32 iAttrib = 0; iAttrib < 12; iAttrib++) { int Attrib = (ePosition << (iAttrib * 2)); bool HasAttrib = ((mVtxDesc & Attrib) != 0); if (!HasAttrib) continue; if (iAttrib < 2) { std::vector *pBuffer = (iAttrib == 0) ? &mPositions : &mNormals; glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBufferData(GL_ARRAY_BUFFER, pBuffer->size() * sizeof(CVector3f), pBuffer->data(), GL_STATIC_DRAW); } else if (iAttrib < 4) { u8 idx = (u8) (iAttrib - 2); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBufferData(GL_ARRAY_BUFFER, mColors[idx].size() * sizeof(CColor), mColors[idx].data(), GL_STATIC_DRAW); } else { u8 idx = (u8) (iAttrib - 4); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBufferData(GL_ARRAY_BUFFER, mTexCoords[idx].size() * sizeof(CVector2f), mTexCoords[idx].data(), GL_STATIC_DRAW); } } mBuffered = true; } void CVertexBuffer::Bind() { if (!mBuffered) Buffer(); CVertexArrayManager::Current()->BindVAO(this); } void CVertexBuffer::Unbind() { glBindVertexArray(0); } bool CVertexBuffer::IsBuffered() { return mBuffered; } EVertexDescription CVertexBuffer::VertexDesc() { return mVtxDesc; } void CVertexBuffer::SetVertexDesc(EVertexDescription Desc) { Clear(); mVtxDesc = Desc; } u32 CVertexBuffer::Size() { return mPositions.size(); } GLuint CVertexBuffer::CreateVAO() { GLuint VertexArray; glGenVertexArrays(1, &VertexArray); glBindVertexArray(VertexArray); for (u32 iAttrib = 0; iAttrib < 12; iAttrib++) { int Attrib = (ePosition << (iAttrib * 2)); bool HasAttrib = ((mVtxDesc & Attrib) != 0); if (!HasAttrib) continue; if (iAttrib < 2) { glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glVertexAttribPointer(iAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(CVector3f), (void*) 0); glEnableVertexAttribArray(iAttrib); } else if (iAttrib < 4) { glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glVertexAttribPointer(iAttrib, 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(CColor), (void*) 0); glEnableVertexAttribArray(iAttrib); } else { glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glVertexAttribPointer(iAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(CVector2f), (void*) 0); glEnableVertexAttribArray(iAttrib); } } glBindVertexArray(0); return VertexArray; }