]> git.tdb.fi Git - libs/gl.git/blob - source/instancearray.cpp
Initial support for instanced rendering
[libs/gl.git] / source / instancearray.cpp
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>
7 #include "buffer.h"
8 #include "camera.h"
9 #include "instancearray.h"
10 #include "mesh.h"
11 #include "object.h"
12 #include "objectinstance.h"
13 #include "renderer.h"
14 #include "technique.h"
15 #include "vertexsetup.h"
16
17 using namespace std;
18
19 namespace Msp {
20 namespace GL {
21
22 InstanceArray::InstanceArray(const Object &o):
23         object(o),
24         instance_data(0),
25         instance_buffer(0),
26         vtx_setup(0),
27         matrix_offset(0)
28 {
29         if(ARB_vertex_array_object && ARB_instanced_arrays && ARB_draw_instanced)
30         {
31                 instance_data = new VertexArray((ATTRIB4,12, ATTRIB4,13, ATTRIB4,14));
32                 const VertexFormat &fmt = instance_data->get_format();
33                 matrix_offset = fmt.offset(make_indexed_component(ATTRIB4, 12));
34
35                 instance_buffer = new Buffer(ARRAY_BUFFER);
36                 instance_data->use_buffer(instance_buffer);
37
38                 vtx_setup = new VertexSetup;
39                 vtx_setup->set_vertex_array(object.get_mesh()->get_vertices());
40                 vtx_setup->set_index_buffer(*object.get_mesh()->get_index_buffer());
41                 vtx_setup->set_instance_array(instance_data);
42         }
43         else
44                 static Require req(ARB_vertex_shader);
45 }
46
47 InstanceArray::~InstanceArray()
48 {
49         delete vtx_setup;
50         delete instance_data;
51         delete instance_buffer;
52 }
53
54 void InstanceArray::append(ObjectInstance *inst)
55 {
56         instances.push_back(inst);
57         if(instance_data)
58         {
59                 if(instance_data->size()<instances.size())
60                         instance_data->append();
61                 update_instance_matrix(instances.size()-1);
62         }
63 }
64
65 void InstanceArray::remove(ObjectInstance &inst)
66 {
67         vector<ObjectInstance *>::iterator i = find(instances, &inst);
68         if(i==instances.end())
69                 throw key_error(&inst);
70
71         delete *i;
72         *i = instances.back();
73         instances.pop_back();
74 }
75
76 void InstanceArray::update_instance_matrix(unsigned index)
77 {
78         if(!instance_data)
79                 return;
80
81         const Matrix &m = *instances[index]->get_matrix();
82
83         float *d = instance_data->modify(instances.size()-1);
84         for(unsigned i=0; i<12; ++i)
85                 d[matrix_offset+i] = m(i/4, i%4);
86 }
87
88 void InstanceArray::render(Renderer &renderer, const Tag &tag) const
89 {
90         if(instances.empty())
91                 return;
92
93         if(instance_data)
94         {
95                 const Technique *tech = object.get_technique();
96                 if(!tech)
97                         throw logic_error("no technique");
98                 if(!tech->has_pass(tag))
99                         return;
100                 const RenderPass &pass = tech->get_pass(tag);
101
102                 const Mesh *mesh = object.get_mesh();
103                 mesh->get_vertices().refresh();
104                 instance_data->refresh();
105
106                 Renderer::Push push(renderer);
107                 pass.apply(renderer);
108                 mesh->draw_instanced(renderer, *vtx_setup, instances.size());
109         }
110         else
111         {
112                 for(vector<ObjectInstance *>::const_iterator i=instances.begin(); i!=instances.end(); ++i)
113                 {
114                         const Matrix &m = *(*i)->get_matrix();
115                         glVertexAttrib4f(12, m(0, 0), m(0, 1), m(0, 2), m(0, 3));
116                         glVertexAttrib4f(13, m(1, 0), m(1, 1), m(1, 2), m(1, 3));
117                         glVertexAttrib4f(14, m(2, 0), m(2, 1), m(2, 2), m(2, 3));
118                         (*i)->render(renderer, tag);
119                 }
120         }
121 }
122
123 } // namespace GL
124 } // namespace Msp