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