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