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