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