-#include <msp/gl/extensions/arb_vertex_array_object.h>
-#include <msp/gl/extensions/arb_vertex_buffer_object.h>
-#include <msp/gl/extensions/arb_vertex_shader.h>
-#include "buffer.h"
-#include "error.h"
-#include "mesh.h"
-#include "renderer.h"
-#include "resourcemanager.h"
-#include "vertexsetup.h"
-
-using namespace std;
-
-namespace Msp {
-namespace GL {
-
-Mesh::Mesh(ResourceManager *rm):
- vertices(VERTEX3)
-{
- init(rm);
-}
-
-Mesh::Mesh(const VertexFormat &f, ResourceManager *rm):
- vertices(f)
-{
- init(rm);
-}
-
-void Mesh::init(ResourceManager *rm)
-{
- vbuf = 0;
- ibuf = 0;
- dirty = 0;
- disallow_rendering = false;
- winding = 0;
-
- if(rm)
- set_manager(rm);
-}
-
-Mesh::~Mesh()
-{
- set_manager(0);
- delete vbuf;
- delete ibuf;
-}
-
-void Mesh::clear()
-{
- vertices.clear();
- batches.clear();
-}
-
-void Mesh::check_buffers(unsigned mask)
-{
- if(mask&VERTEX_BUFFER)
- {
- unsigned req_size = vertices.get_required_buffer_size();
- if(!vbuf || (vbuf->get_size()>0 && vbuf->get_size()<req_size))
- {
- delete vbuf;
- vbuf = new Buffer(ARRAY_BUFFER);
- vertices.use_buffer(vbuf);
- vtx_setup.set_vertex_array(vertices);
- dirty |= VERTEX_BUFFER;
- }
- }
-
- if(mask&INDEX_BUFFER)
- {
- unsigned req_size = (batches.empty() ? 0 : batches.front().get_required_buffer_size());
- if(!ibuf || (ibuf->get_size()>0 && ibuf->get_size()<req_size))
- {
- delete ibuf;
- ibuf = new Buffer(ELEMENT_ARRAY_BUFFER);
- if(!batches.empty())
- batches.front().change_buffer(ibuf);
- vtx_setup.set_index_buffer(*ibuf);
- dirty |= INDEX_BUFFER;
- }
- }
-}
-
-unsigned Mesh::get_n_vertices() const
-{
- return vertices.size();
-}
-
-float *Mesh::modify_vertex(unsigned i)
-{
- return vertices.modify(i);
-}
-
-void Mesh::add_batch(const Batch &b)
-{
- if(batches.empty())
- {
- batches.push_back(b);
- if(ibuf)
- batches.back().use_buffer(ibuf);
- }
- else if(batches.back().can_append(b.get_type()))
- batches.back().append(b);
- else
- {
- bool reallocate = (batches.size()==batches.capacity());
- if(reallocate)
- {
- for(vector<Batch>::iterator i=batches.end(); i!=batches.begin(); )
- (--i)->use_buffer(0);
- }
-
- Batch *prev = &batches.back();
- batches.push_back(b);
- if(reallocate)
- {
- prev = 0;
- for(vector<Batch>::iterator i=batches.begin(); i!=batches.end(); ++i)
- {
- i->use_buffer(ibuf, prev);
- prev = &*i;
- }
- }
- else
- batches.back().use_buffer(ibuf, prev);
- }
-
- check_buffers(INDEX_BUFFER);
-}
-
-void Mesh::set_winding(const WindingTest *w)
-{
- winding = w;
-}
-
-void Mesh::draw(Renderer &renderer) const
-{
- draw(renderer, 0, 0);
-}
-
-void Mesh::draw_instanced(Renderer &renderer, const VertexSetup &vs, unsigned count) const
-{
- if(vs.get_vertex_array()!=&vertices)
- throw invalid_argument("Mesh::draw_instanced");
-
- draw(renderer, &vs, count);
-}
-
-void Mesh::draw(Renderer &renderer, const VertexSetup *vs, unsigned count) const
-{
- if(manager)
- {
- manager->resource_used(*this);
- if(disallow_rendering)
- return;
- }
-
- if(dirty)
- resize_buffers();
-
- renderer.set_vertex_setup(vs ? vs : &vtx_setup);
- renderer.set_winding_test(winding);
-
- if(!count)
- {
- for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
- renderer.draw(*i);
- }
- else
- {
- for(vector<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
- renderer.draw_instanced(*i, count);
- }
-}
-
-void Mesh::resize_buffers() const
-{
- if(dirty&VERTEX_BUFFER)
- vbuf->storage(vertices.get_required_buffer_size());
- if(dirty&INDEX_BUFFER)
- ibuf->storage(batches.front().get_required_buffer_size());
- dirty = 0;
-}
-
-Resource::AsyncLoader *Mesh::load(IO::Seekable &io, const Resources *)
-{
- return new AsyncLoader(*this, io);
-}
-
-UInt64 Mesh::get_data_size() const
-{
- UInt64 size = 0;
- if(vbuf)
- size += vbuf->get_size();
- if(ibuf)
- size += ibuf->get_size();
- return size;
-}
-
-void Mesh::unload()
-{
- vertices.clear();
- vertices.use_buffer(0);
- batches.clear();
- delete vbuf;
- delete ibuf;
- vbuf = 0;
- ibuf = 0;
-}
-
-
-Mesh::Loader::Loader(Mesh &m, bool g):
- DataFile::ObjectLoader<Mesh>(m),
- allow_gl_calls(g)
-{
- add("batch", &Loader::batch);
- add("vertices", &Loader::vertices);
- add("winding", &Loader::winding);
-}
-
-void Mesh::Loader::vertices(const vector<VertexComponent> &c)
-{
- if(c.empty())
- throw invalid_argument("No vertex components");
-
- VertexFormat fmt;
- for(vector<VertexComponent>::const_iterator i=c.begin(); i!=c.end(); ++i)
- fmt = (fmt, *i);
- obj.vertices.reset(fmt);
- load_sub(obj.vertices);
- if(allow_gl_calls)
- {
- obj.check_buffers(VERTEX_BUFFER);
- obj.vtx_setup.set_vertex_array(obj.vertices);
- }
-}
-
-void Mesh::Loader::batch(PrimitiveType p)
-{
- Batch btc(p);
- load_sub(btc);
- obj.add_batch(btc);
-}
-
-void Mesh::Loader::winding(FaceWinding w)
-{
- if(w==CLOCKWISE)
- obj.winding = &WindingTest::clockwise();
- else if(w==COUNTERCLOCKWISE)
- obj.winding = &WindingTest::counterclockwise();
-}
-
-
-Mesh::AsyncLoader::AsyncLoader(Mesh &m, IO::Seekable &i):
- mesh(m),
- io(i),
- vertex_updater(0),
- index_updater(0),
- phase(0)
-{
- mesh.disallow_rendering = true;
- mesh.check_buffers(VERTEX_BUFFER|INDEX_BUFFER);
-}
-
-Mesh::AsyncLoader::~AsyncLoader()
-{
- mesh.disallow_rendering = false;
- delete vertex_updater;
- delete index_updater;
-}
-
-bool Mesh::AsyncLoader::needs_sync() const
-{
- return phase%2;
-}
-
-bool Mesh::AsyncLoader::process()
-{
- if(phase==0)
- {
- // TODO use correct filename
- DataFile::Parser parser(io, "async");
- Loader loader(mesh, false);
- loader.load(parser);
- }
- else if(phase==1)
- {
- mesh.resize_buffers();
- mesh.vtx_setup.set_vertex_array(vertices);
- vertex_updater = mesh.vertices.refresh_async();
- if(!mesh.batches.empty())
- index_updater = mesh.batches.front().refresh_async();
- }
- else if(phase==2)
- {
- if(vertex_updater)
- vertex_updater->upload_data();
- if(index_updater)
- index_updater->upload_data();
- }
- else if(phase==3)
- {
- delete vertex_updater;
- vertex_updater = 0;
- delete index_updater;
- index_updater = 0;
- }
-
- ++phase;
- if(phase==1 && !mesh.vbuf && !mesh.ibuf)
- phase += 3;
- return phase>3;
-}
-
-} // namespace GL
-} // namespace Msp