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