]> git.tdb.fi Git - libs/gl.git/blob - source/mesh.cpp
Check the flat qualifier from the correct member
[libs/gl.git] / source / 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/nv_primitive_restart.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         vertices(VERTEX3)
19 {
20         init(rm);
21 }
22
23 Mesh::Mesh(const VertexFormat &f, ResourceManager *rm):
24         vertices(f)
25 {
26         init(rm);
27 }
28
29 void Mesh::init(ResourceManager *rm)
30 {
31         vbuf = 0;
32         ibuf = 0;
33         vtx_setup = 0;
34         defer_buffers = ARB_vertex_buffer_object;
35         disallow_rendering = false;
36         winding = 0;
37
38         if(rm)
39                 set_manager(rm);
40 }
41
42 Mesh::~Mesh()
43 {
44         set_manager(0);
45         delete vtx_setup;
46         delete vbuf;
47         delete ibuf;
48 }
49
50 void Mesh::clear()
51 {
52         vertices.clear();
53         batches.clear();
54 }
55
56 void Mesh::use_buffers(bool b)
57 {
58         defer_buffers = false;
59         if(b)
60                 create_buffers();
61         else
62         {
63                 vertices.use_buffer(0);
64                 delete vbuf;
65                 vbuf = 0;
66                 delete ibuf;
67                 ibuf = 0;
68         }
69 }
70
71 void Mesh::create_buffers()
72 {
73         defer_buffers = false;
74
75         if(!vbuf)
76                 vbuf = new Buffer(ARRAY_BUFFER);
77         vertices.use_buffer(vbuf);
78
79         if(!ibuf)
80                 ibuf = new Buffer(ELEMENT_ARRAY_BUFFER);
81
82         if(ARB_vertex_array_object && !vtx_setup)
83         {
84                 vtx_setup = new VertexSetup;
85                 vtx_setup->set_vertex_array(vertices);
86                 vtx_setup->set_index_buffer(*ibuf);
87         }
88 }
89
90 unsigned Mesh::get_n_vertices() const
91 {
92         return vertices.size();
93 }
94
95 float *Mesh::modify_vertex(unsigned i)
96 {
97         return vertices.modify(i);
98 }
99
100 void Mesh::add_batch(const Batch &b)
101 {
102         if(defer_buffers)
103                 create_buffers();
104
105         if(!batches.empty() && batches.back().can_append(b.get_type()))
106                 batches.back().append(b);
107         else
108         {
109                 bool reallocate = (batches.size()==batches.capacity());
110                 if(reallocate && ibuf)
111                 {
112                         for(vector<Batch>::iterator i=batches.end(); i!=batches.begin(); )
113                                 (--i)->use_buffer(0);
114                 }
115
116                 Batch *prev = (batches.empty() ? 0 : &batches.back());
117                 batches.push_back(b);
118                 if(ibuf)
119                 {
120                         if(reallocate)
121                         {
122                                 prev = 0;
123                                 for(vector<Batch>::iterator i=batches.begin(); i!=batches.end(); ++i)
124                                 {
125                                         i->use_buffer(ibuf, prev);
126                                         prev = &*i;
127                                 }
128                         }
129                         else
130                                 batches.back().use_buffer(ibuf, prev);
131                 }
132         }
133 }
134
135 void Mesh::set_winding(const WindingTest *w)
136 {
137         winding = w;
138 }
139
140 void Mesh::draw() const
141 {
142         const Mesh *cur = current();
143         if(cur && cur!=this)
144                 throw invalid_operation("Mesh::draw");
145
146         if(manager)
147         {
148                 manager->resource_used(*this);
149                 if(disallow_rendering)
150                         return;
151         }
152
153         if(!current())
154                 vertices.apply();
155         BindRestore bind_ibuf(ibuf, ELEMENT_ARRAY_BUFFER);
156         Bind bind_winding(winding);
157
158         for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
159                 i->draw();
160 }
161
162 void Mesh::draw(Renderer &renderer) const
163 {
164         if(manager)
165         {
166                 manager->resource_used(*this);
167                 if(disallow_rendering)
168                         return;
169         }
170
171         renderer.set_mesh(this);
172         renderer.set_winding_test(winding);
173
174         for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
175                 renderer.draw(*i);
176 }
177
178 void Mesh::draw_instanced(Renderer &renderer, const VertexSetup &vs, unsigned count) const
179 {
180         if(vs.get_vertex_array()!=&vertices)
181                 throw invalid_argument("Mesh::draw_instanced");
182
183         if(manager)
184         {
185                 manager->resource_used(*this);
186                 if(disallow_rendering)
187                         return;
188         }
189
190         renderer.set_vertex_setup(&vs);
191         renderer.set_winding_test(winding);
192
193         for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
194                 renderer.draw_instanced(*i, count);
195 }
196
197 void Mesh::bind() const
198 {
199         /* If VAOs are not supported, vtx_setup is zero and set_current won't get
200         called.  Thus unbind won't try to call a null function either. */
201         if(!vtx_setup)
202         {
203                 unbind();
204                 vertices.apply(false);
205         }
206         else if(set_current(this))
207         {
208                 vtx_setup->bind();
209                 vertices.refresh();
210         }
211 }
212
213 void Mesh::unbind()
214 {
215         if(set_current(0))
216                 VertexSetup::unbind();
217 }
218
219 Resource::AsyncLoader *Mesh::load(IO::Seekable &io, const Resources *)
220 {
221         return new AsyncLoader(*this, io);
222 }
223
224 UInt64 Mesh::get_data_size() const
225 {
226         UInt64 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         delete vbuf;
240         delete ibuf;
241         defer_buffers = (vbuf || ibuf);
242         vbuf = 0;
243         ibuf = 0;
244 }
245
246
247 Mesh::Loader::Loader(Mesh &m):
248         DataFile::ObjectLoader<Mesh>(m)
249 {
250         add("batch",    &Loader::batch);
251         add("vertices", &Loader::vertices);
252         add("winding",  &Loader::winding);
253 }
254
255 void Mesh::Loader::vertices(const vector<VertexComponent> &c)
256 {
257         if(c.empty())
258                 throw invalid_argument("No vertex components");
259
260         VertexFormat fmt;
261         for(vector<VertexComponent>::const_iterator i=c.begin(); i!=c.end(); ++i)
262                 fmt = (fmt, *i);
263         obj.vertices.reset(fmt);
264         if(obj.vtx_setup)
265                 // Set it again to force the vertex setup to update
266                 obj.vtx_setup->set_vertex_array(obj.vertices);
267         load_sub(obj.vertices);
268 }
269
270 void Mesh::Loader::batch(PrimitiveType p)
271 {
272         Batch btc(p);
273         load_sub(btc);
274         obj.add_batch(btc);
275 }
276
277 void Mesh::Loader::winding(FaceWinding w)
278 {
279         if(w==CLOCKWISE)
280                 obj.winding = &WindingTest::clockwise();
281         else if(w==COUNTERCLOCKWISE)
282                 obj.winding = &WindingTest::counterclockwise();
283 }
284
285
286 Mesh::AsyncLoader::AsyncLoader(Mesh &m, IO::Seekable &i):
287         mesh(m),
288         io(i),
289         vertex_updater(0),
290         index_updater(0),
291         phase(0)
292 {
293         // Make sure the extension is initialized in the rendering thread.
294         (void)(bool)NV_primitive_restart;
295
296         mesh.disallow_rendering = true;
297         if(mesh.defer_buffers)
298                 mesh.create_buffers();
299 }
300
301 Mesh::AsyncLoader::~AsyncLoader()
302 {
303         mesh.disallow_rendering = false;
304         delete vertex_updater;
305         delete index_updater;
306 }
307
308 bool Mesh::AsyncLoader::needs_sync() const
309 {
310         return phase%2;
311 }
312
313 bool Mesh::AsyncLoader::process()
314 {
315         if(phase==0)
316         {
317                 // TODO use correct filename
318                 DataFile::Parser parser(io, "async");
319                 Loader loader(mesh);
320                 loader.load(parser);
321         }
322         else if(phase==1)
323         {
324                 vertex_updater = mesh.vertices.refresh_async();
325                 if(!mesh.batches.empty())
326                         index_updater = mesh.batches.front().refresh_async();
327         }
328         else if(phase==2)
329         {
330                 if(vertex_updater)
331                         vertex_updater->upload_data();
332                 if(index_updater)
333                         index_updater->upload_data();
334         }
335         else if(phase==3)
336         {
337                 delete vertex_updater;
338                 vertex_updater = 0;
339                 delete index_updater;
340                 index_updater = 0;
341         }
342
343         ++phase;
344         if(phase==1 && !mesh.vbuf && !mesh.ibuf)
345                 phase += 3;
346         return phase>3;
347 }
348
349 } // namespace GL
350 } // namespace Msp