X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fmaterials%2Frendermethod.cpp;fp=source%2Fmaterials%2Frendermethod.cpp;h=a6a843ee59f1770dbe17b9d9d2286ad3c79a8dcf;hb=c0b7d6ee4a7478f5aecb1504429ec1fc846d64ed;hp=0000000000000000000000000000000000000000;hpb=5008778dbb1840bf7c6d479800d2b932f8386fb2;p=libs%2Fgl.git diff --git a/source/materials/rendermethod.cpp b/source/materials/rendermethod.cpp new file mode 100644 index 00000000..a6a843ee --- /dev/null +++ b/source/materials/rendermethod.cpp @@ -0,0 +1,239 @@ +#include +#include +#include +#include "error.h" +#include "rendermethod.h" +#include "program.h" +#include "programdata.h" +#include "renderer.h" +#include "texture.h" +#include "texture2d.h" + +using namespace std; + +namespace Msp { +namespace GL { + +RenderMethod::RenderMethod(): + shprog(0), + shprog_from_material(false), + shdata(0), + material(0), + face_cull(CULL_BACK), + receive_shadows(false), + image_based_lighting(false) +{ } + +void RenderMethod::set_material_textures() +{ + 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(*tag)); +} + +void RenderMethod::maybe_create_material_shader() +{ + if(shprog && !shprog_from_material) + return; + + 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); + + shprog_from_material = true; +} + +void RenderMethod::set_shader_program(const Program *prog, const ProgramData *data) +{ + shprog = prog; + shprog_from_material = false; + shdata = (data ? new ProgramData(*data) : 0); +} + +Tag RenderMethod::get_slotted_uniform_tag(Tag slot) const +{ + auto i = uniform_slots.find(slot); + if(i==uniform_slots.end()) + return Tag(); + return i->second; +} + +void RenderMethod::set_material(const Material *mat) +{ + material = mat; + maybe_create_material_shader(); + set_material_textures(); +} + +void RenderMethod::set_texture(Tag tag, const Texture *tex, const Sampler *samp) +{ + auto 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 RenderMethod::get_texture_tag(const string &slot) const +{ + auto i = find_member(textures, slot, &TextureSlot::slot_name); + return (i!=textures.end() ? i->tag : Tag()); +} + +void RenderMethod::set_face_cull(CullMode fc) +{ + face_cull = fc; +} + +void RenderMethod::set_receive_shadows(bool rs) +{ + receive_shadows = rs; +} + +void RenderMethod::apply(Renderer &renderer) const +{ + for(const TextureSlot &t: textures) + renderer.set_texture(t.tag, t.texture, t.sampler); + renderer.set_shader_program(shprog, shdata.get()); + if(material) + renderer.add_shader_data(material->get_shader_data()); + renderer.set_face_cull(face_cull); +} + +void RenderMethod::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 RenderMethod::Loader::shared_actions; + +RenderMethod::Loader::Loader(RenderMethod &p): + DataFile::CollectionObjectLoader(p, 0) +{ + set_actions(shared_actions); +} + +RenderMethod::Loader::Loader(RenderMethod &p, Collection &c): + DataFile::CollectionObjectLoader(p, &c) +{ + set_actions(shared_actions); +} + +void RenderMethod::Loader::init_actions() +{ + add("face_cull", &RenderMethod::face_cull); + add("shader", &Loader::shader); + add("image_based_lighting", &RenderMethod::image_based_lighting); + add("material", &Loader::material_inline); + add("material", &Loader::material); + add("material_slot", &RenderMethod::material_slot); + add("receive_shadows", &RenderMethod::receive_shadows); + add("texture", &Loader::texture); + add("uniforms", &Loader::uniforms); + add("uniform_slot", &Loader::uniform_slot); + add("uniform_slot", &Loader::uniform_slot2); +} + +void RenderMethod::Loader::set_inline_base_name(const string &n) +{ + inline_base_name = n; +} + +void RenderMethod::Loader::finish() +{ + if(obj.material) + obj.maybe_create_material_shader(); +} + +void RenderMethod::Loader::material_inline() +{ + Material::GenericLoader ldr(coll); + load_sub_with(ldr); + RefPtr mat = ldr.get_material(); + get_collection().add(inline_base_name+".mat", mat.get()); + obj.material = mat.release(); + obj.set_material_textures(); +} + +void RenderMethod::Loader::material(const string &name) +{ + obj.material = &get_collection().get(name); + obj.set_material_textures(); +} + +void RenderMethod::Loader::shader(const string &n) +{ + obj.shprog = &get_collection().get(n); + obj.shprog_from_material = false; + if(obj.shdata) + obj.shdata = new ProgramData(*obj.shdata, obj.shprog); +} + +void RenderMethod::Loader::texture(const string &n) +{ + auto 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 RenderMethod::Loader::uniforms() +{ + 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); +} + +void RenderMethod::Loader::uniform_slot(const string &name) +{ + uniform_slot2(name, name); +} + +void RenderMethod::Loader::uniform_slot2(const string &name, const string &slot) +{ + obj.uniform_slots[slot] = name; +} + + +RenderMethod::TextureSlot::Loader::Loader(TextureSlot &ts, const string &an, Collection *c): + CollectionObjectLoader(ts, c), + auto_slot_name(an) +{ + add("sampler", &TextureSlot::sampler); + add("slot", &Loader::slot_auto); + add("slot", &TextureSlot::slot_name); + add("texture", &TextureSlot::texture); +} + +void RenderMethod::TextureSlot::Loader::slot_auto() +{ + obj.slot_name = auto_slot_name; +} + +} // namespace GL +} // namespace Msp