X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Frender%2Finstancearray.cpp;h=eec72f98dc18144c777f8ae61bb5eb3d18677db0;hp=231bebe1beaabe28df632d9dc0ce1f1b58db0109;hb=HEAD;hpb=3a6eb030fb4eca4c2a317f270704fddf31613130 diff --git a/source/render/instancearray.cpp b/source/render/instancearray.cpp index 231bebe1..20dcb888 100644 --- a/source/render/instancearray.cpp +++ b/source/render/instancearray.cpp @@ -1,37 +1,28 @@ #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 "program.h" #include "renderer.h" #include "technique.h" -#include "vertexsetup.h" using namespace std; namespace Msp { namespace GL { -InstanceArray::InstanceArray(const Object &o): +InstanceArrayBase::InstanceArrayBase(const Object &o, size_t s): object(o), - instance_data(0), - instance_buffer(0), - vtx_setup(0), - matrix_location(-1), - matrix_offset(0) + instance_size(s), + default_count(max(4096U/instance_size, 8U)) { const Technique *tech = object.get_technique(); - const Technique::PassMap &passes = tech->get_passes(); - for(Technique::PassMap::const_iterator i=passes.begin(); i!=passes.end(); ++i) + for(const auto &kvp: tech->get_methods()) { - const Program *shprog = i->second.get_shader_program(); + const Program *shprog = kvp.second.get_shader_program(); if(!shprog) throw invalid_argument("InstanceArray::InstanceArray"); @@ -42,110 +33,179 @@ InstanceArray::InstanceArray(const Object &o): throw invalid_argument("InstanceArray::InstanceArray"); } - if(ARB_vertex_array_object && ARB_instanced_arrays && ARB_draw_instanced) - { - instance_data = new VertexArray((RAW_ATTRIB4,matrix_location, RAW_ATTRIB4,matrix_location+1, RAW_ATTRIB4,matrix_location+2)); - const VertexFormat &fmt = instance_data->get_format(); - matrix_offset = fmt.offset(make_indexed_attribute(RAW_ATTRIB4, matrix_location)); + instance_data.set_format((RAW_ATTRIB4,matrix_location, RAW_ATTRIB4,matrix_location+1, RAW_ATTRIB4,matrix_location+2)); + const VertexFormat &fmt = instance_data.get_format(); + matrix_offset = fmt.offset((RAW_ATTRIB4,matrix_location)); - instance_buffer = new Buffer(ARRAY_BUFFER); - instance_data->use_buffer(instance_buffer); + instance_buffer = new 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); + const Mesh *mesh = object.get_mesh(); + + vtx_setup.set_format_instanced(mesh->get_vertices().get_format(), fmt); + vtx_setup.set_vertex_array(mesh->get_vertices()); + vtx_setup.set_index_buffer(*mesh->get_index_buffer(), mesh->get_batches().front().get_index_type()); + vtx_setup.set_instance_array(instance_data); } -InstanceArray::~InstanceArray() +InstanceArrayBase::~InstanceArrayBase() { - for(vector::iterator i=instances.begin(); i!=instances.end(); ++i) - delete *i; - delete vtx_setup; - delete instance_data; delete instance_buffer; + for(Block &b: storage) + delete[] b.begin; } -void InstanceArray::append(ObjectInstance *inst) +void InstanceArrayBase::add_block(size_t count) { - instances.push_back(inst); - if(instance_data) + storage.emplace_back(); + Block &block = storage.back(); + block.begin = new char[count*instance_size]; + block.end = block.begin+count*instance_size; + + size_t block_index = storage.size()-1; + size_t base = slots.size(); + slots.resize(base+count); + for(size_t i=0; isize()append(); - unsigned req_size = instance_data->get_required_buffer_size(); - if(instance_buffer->get_size()>0 && instance_buffer->get_size()use_buffer(instance_buffer); - } - } - update_instance_matrix(instances.size()-1); + Slot &slot = slots[base+i]; + slot.next_free = base+i+1; + slot.block_index = block_index; + slot.index_in_block = i; } + + if(first_free>0) + slots[last_free].next_free = base; + else + { + first_free = base; + last_free = slots.size()-1; + } + + slots.back().next_free = first_free; } -void InstanceArray::remove(ObjectInstance &inst) +size_t InstanceArrayBase::allocate() { - vector::iterator i = find(instances, &inst); - if(i==instances.end()) - throw key_error(&inst); + if(first_free<0) + add_block(default_count); - delete *i; - *i = instances.back(); - instances.pop_back(); + size_t index = first_free; + Slot &slot = slots[index]; + if(first_free==last_free) + { + first_free = -1; + last_free = -1; + } + else + { + first_free = slot.next_free; + slots[last_free].next_free = first_free; + } + + slot.used = true; + slot.array_index = instance_count++; + if(instance_data.size()get_matrix(); +size_t InstanceArrayBase::find_index(char *addr) const +{ + size_t base = 0; + for(const Block &b: storage) + { + if(addr>=b.begin && addrmodify(instances.size()-1); - for(unsigned i=0; i<12; ++i) - d[matrix_offset+i] = m(i/4, i%4); + throw out_of_range("InstanceArrayBase::find_index"); } -void InstanceArray::render(Renderer &renderer, Tag tag) const +void InstanceArrayBase::release(size_t index) { - if(instances.empty()) - return; + Slot &slot = slots[index]; + + --instance_count; + if(slot.array_index=0) { - const Technique *tech = object.get_technique(); - if(!tech) - throw logic_error("no technique"); - const RenderPass *pass = tech->find_pass(tag); - if(!pass) - return; - - const Mesh *mesh = object.get_mesh(); - mesh->get_vertices().refresh(); - if(instance_buffer->get_size()==0) - instance_buffer->storage(instance_data->get_required_buffer_size()); - instance_data->refresh(); - - Renderer::Push push(renderer); - pass->apply(renderer); - mesh->draw_instanced(renderer, *vtx_setup, instances.size()); + slot.next_free = first_free; + slots[last_free].next_free = index; } else { - for(vector::const_iterator i=instances.begin(); i!=instances.end(); ++i) - { - const Matrix &m = *(*i)->get_matrix(); - for(unsigned j=0; j<3; ++j) - glVertexAttrib4f(matrix_location+j, m(j, 0), m(j, 1), m(j, 2), m(j, 3)); - (*i)->render(renderer, tag); - } + slot.next_free = index; + first_free = index; } + last_free = index; +} + +void InstanceArrayBase::update_instance_matrix(size_t index, const Matrix &matrix) +{ + float *d = reinterpret_cast(instance_data.modify(slots[index].array_index)+matrix_offset); + for(unsigned i=0; i<12; ++i) + d[i] = matrix(i/4, i%4); +} + +void InstanceArrayBase::render(Renderer &renderer, Tag tag) const +{ + if(!instance_count) + return; + + const Technique *tech = object.get_technique(); + if(!tech) + throw logic_error("no technique"); + const RenderMethod *method = tech->find_method(tag); + if(!method) + return; + + const Mesh *mesh = object.get_mesh(); + if(instance_buffer->get_size()==0) + instance_buffer->storage(instance_data.get_required_buffer_size(), STREAMING); + + Renderer::Push push(renderer); + renderer.set_pipeline_key(this, tag.id); + method->apply(renderer); + mesh->draw_instanced(renderer, vtx_setup, instance_count); +} + + +DataFile::Loader::ActionMap InstanceArrayBase::Loader::shared_actions; + +InstanceArrayBase::Loader::Loader(InstanceArrayBase &o): + ObjectLoader(o) +{ + set_actions(shared_actions); +} + +void InstanceArrayBase::Loader::init_actions() +{ + add("instance", &Loader::instance); } } // namespace GL