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