GraphicsTest/Draw.cpp

219 lines
6.5 KiB
C++

#include "Draw.h"
namespace NB{
DrawWarning::DrawWarning(const std::string& msg) : std::runtime_error(msg) {}
uint8_t GLSLTypeSize(GLenum type) {
switch(type) {
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_HALF_FLOAT:
return 2;
break;
case GL_INT:
case GL_UNSIGNED_INT:
case GL_FLOAT:
return 4;
break;
case GL_DOUBLE:
return 8;
break;
default:
return 1;
break;
}
}
uint8_t GLSLPrimitiveVertexSize(GLenum type, unsigned int num_prims) {
switch(type) {
case GL_POINTS:
return num_prims;
case GL_LINES:
return num_prims*2;
break;
case GL_LINE_STRIP:
return num_prims+1;
break;
case GL_LINE_LOOP:
return num_prims;
break;
case GL_TRIANGLES:
return num_prims*3;
break;
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
return num_prims+2;
break;
case GL_QUADS:
return 4*num_prims;
break;
case GL_QUAD_STRIP:
return 2*num_prims+2;
break;
default:
return num_prims;
break;
}
}
DrawBuffer::DrawBuffer(
std::vector<VertexAttribute> vas,
const Shader& shader
) : _vertex_attributes(vas), _shader(shader),
_vert_data(GL_ARRAY_BUFFER), _elmt_data(GL_ELEMENT_ARRAY_BUFFER) {}
unsigned int DrawBuffer::vertSize() const {
size_t num_attrs = _vertex_attributes.size();
size_t vert_size = 0;
for (int i = 0; i < num_attrs; ++i) {
vert_size += _vertex_attributes[i].GLSLSize*GLSLTypeSize(_vertex_attributes[i].GLSLType);
}
return vert_size;
}
std::vector<VertexAttributePointer> DrawBuffer::getLayout() const {
unsigned int num_attrs = _vertex_attributes.size();
std::vector<VertexAttributePointer> ret(num_attrs);
for (int i = 0; i < num_attrs; ++i) {
ret[i] = _vertex_attributes[i].ptr;
}
return ret;
}
void DrawBuffer::draw() const {
_shader.use();
glBindVertexArray(_VAO);
glDrawElements(_gl_primitive_type, _elmt_data.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
const Shader DrawBuffer::shader() const {
return _shader;
}
bool DrawBuffer::keepLocalElement() const { return _elmt_data.keepLocal(); }
bool DrawBuffer::keepLocalVertex() const { return _vert_data.keepLocal(); }
unsigned int DrawBuffer::elementBufferID() const { return _elmt_data.id(); }
unsigned int DrawBuffer::vertexBufferID() const { return _vert_data.id(); }
bool DrawBuffer::keepLocalElement(bool keep) { return _elmt_data.keepLocal(keep); }
bool DrawBuffer::keepLocalVertex(bool keep) { return _vert_data.keepLocal(keep); }
const Shader DrawBuffer::shader(const Shader& new_shader) {
_shader = new_shader;
return _shader;
}
std::vector<VertexAttributePointer> DrawBuffer::setLayout() {
int vert_size = vertSize();
unsigned int num_attrs = _vertex_attributes.size();
std::vector<VertexAttributePointer> ret(num_attrs);
unsigned int curr_byte = 0;
for (int i = 0; i < num_attrs; ++i) {
_vertex_attributes[i].ptr.stride = vert_size;
_vertex_attributes[i].ptr.offset = curr_byte;
curr_byte += _vertex_attributes[i].GLSLSize * GLSLTypeSize(_vertex_attributes[i].GLSLType);
ret[i] = _vertex_attributes[i].ptr;
}
return getLayout();
}
std::vector<VertexAttributePointer> DrawBuffer::setLayout(std::vector<VertexAttributePointer> vap) {
unsigned int num_attrs = _vertex_attributes.size();
if (vap.size() != num_attrs) {
throw DrawWarning("DrawBuffer Vertex Attributes and passed Vertex Attributes do not match.");
}
for (int i = 0; i < num_attrs; ++i) {
if (vap[i].stride == -1) {
throw DrawWarning("Unset Vertex Attribute Pointer in index " + std::to_string(i) + ".");
}
_vertex_attributes[i].ptr = vap[i];
}
return getLayout();
}
void DrawBuffer::generateElementBuffer(unsigned int num_prims, GLenum gl_primitive_type) {
generateElementBuffer(std::vector<unsigned int>(GLSLPrimitiveVertexSize(gl_primitive_type, num_prims)));
}
void DrawBuffer::generateElementBuffer(std::vector<unsigned int> elements, GLenum gl_primitive_type) {
_num_prims = elements.size();
_gl_primitive_type = gl_primitive_type;
_elmt_data.setData(elements);
}
void DrawBuffer::generateVertexBuffer(unsigned int num_verts) {
generateVertexBuffer(std::vector<unsigned char>(num_verts * vertSize()));
}
void DrawBuffer::generateVertexBuffer(std::vector<unsigned char> vert_data) {
int vert_size = vertSize();
if (vert_data.size() % vert_size != 0) {
throw DrawWarning("Starting data does not match vertex size of " + std::to_string(vert_size) + ".");
}
_num_verts = vert_data.size() / vert_size;
unsigned int num_attrs = _vertex_attributes.size();
for (int i = 0; i < num_attrs; ++i) {
if (_vertex_attributes[i].ptr.stride == -1) {
setLayout();
i = num_attrs+1;
}
}
// TODO: Make it not static draw all the time
glGenVertexArrays(1, &_VAO);
glBindVertexArray(_VAO);
_vert_data.setData(vert_data);
_elmt_data.bind();
for (GLuint i = 0; i < num_attrs; ++i) {
glVertexAttribPointer(
i,
_vertex_attributes[i].GLSLSize,
_vertex_attributes[i].GLSLType,
_vertex_attributes[i].GLSLNormalization,
_vertex_attributes[i].ptr.stride,
(void*)(_vertex_attributes[i].ptr.offset)
);
glEnableVertexAttribArray(i);
}
glBindVertexArray(0);
}
void DrawBuffer::loadElementBuffer(const std::vector<unsigned int>& elements, unsigned int offset, GLenum gl_primitive_type) {
glBindVertexArray(_VAO);
if (!_elmt_data.isInitialized()) {
std::vector<unsigned int> load_data(offset);
load_data.insert(load_data.end(), elements.begin(), elements.end());
generateElementBuffer(load_data);
} else {
if (gl_primitive_type != _gl_primitive_type) {
throw DrawWarning("Attempting to overload GL primitive type.");
}
_elmt_data.loadData(elements, offset);
}
glBindVertexArray(0);
}
void DrawBuffer::loadVertexBuffer(const std::vector<unsigned char>& data, unsigned int offset) {
glBindVertexArray(_VAO);
if (!_vert_data.isInitialized()) {
std::vector<unsigned char> load_data(offset);
load_data.insert(load_data.end(), data.begin(), data.end());
generateVertexBuffer(load_data);
} else {
_vert_data.loadData(data, offset);
}
glBindVertexArray(0);
}
}