]> git.tdb.fi Git - libs/gl.git/blob - source/core/mesh.cpp
Only allow VertexArray's format to be set once
[libs/gl.git] / source / core / 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 <msp/gl/extensions/khr_debug.h>
5 #include "buffer.h"
6 #include "error.h"
7 #include "mesh.h"
8 #include "renderer.h"
9 #include "resourcemanager.h"
10 #include "vertexsetup.h"
11
12 using namespace std;
13
14 namespace Msp {
15 namespace GL {
16
17 Mesh::Mesh(ResourceManager *rm)
18 {
19         init(rm);
20 }
21
22 Mesh::Mesh(const VertexFormat &f, ResourceManager *rm)
23 {
24         init(rm);
25         storage(f);
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         batches.clear();
44         delete vbuf;
45         delete ibuf;
46 }
47
48 void Mesh::storage(const VertexFormat &fmt)
49 {
50         if(!vertices.get_format().empty())
51                 throw invalid_operation("Mesh::storage");
52
53         vertices.set_format(fmt);
54         vtx_setup.set_format(fmt);
55 }
56
57 void Mesh::clear()
58 {
59         vertices.clear();
60         batches.clear();
61 }
62
63 void Mesh::check_buffers(unsigned mask)
64 {
65         if(mask&VERTEX_BUFFER)
66         {
67                 unsigned req_size = vertices.get_required_buffer_size();
68                 if(!vbuf || (vbuf->get_size()>0 && vbuf->get_size()<req_size))
69                 {
70                         delete vbuf;
71                         vbuf = new Buffer(ARRAY_BUFFER);
72                         vertices.use_buffer(vbuf);
73                         vtx_setup.set_vertex_array(vertices);
74                         dirty |= VERTEX_BUFFER;
75
76 #ifdef DEBUG
77                         if(!debug_name.empty())
78                                 vbuf->set_debug_name(debug_name+" [VBO]");
79 #endif
80                 }
81         }
82
83         if(mask&INDEX_BUFFER)
84         {
85                 unsigned req_size = (batches.empty() ? 0 : batches.front().get_required_buffer_size());
86                 if(!ibuf || (ibuf->get_size()>0 && ibuf->get_size()<req_size))
87                 {
88                         delete ibuf;
89                         ibuf = new Buffer(ELEMENT_ARRAY_BUFFER);
90                         if(!batches.empty())
91                                 batches.front().change_buffer(ibuf);
92                         vtx_setup.set_index_buffer(*ibuf);
93                         dirty |= INDEX_BUFFER;
94
95 #ifdef DEBUG
96                         if(!debug_name.empty())
97                                 vbuf->set_debug_name(debug_name+" [IBO]");
98 #endif
99                 }
100         }
101 }
102
103 unsigned Mesh::get_n_vertices() const
104 {
105         return vertices.size();
106 }
107
108 float *Mesh::modify_vertex(unsigned i)
109 {
110         if(vertices.get_format().empty())
111                 throw invalid_operation("Mesh::modify_vertex");
112         return vertices.modify(i);
113 }
114
115 void Mesh::add_batch(const Batch &b)
116 {
117         if(batches.empty())
118         {
119                 batches.push_back(b);
120                 if(ibuf)
121                         batches.back().use_buffer(ibuf);
122         }
123         else if(batches.back().can_append(b.get_type()))
124                 batches.back().append(b);
125         else
126         {
127                 bool reallocate = (batches.size()==batches.capacity());
128                 if(reallocate)
129                 {
130                         for(vector<Batch>::iterator i=batches.end(); i!=batches.begin(); )
131                                 (--i)->use_buffer(0);
132                 }
133
134                 Batch *prev = &batches.back();
135                 batches.push_back(b);
136                 if(reallocate)
137                 {
138                         prev = 0;
139                         for(vector<Batch>::iterator i=batches.begin(); i!=batches.end(); ++i)
140                         {
141                                 i->use_buffer(ibuf, prev);
142                                 prev = &*i;
143                         }
144                 }
145                 else
146                         batches.back().use_buffer(ibuf, prev);
147         }
148
149         check_buffers(INDEX_BUFFER);
150 }
151
152 void Mesh::set_winding(const WindingTest *w)
153 {
154         winding = w;
155 }
156
157 void Mesh::draw(Renderer &renderer) const
158 {
159         draw(renderer, 0, 0);
160 }
161
162 void Mesh::draw_instanced(Renderer &renderer, const VertexSetup &vs, unsigned count) const
163 {
164         if(vs.get_vertex_array()!=&vertices)
165                 throw invalid_argument("Mesh::draw_instanced");
166
167         draw(renderer, &vs, count);
168 }
169
170 void Mesh::draw(Renderer &renderer, const VertexSetup *vs, unsigned count) const
171 {
172         if(manager)
173         {
174                 manager->resource_used(*this);
175                 if(disallow_rendering)
176                         return;
177         }
178
179         if(batches.empty())
180                 return;
181
182         if(dirty)
183                 resize_buffers();
184
185         renderer.set_vertex_setup(vs ? vs : &vtx_setup);
186         renderer.set_winding_test(winding);
187
188         if(!count)
189         {
190                 for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
191                         renderer.draw(*i);
192         }
193         else
194         {
195                 for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
196                         renderer.draw_instanced(*i, count);
197         }
198 }
199
200 void Mesh::resize_buffers() const
201 {
202         if(dirty&VERTEX_BUFFER)
203                 vbuf->storage(vertices.get_required_buffer_size());
204         if((dirty&INDEX_BUFFER) && !batches.empty())
205                 ibuf->storage(batches.front().get_required_buffer_size());
206         dirty = 0;
207 }
208
209 Resource::AsyncLoader *Mesh::load(IO::Seekable &io, const Resources *)
210 {
211         return new AsyncLoader(*this, io);
212 }
213
214 UInt64 Mesh::get_data_size() const
215 {
216         UInt64 size = 0;
217         if(vbuf)
218                 size += vbuf->get_size();
219         if(ibuf)
220                 size += ibuf->get_size();
221         return size;
222 }
223
224 void Mesh::unload()
225 {
226         vertices.clear();
227         vertices.use_buffer(0);
228         batches.clear();
229         vtx_setup.unload();
230         delete vbuf;
231         delete ibuf;
232         vbuf = 0;
233         ibuf = 0;
234 }
235
236 void Mesh::set_debug_name(const string &name)
237 {
238 #ifdef DEBUG
239         debug_name = name;
240         if(vbuf)
241                 vbuf->set_debug_name(name+" [VBO]");
242         if(ibuf)
243                 ibuf->set_debug_name(name+" [IBO]");
244         vtx_setup.set_debug_name(name+" [VAO]");
245 #else
246         (void)name;
247 #endif
248 }
249
250
251 Mesh::Loader::Loader(Mesh &m, bool g):
252         DataFile::ObjectLoader<Mesh>(m),
253         allow_gl_calls(g)
254 {
255         add("batch",    &Loader::batch);
256         add("storage",  &Loader::storage);
257         add("vertices", &Loader::vertices);
258         add("vertices", &Loader::vertices_with_format);
259         add("winding",  &Loader::winding);
260 }
261
262 void Mesh::Loader::storage(const vector<VertexAttribute> &a)
263 {
264         if(a.empty())
265                 throw invalid_argument("No vertex attributes");
266
267         VertexFormat fmt;
268         for(vector<VertexAttribute>::const_iterator i=a.begin(); i!=a.end(); ++i)
269                 fmt = (fmt, *i);
270         obj.storage(fmt);
271 }
272
273 void Mesh::Loader::vertices()
274 {
275         load_sub(obj.vertices);
276         if(allow_gl_calls)
277                 obj.check_buffers(VERTEX_BUFFER);
278 }
279
280 void Mesh::Loader::vertices_with_format(const vector<VertexAttribute> &a)
281 {
282         storage(a);
283         vertices();
284 }
285
286 void Mesh::Loader::batch(PrimitiveType p)
287 {
288         Batch btc(p);
289         load_sub(btc);
290         obj.add_batch(btc);
291 }
292
293 void Mesh::Loader::winding(FaceWinding w)
294 {
295         if(w==CLOCKWISE)
296                 obj.winding = &WindingTest::clockwise();
297         else if(w==COUNTERCLOCKWISE)
298                 obj.winding = &WindingTest::counterclockwise();
299 }
300
301
302 Mesh::AsyncLoader::AsyncLoader(Mesh &m, IO::Seekable &i):
303         mesh(m),
304         io(i),
305         vertex_updater(0),
306         index_updater(0),
307         phase(0)
308 {
309         mesh.disallow_rendering = true;
310         mesh.check_buffers(VERTEX_BUFFER|INDEX_BUFFER);
311 }
312
313 Mesh::AsyncLoader::~AsyncLoader()
314 {
315         mesh.disallow_rendering = false;
316         delete vertex_updater;
317         delete index_updater;
318 }
319
320 bool Mesh::AsyncLoader::needs_sync() const
321 {
322         return phase%2;
323 }
324
325 bool Mesh::AsyncLoader::process()
326 {
327         if(phase==0)
328         {
329                 // TODO use correct filename
330                 DataFile::Parser parser(io, "async");
331                 Loader loader(mesh, false);
332                 loader.load(parser);
333         }
334         else if(phase==1)
335         {
336                 mesh.resize_buffers();
337                 vertex_updater = mesh.vertices.refresh_async();
338                 if(!mesh.batches.empty())
339                         index_updater = mesh.batches.front().refresh_async();
340         }
341         else if(phase==2)
342         {
343                 if(vertex_updater)
344                         vertex_updater->upload_data();
345                 if(index_updater)
346                         index_updater->upload_data();
347         }
348         else if(phase==3)
349         {
350                 delete vertex_updater;
351                 vertex_updater = 0;
352                 delete index_updater;
353                 index_updater = 0;
354         }
355
356         ++phase;
357         if(phase==1 && !mesh.vbuf && !mesh.ibuf)
358                 phase += 3;
359         return phase>3;
360 }
361
362 } // namespace GL
363 } // namespace Msp