X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fmaterials%2Frenderpass.cpp;h=62056ff9f56c63f103edb920ee8b546c7b13fe91;hp=810b3673e584671423c95795a0eaab5cdd9c5e93;hb=3ac3a51c623271da815c8ee60c484445871753bf;hpb=4c856cc3c0425fef1d123fe846ab19fbb10ab6c6 diff --git a/source/materials/renderpass.cpp b/source/materials/renderpass.cpp index 810b3673..62056ff9 100644 --- a/source/materials/renderpass.cpp +++ b/source/materials/renderpass.cpp @@ -1,8 +1,8 @@ +#include #include #include #include #include "error.h" -#include "material.h" #include "renderpass.h" #include "program.h" #include "programdata.h" @@ -10,6 +10,7 @@ #include "texture.h" #include "texture2d.h" #include "texturing.h" +#include "uniform.h" using namespace std; @@ -21,159 +22,182 @@ RenderPass::RenderPass(): shprog_from_material(false), shdata(0), material(0), - texturing(0), - back_faces(false) + back_faces(false), + receive_shadows(false), + image_based_lighting(false) { } -RenderPass::RenderPass(const RenderPass &other): - shprog(other.shprog), - shprog_from_material(other.shprog_from_material), - shdata(other.shdata), - uniform_slots(other.uniform_slots), - material(other.material), - material_slot(other.material_slot), - texturing(other.texturing ? new Texturing(*other.texturing) : 0), - tex_names(other.tex_names), - back_faces(other.back_faces) -{ } - -RenderPass &RenderPass::operator=(const RenderPass &other) -{ - shprog = other.shprog; - shprog_from_material = other.shprog_from_material; - shdata = other.shdata; - uniform_slots = other.uniform_slots; - material = other.material; - material_slot = other.material_slot; - texturing = other.texturing ? new Texturing(*other.texturing) : 0; - tex_names = other.tex_names; - back_faces = other.back_faces; - return *this; -} - -RenderPass::~RenderPass() +void RenderPass::set_material_textures() { - delete texturing; -} - -void RenderPass::finalize_material(DataFile::Collection *coll) -{ - maybe_create_material_shader(coll); - ensure_private_shader_data(); - - if(!texturing) - texturing = new Texturing; - material->attach_textures_to(*texturing, *shdata); + const Tag *material_texture_tags = material->get_texture_tags(); + for(const Tag *tag=material_texture_tags; tag->id; ++tag) + set_texture(*tag, material->get_texture(*tag), material->get_sampler()); } -void RenderPass::maybe_create_material_shader(DataFile::Collection *coll) +void RenderPass::maybe_create_material_shader() { if(shprog && !shprog_from_material) return; - if(coll) - { - shprog = material->create_compatible_shader(*coll); - shprog.keep(); - } - else - throw invalid_operation("no collection"); + map extra_spec; + if(receive_shadows) + extra_spec["use_shadow_map"] = true; + if(image_based_lighting) + extra_spec["use_image_based_lighting"] = true; + + shprog = material->create_compatible_shader(extra_spec); if(shdata) - shdata = new ProgramData(*shdata, shprog.get()); + shdata = new ProgramData(*shdata, shprog); shprog_from_material = true; } -void RenderPass::ensure_private_shader_data() -{ - if(!shprog) - throw invalid_operation("RenderPass::ensure_private_shader_data"); - - if(!shdata) - shdata = new ProgramData(shprog.get()); - else if(shdata.refcount()>1) - shdata = new ProgramData(*shdata); -} - void RenderPass::set_shader_program(const Program *prog, const ProgramData *data) { shprog = prog; - shprog.keep(); shprog_from_material = false; shdata = (data ? new ProgramData(*data) : 0); - if(material) - finalize_material(0); } -const string &RenderPass::get_slotted_uniform_name(const string &slot) const +Tag RenderPass::get_slotted_uniform_tag(Tag slot) const { - map::const_iterator i = uniform_slots.find(slot); + map::const_iterator i = uniform_slots.find(slot); if(i==uniform_slots.end()) - { - static string empty; - return empty; - } + return Tag(); return i->second; } -void RenderPass::set_material(const Material *mat, DataFile::Collection *coll) +void RenderPass::set_material(const Material *mat) { material = mat; - material.keep(); - finalize_material(coll); + maybe_create_material_shader(); + set_material_textures(); +} + +void RenderPass::set_texture(Tag tag, const Texture *tex, const Sampler *samp) +{ + vector::iterator i = find_member(textures, tag, &TextureSlot::tag); + if(i==textures.end()) + { + textures.push_back(TextureSlot(tag)); + i = textures.end()-1; + } + i->texture = tex; + if(samp) + i->sampler = samp; +} + +Tag RenderPass::get_texture_tag(const string &slot) const +{ + vector::const_iterator i = find_member(textures, slot, &TextureSlot::slot_name); + return (i!=textures.end() ? i->tag : Tag()); } void RenderPass::set_texture(unsigned index, const Texture *tex, const Sampler *samp) { - if(!texturing) - texturing = new Texturing; + if(!shprog) + throw invalid_operation("RenderPass::set_texture"); - texturing->attach(index, *tex, (samp ? samp : texturing->get_attached_sampler(index))); + const vector &uniforms = shprog->get_uniforms(); + for(vector::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + if(is_image(i->type) && i->binding==static_cast(index)) + return set_texture(i->tag, tex, samp); + + if(shdata) + { + const vector &tags = shdata->get_uniform_tags(); + for(vector::const_iterator i=tags.begin(); i!=tags.end(); ++i) + { + vector::const_iterator j = find_member(uniforms, *i, &Program::UniformInfo::tag); + if(j==uniforms.end() || !is_image(j->type)) + continue; + if(const Uniform1i *uni1i = dynamic_cast(shdata->find_uniform(*i))) + if(uni1i->get()==static_cast(index)) + return set_texture(*i, tex, samp); + } + } } int RenderPass::get_texture_index(const string &n) const { - map::const_iterator i = tex_names.find(n); - if(i==tex_names.end()) - return -1; - return i->second; + vector::const_iterator i = find_member(textures, n, &TextureSlot::slot_name); + return (shprog && i!=textures.end() ? shprog->get_uniform_binding(i->tag) : -1); +} + +void RenderPass::set_back_faces(bool bf) +{ + back_faces = bf; +} + +void RenderPass::set_receive_shadows(bool rs) +{ + receive_shadows = rs; } void RenderPass::apply(Renderer &renderer) const { - renderer.set_texturing(texturing); - renderer.set_material(material.get()); - renderer.set_shader_program(shprog.get(), shdata.get()); + for(vector::const_iterator i=textures.begin(); i!=textures.end(); ++i) + renderer.set_texture(i->tag, i->texture, i->sampler); + renderer.set_material(material); + renderer.set_shader_program(shprog, shdata.get()); renderer.set_reverse_winding(back_faces); } +void RenderPass::set_debug_name(const string &name) +{ +#ifdef DEBUG + if(shdata.refcount()==1) + shdata->set_debug_name(name+" [UBO]"); +#else + (void)name; +#endif +} + + +DataFile::Loader::ActionMap RenderPass::Loader::shared_actions; RenderPass::Loader::Loader(RenderPass &p): DataFile::CollectionObjectLoader(p, 0) { - init(); + set_actions(shared_actions); } RenderPass::Loader::Loader(RenderPass &p, Collection &c): DataFile::CollectionObjectLoader(p, &c) { - init(); + set_actions(shared_actions); } -void RenderPass::Loader::init() +void RenderPass::Loader::init_actions() { add("shader", &Loader::shader); + add("image_based_lighting", &RenderPass::image_based_lighting); add("material", &Loader::material_inline); add("material", &Loader::material); add("material_slot", &RenderPass::material_slot); add("back_faces",&RenderPass::back_faces); - add("texunit", &Loader::texunit); - add("texunit", &Loader::texunit_auto); - add("texunit", &Loader::texunit_named); + add("receive_shadows", &RenderPass::receive_shadows); + add("texture", &Loader::texture); add("uniforms", &Loader::uniforms); add("uniform_slot", &Loader::uniform_slot); add("uniform_slot", &Loader::uniform_slot2); + + // Deprecated + add("texunit", &Loader::texunit); + add("texunit", &Loader::texture); + add("texunit", &Loader::texunit_named); +} + +void RenderPass::Loader::set_inline_base_name(const string &n) +{ + inline_base_name = n; +} + +void RenderPass::Loader::finish() +{ + if(obj.material) + obj.maybe_create_material_shader(); } // Temporary compatibility feature @@ -191,57 +215,76 @@ void RenderPass::Loader::material_inline() { Material::GenericLoader ldr(coll); load_sub_with(ldr); - obj.material = ldr.get_material(); - obj.finalize_material(coll); + RefPtr mat = ldr.get_material(); + get_collection().add(inline_base_name+".mat", mat.get()); + obj.material = mat.release(); + obj.set_material_textures(); } void RenderPass::Loader::material(const string &name) { obj.material = &get_collection().get(name); - obj.material.keep(); - obj.finalize_material(coll); + obj.set_material_textures(); } void RenderPass::Loader::shader(const string &n) { obj.shprog = &get_collection().get(get_shader_name(n)); - obj.shprog.keep(); obj.shprog_from_material = false; if(obj.shdata) - obj.shdata = new ProgramData(*obj.shdata, obj.shprog.get()); - if(obj.material) - obj.finalize_material(coll); + obj.shdata = new ProgramData(*obj.shdata, obj.shprog); } -void RenderPass::Loader::texunit(unsigned i) +void RenderPass::Loader::texture(const string &n) { - if(!obj.texturing) - obj.texturing = new Texturing; - TextureLoader ldr(*obj.texturing, i, coll); + vector::iterator i = find_member(obj.textures, Tag(n), &TextureSlot::tag); + if(i==obj.textures.end()) + { + obj.textures.push_back(TextureSlot(n)); + i = obj.textures.end()-1; + } + TextureSlot::Loader ldr(*i, n, coll); load_sub_with(ldr); } -void RenderPass::Loader::texunit_auto(const string &n) +void RenderPass::Loader::texunit(unsigned) { - if(!obj.texturing) - obj.texturing = new Texturing; - int i = obj.texturing->find_free_unit(n); - if(i<0) - throw runtime_error("no free texunit"); - texunit_named(i, n); + IO::print(IO::cerr, "Warning: specifying textures by unit number is deprecated and may not produce expected results"); + string name; + if(obj.shprog) + { + const vector &uniforms = obj.shprog->get_uniforms(); + for(vector::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) + if(is_image(i->type) && i->binding>=0) + { + if(!name.empty()) + { + name.clear(); + break; + } + name = i->name; + } + } + + if(name.empty()) + throw runtime_error("Could not determine name for texture"); + + texture(name); } -void RenderPass::Loader::texunit_named(unsigned i, const string &n) +void RenderPass::Loader::texunit_named(unsigned, const string &n) { - texunit(i); - obj.tex_names[n] = i; - obj.ensure_private_shader_data(); - obj.shdata->uniform(n, static_cast(i)); + texture(n); } void RenderPass::Loader::uniforms() { - obj.ensure_private_shader_data(); + if(!obj.shprog || obj.shprog_from_material) + throw runtime_error("Shader is required for uniforms"); + if(!obj.shdata) + obj.shdata = new ProgramData(obj.shprog); + else if(obj.shdata.refcount()>1) + obj.shdata = new ProgramData(*obj.shdata); load_sub(*obj.shdata); } @@ -256,32 +299,19 @@ void RenderPass::Loader::uniform_slot2(const string &name, const string &slot) } -RenderPass::TextureLoader::TextureLoader(Texturing &t, unsigned i, Collection *c): - DataFile::CollectionObjectLoader(t, c), - index(i), - tex(0), - samp(0) -{ - add("sampler", &TextureLoader::sampler); - add("texture", &TextureLoader::texture); -} - -void RenderPass::TextureLoader::finish() -{ - if(tex) - obj.attach(index, *tex, samp); - else if(samp) - obj.attach(index, *samp); -} - -void RenderPass::TextureLoader::sampler(const string &name) +RenderPass::TextureSlot::Loader::Loader(TextureSlot &ts, const string &an, Collection *c): + CollectionObjectLoader(ts, c), + auto_slot_name(an) { - samp = &get_collection().get(name); + add("sampler", &TextureSlot::sampler); + add("slot", &Loader::slot_auto); + add("slot", &TextureSlot::slot_name); + add("texture", &TextureSlot::texture); } -void RenderPass::TextureLoader::texture(const string &name) +void RenderPass::TextureSlot::Loader::slot_auto() { - tex = &get_collection().get(name); + obj.slot_name = auto_slot_name; } } // namespace GL