1 #include <msp/core/algorithm.h>
2 #include <msp/core/maputils.h>
3 #include <msp/gl/extensions/arb_draw_instanced.h>
4 #include <msp/gl/extensions/arb_instanced_arrays.h>
5 #include <msp/gl/extensions/arb_vertex_array_object.h>
6 #include <msp/gl/extensions/arb_vertex_shader.h>
9 #include "instancearray.h"
12 #include "objectinstance.h"
14 #include "technique.h"
15 #include "vertexsetup.h"
22 InstanceArray::InstanceArray(const Object &o):
30 const Technique *tech = object.get_technique();
31 const Technique::PassMap &passes = tech->get_passes();
32 for(Technique::PassMap::const_iterator i=passes.begin(); i!=passes.end(); ++i)
34 const Program *shprog = i->second.get_shader_program();
36 throw invalid_argument("InstanceArray::InstanceArray");
38 int loc = shprog->get_attribute_location("instance_transform");
40 matrix_location = loc;
41 else if(loc!=matrix_location)
42 throw invalid_argument("InstanceArray::InstanceArray");
45 if(ARB_vertex_array_object && ARB_instanced_arrays && ARB_draw_instanced)
47 instance_data = new VertexArray((ATTRIB4,matrix_location, ATTRIB4,matrix_location+1, ATTRIB4,matrix_location+2));
48 const VertexFormat &fmt = instance_data->get_format();
49 matrix_offset = fmt.offset(make_indexed_component(ATTRIB4, matrix_location));
51 instance_buffer = new Buffer(ARRAY_BUFFER);
52 instance_data->use_buffer(instance_buffer);
54 vtx_setup = new VertexSetup;
55 vtx_setup->set_vertex_array(object.get_mesh()->get_vertices());
56 vtx_setup->set_index_buffer(*object.get_mesh()->get_index_buffer());
57 vtx_setup->set_instance_array(instance_data);
60 static Require req(ARB_vertex_shader);
63 InstanceArray::~InstanceArray()
65 for(std::vector<ObjectInstance *>::iterator i=instances.begin(); i!=instances.end(); ++i)
69 delete instance_buffer;
72 void InstanceArray::append(ObjectInstance *inst)
74 instances.push_back(inst);
77 if(instance_data->size()<instances.size())
78 instance_data->append();
79 update_instance_matrix(instances.size()-1);
83 void InstanceArray::remove(ObjectInstance &inst)
85 vector<ObjectInstance *>::iterator i = find(instances, &inst);
86 if(i==instances.end())
87 throw key_error(&inst);
90 *i = instances.back();
94 void InstanceArray::update_instance_matrix(unsigned index)
99 const Matrix &m = *instances[index]->get_matrix();
101 float *d = instance_data->modify(instances.size()-1);
102 for(unsigned i=0; i<12; ++i)
103 d[matrix_offset+i] = m(i/4, i%4);
106 void InstanceArray::render(Renderer &renderer, const Tag &tag) const
108 if(instances.empty())
113 const Technique *tech = object.get_technique();
115 throw logic_error("no technique");
116 if(!tech->has_pass(tag))
118 const RenderPass &pass = tech->get_pass(tag);
120 const Mesh *mesh = object.get_mesh();
121 mesh->get_vertices().refresh();
122 instance_data->refresh();
124 Renderer::Push push(renderer);
125 pass.apply(renderer);
126 mesh->draw_instanced(renderer, *vtx_setup, instances.size());
130 for(vector<ObjectInstance *>::const_iterator i=instances.begin(); i!=instances.end(); ++i)
132 const Matrix &m = *(*i)->get_matrix();
133 for(unsigned j=0; j<3; ++j)
134 glVertexAttrib4f(matrix_location+j, m(j, 0), m(j, 1), m(j, 2), m(j, 3));
135 (*i)->render(renderer, tag);