X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fprogramdata.cpp;h=5f124a907fc8eebbb034d25cddb5ba475c67c022;hp=9ab0731d8164852352f12f38808e36a2f7aed37d;hb=bec07999d95b76f4b47cffcc564d0cd0afc0435e;hpb=b617c5d7b5283ad260a77f01e42e6170cabbc03d diff --git a/source/programdata.cpp b/source/programdata.cpp index 9ab0731d..5f124a90 100644 --- a/source/programdata.cpp +++ b/source/programdata.cpp @@ -1,137 +1,961 @@ -/* $Id$ - -This file is part of libmspgl -Copyright © 2007 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - -#include "extension.h" +#include +#include +#include +#include +#include "buffer.h" +#include "color.h" +#include "error.h" +#include "matrix.h" #include "program.h" #include "programdata.h" #include "uniform.h" +#include "uniformblock.h" +#include "vector.h" using namespace std; namespace Msp { namespace GL { -ProgramData::ProgramData() +ProgramData::ProgramData(const Program *p): + tied_program(p), + last_block(0), + buffer(0), + dirty(0) +{ } + +// Blocks are intentionally left uncopied +ProgramData::ProgramData(const ProgramData &other): + tied_program(other.tied_program), + uniforms(other.uniforms), + last_block(0), + buffer(0), + dirty(0) { - static RequireExtension _ext("GL_ARB_shader_objects"); + for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + i->value = i->value->clone(); } -ProgramData::ProgramData(const ProgramData &other): - data(other.data) +ProgramData::ProgramData(const ProgramData &other, const Program *p): + tied_program(p), + last_block(0), + buffer(0), + dirty(0) +{ + if(tied_program) + { + for(vector::const_iterator i=other.uniforms.begin(); i!=other.uniforms.end(); ++i) + tied_program->get_uniform_info(i->name); + } + + uniforms = other.uniforms; + for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + i->value = i->value->clone(); +} + +ProgramData &ProgramData::operator=(const ProgramData &other) { - for(map::iterator i=data.begin(); i!=data.end(); ++i) - i->second = i->second->clone(); + tied_program = other.tied_program; + + uniforms = other.uniforms; + for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + i->value = i->value->clone(); + + for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i) + delete i->second.block; + programs.clear(); + + last_block = 0; + buffer = 0; + dirty = 0; + + return *this; } ProgramData::~ProgramData() { - for(map::iterator i=data.begin(); i!=data.end(); ++i) - delete i->second; + for(vector::iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + delete i->value; + for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i) + { + if(i->second.indices.type_flag==0xFE) + delete i->second.indices.dynamic.values; + delete i->second.block; + } + delete buffer; } -void ProgramData::uniform(int index, Uniform *uni) +void ProgramData::uniform(const string &name, Uniform *uni) { - if(index<0) + try + { + if(!validate_name(name)) + { + delete uni; + return; + } + } + catch(...) { delete uni; + throw; + } + + int i = find_uniform_index(name); + if(i<0) + return add_uniform(name, uni); + + uniforms[i].replace_value(uni); + dirty |= 1< +void ProgramData::uniform(const string &name, V value) +{ + if(!validate_name(name)) + return; + + int i = find_uniform_index(name); + if(i<0) + return add_uniform(name, new T(value)); + + if(T *uni = dynamic_cast(uniforms[i].value)) + uni->set(value); + else + uniforms[i].replace_value(new T(value)); + + dirty |= 1< +void ProgramData::uniform_array(const string &name, unsigned n, V value) +{ + if(!validate_name(name)) return; + + int i = find_uniform_index(name); + if(i<0) + return add_uniform(name, new UniformArray(n, value)); + + UniformArray *uni = dynamic_cast *>(uniforms[i].value); + if(uni && n==uni->size()) + uni->set(value); + else + uniforms[i].replace_value(new UniformArray(n, value)); + + dirty |= 1<get_uniform_info(name); + else if(name[name.size()-1]==']') + throw invalid_argument("ProgramData::uniform"); + return true; + } +#ifdef DEBUG + catch(const exception &e) + { + IO::print(IO::cerr, "Error while setting uniform %s: %s: %s\n", name, Debug::demangle(typeid(e).name()), e.what()); + return false; } +#endif +} - map::iterator i = data.find(index); - if(i!=data.end()) +void ProgramData::add_uniform(const string &name, Uniform *uni) +{ + if(uniforms.size()>=MASK_BITS) { - delete i->second; - i->second = uni; + delete uni; + throw too_many_uniforms(name); } - else - data[index] = uni; + + vector::iterator j = lower_bound(uniforms.begin(), uniforms.end(), name, uniform_name_compare); + + NamedUniform nu; + nu.name = name; + nu.value = uni; + uniforms.insert(j, nu); + + dirty = ALL_ONES; +} + +void ProgramData::uniform(const string &name, const Uniform &u) +{ + uniform(name, u.clone()); +} + +void ProgramData::uniform(const string &name, int v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, float v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, int v0, int v1) +{ + int va[2] = { v0, v1 }; + uniform2(name, va); +} + +void ProgramData::uniform(const string &name, float v0, float v1) +{ + float va[2] = { v0, v1 }; + uniform2(name, va); +} + +void ProgramData::uniform2(const string &name, const int *v) +{ + uniform(name, v); +} + +void ProgramData::uniform2(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, int v0, int v1, int v2) +{ + int va[3] = { v0, v1, v2 }; + uniform3(name, va); +} + +void ProgramData::uniform(const string &name, float v0, float v1, float v2) +{ + float va[3] = { v0, v1, v2 }; + uniform3(name, va); +} + +void ProgramData::uniform(const string &name, const Vector3 &v) +{ + uniform(name, v.x, v.y, v.z); +} + +void ProgramData::uniform3(const string &name, const int *v) +{ + uniform(name, v); +} + +void ProgramData::uniform3(const string &name, const float *v) +{ + uniform(name, 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, v); +} + +void ProgramData::uniform4(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix2(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix2(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix3x2(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix3x2(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix4x2(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix4x2(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix2x3(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix2x3(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix3(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix3(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix4x3(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix4x3(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix2x4(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix2x4(const string &name, const float *v) +{ + uniform(name, v); +} + +void ProgramData::uniform(const string &name, const LinAl::Matrix &m) +{ + uniform_matrix3x4(name, &m(0, 0)); +} + +void ProgramData::uniform_matrix3x4(const string &name, const float *v) +{ + uniform(name, 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, v); +} + +void ProgramData::uniform1_array(const string &name, unsigned n, const int *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform1_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform2_array(const string &name, unsigned n, const int *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform2_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); } -void ProgramData::uniform(int index, int v) +void ProgramData::uniform3_array(const string &name, unsigned n, const int *v) { - uniform(index, new Uniform1i(v)); + uniform_array(name, n, v); } -void ProgramData::uniform(int index, float v) +void ProgramData::uniform3_array(const string &name, unsigned n, const float *v) { - uniform(index, new Uniform1f(v)); + uniform_array(name, n, v); } -void ProgramData::uniform(int index, float v0, float v1) +void ProgramData::uniform4_array(const string &name, unsigned n, const int *v) { - uniform(index, new Uniform2f(v0, v1)); + uniform_array(name, n, v); } -void ProgramData::uniform2(int index, const float *v) +void ProgramData::uniform4_array(const string &name, unsigned n, const float *v) { - uniform(index, v[0], v[1]); + uniform_array(name, n, v); } -void ProgramData::uniform(int index, float v0, float v1, float v2) +void ProgramData::uniform_matrix2_array(const string &name, unsigned n, const float *v) { - uniform(index, new Uniform3f(v0, v1, v2)); + uniform_array(name, n, v); } -void ProgramData::uniform3(int index, const float *v) +void ProgramData::uniform_matrix3x2_array(const string &name, unsigned n, const float *v) { - uniform(index, v[0], v[1], v[2]); + uniform_array(name, n, v); } -void ProgramData::uniform(int index, float v0, float v1, float v2, float v3) +void ProgramData::uniform_matrix4x2_array(const string &name, unsigned n, const float *v) { - uniform(index, new Uniform4f(v0, v1, v2, v3)); + uniform_array(name, n, v); } -void ProgramData::uniform4(int index, const float *v) +void ProgramData::uniform_matrix2x3_array(const string &name, unsigned n, const float *v) { - uniform(index, v[0], v[1], v[2], v[3]); + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix3_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix4x3_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix2x4_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix3x4_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::uniform_matrix4_array(const string &name, unsigned n, const float *v) +{ + uniform_array(name, n, v); +} + +void ProgramData::remove_uniform(const string &name) +{ + vector::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 ProgramData::get_uniform_names() const +{ + vector names; + names.reserve(uniforms.size()); + for(vector::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::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; iname); + if(j>=0) + { + indices[i] = j; + if(static_cast(j)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_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); + + 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; } void ProgramData::apply() const { - for(map::const_iterator i=data.begin(); i!=data.end(); ++i) - i->second->apply(i->first); + const Program *prog = Program::current(); + if(!prog) + throw invalid_operation("ProgramData::apply"); + + Program::LayoutHash layout = prog->get_uniform_layout_hash(); + ProgramUniforms &pu = programs[layout]; + + Mask force_dirty = (dirty==ALL_ONES ? ALL_ONES : 0U); + Mask affected = (dirty&pu.used) | force_dirty; + if(affected|pu.dirty) + { + /* If the global dirty flag affects this program, add it to per-program + dirty flags and clear the global flag. A previously unseen program will + cause this to happen if there's any dirty uniforms. */ + if(affected) + { + for(BlockMap::iterator i=blocks.begin(); i!=blocks.end(); ++i) + i->second.dirty |= (dirty&i->second.used) | force_dirty; + for(ProgramMap::iterator i=programs.begin(); i!=programs.end(); ++i) + i->second.dirty |= (dirty&i->second.used) | force_dirty; + dirty = 0; + } + + const Program::UniformBlockMap &prog_blocks = prog->get_uniform_blocks(); + + UniformBlock *old_last_block = last_block; + if(pu.dirty==ALL_ONES) + { + /* The set of uniforms has changed since this program was last used. + Regenerate the list of uniform blocks. */ + pu.blocks.clear(); + pu.blocks.reserve(prog_blocks.size()); + + pu.used = 0; + for(Program::UniformBlockMap::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i) + { + SharedBlock *shared = get_shared_block(i->second); + if(shared) + { + if(shared->dirty==ALL_ONES) + update_block_uniform_indices(*shared, i->second); + pu.used |= shared->used; + } + + pu.blocks.push_back(ProgramBlock(i->second.bind_point, shared)); + } + } + + // Update the contents of all dirty blocks. + bool buffered_blocks_updated = false; + std::vector::iterator j = pu.blocks.begin(); + for(Program::UniformBlockMap::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i, ++j) + { + if(!j->shared || !j->shared->dirty) + continue; + + update_block(*j->shared, i->second); + j->shared->dirty = 0; + buffered_blocks_updated |= (j->bind_point>=0); + } + + pu.dirty = 0; + + /* If any blocks stored in the buffer were updated, bind the buffer here + to avoid state thrashing. */ + if(buffered_blocks_updated && !ARB_direct_state_access) + buffer->bind(); + + if(last_block!=old_last_block) + { + unsigned required_size = last_block->get_required_buffer_size(); + if(last_block->get_required_buffer_size()>buffer->get_size()) + { + if(buffer->get_size()>0) + { + delete buffer; + buffer = new Buffer(UNIFORM_BUFFER); + last_block->change_buffer(buffer); + } + + buffer->storage(required_size); + } + } + } + + for(vector::iterator i=pu.blocks.begin(); i!=pu.blocks.end(); ++i) + if(i->block) + i->block->apply(i->bind_point); +} + + +ProgramData::NamedUniform::NamedUniform(): + value(0) +{ } + +void ProgramData::NamedUniform::replace_value(Uniform *v) +{ + /* UniformBlock does not copy the uniforms, so existing default blocks + will be left with stale pointers. This is not a problem as long as no + one stores pointers to the blocks and expects them to stay valid. */ + delete value; + value = v; +} + + +ProgramData::SharedBlock::SharedBlock(UniformBlock *b): + used(0), + dirty(0), + block(b) +{ + indices.type_flag = 0xFD; +} + +const UInt8 *ProgramData::SharedBlock::get_uniform_indices() const +{ + return (indices.type_flag==0xFE ? indices.dynamic.values : indices.values); } -ProgramData::Loader::Loader(ProgramData &pd, Program &pr): - DataFile::ObjectLoader(pd), - prog(pr) +ProgramData::ProgramBlock::ProgramBlock(): + bind_point(-1), + block(0), + shared(0) +{ } + +ProgramData::ProgramBlock::ProgramBlock(int p, SharedBlock *b): + bind_point(p), + block((b && b->used) ? b->block : 0), + shared(b) +{ } + + +ProgramData::ProgramUniforms::ProgramUniforms(): + used(ALL_ONES), + dirty(ALL_ONES) +{ } + + +ProgramData::Loader::Loader(ProgramData &pd): + DataFile::ObjectLoader(pd) { + add("uniform", &Loader::uniform1i); add("uniform1i", &Loader::uniform1i); + add("uniform", &Loader::uniform1f); add("uniform1f", &Loader::uniform1f); + add("uniform", &Loader::uniform2i); + add("uniform2i", &Loader::uniform2i); + add("uniform", &Loader::uniform2f); add("uniform2f", &Loader::uniform2f); + add("uniform", &Loader::uniform3i); + add("uniform3i", &Loader::uniform3i); + add("uniform", &Loader::uniform3f); add("uniform3f", &Loader::uniform3f); + add("uniform", &Loader::uniform4i); + add("uniform4i", &Loader::uniform4i); + add("uniform", &Loader::uniform4f); add("uniform4f", &Loader::uniform4f); + add("uniform1i_array", &Loader::uniform1i_array); + add("uniform1f_array", &Loader::uniform1f_array); + add("uniform2f_array", &Loader::uniform2f_array); + add("uniform3f_array", &Loader::uniform3f_array); + add("uniform4f_array", &Loader::uniform4f_array); + add("uniform_array", &Loader::uniform_array); } void ProgramData::Loader::uniform1i(const string &n, int v) { - obj.uniform(prog.get_uniform_location(n), v); + obj.uniform(n, v); } void ProgramData::Loader::uniform1f(const string &n, float v) { - obj.uniform(prog.get_uniform_location(n), v); + obj.uniform(n, v); +} + +void ProgramData::Loader::uniform2i(const string &n, int v0, int v1) +{ + obj.uniform(n, v0, v1); } void ProgramData::Loader::uniform2f(const string &n, float v0, float v1) { - obj.uniform(prog.get_uniform_location(n), v0, v1); + obj.uniform(n, v0, v1); +} + +void ProgramData::Loader::uniform3i(const string &n, int v0, int v1, int v2) +{ + obj.uniform(n, v0, v1, v2); } void ProgramData::Loader::uniform3f(const string &n, float v0, float v1, float v2) { - obj.uniform(prog.get_uniform_location(n), v0, v1, v2); + obj.uniform(n, v0, v1, v2); +} + +void ProgramData::Loader::uniform4i(const string &n, int v0, int v1, int v2, int v3) +{ + obj.uniform(n, v0, v1, v2, v3); } void ProgramData::Loader::uniform4f(const string &n, float v0, float v1, float v2, float v3) { - obj.uniform(prog.get_uniform_location(n), v0, v1, v2, v3); + obj.uniform(n, v0, v1, v2, v3); +} + +void ProgramData::Loader::uniform_array_(const string &n, DataType t, unsigned e) +{ + ArrayLoader ldr(t, e); + load_sub_with(ldr); + unsigned size = ldr.get_size(); + if(!size) + throw logic_error("empty uniform array"); + + DataType type = ldr.get_data_type(); + unsigned elem_size = ldr.get_element_size(); + if(type==INT) + { + const int *data = reinterpret_cast(ldr.get_data()); + if(elem_size==1) + obj.uniform1_array(n, size, data); + else if(elem_size==2) + obj.uniform2_array(n, size, data); + else if(elem_size==3) + obj.uniform3_array(n, size, data); + else if(elem_size==4) + obj.uniform4_array(n, size, data); + else + throw logic_error("unsupported combination of array type and element size"); + } + else if(type==FLOAT) + { + const float *data = reinterpret_cast(ldr.get_data()); + if(elem_size==1) + obj.uniform1_array(n, size, data); + else if(elem_size==2) + obj.uniform2_array(n, size, data); + else if(elem_size==3) + obj.uniform3_array(n, size, data); + else if(elem_size==4) + obj.uniform4_array(n, size, data); + else + throw logic_error("unsupported combination of array type and element size"); + } + else + throw logic_error("unsupported array type"); +} + +void ProgramData::Loader::uniform1i_array(const string &n) +{ + uniform_array_(n, INT, 1); +} + +void ProgramData::Loader::uniform1f_array(const string &n) +{ + uniform_array_(n, FLOAT, 1); +} + +void ProgramData::Loader::uniform2i_array(const string &n) +{ + uniform_array_(n, INT, 2); +} + +void ProgramData::Loader::uniform2f_array(const string &n) +{ + uniform_array_(n, FLOAT, 2); +} + +void ProgramData::Loader::uniform3i_array(const string &n) +{ + uniform_array_(n, INT, 3); +} + +void ProgramData::Loader::uniform3f_array(const string &n) +{ + uniform_array_(n, FLOAT, 3); +} + +void ProgramData::Loader::uniform4i_array(const string &n) +{ + uniform_array_(n, INT, 4); +} + +void ProgramData::Loader::uniform4f_array(const string &n) +{ + uniform_array_(n, FLOAT, 4); +} + +void ProgramData::Loader::uniform_array(const string &n) +{ + uniform_array_(n, static_cast(0), 0); +} + + +ProgramData::ArrayLoader::ArrayLoader(DataType t, unsigned e): + type(t), + element_size(e) +{ + add("uniform", &ArrayLoader::uniform1i); + add("uniform1i", &ArrayLoader::uniform1i); + add("uniform", &ArrayLoader::uniform1f); + add("uniform1f", &ArrayLoader::uniform1f); + add("uniform", &ArrayLoader::uniform2f); + add("uniform2f", &ArrayLoader::uniform2f); + add("uniform", &ArrayLoader::uniform3f); + add("uniform3f", &ArrayLoader::uniform3f); + add("uniform", &ArrayLoader::uniform4f); + add("uniform4f", &ArrayLoader::uniform4f); +} + +void ProgramData::ArrayLoader::uniform(DataType t, unsigned e, const void *v) +{ + if(element_size && (t!=type || e!=element_size)) + throw logic_error("heterogeneous array contents"); + + if(!element_size) + { + type = t; + element_size = e; + } + + const char *cv = reinterpret_cast(v); + data.insert(data.end(), cv, cv+element_size*4); +} + +void ProgramData::ArrayLoader::uniform1i(int v) +{ + uniform(INT, 1, &v); +} + +void ProgramData::ArrayLoader::uniform1f(float v) +{ + uniform(FLOAT, 1, &v); +} + +void ProgramData::ArrayLoader::uniform2i(int v0, int v1) +{ + int va[2] = { v0, v1 }; + uniform(INT, 2, va); +} + +void ProgramData::ArrayLoader::uniform2f(float v0, float v1) +{ + float va[2] = { v0, v1 }; + uniform(FLOAT, 2, va); +} + +void ProgramData::ArrayLoader::uniform3i(int v0, int v1, int v2) +{ + int va[3] = { v0, v1, v2 }; + uniform(INT, 3, va); +} + +void ProgramData::ArrayLoader::uniform3f(float v0, float v1, float v2) +{ + float va[3] = { v0, v1, v2 }; + uniform(FLOAT, 3, va); +} + +void ProgramData::ArrayLoader::uniform4i(int v0, int v1, int v2, int v3) +{ + int va[4] = { v0, v1, v2, v3 }; + uniform(INT, 4, va); +} + +void ProgramData::ArrayLoader::uniform4f(float v0, float v1, float v2, float v3) +{ + float va[4] = { v0, v1, v2, v3 }; + uniform(FLOAT, 4, va); } } // namespace GL