// BlockyFroggy
// Copyright © 2017 John Ryland.
// All rights reserved.
#pragma once
#ifndef VERTEX_ARRAY_H
#define VERTEX_ARRAY_H
#include "OpenGL.h"
#include "GLProgram.h"
typedef GLProgram::ProgramCallback VertexBindFunc;
enum PrimitiveType
{
Triangles,
Lines
};
////////////////////////////////////////////////////////////////////
// Declaration
template <typename VertexType>
class VertexArray
{
public:
void createVertexBuffer(enum PrimitiveType a_type = Triangles);
void destroyVertexBuffer();
void update();
void draw();
void sync();
VertexBindFunc bindAttributesFunction();
GLuint m_primitiveType = GL_TRIANGLES;
GLuint m_vertexArray = 0;
GLuint m_vertexBuffer = 0;
std::vector<VertexType> m_vertexData;
size_t m_gpuAllocatedSize = 0;
size_t m_vertexDataSize = 0;
};
////////////////////////////////////////////////////////////////////
// Implementation
template <typename VertexType>
void VertexArray<VertexType>::createVertexBuffer(enum PrimitiveType a_type)
{
m_primitiveType = (a_type == Triangles) ? GL_TRIANGLES : GL_LINES;
glGenVertexArraysOES(1, &m_vertexArray);
glBindVertexArrayOES(m_vertexArray);
glGenBuffers(1, &m_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
VertexType::visit(AttribPointerVisitor);
glBindVertexArrayOES(0);
// init data
update();
}
template <typename VertexType>
void VertexArray<VertexType>::destroyVertexBuffer()
{
glDeleteBuffers(1, &m_vertexBuffer);
glDeleteVertexArraysOES(1, &m_vertexArray);
m_vertexData.clear();
m_vertexDataSize = 0;
}
template <typename VertexType>
void VertexArray<VertexType>::update()
{
// update data
glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
m_vertexDataSize = m_vertexData.size();
// Seems like sub-loading isn't really an improvement (need to test more)
//if (m_vertexDataSize > m_gpuAllocatedSize) {
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexType) * m_vertexDataSize, (void*)m_vertexData.data(), GL_STATIC_DRAW);
m_gpuAllocatedSize = m_vertexDataSize;
/*
} else {
if (m_vertexDataSize)
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VertexType) * m_vertexDataSize, (void*)m_vertexData.data());
}
*/
}
template <typename VertexType>
void VertexArray<VertexType>::sync()
{
if (m_vertexData.size())
{
update();
m_vertexData.clear();
m_vertexData.shrink_to_fit();
}
}
template <typename VertexType>
void VertexArray<VertexType>::draw()
{
if (!m_vertexDataSize)
return;
glBindVertexArrayOES(m_vertexArray);
//m_program.useProgram();
//glCullFace(GL_BACK);
// setup uniforms
//LogTag(LL_Debug, "VTX", "size: %i", int(m_vertexData.size()));
glDrawArrays(m_primitiveType, 0, GLsizei(m_vertexDataSize)); // tri-strips are better
}
template <typename VertexType>
VertexBindFunc VertexArray<VertexType>::bindAttributesFunction()
{
return [](GLuint a_program) {
auto bindAttribFunc = [a_program](const char* name, GLuint index, GLsizei, GLenum, GLboolean, GLsizei, const void*) {
glBindAttribLocation(a_program, index, name);
};
VertexType::visit(bindAttribFunc);
};
}
#endif // VERTEX_ARRAY_H