+ uniform(name, v.x, v.y, v.z);
+}
+
+void ProgramData::uniform3(const string &name, const int *v)
+{
+ uniform(name, new Uniform3i(v));
+}
+
+void ProgramData::uniform3(const string &name, const float *v)
+{
+ uniform(name, new Uniform3f(v));
+}
+
+void ProgramData::uniform(const string &name, int v0, int v1, int v2, int v3)
+{
+ int va[4] = { v0, v1, v2, v3 };
+ uniform4(name, va);
+}
+
+void ProgramData::uniform(const string &name, float v0, float v1, float v2, float v3)
+{
+ float va[4] = { v0, v1, v2, v3 };
+ uniform4(name, va);
+}
+
+void ProgramData::uniform(const string &name, const Vector4 &v)
+{
+ uniform(name, v.x, v.y, v.z, v.w);
+}
+
+void ProgramData::uniform(const string &name, const Color &c)
+{
+ uniform(name, c.r, c.g, c.b, c.a);
+}
+
+void ProgramData::uniform4(const string &name, const int *v)
+{
+ uniform(name, new Uniform4i(v));
+}
+
+void ProgramData::uniform4(const string &name, const float *v)
+{
+ uniform(name, new Uniform4f(v));
+}
+
+void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 2, 2> &m)
+{
+ uniform_matrix2(name, &m(0, 0));
+}
+
+void ProgramData::uniform_matrix2(const string &name, const float *v)
+{
+ uniform(name, new UniformMatrix2x2f(v));
+}
+
+void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 3, 3> &m)
+{
+ uniform_matrix3(name, &m(0, 0));
+}
+
+void ProgramData::uniform_matrix3(const string &name, const float *v)
+{
+ uniform(name, new UniformMatrix3x3f(v));
+}
+
+void ProgramData::uniform(const string &name, const Matrix &m)
+{
+ uniform_matrix4(name, m.data());
+}
+
+void ProgramData::uniform_matrix4(const string &name, const float *v)
+{
+ uniform(name, new UniformMatrix4x4f(v));
+}
+
+void ProgramData::uniform1_array(const string &name, unsigned n, const int *v)
+{
+ uniform(name, new UniformArray<Uniform1i>(n, v));
+}
+
+void ProgramData::uniform1_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<Uniform1f>(n, v));
+}
+
+void ProgramData::uniform2_array(const string &name, unsigned n, const int *v)
+{
+ uniform(name, new UniformArray<Uniform2i>(n, v));
+}
+
+void ProgramData::uniform2_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<Uniform2f>(n, v));
+}
+
+void ProgramData::uniform3_array(const string &name, unsigned n, const int *v)
+{
+ uniform(name, new UniformArray<Uniform3i>(n, v));
+}
+
+void ProgramData::uniform3_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<Uniform3f>(n, v));
+}
+
+void ProgramData::uniform4_array(const string &name, unsigned n, const int *v)
+{
+ uniform(name, new UniformArray<Uniform4i>(n, v));
+}
+
+void ProgramData::uniform4_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<Uniform4f>(n, v));
+}
+
+void ProgramData::uniform_matrix4_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<UniformMatrix4x4f>(n, v));
+}
+
+void ProgramData::remove_uniform(const string &name)
+{
+ SlotMap::iterator i = uniform_slots.find(name);
+ if(i!=uniform_slots.end())
+ {
+ vector<Uniform *>::iterator j = uniforms.begin()+i->second;
+ delete *j;
+ uniforms.erase(j);
+
+ for(SlotMap::iterator k=uniform_slots.begin(); k!=uniform_slots.end(); ++k)
+ if(k->second>i->second)
+ --k->second;
+
+ uniform_slots.erase(i);
+
+ dirty = ALL_ONES;
+ }
+}
+
+vector<string> ProgramData::get_uniform_names() const
+{
+ vector<string> names;
+ for(SlotMap::const_iterator i=uniform_slots.begin(); i!=uniform_slots.end(); ++i)
+ names.push_back(i->first);
+ return names;
+}
+
+const Uniform &ProgramData::get_uniform(const string &name) const
+{
+ return *uniforms[get_item(uniform_slots, name)];
+}
+
+unsigned ProgramData::compute_slot_mask(const Program::UniformBlockInfo &block) const
+{
+ unsigned mask = 0;
+ for(vector<const Program::UniformInfo *>::const_iterator i=block.uniforms.begin(); i!=block.uniforms.end(); ++i)
+ {
+ SlotMap::const_iterator j = uniform_slots.find((*i)->name);
+ /* TODO issue a warning (or even error?) either here or in update_block
+ if all uniforms for a buffer-backed block are not found */
+ if(j!=uniform_slots.end() && j->second<MASK_BITS)
+ mask |= 1<<j->second;
+ }
+
+ return mask;
+}
+
+void ProgramData::update_block(UniformBlock &block, const Program::UniformBlockInfo &info) const
+{
+ for(vector<const Program::UniformInfo *>::const_iterator i=info.uniforms.begin(); i!=info.uniforms.end(); ++i)
+ {
+ SlotMap::const_iterator j = uniform_slots.find((*i)->name);
+ if(j!=uniform_slots.end())
+ block.attach(**i, *uniforms[j->second]);
+ }
+}
+
+ProgramData::SharedBlock *ProgramData::get_shared_block(const Program::UniformBlockInfo &info) const
+{
+ BlockMap::iterator i = blocks.find(info.layout_hash);
+ if(i==blocks.end())
+ {
+ unsigned used = compute_slot_mask(info);
+ if(!used)
+ return 0;
+
+ UniformBlock *block;
+ if(info.bind_point>=0)
+ {
+ if(!buffer)
+ {
+ buffer = new Buffer(UNIFORM_BUFFER);
+ buffer->set_usage(STREAM_DRAW);
+ }
+
+ block = new UniformBlock(info.data_size);
+ block->use_buffer(buffer, last_block);
+ last_block = block;
+ }
+ else
+ block = new UniformBlock;
+
+ i = blocks.insert(BlockMap::value_type(info.layout_hash, SharedBlock(used, block))).first;
+ }
+
+ return &i->second;