]> git.tdb.fi Git - libs/gl.git/blob - source/core/mesh.cpp
Use the same index type for all of a Mesh's batches
[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         face_winding = NON_MANIFOLD;
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;
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;
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         DataType existing_type = batches.front().get_index_type();
150         DataType added_type = batches.back().get_index_type();
151         if(existing_type!=added_type)
152         {
153                 if(get_type_size(existing_type)>get_type_size(added_type))
154                         batches.back().set_index_type(existing_type);
155                 else
156                 {
157                         for(vector<Batch>::iterator i=batches.begin(); i!=batches.end(); ++i)
158                                 i->set_index_type(added_type);
159                 }
160         }
161
162         check_buffers(INDEX_BUFFER);
163 }
164
165 void Mesh::set_winding(FaceWinding w)
166 {
167         face_winding = w;
168 }
169
170 void Mesh::draw(Renderer &renderer) const
171 {
172         draw(renderer, 0, 0);
173 }
174
175 void Mesh::draw_instanced(Renderer &renderer, const VertexSetup &vs, unsigned count) const
176 {
177         if(vs.get_vertex_array()!=&vertices)
178                 throw invalid_argument("Mesh::draw_instanced");
179
180         draw(renderer, &vs, count);
181 }
182
183 void Mesh::draw(Renderer &renderer, const VertexSetup *vs, unsigned count) const
184 {
185         if(manager)
186         {
187                 manager->resource_used(*this);
188                 if(disallow_rendering)
189                         return;
190         }
191
192         if(batches.empty())
193                 return;
194
195         if(dirty)
196                 resize_buffers();
197
198         renderer.set_vertex_setup(vs ? vs : &vtx_setup);
199         renderer.set_front_face(face_winding);
200
201         if(!count)
202         {
203                 for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
204                         renderer.draw(*i);
205         }
206         else
207         {
208                 for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
209                         renderer.draw_instanced(*i, count);
210         }
211 }
212
213 void Mesh::resize_buffers() const
214 {
215         if(dirty&VERTEX_BUFFER)
216                 vbuf->storage(vertices.get_required_buffer_size());
217         if((dirty&INDEX_BUFFER) && !batches.empty())
218                 ibuf->storage(batches.front().get_required_buffer_size());
219         dirty = 0;
220 }
221
222 Resource::AsyncLoader *Mesh::load(IO::Seekable &io, const Resources *)
223 {
224         return new AsyncLoader(*this, io);
225 }
226
227 UInt64 Mesh::get_data_size() const
228 {
229         UInt64 size = 0;
230         if(vbuf)
231                 size += vbuf->get_size();
232         if(ibuf)
233                 size += ibuf->get_size();
234         return size;
235 }
236
237 void Mesh::unload()
238 {
239         vertices.clear();
240         vertices.use_buffer(0);
241         batches.clear();
242         vtx_setup.unload();
243         delete vbuf;
244         delete ibuf;
245         vbuf = 0;
246         ibuf = 0;
247 }
248
249 void Mesh::set_debug_name(const string &name)
250 {
251 #ifdef DEBUG
252         debug_name = name;
253         if(vbuf)
254                 vbuf->set_debug_name(name+" [VBO]");
255         if(ibuf)
256                 ibuf->set_debug_name(name+" [IBO]");
257         vtx_setup.set_debug_name(name+" [VAO]");
258 #else
259         (void)name;
260 #endif
261 }
262
263
264 Mesh::Loader::Loader(Mesh &m, bool g):
265         DataFile::ObjectLoader<Mesh>(m),
266         allow_gl_calls(g)
267 {
268         add("batch",    &Loader::batch);
269         add("storage",  &Loader::storage);
270         add("vertices", &Loader::vertices);
271         add("vertices", &Loader::vertices_with_format);
272         add("winding",  &Mesh::face_winding);
273 }
274
275 void Mesh::Loader::storage(const vector<VertexAttribute> &a)
276 {
277         if(a.empty())
278                 throw invalid_argument("No vertex attributes");
279
280         VertexFormat fmt;
281         for(vector<VertexAttribute>::const_iterator i=a.begin(); i!=a.end(); ++i)
282                 fmt = (fmt, *i);
283         obj.storage(fmt);
284 }
285
286 void Mesh::Loader::vertices()
287 {
288         load_sub(obj.vertices);
289         if(allow_gl_calls)
290                 obj.check_buffers(VERTEX_BUFFER);
291 }
292
293 void Mesh::Loader::vertices_with_format(const vector<VertexAttribute> &a)
294 {
295         storage(a);
296         vertices();
297 }
298
299 void Mesh::Loader::batch(PrimitiveType p)
300 {
301         Batch btc(p);
302         load_sub(btc);
303         obj.add_batch(btc);
304 }
305
306
307 Mesh::AsyncLoader::AsyncLoader(Mesh &m, IO::Seekable &i):
308         mesh(m),
309         io(i),
310         vertex_updater(0),
311         index_updater(0),
312         phase(0)
313 {
314         mesh.disallow_rendering = true;
315         mesh.check_buffers(VERTEX_BUFFER|INDEX_BUFFER);
316 }
317
318 Mesh::AsyncLoader::~AsyncLoader()
319 {
320         mesh.disallow_rendering = false;
321         delete vertex_updater;
322         delete index_updater;
323 }
324
325 bool Mesh::AsyncLoader::needs_sync() const
326 {
327         return phase%2;
328 }
329
330 bool Mesh::AsyncLoader::process()
331 {
332         if(phase==0)
333         {
334                 // TODO use correct filename
335                 DataFile::Parser parser(io, "async");
336                 Loader loader(mesh, false);
337                 loader.load(parser);
338         }
339         else if(phase==1)
340         {
341                 mesh.resize_buffers();
342                 vertex_updater = mesh.vertices.refresh_async();
343                 if(!mesh.batches.empty())
344                         index_updater = mesh.batches.front().refresh_async();
345         }
346         else if(phase==2)
347         {
348                 if(vertex_updater)
349                         vertex_updater->upload_data();
350                 if(index_updater)
351                         index_updater->upload_data();
352         }
353         else if(phase==3)
354         {
355                 delete vertex_updater;
356                 vertex_updater = 0;
357                 delete index_updater;
358                 index_updater = 0;
359         }
360
361         ++phase;
362         if(phase==1 && !mesh.vbuf && !mesh.ibuf)
363                 phase += 3;
364         return phase>3;
365 }
366
367 } // namespace GL
368 } // namespace Msp