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