]> git.tdb.fi Git - libs/gl.git/blob - source/mesh.cpp
a463ba7fb7c7a1414ee42ed116264d672730f514
[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::bind() const
179 {
180         /* If VAOs are not supported, vtx_setup is zero and set_current won't get
181         called.  Thus unbind won't try to call a null function either. */
182         if(!vtx_setup)
183         {
184                 unbind();
185                 vertices.apply(false);
186         }
187         else if(set_current(this))
188         {
189                 vtx_setup->bind();
190                 vertices.refresh();
191         }
192 }
193
194 void Mesh::unbind()
195 {
196         if(set_current(0))
197                 VertexSetup::unbind();
198 }
199
200 Resource::AsyncLoader *Mesh::load(IO::Seekable &io, const Resources *)
201 {
202         return new AsyncLoader(*this, io);
203 }
204
205 UInt64 Mesh::get_data_size() const
206 {
207         UInt64 size = 0;
208         if(vbuf)
209                 size += vbuf->get_size();
210         if(ibuf)
211                 size += ibuf->get_size();
212         return size;
213 }
214
215 void Mesh::unload()
216 {
217         vertices.clear();
218         vertices.use_buffer(0);
219         batches.clear();
220         delete vbuf;
221         delete ibuf;
222         defer_buffers = (vbuf || ibuf);
223         vbuf = 0;
224         ibuf = 0;
225 }
226
227
228 Mesh::Loader::Loader(Mesh &m):
229         DataFile::ObjectLoader<Mesh>(m)
230 {
231         add("batch",    &Loader::batch);
232         add("vertices", &Loader::vertices);
233         add("winding",  &Loader::winding);
234 }
235
236 void Mesh::Loader::vertices(const vector<VertexComponent> &c)
237 {
238         if(c.empty())
239                 throw invalid_argument("No vertex components");
240
241         VertexFormat fmt;
242         for(vector<VertexComponent>::const_iterator i=c.begin(); i!=c.end(); ++i)
243                 fmt = (fmt, *i);
244         obj.vertices.reset(fmt);
245         if(obj.vtx_setup)
246                 // Set it again to force the vertex setup to update
247                 obj.vtx_setup->set_vertex_array(obj.vertices);
248         load_sub(obj.vertices);
249 }
250
251 void Mesh::Loader::batch(PrimitiveType p)
252 {
253         Batch btc(p);
254         load_sub(btc);
255         obj.add_batch(btc);
256 }
257
258 void Mesh::Loader::winding(FaceWinding w)
259 {
260         if(w==CLOCKWISE)
261                 obj.winding = &WindingTest::clockwise();
262         else if(w==COUNTERCLOCKWISE)
263                 obj.winding = &WindingTest::counterclockwise();
264 }
265
266
267 Mesh::AsyncLoader::AsyncLoader(Mesh &m, IO::Seekable &i):
268         mesh(m),
269         io(i),
270         vertex_updater(0),
271         index_updater(0),
272         phase(0)
273 {
274         // Make sure the extension is initialized in the rendering thread.
275         (void)(bool)NV_primitive_restart;
276
277         mesh.disallow_rendering = true;
278         if(mesh.defer_buffers)
279                 mesh.create_buffers();
280 }
281
282 Mesh::AsyncLoader::~AsyncLoader()
283 {
284         mesh.disallow_rendering = false;
285         delete vertex_updater;
286         delete index_updater;
287 }
288
289 bool Mesh::AsyncLoader::needs_sync() const
290 {
291         return phase%2;
292 }
293
294 bool Mesh::AsyncLoader::process()
295 {
296         if(phase==0)
297         {
298                 // TODO use correct filename
299                 DataFile::Parser parser(io, "async");
300                 Loader loader(mesh);
301                 loader.load(parser);
302         }
303         else if(phase==1)
304         {
305                 vertex_updater = mesh.vertices.refresh_async();
306                 if(!mesh.batches.empty())
307                         index_updater = mesh.batches.front().refresh_async();
308         }
309         else if(phase==2)
310         {
311                 if(vertex_updater)
312                         vertex_updater->upload_data();
313                 if(index_updater)
314                         index_updater->upload_data();
315         }
316         else if(phase==3)
317         {
318                 delete vertex_updater;
319                 vertex_updater = 0;
320                 delete index_updater;
321                 index_updater = 0;
322         }
323
324         ++phase;
325         if(phase==1 && !mesh.vbuf && !mesh.ibuf)
326                 phase += 3;
327         return phase>3;
328 }
329
330 } // namespace GL
331 } // namespace Msp