]> git.tdb.fi Git - libs/gl.git/blob - source/mesh.cpp
Remove last fragments of rendererless rendering
[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(Renderer &renderer) const
118 {
119         if(manager)
120         {
121                 manager->resource_used(*this);
122                 if(disallow_rendering)
123                         return;
124         }
125
126         renderer.set_mesh(this);
127         renderer.set_winding_test(winding);
128
129         for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
130                 renderer.draw(*i);
131 }
132
133 void Mesh::draw_instanced(Renderer &renderer, const VertexSetup &vs, unsigned count) const
134 {
135         if(vs.get_vertex_array()!=&vertices)
136                 throw invalid_argument("Mesh::draw_instanced");
137
138         if(manager)
139         {
140                 manager->resource_used(*this);
141                 if(disallow_rendering)
142                         return;
143         }
144
145         renderer.set_vertex_setup(&vs);
146         renderer.set_winding_test(winding);
147
148         for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
149                 renderer.draw_instanced(*i, count);
150 }
151
152 void Mesh::bind() const
153 {
154         if(set_current(this))
155         {
156                 vtx_setup.bind();
157                 vertices.refresh();
158         }
159 }
160
161 void Mesh::unbind()
162 {
163         if(set_current(0))
164                 VertexSetup::unbind();
165 }
166
167 Resource::AsyncLoader *Mesh::load(IO::Seekable &io, const Resources *)
168 {
169         return new AsyncLoader(*this, io);
170 }
171
172 UInt64 Mesh::get_data_size() const
173 {
174         UInt64 size = 0;
175         if(vbuf)
176                 size += vbuf->get_size();
177         if(ibuf)
178                 size += ibuf->get_size();
179         return size;
180 }
181
182 void Mesh::unload()
183 {
184         vertices.clear();
185         vertices.use_buffer(0);
186         batches.clear();
187         delete vbuf;
188         delete ibuf;
189         vbuf = 0;
190         ibuf = 0;
191 }
192
193
194 Mesh::Loader::Loader(Mesh &m):
195         DataFile::ObjectLoader<Mesh>(m)
196 {
197         add("batch",    &Loader::batch);
198         add("vertices", &Loader::vertices);
199         add("winding",  &Loader::winding);
200 }
201
202 void Mesh::Loader::vertices(const vector<VertexComponent> &c)
203 {
204         if(c.empty())
205                 throw invalid_argument("No vertex components");
206
207         VertexFormat fmt;
208         for(vector<VertexComponent>::const_iterator i=c.begin(); i!=c.end(); ++i)
209                 fmt = (fmt, *i);
210         obj.vertices.reset(fmt);
211         if(obj.vbuf)
212                 // Set it again to force the vertex setup to update
213                 obj.vtx_setup.set_vertex_array(obj.vertices);
214         load_sub(obj.vertices);
215 }
216
217 void Mesh::Loader::batch(PrimitiveType p)
218 {
219         Batch btc(p);
220         load_sub(btc);
221         obj.add_batch(btc);
222 }
223
224 void Mesh::Loader::winding(FaceWinding w)
225 {
226         if(w==CLOCKWISE)
227                 obj.winding = &WindingTest::clockwise();
228         else if(w==COUNTERCLOCKWISE)
229                 obj.winding = &WindingTest::counterclockwise();
230 }
231
232
233 Mesh::AsyncLoader::AsyncLoader(Mesh &m, IO::Seekable &i):
234         mesh(m),
235         io(i),
236         vertex_updater(0),
237         index_updater(0),
238         phase(0)
239 {
240         mesh.disallow_rendering = true;
241         mesh.create_buffers();
242 }
243
244 Mesh::AsyncLoader::~AsyncLoader()
245 {
246         mesh.disallow_rendering = false;
247         delete vertex_updater;
248         delete index_updater;
249 }
250
251 bool Mesh::AsyncLoader::needs_sync() const
252 {
253         return phase%2;
254 }
255
256 bool Mesh::AsyncLoader::process()
257 {
258         if(phase==0)
259         {
260                 // TODO use correct filename
261                 DataFile::Parser parser(io, "async");
262                 Loader loader(mesh);
263                 loader.load(parser);
264         }
265         else if(phase==1)
266         {
267                 vertex_updater = mesh.vertices.refresh_async();
268                 if(!mesh.batches.empty())
269                         index_updater = mesh.batches.front().refresh_async();
270         }
271         else if(phase==2)
272         {
273                 if(vertex_updater)
274                         vertex_updater->upload_data();
275                 if(index_updater)
276                         index_updater->upload_data();
277         }
278         else if(phase==3)
279         {
280                 delete vertex_updater;
281                 vertex_updater = 0;
282                 delete index_updater;
283                 index_updater = 0;
284         }
285
286         ++phase;
287         if(phase==1 && !mesh.vbuf && !mesh.ibuf)
288                 phase += 3;
289         return phase>3;
290 }
291
292 } // namespace GL
293 } // namespace Msp