]> git.tdb.fi Git - libs/gl.git/blob - source/render/instancearray.cpp
Add an abstraction for queries
[libs/gl.git] / source / render / instancearray.cpp
1 #include <msp/core/algorithm.h>
2 #include <msp/core/maputils.h>
3 #include "buffer.h"
4 #include "camera.h"
5 #include "instancearray.h"
6 #include "mesh.h"
7 #include "object.h"
8 #include "objectinstance.h"
9 #include "program.h"
10 #include "renderer.h"
11 #include "technique.h"
12
13 using namespace std;
14
15 namespace Msp {
16 namespace GL {
17
18 InstanceArray::InstanceArray(const Object &o):
19         object(o),
20         instance_buffer(0),
21         matrix_location(-1),
22         matrix_offset(0)
23 {
24         const Technique *tech = object.get_technique();
25         for(const auto &kvp: tech->get_passes())
26         {
27                 const Program *shprog = kvp.second.get_shader_program();
28                 if(!shprog)
29                         throw invalid_argument("InstanceArray::InstanceArray");
30
31                 int loc = shprog->get_attribute_location("instance_transform");
32                 if(matrix_location<0)
33                         matrix_location = loc;
34                 else if(loc!=matrix_location)
35                         throw invalid_argument("InstanceArray::InstanceArray");
36         }
37
38         instance_data.set_format((RAW_ATTRIB4,matrix_location, RAW_ATTRIB4,matrix_location+1, RAW_ATTRIB4,matrix_location+2));
39         const VertexFormat &fmt = instance_data.get_format();
40         matrix_offset = fmt.offset((RAW_ATTRIB4,matrix_location));
41
42         instance_buffer = new Buffer;
43         instance_data.use_buffer(instance_buffer);
44
45         const Mesh *mesh = object.get_mesh();
46
47         vtx_setup.set_format_instanced(mesh->get_vertices().get_format(), fmt);
48         vtx_setup.set_vertex_array(mesh->get_vertices());
49         vtx_setup.set_index_buffer(*mesh->get_index_buffer(), mesh->get_batches().front().get_index_type());
50         vtx_setup.set_instance_array(instance_data);
51 }
52
53 InstanceArray::~InstanceArray()
54 {
55         for(ObjectInstance *i: instances)
56                 delete i;
57         delete instance_buffer;
58 }
59
60 void InstanceArray::append(ObjectInstance *inst)
61 {
62         instances.push_back(inst);
63         if(instance_data.size()<instances.size())
64         {
65                 instance_data.append();
66                 unsigned req_size = instance_data.get_required_buffer_size();
67                 if(instance_buffer->get_size()>0 && instance_buffer->get_size()<req_size)
68                 {
69                         delete instance_buffer;
70                         instance_buffer = new Buffer;
71                         instance_data.use_buffer(instance_buffer);
72                 }
73         }
74         update_instance_matrix(instances.size()-1);
75 }
76
77 void InstanceArray::remove(ObjectInstance &inst)
78 {
79         auto i = find(instances, &inst);
80         if(i==instances.end())
81                 throw key_error(&inst);
82
83         delete *i;
84         *i = instances.back();
85         instances.pop_back();
86 }
87
88 void InstanceArray::update_instance_matrix(unsigned index)
89 {
90         const Matrix &m = *instances[index]->get_matrix();
91
92         float *d = reinterpret_cast<float *>(instance_data.modify(instances.size()-1)+matrix_offset);
93         for(unsigned i=0; i<12; ++i)
94                 d[i] = m(i/4, i%4);
95 }
96
97 void InstanceArray::render(Renderer &renderer, Tag tag) const
98 {
99         if(instances.empty())
100                 return;
101
102         const Technique *tech = object.get_technique();
103         if(!tech)
104                 throw logic_error("no technique");
105         const RenderPass *pass = tech->find_pass(tag);
106         if(!pass)
107                 return;
108
109         const Mesh *mesh = object.get_mesh();
110         mesh->get_vertices().refresh();
111         if(instance_buffer->get_size()==0)
112                 instance_buffer->storage(instance_data.get_required_buffer_size());
113         instance_data.refresh();
114
115         Renderer::Push push(renderer);
116         pass->apply(renderer);
117         mesh->draw_instanced(renderer, vtx_setup, instances.size());
118 }
119
120 } // namespace GL
121 } // namespace Msp