]> git.tdb.fi Git - libs/gl.git/blob - source/mesh.cpp
Make buffer storage immutable and use ARB_buffer_storage
[libs/gl.git] / source / mesh.cpp
1 #include <msp/gl/extensions/arb_vertex_array_object.h>
2 #include <msp/gl/extensions/arb_vertex_buffer_object.h>
3 #include <msp/gl/extensions/arb_vertex_shader.h>
4 #include "buffer.h"
5 #include "error.h"
6 #include "mesh.h"
7 #include "renderer.h"
8 #include "resourcemanager.h"
9 #include "vertexsetup.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace GL {
15
16 Mesh::Mesh(ResourceManager *rm):
17         vertices(VERTEX3)
18 {
19         init(rm);
20 }
21
22 Mesh::Mesh(const VertexFormat &f, ResourceManager *rm):
23         vertices(f)
24 {
25         init(rm);
26 }
27
28 void Mesh::init(ResourceManager *rm)
29 {
30         vbuf = 0;
31         ibuf = 0;
32         dirty = 0;
33         disallow_rendering = false;
34         winding = 0;
35
36         if(rm)
37                 set_manager(rm);
38 }
39
40 Mesh::~Mesh()
41 {
42         set_manager(0);
43         delete vbuf;
44         delete ibuf;
45 }
46
47 void Mesh::clear()
48 {
49         vertices.clear();
50         batches.clear();
51 }
52
53 void Mesh::check_buffers(unsigned mask)
54 {
55         if(mask&VERTEX_BUFFER)
56         {
57                 unsigned req_size = vertices.get_required_buffer_size();
58                 if(!vbuf || (vbuf->get_size()>0 && vbuf->get_size()<req_size))
59                 {
60                         delete vbuf;
61                         vbuf = new Buffer(ARRAY_BUFFER);
62                         vertices.use_buffer(vbuf);
63                         vtx_setup.set_vertex_array(vertices);
64                         dirty |= VERTEX_BUFFER;
65                 }
66         }
67
68         if(mask&INDEX_BUFFER)
69         {
70                 unsigned req_size = (batches.empty() ? 0 : batches.front().get_required_buffer_size());
71                 if(!ibuf || (ibuf->get_size()>0 && ibuf->get_size()<req_size))
72                 {
73                         delete ibuf;
74                         ibuf = new Buffer(ELEMENT_ARRAY_BUFFER);
75                         if(!batches.empty())
76                                 batches.front().change_buffer(ibuf);
77                         vtx_setup.set_index_buffer(*ibuf);
78                         dirty |= INDEX_BUFFER;
79                 }
80         }
81 }
82
83 unsigned Mesh::get_n_vertices() const
84 {
85         return vertices.size();
86 }
87
88 float *Mesh::modify_vertex(unsigned i)
89 {
90         return vertices.modify(i);
91 }
92
93 void Mesh::add_batch(const Batch &b)
94 {
95         if(batches.empty())
96         {
97                 batches.push_back(b);
98                 if(ibuf)
99                         batches.back().use_buffer(ibuf);
100         }
101         else if(batches.back().can_append(b.get_type()))
102                 batches.back().append(b);
103         else
104         {
105                 bool reallocate = (batches.size()==batches.capacity());
106                 if(reallocate)
107                 {
108                         for(vector<Batch>::iterator i=batches.end(); i!=batches.begin(); )
109                                 (--i)->use_buffer(0);
110                 }
111
112                 Batch *prev = &batches.back();
113                 batches.push_back(b);
114                 if(reallocate)
115                 {
116                         prev = 0;
117                         for(vector<Batch>::iterator i=batches.begin(); i!=batches.end(); ++i)
118                         {
119                                 i->use_buffer(ibuf, prev);
120                                 prev = &*i;
121                         }
122                 }
123                 else
124                         batches.back().use_buffer(ibuf, prev);
125         }
126
127         check_buffers(INDEX_BUFFER);
128 }
129
130 void Mesh::set_winding(const WindingTest *w)
131 {
132         winding = w;
133 }
134
135 void Mesh::draw(Renderer &renderer) const
136 {
137         draw(renderer, 0, 0);
138 }
139
140 void Mesh::draw_instanced(Renderer &renderer, const VertexSetup &vs, unsigned count) const
141 {
142         if(vs.get_vertex_array()!=&vertices)
143                 throw invalid_argument("Mesh::draw_instanced");
144
145         draw(renderer, &vs, count);
146 }
147
148 void Mesh::draw(Renderer &renderer, const VertexSetup *vs, unsigned count) const
149 {
150         if(manager)
151         {
152                 manager->resource_used(*this);
153                 if(disallow_rendering)
154                         return;
155         }
156
157         if(dirty)
158                 resize_buffers();
159
160         renderer.set_vertex_setup(vs ? vs : &vtx_setup);
161         renderer.set_winding_test(winding);
162
163         if(!count)
164         {
165                 for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
166                         renderer.draw(*i);
167         }
168         else
169         {
170                 for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
171                         renderer.draw_instanced(*i, count);
172         }
173 }
174
175 void Mesh::resize_buffers() const
176 {
177         if(dirty&VERTEX_BUFFER)
178                 vbuf->storage(vertices.get_required_buffer_size());
179         if(dirty&INDEX_BUFFER)
180                 ibuf->storage(batches.front().get_required_buffer_size());
181         dirty = 0;
182 }
183
184 Resource::AsyncLoader *Mesh::load(IO::Seekable &io, const Resources *)
185 {
186         return new AsyncLoader(*this, io);
187 }
188
189 UInt64 Mesh::get_data_size() const
190 {
191         UInt64 size = 0;
192         if(vbuf)
193                 size += vbuf->get_size();
194         if(ibuf)
195                 size += ibuf->get_size();
196         return size;
197 }
198
199 void Mesh::unload()
200 {
201         vertices.clear();
202         vertices.use_buffer(0);
203         batches.clear();
204         delete vbuf;
205         delete ibuf;
206         vbuf = 0;
207         ibuf = 0;
208 }
209
210
211 Mesh::Loader::Loader(Mesh &m):
212         DataFile::ObjectLoader<Mesh>(m)
213 {
214         add("batch",    &Loader::batch);
215         add("vertices", &Loader::vertices);
216         add("winding",  &Loader::winding);
217 }
218
219 void Mesh::Loader::vertices(const vector<VertexComponent> &c)
220 {
221         if(c.empty())
222                 throw invalid_argument("No vertex components");
223
224         VertexFormat fmt;
225         for(vector<VertexComponent>::const_iterator i=c.begin(); i!=c.end(); ++i)
226                 fmt = (fmt, *i);
227         obj.vertices.reset(fmt);
228         load_sub(obj.vertices);
229         obj.check_buffers(VERTEX_BUFFER);
230 }
231
232 void Mesh::Loader::batch(PrimitiveType p)
233 {
234         Batch btc(p);
235         load_sub(btc);
236         obj.add_batch(btc);
237 }
238
239 void Mesh::Loader::winding(FaceWinding w)
240 {
241         if(w==CLOCKWISE)
242                 obj.winding = &WindingTest::clockwise();
243         else if(w==COUNTERCLOCKWISE)
244                 obj.winding = &WindingTest::counterclockwise();
245 }
246
247
248 Mesh::AsyncLoader::AsyncLoader(Mesh &m, IO::Seekable &i):
249         mesh(m),
250         io(i),
251         vertex_updater(0),
252         index_updater(0),
253         phase(0)
254 {
255         mesh.disallow_rendering = true;
256         mesh.check_buffers(VERTEX_BUFFER|INDEX_BUFFER);
257 }
258
259 Mesh::AsyncLoader::~AsyncLoader()
260 {
261         mesh.disallow_rendering = false;
262         delete vertex_updater;
263         delete index_updater;
264 }
265
266 bool Mesh::AsyncLoader::needs_sync() const
267 {
268         return phase%2;
269 }
270
271 bool Mesh::AsyncLoader::process()
272 {
273         if(phase==0)
274         {
275                 // TODO use correct filename
276                 DataFile::Parser parser(io, "async");
277                 Loader loader(mesh);
278                 loader.load(parser);
279         }
280         else if(phase==1)
281         {
282                 mesh.resize_buffers();
283                 vertex_updater = mesh.vertices.refresh_async();
284                 if(!mesh.batches.empty())
285                         index_updater = mesh.batches.front().refresh_async();
286         }
287         else if(phase==2)
288         {
289                 if(vertex_updater)
290                         vertex_updater->upload_data();
291                 if(index_updater)
292                         index_updater->upload_data();
293         }
294         else if(phase==3)
295         {
296                 delete vertex_updater;
297                 vertex_updater = 0;
298                 delete index_updater;
299                 index_updater = 0;
300         }
301
302         ++phase;
303         if(phase==1 && !mesh.vbuf && !mesh.ibuf)
304                 phase += 3;
305         return phase>3;
306 }
307
308 } // namespace GL
309 } // namespace Msp