+ uniform(name, c.r, c.g, c.b, c.a);
+}
+
+void ProgramData::uniform4(const string &name, const float *v)
+{
+ uniform(name, new Uniform4f(v));
+}
+
+void ProgramData::uniform_matrix4(const string &name, const float *v)
+{
+ uniform(name, new UniformMatrix4x4f(v));
+}
+
+void ProgramData::uniform_matrix4(const string &name, const Matrix &m)
+{
+ float v[16];
+ copy(m.data(), m.data()+16, v);
+ uniform_matrix4(name, 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 float *v)
+{
+ uniform(name, new UniformArray<Uniform2f>(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 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));
+}
+
+const UniformBlock &ProgramData::get_block(const Program &prog) const
+{
+ if(modified)
+ {
+ for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+ i->second.dirty = true;
+ modified = false;
+ }
+
+ unsigned layout_hash = prog.get_uniform_layout_hash();
+ map<unsigned, Block>::iterator i = blocks.find(layout_hash);
+ if(i==blocks.end())
+ {
+ i = blocks.insert(BlockMap::value_type(layout_hash, Block())).first;
+ i->second.dirty = true;
+ i->second.block = new UniformBlock;
+ }
+
+ UniformBlock &block = *i->second.block;
+ if(i->second.dirty)
+ {
+ for(UniformMap::const_iterator j=uniforms.begin(); j!=uniforms.end(); ++j)
+ {
+ int loc = prog.get_uniform_location(j->first);
+ if(loc>=0)
+ block.attach(loc, *j->second);
+ }
+ i->second.dirty = false;
+ }
+
+ return block;