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