namespace Msp {
namespace GL {
-Mesh::Mesh(ResourceManager *rm):
- vertices(VERTEX3)
+Mesh::Mesh(ResourceManager *rm)
{
init(rm);
}
-Mesh::Mesh(const VertexFormat &f, ResourceManager *rm):
- vertices(f)
+Mesh::Mesh(const VertexFormat &f, ResourceManager *rm)
{
init(rm);
+ storage(f);
}
void Mesh::init(ResourceManager *rm)
delete ibuf;
}
+void Mesh::storage(const VertexFormat &fmt)
+{
+ if(!vertices.get_format().empty())
+ throw invalid_operation("Mesh::storage");
+
+ vertices.set_format(fmt);
+ vtx_setup.set_format(fmt);
+}
+
void Mesh::clear()
{
vertices.clear();
float *Mesh::modify_vertex(unsigned i)
{
+ if(vertices.get_format().empty())
+ throw invalid_operation("Mesh::modify_vertex");
return vertices.modify(i);
}
allow_gl_calls(g)
{
add("batch", &Loader::batch);
+ add("storage", &Loader::storage);
add("vertices", &Loader::vertices);
+ add("vertices", &Loader::vertices_with_format);
add("winding", &Loader::winding);
}
-void Mesh::Loader::vertices(const vector<VertexAttribute> &a)
+void Mesh::Loader::storage(const vector<VertexAttribute> &a)
{
if(a.empty())
throw invalid_argument("No vertex attributes");
VertexFormat fmt;
for(vector<VertexAttribute>::const_iterator i=a.begin(); i!=a.end(); ++i)
fmt = (fmt, *i);
- obj.vertices.reset(fmt);
+ obj.storage(fmt);
+}
+
+void Mesh::Loader::vertices()
+{
load_sub(obj.vertices);
if(allow_gl_calls)
- {
obj.check_buffers(VERTEX_BUFFER);
- obj.vtx_setup.refresh();
- }
+}
+
+void Mesh::Loader::vertices_with_format(const vector<VertexAttribute> &a)
+{
+ storage(a);
+ vertices();
}
void Mesh::Loader::batch(PrimitiveType p)
else if(phase==1)
{
mesh.resize_buffers();
- mesh.vtx_setup.refresh();
vertex_updater = mesh.vertices.refresh_async();
if(!mesh.batches.empty())
index_updater = mesh.batches.front().refresh_async();
public:
Loader(Mesh &, bool = true);
private:
- void vertices(const std::vector<VertexAttribute> &);
+ void storage(const std::vector<VertexAttribute> &);
+ void vertices();
+ void vertices_with_format(const std::vector<VertexAttribute> &);
void batch(PrimitiveType);
void winding(FaceWinding);
};
public:
~Mesh();
+ void storage(const VertexFormat &);
+
void clear();
private:
void check_buffers(unsigned);
namespace Msp {
namespace GL {
+VertexArray::VertexArray():
+ stride(0)
+{ }
+
VertexArray::VertexArray(const VertexFormat &f)
{
- reset(f);
+ set_format(f);
}
-void VertexArray::reset(const VertexFormat &f)
+void VertexArray::set_format(const VertexFormat &f)
{
- clear();
+ if(!format.empty())
+ throw invalid_operation("VertexArray::set_format");
format = f;
stride = format.stride();
}
void VertexArray::reserve(unsigned n)
{
+ if(format.empty())
+ throw invalid_operation("VertexArray::reserve");
data.reserve(n*stride);
}
float *VertexArray::append()
{
+ if(format.empty())
+ throw invalid_operation("VertexArray::append");
data.insert(data.end(), stride, 0.0f);
update_offset();
dirty = true;
float *VertexArray::modify(unsigned i)
{
+ if(format.empty())
+ throw invalid_operation("VertexArray::modify");
dirty = true;
return &data[0]+i*stride;
}
VertexArray(const VertexArray &);
VertexArray &operator=(const VertexArray &);
public:
+ VertexArray();
+
+ /// Construct a VertexArray and set its format.
VertexArray(const VertexFormat &);
- /// Resets the VertexArray to a different format. All data is cleared.
- void reset(const VertexFormat &);
+ /// Deprecated. Use set_format.
+ DEPRECATED void reset(const VertexFormat &f) { set_format(f); }
+
+ /// Sets the format of the VertexArray.
+ void set_format(const VertexFormat &);
const VertexFormat &get_format() const { return format; }
glDeleteVertexArrays(1, &id);
}
+void VertexSetup::set_format(const VertexFormat &vfmt)
+{
+ if(!verify_format(vfmt))
+ throw invalid_argument("VertexSetup::set_format");
+ if(!vertex_format.empty())
+ throw invalid_operation("VertexSetup::set_format");
+
+ vertex_format = vfmt;
+}
+
+void VertexSetup::set_format_instanced(const VertexFormat &vfmt, const VertexFormat &ifmt)
+{
+ if(!verify_format(vfmt) || !verify_format(ifmt))
+ throw invalid_argument("VertexSetup::set_format");
+ if(!vertex_format.empty())
+ throw invalid_operation("VertexSetup::set_format");
+
+ vertex_format = vfmt;
+ inst_format = ifmt;
+}
+
void VertexSetup::set_vertex_array(const VertexArray &a)
{
- if(!verify_array(a))
+ if(vertex_format.empty())
+ throw invalid_operation("VertexSetup::set_vertex_array");
+ if(a.get_format()!=vertex_format)
+ throw incompatible_data("VertexSetup::set_vertex_array");
+ if(!a.get_buffer())
throw invalid_argument("VertexSetup::set_vertex_array");
vertex_array = &a;
- update(get_update_mask(VERTEX_ARRAY, vertex_format, *vertex_array));
- vertex_format = vertex_array->get_format();
+ update(VERTEX_ARRAY);
}
-void VertexSetup::set_instance_array(const VertexArray *a)
+void VertexSetup::set_instance_array(const VertexArray &a)
{
- if(a)
- {
- if(!verify_array(*a))
- throw invalid_argument("VertexSetup::set_instance_array");
+ if(inst_format.empty())
+ throw invalid_operation("VertexSetup::set_instance_array");
+ if(a.get_format()!=inst_format)
+ throw incompatible_data("VertexSetup::set_instance_array");
+ if(!a.get_buffer())
+ throw invalid_argument("VertexSetup::set_instance_array");
- static Require req(ARB_instanced_arrays);
- }
+ static Require req(ARB_instanced_arrays);
- inst_array = a;
- update(get_update_mask(INSTANCE_ARRAY, inst_format, *inst_array));
- inst_format = inst_array->get_format();
+ inst_array = &a;
+ update(INSTANCE_ARRAY);
}
void VertexSetup::set_index_buffer(const Buffer &ibuf)
update(INDEX_BUFFER);
}
-void VertexSetup::refresh()
+bool VertexSetup::verify_format(const VertexFormat &fmt)
{
- if(vertex_array && vertex_array->get_format()!=vertex_format)
- set_vertex_array(*vertex_array);
-
- if(inst_array && inst_array->get_format()!=inst_format)
- set_instance_array(inst_array);
-}
-
-bool VertexSetup::verify_array(const VertexArray &array)
-{
- if(!array.get_buffer())
+ if(fmt.empty())
return false;
static int max_attribs = -1;
if(max_attribs<0)
max_attribs = get_i(GL_MAX_VERTEX_ATTRIBS);
- const VertexFormat &fmt = array.get_format();
for(const unsigned char *a=fmt.begin(); a!=fmt.end(); ++a)
if(static_cast<int>(get_attribute_semantic(*a))>=max_attribs)
return false;
return true;
}
-unsigned VertexSetup::get_attribs(const VertexFormat &fmt)
-{
- unsigned mask = 0;
- for(const unsigned char *a=fmt.begin(); a!=fmt.end(); ++a)
- mask |= 1<<get_attribute_semantic(*a);
- return mask;
-}
-
-unsigned VertexSetup::get_update_mask(unsigned base, const VertexFormat &cur_fmt, const VertexArray &new_array)
-{
- unsigned unused = get_attribs(cur_fmt)&~get_attribs(new_array.get_format());
- return base | (unused ? UNUSED_ATTRIBS | (unused<<ATTRIB_SHIFT) : 0);
-}
-
void VertexSetup::update(unsigned mask) const
{
static bool direct = ARB_direct_state_access && ARB_vertex_attrib_binding;
return;
}
- if(mask&UNUSED_ATTRIBS)
- {
- for(unsigned i=0, am=mask>>ATTRIB_SHIFT; am; ++i, am>>=1)
- if(am&1)
- {
- if(direct)
- glDisableVertexArrayAttrib(id, i);
- else
- glDisableVertexAttribArray(i);
- }
- }
-
if(mask&VERTEX_ARRAY)
update_vertex_array(*vertex_array, 0, 0, direct);
BindRestore _bind(*this);
Buffer::unbind_from(ARRAY_BUFFER);
- unsigned mask = get_attribs(vertex_format)|get_attribs(inst_format);
- for(unsigned i=0; mask; ++i, mask>>=1)
- if(mask&1)
- {
- glDisableVertexAttribArray(i);
- glVertexAttribPointer(i, 1, GL_FLOAT, false, 0, 0);
- }
+ for(const unsigned char *a=vertex_format.begin(); a!=vertex_format.end(); ++a)
+ {
+ unsigned sem = get_attribute_semantic(*a);
+ glDisableVertexAttribArray(sem);
+ glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
+ }
+ for(const unsigned char *a=inst_format.begin(); a!=inst_format.end(); ++a)
+ {
+ unsigned sem = get_attribute_semantic(*a);
+ glDisableVertexAttribArray(sem);
+ glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
+ }
+
glBindBuffer(ELEMENT_ARRAY_BUFFER, 0);
}
{
VERTEX_ARRAY = 1,
INSTANCE_ARRAY = 2,
- INDEX_BUFFER = 4,
- UNUSED_ATTRIBS = 8,
- ATTRIB_SHIFT = 4
+ INDEX_BUFFER = 4
};
unsigned id;
VertexSetup();
~VertexSetup();
+ void set_format(const VertexFormat &);
+ void set_format_instanced(const VertexFormat &, const VertexFormat &);
+
void set_vertex_array(const VertexArray &);
- void set_instance_array(const VertexArray *);
+ void set_instance_array(const VertexArray &);
void set_index_buffer(const Buffer &);
- void refresh();
const VertexArray *get_vertex_array() const { return vertex_array; }
const VertexArray *get_instance_array() const { return inst_array; }
const Buffer *get_index_buffer() const { return index_buffer; }
private:
- static bool verify_array(const VertexArray &);
- static unsigned get_attribs(const VertexFormat &);
- static unsigned get_update_mask(unsigned, const VertexFormat &, const VertexArray &);
+ static bool verify_format(const VertexFormat &);
void update(unsigned) const;
void update_vertex_array(const VertexArray &, unsigned, unsigned, bool) const;
instance_data->use_buffer(instance_buffer);
vtx_setup = new VertexSetup;
+ vtx_setup->set_format_instanced(object.get_mesh()->get_vertices().get_format(), fmt);
vtx_setup->set_vertex_array(object.get_mesh()->get_vertices());
vtx_setup->set_index_buffer(*object.get_mesh()->get_index_buffer());
- vtx_setup->set_instance_array(instance_data);
+ vtx_setup->set_instance_array(*instance_data);
}
else
static Require req(ARB_vertex_shader);