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