310 lines
9.0 KiB
C++
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();
|
|
}
|
|
|
|
} |