]> git.tdb.fi Git - libs/gl.git/blob - source/core/mesh.cpp
Do an early return from Mesh::draw if there's no data
[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 "buffer.h"
5 #include "error.h"
6 #include "mesh.h"
7 #include "renderer.h"
8 #include "resourcemanager.h"
9 #include "vertexsetup.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace GL {
15
16 Mesh::Mesh(ResourceManager *rm):
17         vertices(VERTEX3)
18 {
19         init(rm);
20 }
21
22 Mesh::Mesh(const VertexFormat &f, ResourceManager *rm):
23         vertices(f)
24 {
25         init(rm);
26 }
27
28 void Mesh::init(ResourceManager *rm)
29 {
30         vbuf = 0;
31         ibuf = 0;
32         dirty = 0;
33         disallow_rendering = false;
34         winding = 0;
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::clear()
49 {
50         vertices.clear();
51         batches.clear();
52 }
53
54 void Mesh::check_buffers(unsigned mask)
55 {
56         if(mask&VERTEX_BUFFER)
57         {
58                 unsigned req_size = vertices.get_required_buffer_size();
59                 if(!vbuf || (vbuf->get_size()>0 && vbuf->get_size()<req_size))
60                 {
61                         delete vbuf;
62                         vbuf = new Buffer(ARRAY_BUFFER);
63                         vertices.use_buffer(vbuf);
64                         vtx_setup.set_vertex_array(vertices);
65                         dirty |= VERTEX_BUFFER;
66                 }
67         }
68
69         if(mask&INDEX_BUFFER)
70         {
71                 unsigned req_size = (batches.empty() ? 0 : batches.front().get_required_buffer_size());
72                 if(!ibuf || (ibuf->get_size()>0 && ibuf->get_size()<req_size))
73                 {
74                         delete ibuf;
75                         ibuf = new Buffer(ELEMENT_ARRAY_BUFFER);
76                         if(!batches.empty())
77                                 batches.front().change_buffer(ibuf);
78                         vtx_setup.set_index_buffer(*ibuf);
79                         dirty |= INDEX_BUFFER;
80                 }
81         }
82 }
83
84 unsigned Mesh::get_n_vertices() const
85 {
86         return vertices.size();
87 }
88
89 float *Mesh::modify_vertex(unsigned i)
90 {
91         return vertices.modify(i);
92 }
93
94 void Mesh::add_batch(const Batch &b)
95 {
96         if(batches.empty())
97         {
98                 batches.push_back(b);
99                 if(ibuf)
100                         batches.back().use_buffer(ibuf);
101         }
102         else if(batches.back().can_append(b.get_type()))
103                 batches.back().append(b);
104         else
105         {
106                 bool reallocate = (batches.size()==batches.capacity());
107                 if(reallocate)
108                 {
109                         for(vector<Batch>::iterator i=batches.end(); i!=batches.begin(); )
110                                 (--i)->use_buffer(0);
111                 }
112
113                 Batch *prev = &batches.back();
114                 batches.push_back(b);
115                 if(reallocate)
116                 {
117                         prev = 0;
118                         for(vector<Batch>::iterator i=batches.begin(); i!=batches.end(); ++i)
119                         {
120                                 i->use_buffer(ibuf, prev);
121                                 prev = &*i;
122                         }
123                 }
124                 else
125                         batches.back().use_buffer(ibuf, prev);
126         }
127
128         check_buffers(INDEX_BUFFER);
129 }
130
131 void Mesh::set_winding(const WindingTest *w)
132 {
133         winding = w;
134 }
135
136 void Mesh::draw(Renderer &renderer) const
137 {
138         draw(renderer, 0, 0);
139 }
140
141 void Mesh::draw_instanced(Renderer &renderer, const VertexSetup &vs, unsigned count) const
142 {
143         if(vs.get_vertex_array()!=&vertices)
144                 throw invalid_argument("Mesh::draw_instanced");
145
146         draw(renderer, &vs, count);
147 }
148
149 void Mesh::draw(Renderer &renderer, const VertexSetup *vs, unsigned count) const
150 {
151         if(manager)
152         {
153                 manager->resource_used(*this);
154                 if(disallow_rendering)
155                         return;
156         }
157
158         if(batches.empty())
159                 return;
160
161         if(dirty)
162                 resize_buffers();
163
164         renderer.set_vertex_setup(vs ? vs : &vtx_setup);
165         renderer.set_winding_test(winding);
166
167         if(!count)
168         {
169                 for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
170                         renderer.draw(*i);
171         }
172         else
173         {
174                 for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
175                         renderer.draw_instanced(*i, count);
176         }
177 }
178
179 void Mesh::resize_buffers() const
180 {
181         if(dirty&VERTEX_BUFFER)
182                 vbuf->storage(vertices.get_required_buffer_size());
183         if((dirty&INDEX_BUFFER) && !batches.empty())
184                 ibuf->storage(batches.front().get_required_buffer_size());
185         dirty = 0;
186 }
187
188 Resource::AsyncLoader *Mesh::load(IO::Seekable &io, const Resources *)
189 {
190         return new AsyncLoader(*this, io);
191 }
192
193 UInt64 Mesh::get_data_size() const
194 {
195         UInt64 size = 0;
196         if(vbuf)
197                 size += vbuf->get_size();
198         if(ibuf)
199                 size += ibuf->get_size();
200         return size;
201 }
202
203 void Mesh::unload()
204 {
205         vertices.clear();
206         vertices.use_buffer(0);
207         batches.clear();
208         delete vbuf;
209         delete ibuf;
210         vbuf = 0;
211         ibuf = 0;
212 }
213
214
215 Mesh::Loader::Loader(Mesh &m, bool g):
216         DataFile::ObjectLoader<Mesh>(m),
217         allow_gl_calls(g)
218 {
219         add("batch",    &Loader::batch);
220         add("vertices", &Loader::vertices);
221         add("winding",  &Loader::winding);
222 }
223
224 void Mesh::Loader::vertices(const vector<VertexAttribute> &a)
225 {
226         if(a.empty())
227                 throw invalid_argument("No vertex attributes");
228
229         VertexFormat fmt;
230         for(vector<VertexAttribute>::const_iterator i=a.begin(); i!=a.end(); ++i)
231                 fmt = (fmt, *i);
232         obj.vertices.reset(fmt);
233         load_sub(obj.vertices);
234         if(allow_gl_calls)
235         {
236                 obj.check_buffers(VERTEX_BUFFER);
237                 obj.vtx_setup.refresh();
238         }
239 }
240
241 void Mesh::Loader::batch(PrimitiveType p)
242 {
243         Batch btc(p);
244         load_sub(btc);
245         obj.add_batch(btc);
246 }
247
248 void Mesh::Loader::winding(FaceWinding w)
249 {
250         if(w==CLOCKWISE)
251                 obj.winding = &WindingTest::clockwise();
252         else if(w==COUNTERCLOCKWISE)
253                 obj.winding = &WindingTest::counterclockwise();
254 }
255
256
257 Mesh::AsyncLoader::AsyncLoader(Mesh &m, IO::Seekable &i):
258         mesh(m),
259         io(i),
260         vertex_updater(0),
261         index_updater(0),
262         phase(0)
263 {
264         mesh.disallow_rendering = true;
265         mesh.check_buffers(VERTEX_BUFFER|INDEX_BUFFER);
266 }
267
268 Mesh::AsyncLoader::~AsyncLoader()
269 {
270         mesh.disallow_rendering = false;
271         delete vertex_updater;
272         delete index_updater;
273 }
274
275 bool Mesh::AsyncLoader::needs_sync() const
276 {
277         return phase%2;
278 }
279
280 bool Mesh::AsyncLoader::process()
281 {
282         if(phase==0)
283         {
284                 // TODO use correct filename
285                 DataFile::Parser parser(io, "async");
286                 Loader loader(mesh, false);
287                 loader.load(parser);
288         }
289         else if(phase==1)
290         {
291                 mesh.resize_buffers();
292                 mesh.vtx_setup.refresh();
293                 vertex_updater = mesh.vertices.refresh_async();
294                 if(!mesh.batches.empty())
295                         index_updater = mesh.batches.front().refresh_async();
296         }
297         else if(phase==2)
298         {
299                 if(vertex_updater)
300                         vertex_updater->upload_data();
301                 if(index_updater)
302                         index_updater->upload_data();
303         }
304         else if(phase==3)
305         {
306                 delete vertex_updater;
307                 vertex_updater = 0;
308                 delete index_updater;
309                 index_updater = 0;
310         }
311
312         ++phase;
313         if(phase==1 && !mesh.vbuf && !mesh.ibuf)
314                 phase += 3;
315         return phase>3;
316 }
317
318 } // namespace GL
319 } // namespace Msp