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