]> git.tdb.fi Git - libs/gl.git/blob - source/mesh.cpp
Remove the deprecated ProgramBuilder class
[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         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(dirty)
159                 resize_buffers();
160
161         renderer.set_vertex_setup(vs ? vs : &vtx_setup);
162         renderer.set_winding_test(winding);
163
164         if(!count)
165         {
166                 for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
167                         renderer.draw(*i);
168         }
169         else
170         {
171                 for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
172                         renderer.draw_instanced(*i, count);
173         }
174 }
175
176 void Mesh::resize_buffers() const
177 {
178         if(dirty&VERTEX_BUFFER)
179                 vbuf->storage(vertices.get_required_buffer_size());
180         if(dirty&INDEX_BUFFER)
181                 ibuf->storage(batches.front().get_required_buffer_size());
182         dirty = 0;
183 }
184
185 Resource::AsyncLoader *Mesh::load(IO::Seekable &io, const Resources *)
186 {
187         return new AsyncLoader(*this, io);
188 }
189
190 UInt64 Mesh::get_data_size() const
191 {
192         UInt64 size = 0;
193         if(vbuf)
194                 size += vbuf->get_size();
195         if(ibuf)
196                 size += ibuf->get_size();
197         return size;
198 }
199
200 void Mesh::unload()
201 {
202         vertices.clear();
203         vertices.use_buffer(0);
204         batches.clear();
205         delete vbuf;
206         delete ibuf;
207         vbuf = 0;
208         ibuf = 0;
209 }
210
211
212 Mesh::Loader::Loader(Mesh &m, bool g):
213         DataFile::ObjectLoader<Mesh>(m),
214         allow_gl_calls(g)
215 {
216         add("batch",    &Loader::batch);
217         add("vertices", &Loader::vertices);
218         add("winding",  &Loader::winding);
219 }
220
221 void Mesh::Loader::vertices(const vector<VertexComponent> &c)
222 {
223         if(c.empty())
224                 throw invalid_argument("No vertex components");
225
226         VertexFormat fmt;
227         for(vector<VertexComponent>::const_iterator i=c.begin(); i!=c.end(); ++i)
228                 fmt = (fmt, *i);
229         obj.vertices.reset(fmt);
230         load_sub(obj.vertices);
231         if(allow_gl_calls)
232         {
233                 obj.check_buffers(VERTEX_BUFFER);
234                 obj.vtx_setup.refresh();
235         }
236 }
237
238 void Mesh::Loader::batch(PrimitiveType p)
239 {
240         Batch btc(p);
241         load_sub(btc);
242         obj.add_batch(btc);
243 }
244
245 void Mesh::Loader::winding(FaceWinding w)
246 {
247         if(w==CLOCKWISE)
248                 obj.winding = &WindingTest::clockwise();
249         else if(w==COUNTERCLOCKWISE)
250                 obj.winding = &WindingTest::counterclockwise();
251 }
252
253
254 Mesh::AsyncLoader::AsyncLoader(Mesh &m, IO::Seekable &i):
255         mesh(m),
256         io(i),
257         vertex_updater(0),
258         index_updater(0),
259         phase(0)
260 {
261         mesh.disallow_rendering = true;
262         mesh.check_buffers(VERTEX_BUFFER|INDEX_BUFFER);
263 }
264
265 Mesh::AsyncLoader::~AsyncLoader()
266 {
267         mesh.disallow_rendering = false;
268         delete vertex_updater;
269         delete index_updater;
270 }
271
272 bool Mesh::AsyncLoader::needs_sync() const
273 {
274         return phase%2;
275 }
276
277 bool Mesh::AsyncLoader::process()
278 {
279         if(phase==0)
280         {
281                 // TODO use correct filename
282                 DataFile::Parser parser(io, "async");
283                 Loader loader(mesh, false);
284                 loader.load(parser);
285         }
286         else if(phase==1)
287         {
288                 mesh.resize_buffers();
289                 mesh.vtx_setup.refresh();
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