]> git.tdb.fi Git - libs/gl.git/blob - source/mesh.cpp
Always use VertexSetup in Mesh
[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         disallow_rendering = false;
33         winding = 0;
34
35         if(rm)
36                 set_manager(rm);
37 }
38
39 Mesh::~Mesh()
40 {
41         set_manager(0);
42         delete vbuf;
43         delete ibuf;
44 }
45
46 void Mesh::clear()
47 {
48         vertices.clear();
49         batches.clear();
50 }
51
52 void Mesh::create_buffers()
53 {
54         if(vbuf && ibuf)
55                 return;
56
57         if(!vbuf)
58                 vbuf = new Buffer(ARRAY_BUFFER);
59         vertices.use_buffer(vbuf);
60
61         if(!ibuf)
62                 ibuf = new Buffer(ELEMENT_ARRAY_BUFFER);
63
64         vtx_setup.set_vertex_array(vertices);
65         vtx_setup.set_index_buffer(*ibuf);
66 }
67
68 unsigned Mesh::get_n_vertices() const
69 {
70         return vertices.size();
71 }
72
73 float *Mesh::modify_vertex(unsigned i)
74 {
75         return vertices.modify(i);
76 }
77
78 void Mesh::add_batch(const Batch &b)
79 {
80         create_buffers();
81
82         if(!batches.empty() && batches.back().can_append(b.get_type()))
83                 batches.back().append(b);
84         else
85         {
86                 bool reallocate = (batches.size()==batches.capacity());
87                 if(reallocate && ibuf)
88                 {
89                         for(vector<Batch>::iterator i=batches.end(); i!=batches.begin(); )
90                                 (--i)->use_buffer(0);
91                 }
92
93                 Batch *prev = (batches.empty() ? 0 : &batches.back());
94                 batches.push_back(b);
95                 if(ibuf)
96                 {
97                         if(reallocate)
98                         {
99                                 prev = 0;
100                                 for(vector<Batch>::iterator i=batches.begin(); i!=batches.end(); ++i)
101                                 {
102                                         i->use_buffer(ibuf, prev);
103                                         prev = &*i;
104                                 }
105                         }
106                         else
107                                 batches.back().use_buffer(ibuf, prev);
108                 }
109         }
110 }
111
112 void Mesh::set_winding(const WindingTest *w)
113 {
114         winding = w;
115 }
116
117 void Mesh::draw() const
118 {
119         const Mesh *cur = current();
120         if(cur && cur!=this)
121                 throw invalid_operation("Mesh::draw");
122
123         if(manager)
124         {
125                 manager->resource_used(*this);
126                 if(disallow_rendering)
127                         return;
128         }
129
130         BindRestore bind_vtxs(vtx_setup);
131         BindRestore bind_ibuf(ibuf, ELEMENT_ARRAY_BUFFER);
132         Bind bind_winding(winding);
133
134         for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
135                 i->draw();
136 }
137
138 void Mesh::draw(Renderer &renderer) const
139 {
140         if(manager)
141         {
142                 manager->resource_used(*this);
143                 if(disallow_rendering)
144                         return;
145         }
146
147         renderer.set_mesh(this);
148         renderer.set_winding_test(winding);
149
150         for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
151                 renderer.draw(*i);
152 }
153
154 void Mesh::draw_instanced(Renderer &renderer, const VertexSetup &vs, unsigned count) const
155 {
156         if(vs.get_vertex_array()!=&vertices)
157                 throw invalid_argument("Mesh::draw_instanced");
158
159         if(manager)
160         {
161                 manager->resource_used(*this);
162                 if(disallow_rendering)
163                         return;
164         }
165
166         renderer.set_vertex_setup(&vs);
167         renderer.set_winding_test(winding);
168
169         for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
170                 renderer.draw_instanced(*i, count);
171 }
172
173 void Mesh::bind() const
174 {
175         if(set_current(this))
176         {
177                 vtx_setup.bind();
178                 vertices.refresh();
179         }
180 }
181
182 void Mesh::unbind()
183 {
184         if(set_current(0))
185                 VertexSetup::unbind();
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):
216         DataFile::ObjectLoader<Mesh>(m)
217 {
218         add("batch",    &Loader::batch);
219         add("vertices", &Loader::vertices);
220         add("winding",  &Loader::winding);
221 }
222
223 void Mesh::Loader::vertices(const vector<VertexComponent> &c)
224 {
225         if(c.empty())
226                 throw invalid_argument("No vertex components");
227
228         VertexFormat fmt;
229         for(vector<VertexComponent>::const_iterator i=c.begin(); i!=c.end(); ++i)
230                 fmt = (fmt, *i);
231         obj.vertices.reset(fmt);
232         if(obj.vbuf)
233                 // Set it again to force the vertex setup to update
234                 obj.vtx_setup.set_vertex_array(obj.vertices);
235         load_sub(obj.vertices);
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.create_buffers();
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);
284                 loader.load(parser);
285         }
286         else if(phase==1)
287         {
288                 vertex_updater = mesh.vertices.refresh_async();
289                 if(!mesh.batches.empty())
290                         index_updater = mesh.batches.front().refresh_async();
291         }
292         else if(phase==2)
293         {
294                 if(vertex_updater)
295                         vertex_updater->upload_data();
296                 if(index_updater)
297                         index_updater->upload_data();
298         }
299         else if(phase==3)
300         {
301                 delete vertex_updater;
302                 vertex_updater = 0;
303                 delete index_updater;
304                 index_updater = 0;
305         }
306
307         ++phase;
308         if(phase==1 && !mesh.vbuf && !mesh.ibuf)
309                 phase += 3;
310         return phase>3;
311 }
312
313 } // namespace GL
314 } // namespace Msp