X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fmaterials%2Fsplatmaterial.cpp;fp=source%2Fmaterials%2Fsplatmaterial.cpp;h=21abe4cab1e5c85d3c128226e3467a425e141a4e;hp=0000000000000000000000000000000000000000;hb=5593d59bfe30fd7eecc55bc3580d87fcb91f0248;hpb=e196a09d1df1e8504ff037d1701b7159c4f04e84 diff --git a/source/materials/splatmaterial.cpp b/source/materials/splatmaterial.cpp new file mode 100644 index 00000000..21abe4ca --- /dev/null +++ b/source/materials/splatmaterial.cpp @@ -0,0 +1,280 @@ +#include +#include +#include "pbrmaterial.h" +#include "resources.h" +#include "splatmaterial.h" +#include "texture2d.h" +#include "texture2darray.h" + +using namespace std; + +namespace Msp { +namespace GL { + +const Tag SplatMaterial::texture_tags[] = +{ + Tag("base_color_array"), + Tag("normal_array"), + Tag("metalness_array"), + Tag("roughness_array"), + Tag("occlusion_array"), + Tag("emission_array"), + Tag("fresnel_lookup"), + Tag() +}; + +SplatMaterial::SplatMaterial(): + fresnel_lookup(PbrMaterial::get_or_create_fresnel_lookup()), + fresnel_sampler(Resources::get_global().get("_linear_clamp.samp")) +{ +} + +SplatMaterial::~SplatMaterial() +{ + delete base_color_array.texture; + delete normal_array.texture; + delete metalness_array.texture; + delete roughness_array.texture; + delete occlusion_array.texture; + delete emission_array.texture; +} + +void SplatMaterial::fill_program_info(string &module_name, map &spec_values) const +{ + module_name = "splat.glsl"; + spec_values["use_base_color_map"] = (base_color_array.format!=NO_PIXELFORMAT); + spec_values["use_normal_map"] = (normal_array.format!=NO_PIXELFORMAT); + spec_values["use_metalness_map"] = (metalness_array.format!=NO_PIXELFORMAT); + spec_values["use_roughness_map"] = (roughness_array.format!=NO_PIXELFORMAT); + spec_values["use_occlusion_map"] = (occlusion_array.format!=NO_PIXELFORMAT); + bool use_emission = (emission_array.format!=NO_PIXELFORMAT); + for(auto i=sub_materials.begin(); (!use_emission && i!=sub_materials.end()); ++i) + use_emission = (i->emission.r || i->emission.g || i->emission.b); + spec_values["use_emission"] = use_emission; + spec_values["use_emission_map"] = (emission_array.format!=NO_PIXELFORMAT); +} + +const Texture *SplatMaterial::get_texture(Tag tag) const +{ + if(tag==texture_tags[0]) + return base_color_array.texture; + else if(tag==texture_tags[1]) + return normal_array.texture; + else if(tag==texture_tags[2]) + return metalness_array.texture; + else if(tag==texture_tags[3]) + return roughness_array.texture; + else if(tag==texture_tags[4]) + return occlusion_array.texture; + else if(tag==texture_tags[5]) + return emission_array.texture; + else if(tag==texture_tags[6]) + return &fresnel_lookup; + else + return 0; +} + +const Sampler *SplatMaterial::get_sampler(Tag tag) const +{ + if(tag==texture_tags[6]) + return &fresnel_sampler; + else + return sampler; +} + +void SplatMaterial::set_sub_uniforms(unsigned index) +{ + SubMaterial &sub = sub_materials[index]; + string prefix = format("splat_materials[%d].", index); + shdata.uniform(prefix+"base_color", sub.base_color); + shdata.uniform(prefix+"tint", sub.tint); + shdata.uniform(prefix+"metalness", sub.metalness); + shdata.uniform(prefix+"roughness", sub.roughness); + shdata.uniform(prefix+"emission", sub.emission); +} + +void SplatMaterial::upload_sub(DataFile::Collection &coll, unsigned index) +{ + upload_sub_map(coll, index, &SubMaterial::base_color_map, base_color_array, "base_color"); + upload_sub_map(coll, index, &SubMaterial::normal_map, normal_array, "normal"); + upload_sub_map(coll, index, &SubMaterial::metalness_map, metalness_array, "metalness"); + upload_sub_map(coll, index, &SubMaterial::roughness_map, roughness_array, "roughness"); + upload_sub_map(coll, index, &SubMaterial::occlusion_map, occlusion_array, "occlusion"); + upload_sub_map(coll, index, &SubMaterial::emission_map, emission_array, "emission"); +} + +void SplatMaterial::upload_sub_map(DataFile::Collection &coll, unsigned index, SubMap SubMaterial::*map, MapArray &array, const char *name) +{ + SubMap &sub = sub_materials[index].*map; + if(sub.source_fn.empty()) + return; + + uint64_t layer_mask = 0; + for(const SubMaterial &s: sub_materials) + { + int l = (s.*map).layer; + if(l>=0) + layer_mask |= 1<1; lowest_free_bit>>=1) + ++sub.layer; + + RefPtr io = coll.open_raw(sub.source_fn); + char magic[4] = { }; + io->read(magic, 4); + io->seek(0, IO::S_BEG); + + if(DataFile::RawData::detect_signature(string(magic, 4))) + { + DataFile::RawData raw_data; + raw_data.open_io(*io, sub.source_fn); + raw_data.load(); + array.texture->layer_image(0, sub.layer, raw_data.get_data()); + } + else + { + Graphics::Image image; + image.load_io(*io); + array.texture->layer_image(0, sub.layer, image); + } + + shdata.uniform(format("splat_materials[%d].%s_layer", index, name), sub.layer); +} + + +void SplatMaterial::MapArray::create() +{ + if(!texture && format!=NO_PIXELFORMAT && max_layers>0) + { + texture = new Texture2DArray; + texture->storage(format, width, height, max_layers); + } +} + + +DataFile::Loader::ActionMap SplatMaterial::Loader::shared_actions; + +SplatMaterial::Loader::Loader(SplatMaterial &m, Collection &c): + DerivedObjectLoader>(m, c) +{ + set_actions(shared_actions); +} + +void SplatMaterial::Loader::init_actions() +{ + PropertyLoader::init_actions(); + add("base_color_storage", &Loader::map_storage, &SplatMaterial::base_color_array); + add("emission_storage", &Loader::map_storage, &SplatMaterial::emission_array); + add("metalness_storage", &Loader::map_storage, &SplatMaterial::metalness_array); + add("normal_storage", &Loader::map_storage, &SplatMaterial::normal_array); + add("occlusion_storage", &Loader::map_storage, &SplatMaterial::occlusion_array); + add("roughness_storage", &Loader::map_storage, &SplatMaterial::roughness_array); + add("sub", &SplatMaterial::Loader::sub); +} + +void SplatMaterial::Loader::finish() +{ + obj.base_color_array.create(); + obj.normal_array.create(); + obj.metalness_array.create(); + obj.roughness_array.create(); + obj.occlusion_array.create(); + obj.emission_array.create(); + + DataFile::Collection &c = get_collection(); + for(unsigned i=0; igenerate_mipmap(); + if(obj.normal_array.texture) + obj.normal_array.texture->generate_mipmap(); + if(obj.metalness_array.texture) + obj.metalness_array.texture->generate_mipmap(); + if(obj.roughness_array.texture) + obj.roughness_array.texture->generate_mipmap(); + if(obj.occlusion_array.texture) + obj.occlusion_array.texture->generate_mipmap(); + if(obj.emission_array.texture) + obj.emission_array.texture->generate_mipmap(); +} + +void SplatMaterial::Loader::map_storage(MapArray SplatMaterial::*array, PixelFormat f, unsigned w, unsigned h) +{ + (obj.*array).format = f; + (obj.*array).width = w; + (obj.*array).height = h; +} + +void SplatMaterial::Loader::sub() +{ + SubMaterial sm; + load_sub(sm); + obj.sub_materials.push_back(sm); + + if(!sm.base_color_map.source_fn.empty()) + ++obj.base_color_array.max_layers; + if(!sm.normal_map.source_fn.empty()) + ++obj.normal_array.max_layers; + if(!sm.metalness_map.source_fn.empty()) + ++obj.metalness_array.max_layers; + if(!sm.roughness_map.source_fn.empty()) + ++obj.roughness_array.max_layers; + if(!sm.occlusion_map.source_fn.empty()) + ++obj.occlusion_array.max_layers; + if(!sm.emission_map.source_fn.empty()) + ++obj.emission_array.max_layers; +} + + +DataFile::Loader::ActionMap SplatMaterial::SubMaterial::Loader::shared_actions; + +SplatMaterial::SubMaterial::Loader::Loader(SubMaterial &s): + ObjectLoader(s) +{ + set_actions(shared_actions); +} + +void SplatMaterial::SubMaterial::Loader::init_actions() +{ + add("base_color", &Loader::base_color); + add("base_color_map", &Loader::map, &SubMaterial::base_color_map); + add("emission", &Loader::emission); + add("emission_map", &Loader::map, &SubMaterial::emission_map); + add("metalness", &SubMaterial::metalness); + add("metalness_map", &Loader::map, &SubMaterial::metalness_map); + add("normal_map", &Loader::map, &SubMaterial::normal_map); + add("occlusion_map", &Loader::map, &SubMaterial::occlusion_map); + add("roughness", &SubMaterial::roughness); + add("roughness_map", &Loader::map, &SubMaterial::roughness_map); + add("tint", &Loader::tint); +} + +void SplatMaterial::SubMaterial::Loader::base_color(float r, float g, float b) +{ + obj.base_color = Color(r, g, b); +} + +void SplatMaterial::SubMaterial::Loader::emission(float r, float g, float b) +{ + obj.emission = Color(r, g, b); +} + +void SplatMaterial::SubMaterial::Loader::map(SubMap SubMaterial::*m, const string &fn) +{ + (obj.*m).source_fn = fn; +} + +void SplatMaterial::SubMaterial::Loader::tint(float r, float g, float b, float a) +{ + obj.tint = Color(r, g, b, a); +} + +} // namespace GL +} // namespace Msp