307 lines
9.2 KiB
C++
307 lines
9.2 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(VertexAttributeList vas, GLenum prim_type)
|
|
: _gl_primitive_type(prim_type), _VAO() {
|
|
_vert_data = std::make_shared<Buffer>(GL_ARRAY_BUFFER);
|
|
_elmt_data = std::make_shared<Buffer>(GL_ELEMENT_ARRAY_BUFFER);
|
|
_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 {
|
|
_VAO.bind();
|
|
glDrawElements(_gl_primitive_type, _elmt_data->size() / GLSLTypeSize(GL_INT), GL_UNSIGNED_INT, 0);
|
|
_VAO.unbind();
|
|
}
|
|
|
|
unsigned int DrawBuffer::elementBufferID() const { return _elmt_data->id(); }
|
|
|
|
unsigned int DrawBuffer::vertexBufferID() const { return _vert_data->id(); }
|
|
|
|
RawVec DrawBuffer::vertAttrData(unsigned int i) {
|
|
if (!_vert_data->isInitialized()) {
|
|
throw DrawError("Vertex buffer is not initialized.");
|
|
}
|
|
return _VAO.attributeData(i);
|
|
}
|
|
|
|
RawVec DrawBuffer::vertAttrData(unsigned int i, const RawVec& newdata) {
|
|
if (!(_vert_data->isInitialized())) {
|
|
VertexAttribute va = _VAO.getLayout()[i];
|
|
vertexData(newdata.size() / (va.GLSLSize*GLSLTypeSize(va.GLSLType)));
|
|
std::cout << "From DrawBuffer::vertAttrData(int, RawVec) - vert buf size: " << _vert_data->size() << "\n";
|
|
}
|
|
return _VAO.attributeData(i, newdata);
|
|
}
|
|
|
|
void DrawBuffer::elementData(unsigned int num_prims) {
|
|
elementData(std::vector<unsigned int>(VerticesFromPrimitives(_gl_primitive_type, num_prims)));
|
|
}
|
|
|
|
void DrawBuffer::elementData(const std::vector<unsigned int>& elements) {
|
|
_num_prims = PrimitivesFromVertices(_gl_primitive_type, elements.size());
|
|
_elmt_data->data(vectorToRaw(elements));
|
|
}
|
|
|
|
void DrawBuffer::elementData(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);
|
|
elementData(init_elmts, 0);
|
|
} else {
|
|
_elmt_data->data(vectorToRaw(elements), offset);
|
|
}
|
|
_VAO.unbind();
|
|
}
|
|
|
|
void DrawBuffer::vertexData(unsigned int num_verts) {
|
|
vertexData(RawVec(num_verts * vertSize()));
|
|
}
|
|
|
|
void DrawBuffer::vertexData(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->data(vert_data);
|
|
_VAO.unbind();
|
|
}
|
|
|
|
void DrawBuffer::vertexData(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());
|
|
vertexData(load_data, 0);
|
|
} else {
|
|
try{
|
|
_vert_data->data(data, offset);
|
|
} catch(BufferError& e) {
|
|
THROW_DRAW_ERROR("NB::BufferError in loadVBO:\n\t" + std::string(e.what()));
|
|
}
|
|
}
|
|
_VAO.unbind();
|
|
}
|
|
|
|
// DrawInstanceBufferClass
|
|
DrawInstanceBuffer::DrawInstanceBuffer(
|
|
VertexAttributeList vert_vas,
|
|
VertexAttributeList inst_vas,
|
|
GLenum prim_type
|
|
): DrawBuffer(vert_vas, prim_type) {
|
|
_inst_data = std::make_shared<Buffer>(GL_ARRAY_BUFFER);
|
|
_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()); }
|
|
|
|
unsigned int DrawInstanceBuffer::instanceBufferID() const { return _inst_data->id(); }
|
|
|
|
void DrawInstanceBuffer::instanceData(unsigned int num_inst) {
|
|
instanceData(RawVec(instSize() * num_inst));
|
|
}
|
|
|
|
void DrawInstanceBuffer::instanceData(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->data(inst_data);
|
|
_VAO.unbind();
|
|
}
|
|
|
|
void DrawInstanceBuffer::instanceData(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());
|
|
instanceData(load_data, 0);
|
|
} else {
|
|
try{
|
|
_inst_data->data(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 = 1;
|
|
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 {
|
|
_VAO.bind();
|
|
glDrawElementsInstanced(_gl_primitive_type, _elmt_data->size() / GLSLTypeSize(GL_UNSIGNED_INT), GL_UNSIGNED_INT, (void*)_elmt_data->id(), _num_inst);
|
|
_VAO.unbind();
|
|
}
|
|
|
|
} |