X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Finstancearray.cpp;fp=source%2Finstancearray.cpp;h=4156c6f37101fec121244444370af8ff55202faf;hb=b0059bd068c99dadfc922584911fcb25a21b737b;hp=0000000000000000000000000000000000000000;hpb=f50822b9e73a6ecdacbc4af4c4d9aba435a72386;p=libs%2Fgl.git diff --git a/source/instancearray.cpp b/source/instancearray.cpp new file mode 100644 index 00000000..4156c6f3 --- /dev/null +++ b/source/instancearray.cpp @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include +#include "buffer.h" +#include "camera.h" +#include "instancearray.h" +#include "mesh.h" +#include "object.h" +#include "objectinstance.h" +#include "renderer.h" +#include "technique.h" +#include "vertexsetup.h" + +using namespace std; + +namespace Msp { +namespace GL { + +InstanceArray::InstanceArray(const Object &o): + object(o), + instance_data(0), + instance_buffer(0), + vtx_setup(0), + matrix_offset(0) +{ + if(ARB_vertex_array_object && ARB_instanced_arrays && ARB_draw_instanced) + { + instance_data = new VertexArray((ATTRIB4,12, ATTRIB4,13, ATTRIB4,14)); + const VertexFormat &fmt = instance_data->get_format(); + matrix_offset = fmt.offset(make_indexed_component(ATTRIB4, 12)); + + instance_buffer = new Buffer(ARRAY_BUFFER); + instance_data->use_buffer(instance_buffer); + + vtx_setup = new VertexSetup; + vtx_setup->set_vertex_array(object.get_mesh()->get_vertices()); + vtx_setup->set_index_buffer(*object.get_mesh()->get_index_buffer()); + vtx_setup->set_instance_array(instance_data); + } + else + static Require req(ARB_vertex_shader); +} + +InstanceArray::~InstanceArray() +{ + delete vtx_setup; + delete instance_data; + delete instance_buffer; +} + +void InstanceArray::append(ObjectInstance *inst) +{ + instances.push_back(inst); + if(instance_data) + { + if(instance_data->size()append(); + update_instance_matrix(instances.size()-1); + } +} + +void InstanceArray::remove(ObjectInstance &inst) +{ + vector::iterator i = find(instances, &inst); + if(i==instances.end()) + throw key_error(&inst); + + delete *i; + *i = instances.back(); + instances.pop_back(); +} + +void InstanceArray::update_instance_matrix(unsigned index) +{ + if(!instance_data) + return; + + const Matrix &m = *instances[index]->get_matrix(); + + float *d = instance_data->modify(instances.size()-1); + for(unsigned i=0; i<12; ++i) + d[matrix_offset+i] = m(i/4, i%4); +} + +void InstanceArray::render(Renderer &renderer, const Tag &tag) const +{ + if(instances.empty()) + return; + + if(instance_data) + { + const Technique *tech = object.get_technique(); + if(!tech) + throw logic_error("no technique"); + if(!tech->has_pass(tag)) + return; + const RenderPass &pass = tech->get_pass(tag); + + const Mesh *mesh = object.get_mesh(); + mesh->get_vertices().refresh(); + instance_data->refresh(); + + Renderer::Push push(renderer); + pass.apply(renderer); + mesh->draw_instanced(renderer, *vtx_setup, instances.size()); + } + else + { + for(vector::const_iterator i=instances.begin(); i!=instances.end(); ++i) + { + const Matrix &m = *(*i)->get_matrix(); + glVertexAttrib4f(12, m(0, 0), m(0, 1), m(0, 2), m(0, 3)); + glVertexAttrib4f(13, m(1, 0), m(1, 1), m(1, 2), m(1, 3)); + glVertexAttrib4f(14, m(2, 0), m(2, 1), m(2, 2), m(2, 3)); + (*i)->render(renderer, tag); + } + } +} + +} // namespace GL +} // namespace Msp