GraphicsTest/Draw.cpp

310 lines
9.0 KiB
C++

#include "Draw.h"
namespace NB{
DrawError::DrawError(
const std::string& msg,
const std::string& file,
int line) : std::runtime_error(NB::formatDebugString(msg, file, line)) {}
uint8_t VerticesFromPrimitives(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;
}
}
uint8_t PrimitivesFromVertices(GLenum type, unsigned int num_verts) {
switch(type) {
case GL_POINTS:
return num_verts;
case GL_LINES:
return num_verts/2;
break;
case GL_LINE_STRIP:
return num_verts-1;
break;
case GL_LINE_LOOP:
return num_verts;
break;
case GL_TRIANGLES:
return num_verts/3;
break;
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
return num_verts-2;
break;
case GL_QUADS:
return num_verts/4;
break;
case GL_QUAD_STRIP:
return num_verts/2 - 1;
break;
default:
return num_verts;
break;
}
}
// DrawBuffer class
DrawBuffer::DrawBuffer(const Shader& shader, VertexAttributeList vas, GLenum prim_type)
: _shader(shader), _vert_data(), _elmt_data(),
_gl_primitive_type(prim_type), _VAO() {
_VAO.addVBO(&_vert_data);
_VAO.changeEBO(&_elmt_data);
try {
throw _VAO.checkValid(vas);
} catch (VAOError vaoe) {
if (vaoe.error) {
_VAO.addVertexAttributes(DrawBuffer::defaultVAO(vas));
} else {
_VAO.addVertexAttributes(vas);
}
}
}
VertexAttributeList DrawBuffer::defaultVAO(VertexAttributeList vert_attrs) {
GLuint vert_id = _vert_data.id();
unsigned int vert_size = 0;
for (const VertexAttribute& va : vert_attrs) {
vert_size += va.GLSLSize * GLSLTypeSize(va.GLSLType);
}
unsigned int curr_byte = 0;
for (VertexAttribute& va : vert_attrs) {
va.ptr.buffer = vert_id;
va.ptr.stride = vert_size;
va.ptr.offset = curr_byte;
va.ptr.divisor = 0;
curr_byte += va.GLSLSize * GLSLTypeSize(va.GLSLType);
}
return vert_attrs;
}
VertexAttributeList DrawBuffer::changeVertLayout(unsigned int i, VertexAttributePointer vap) {
GLuint vert_id = _vert_data.id();
vap.buffer = (vap.buffer) ? vap.buffer : vert_id;
VertexAttributeList vas = _VAO.getLayout();
unsigned int idx = 0;
for (const VertexAttribute& va : vas) {
if (va.ptr.buffer == vert_id) {
if (idx == i) {
return _VAO.changeLayout(i, vap);
}
idx++;
}
}
THROW_DRAW_ERROR("Could not find vertex attribute with index " + std::to_string(i));
}
unsigned int DrawBuffer::vertSize() const { return _VAO.vertSize(_vert_data.id()); }
void DrawBuffer::draw() const {
_shader.use();
_VAO.bind();
glDrawElements(_gl_primitive_type, _elmt_data.capacity(), GL_UNSIGNED_INT, 0);
_VAO.unbind();
}
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;
}
void DrawBuffer::generateEBO(unsigned int num_prims) {
generateEBO(std::vector<unsigned int>(VerticesFromPrimitives(_gl_primitive_type, num_prims)));
}
void DrawBuffer::generateEBO(const std::vector<unsigned int>& elements) {
_num_prims = PrimitivesFromVertices(_gl_primitive_type, elements.size());
_elmt_data.keepLocal(false);
_elmt_data.setData(elements);
}
void DrawBuffer::generateVBO(unsigned int num_verts) {
generateVBO(RawVec(num_verts * vertSize()));
}
void DrawBuffer::generateVBO(const RawVec& vert_data) {
// Check for uninitialized Vertex Pointers. If so, will fallback to default VAO setup.
// Otherwise, set VAO to provided Vertex Atributes.
int vert_size = vertSize();
if (vert_data.size() % vert_size != 0) {
THROW_DRAW_ERROR("Initializing data does not match vertex size of " + std::to_string(vert_size) + ".");
}
_num_verts = vert_data.size() / vert_size;
// TODO: Make it not static draw all the time
_VAO.bind();
_vert_data.keepLocal(false);
_vert_data.setData(vert_data);
_VAO.unbind();
}
void DrawBuffer::loadEBO(const std::vector<unsigned int>& elements, unsigned int offset) {
_VAO.bind();
if (!_elmt_data.isInitialized()) {
std::vector<unsigned int> init_elmts(elements);
init_elmts.insert(init_elmts.cbegin(), offset, 0);
generateEBO(init_elmts);
} else {
_elmt_data.setSubData(elements, offset);
}
_VAO.unbind();
}
void DrawBuffer::loadVBO(const RawVec& data, unsigned int offset) {
_VAO.bind();
if (!_vert_data.isInitialized()) {
RawVec load_data(offset);
load_data.insert(load_data.end(), data.begin(), data.end());
generateVBO(load_data);
} else {
try{
_vert_data.setSubData(data, offset);
} catch(BufferError& e) {
THROW_DRAW_ERROR("NB::BufferError in loadVBO:\n\t" + std::string(e.what()));
}
}
_VAO.unbind();
}
// DrawInstanceBufferClass
DrawInstanceBuffer::DrawInstanceBuffer(
const Shader& shad,
VertexAttributeList vert_vas,
VertexAttributeList inst_vas,
GLenum prim_type
): DrawBuffer(shad, vert_vas, prim_type), _inst_data() {
_VAO.addVBO(&_inst_data);
try {
throw _VAO.checkValid(inst_vas);
} catch (VAOError vaoe) {
if (vaoe.error) {
_VAO.addVertexAttributes(defaultVAO(inst_vas));
} else {
_VAO.addVertexAttributes(inst_vas);
}
}
}
unsigned int DrawInstanceBuffer::instSize() const { return _VAO.vertSize(_inst_data.id()); }
void DrawInstanceBuffer::generateIBO(unsigned int num_inst) {
generateIBO(RawVec(instSize() * num_inst));
}
void DrawInstanceBuffer::generateIBO(const RawVec& inst_data) {
int inst_size = instSize();
if (inst_data.size() % inst_size != 0) {
THROW_DRAW_ERROR("Initializing data does not match instance size of " + std::to_string(inst_size) + ".");
}
_num_inst = inst_data.size() / inst_size;
_VAO.bind();
_inst_data.keepLocal(false);
_inst_data.setData(inst_data);
_VAO.unbind();
}
void DrawInstanceBuffer::loadIBO(const RawVec& data, unsigned int offset) {
_VAO.bind();
if (!_inst_data.isInitialized()) {
RawVec load_data(offset);
load_data.insert(load_data.end(), data.begin(), data.end());
generateIBO(load_data);
} else {
try{
_inst_data.setSubData(data, offset);
} catch(BufferError& e) {
THROW_DRAW_ERROR("NB::BufferError in loadIBO:\n\t" + std::string(e.what()));
}
}
_VAO.unbind();
}
VertexAttributeList DrawInstanceBuffer::defaultVAO(VertexAttributeList inst_attrs) {
GLuint inst_id = _inst_data.id();
unsigned int vert_size = 0;
for (const VertexAttribute& va : inst_attrs) {
vert_size += va.GLSLSize * GLSLTypeSize(va.GLSLType);
}
unsigned int curr_byte = 0;
for (VertexAttribute& va : inst_attrs) {
va.ptr.buffer = inst_id;
va.ptr.stride = vert_size;
va.ptr.offset = curr_byte;
va.ptr.divisor = 0;
curr_byte += va.GLSLSize * GLSLTypeSize(va.GLSLType);
}
return inst_attrs;
}
VertexAttributeList DrawInstanceBuffer::changeInstanceLayout(unsigned int i, VertexAttributePointer vap) {
GLuint inst_id = _inst_data.id();
vap.buffer = (vap.buffer) ? vap.buffer : inst_id;
VertexAttributeList vas = _VAO.getLayout();
unsigned int vas_size = vas.size();
unsigned int inst_idx = 0;
unsigned int idx = 0;
for (const VertexAttribute& va : vas) {
if (va.ptr.buffer == inst_id) {
if (inst_idx == i) {
return _VAO.changeLayout(idx, vap);
}
inst_idx++;
}
idx++;
}
THROW_DRAW_ERROR("Could not find instance attribute with index " + std::to_string(i));
}
void DrawInstanceBuffer::draw() const {
_shader.use();
_VAO.bind();
glDrawElementsInstanced(_gl_primitive_type, _elmt_data.capacity(), GL_UNSIGNED_INT, 0, _num_inst);
_VAO.unbind();
}
}