+ uniform(name, new UniformMatrix2x4f(v));
+}
+
+void ProgramData::uniform(const string &name, const LinAl::Matrix<float, 4, 3> &m)
+{
+ uniform_matrix3x4(name, &m(0, 0));
+}
+
+void ProgramData::uniform_matrix3x4(const string &name, const float *v)
+{
+ uniform(name, new UniformMatrix3x4f(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_matrix2_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<UniformMatrix2x2f>(n, v));
+}
+
+void ProgramData::uniform_matrix3x2_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<UniformMatrix3x2f>(n, v));
+}
+
+void ProgramData::uniform_matrix4x2_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<UniformMatrix4x2f>(n, v));
+}
+
+void ProgramData::uniform_matrix2x3_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<UniformMatrix2x3f>(n, v));
+}
+
+void ProgramData::uniform_matrix3_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<UniformMatrix3x3f>(n, v));
+}
+
+void ProgramData::uniform_matrix4x3_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<UniformMatrix4x3f>(n, v));
+}
+
+void ProgramData::uniform_matrix2x4_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<UniformMatrix2x4f>(n, v));
+}
+
+void ProgramData::uniform_matrix3x4_array(const string &name, unsigned n, const float *v)
+{
+ uniform(name, new UniformArray<UniformMatrix3x4f>(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)
+{
+ vector<NamedUniform>::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare);
+ if(i==uniforms.end() || i->name!=name)
+ return;
+
+ delete i->value;
+ uniforms.erase(i);
+
+ dirty = ALL_ONES;
+}
+
+vector<string> ProgramData::get_uniform_names() const
+{
+ vector<string> names;
+ names.reserve(uniforms.size());
+ for(vector<NamedUniform>::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
+ names.push_back(i->name);
+ return names;
+}
+
+const Uniform &ProgramData::get_uniform(const string &name) const
+{
+ int i = find_uniform_index(name);
+ if(i<0)
+ throw key_error(name);
+ return *uniforms[i].value;
+}
+
+const Uniform *ProgramData::find_uniform(const string &name) const
+{
+ int i = find_uniform_index(name);
+ return (i>=0 ? uniforms[i].value : 0);
+}
+
+bool ProgramData::uniform_name_compare(const NamedUniform &nu, const string &name)
+{
+ return nu.name<name;
+}
+
+int ProgramData::find_uniform_index(const string &name) const
+{
+ vector<NamedUniform>::const_iterator i = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare);
+ return ((i!=uniforms.end() && i->name==name) ? i-uniforms.begin() : -1);
+}
+
+void ProgramData::update_block_uniform_indices(SharedBlock &block, const Program::UniformBlockInfo &info) const
+{
+ UInt8 *indices = block.indices.values;
+ if(info.uniforms.size()>16)
+ {
+ if(block.indices.type_flag==0xFD)
+ {
+ block.indices.dynamic.values = new UInt8[info.uniforms.size()];
+ block.indices.type_flag = 0xFE;
+ }
+ indices = block.indices.dynamic.values;
+ }
+
+ block.used = 0;
+ for(unsigned i=0; i<info.uniforms.size(); ++i)
+ {
+ int j = find_uniform_index(info.uniforms[i]->name);
+ if(j>=0)
+ {
+ indices[i] = j;
+ if(static_cast<unsigned>(j)<MASK_BITS)
+ block.used |= 1<<j;
+ }
+ else
+ indices[i] = 0xFF;
+ }
+
+ block.dirty = block.used;
+}
+
+void ProgramData::update_block(SharedBlock &block, const Program::UniformBlockInfo &info) const
+{
+ const UInt8 *indices = block.get_uniform_indices();
+ for(unsigned i=0; i<info.uniforms.size(); ++i)
+ if(indices[i]!=0xFF)
+ block.block->attach(*info.uniforms[i], *uniforms[indices[i]].value);
+}
+
+ProgramData::SharedBlock *ProgramData::get_shared_block(const Program::UniformBlockInfo &info) const
+{
+ BlockMap::iterator i = blocks.find(info.layout_hash);
+ if(i==blocks.end())
+ {
+ bool any_found = false;
+ bool all_found = true;
+ for(vector<const Program::UniformInfo *>::const_iterator j=info.uniforms.begin(); j!=info.uniforms.end(); ++j)
+ {
+ if(find_uniform_index((*j)->name)>=0)
+ any_found = true;
+ else
+ all_found = false;
+ }
+
+ if(!any_found)
+ return 0;
+ else if(!all_found && info.bind_point>=0)
+ {
+#ifdef DEBUG
+ IO::print(IO::cerr, "Warning: not all uniforms for block %s are present\n", info.name);
+#else
+ throw incomplete_uniform_block(info.name);
+#endif
+ }
+
+ 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(block))).first;
+ update_block_uniform_indices(i->second, info);
+ }
+
+ return &i->second;