1 #include <msp/datafile/rawdata.h>
2 #include <msp/strings/format.h>
3 #include "pbrmaterial.h"
5 #include "splatmaterial.h"
7 #include "texture2darray.h"
14 const Tag SplatMaterial::texture_tags[] =
16 Tag("base_color_array"),
18 Tag("metalness_array"),
19 Tag("roughness_array"),
20 Tag("occlusion_array"),
21 Tag("emission_array"),
22 Tag("fresnel_lookup"),
26 SplatMaterial::SplatMaterial():
27 fresnel_lookup(PbrMaterial::get_or_create_fresnel_lookup()),
28 fresnel_sampler(Resources::get_global().get<Sampler>("_linear_clamp.samp"))
32 SplatMaterial::~SplatMaterial()
34 delete base_color_array.texture;
35 delete normal_array.texture;
36 delete metalness_array.texture;
37 delete roughness_array.texture;
38 delete occlusion_array.texture;
39 delete emission_array.texture;
42 void SplatMaterial::fill_program_info(string &module_name, map<string, int> &spec_values) const
44 module_name = "splat.glsl";
45 spec_values["use_base_color_map"] = (base_color_array.format!=NO_PIXELFORMAT);
46 spec_values["use_normal_map"] = (normal_array.format!=NO_PIXELFORMAT);
47 spec_values["use_metalness_map"] = (metalness_array.format!=NO_PIXELFORMAT);
48 spec_values["use_roughness_map"] = (roughness_array.format!=NO_PIXELFORMAT);
49 spec_values["use_occlusion_map"] = (occlusion_array.format!=NO_PIXELFORMAT);
50 bool use_emission = (emission_array.format!=NO_PIXELFORMAT);
51 for(auto i=sub_materials.begin(); (!use_emission && i!=sub_materials.end()); ++i)
52 use_emission = (i->emission.r || i->emission.g || i->emission.b);
53 spec_values["use_emission"] = use_emission;
54 spec_values["use_emission_map"] = (emission_array.format!=NO_PIXELFORMAT);
57 const Texture *SplatMaterial::get_texture(Tag tag) const
59 if(tag==texture_tags[0])
60 return base_color_array.texture;
61 else if(tag==texture_tags[1])
62 return normal_array.texture;
63 else if(tag==texture_tags[2])
64 return metalness_array.texture;
65 else if(tag==texture_tags[3])
66 return roughness_array.texture;
67 else if(tag==texture_tags[4])
68 return occlusion_array.texture;
69 else if(tag==texture_tags[5])
70 return emission_array.texture;
71 else if(tag==texture_tags[6])
72 return &fresnel_lookup;
77 const Sampler *SplatMaterial::get_sampler(Tag tag) const
79 if(tag==texture_tags[6])
80 return &fresnel_sampler;
85 void SplatMaterial::set_sub_uniforms(unsigned index)
87 SubMaterial &sub = sub_materials[index];
88 string prefix = format("splat_materials[%d].", index);
89 shdata.uniform(prefix+"base_color", sub.base_color);
90 shdata.uniform(prefix+"tint", sub.tint);
91 shdata.uniform(prefix+"metalness", sub.metalness);
92 shdata.uniform(prefix+"roughness", sub.roughness);
93 shdata.uniform(prefix+"emission", sub.emission);
96 void SplatMaterial::upload_sub(DataFile::Collection &coll, unsigned index)
98 upload_sub_map(coll, index, &SubMaterial::base_color_map, base_color_array, "base_color");
99 upload_sub_map(coll, index, &SubMaterial::normal_map, normal_array, "normal");
100 upload_sub_map(coll, index, &SubMaterial::metalness_map, metalness_array, "metalness");
101 upload_sub_map(coll, index, &SubMaterial::roughness_map, roughness_array, "roughness");
102 upload_sub_map(coll, index, &SubMaterial::occlusion_map, occlusion_array, "occlusion");
103 upload_sub_map(coll, index, &SubMaterial::emission_map, emission_array, "emission");
106 void SplatMaterial::upload_sub_map(DataFile::Collection &coll, unsigned index, SubMap SubMaterial::*map, MapArray &array, const char *name)
108 SubMap &sub = sub_materials[index].*map;
109 if(sub.source_fn.empty())
112 uint64_t layer_mask = 0;
113 for(const SubMaterial &s: sub_materials)
115 int l = (s.*map).layer;
120 unsigned lowest_free_bit = (~layer_mask)&(layer_mask+1);
122 for(; lowest_free_bit>1; lowest_free_bit>>=1)
125 RefPtr<IO::Seekable> io = coll.open_raw(sub.source_fn);
128 io->seek(0, IO::S_BEG);
130 if(DataFile::RawData::detect_signature(string(magic, 4)))
132 DataFile::RawData raw_data;
133 raw_data.open_io(*io, sub.source_fn);
135 array.texture->layer_image(0, sub.layer, raw_data.get_data());
139 Graphics::Image image;
141 array.texture->layer_image(0, sub.layer, image);
144 shdata.uniform(format("splat_materials[%d].%s_layer", index, name), sub.layer);
148 void SplatMaterial::MapArray::create()
150 if(!texture && format!=NO_PIXELFORMAT && max_layers>0)
152 texture = new Texture2DArray;
153 texture->storage(format, width, height, max_layers);
158 DataFile::Loader::ActionMap SplatMaterial::Loader::shared_actions;
160 SplatMaterial::Loader::Loader(SplatMaterial &m, Collection &c):
161 DerivedObjectLoader<SplatMaterial, PropertyLoader<SplatMaterial>>(m, c)
163 set_actions(shared_actions);
166 void SplatMaterial::Loader::init_actions()
168 PropertyLoader<SplatMaterial>::init_actions();
169 add("base_color_storage", &Loader::map_storage, &SplatMaterial::base_color_array);
170 add("emission_storage", &Loader::map_storage, &SplatMaterial::emission_array);
171 add("metalness_storage", &Loader::map_storage, &SplatMaterial::metalness_array);
172 add("normal_storage", &Loader::map_storage, &SplatMaterial::normal_array);
173 add("occlusion_storage", &Loader::map_storage, &SplatMaterial::occlusion_array);
174 add("roughness_storage", &Loader::map_storage, &SplatMaterial::roughness_array);
175 add("sub", &SplatMaterial::Loader::sub);
178 void SplatMaterial::Loader::finish()
180 obj.base_color_array.create();
181 obj.normal_array.create();
182 obj.metalness_array.create();
183 obj.roughness_array.create();
184 obj.occlusion_array.create();
185 obj.emission_array.create();
187 DataFile::Collection &c = get_collection();
188 for(unsigned i=0; i<obj.sub_materials.size(); ++i)
190 obj.set_sub_uniforms(i);
191 obj.upload_sub(c, i);
194 if(obj.base_color_array.texture)
195 obj.base_color_array.texture->generate_mipmap();
196 if(obj.normal_array.texture)
197 obj.normal_array.texture->generate_mipmap();
198 if(obj.metalness_array.texture)
199 obj.metalness_array.texture->generate_mipmap();
200 if(obj.roughness_array.texture)
201 obj.roughness_array.texture->generate_mipmap();
202 if(obj.occlusion_array.texture)
203 obj.occlusion_array.texture->generate_mipmap();
204 if(obj.emission_array.texture)
205 obj.emission_array.texture->generate_mipmap();
208 void SplatMaterial::Loader::map_storage(MapArray SplatMaterial::*array, PixelFormat f, unsigned w, unsigned h)
210 (obj.*array).format = f;
211 (obj.*array).width = w;
212 (obj.*array).height = h;
215 void SplatMaterial::Loader::sub()
219 obj.sub_materials.push_back(sm);
221 if(!sm.base_color_map.source_fn.empty())
222 ++obj.base_color_array.max_layers;
223 if(!sm.normal_map.source_fn.empty())
224 ++obj.normal_array.max_layers;
225 if(!sm.metalness_map.source_fn.empty())
226 ++obj.metalness_array.max_layers;
227 if(!sm.roughness_map.source_fn.empty())
228 ++obj.roughness_array.max_layers;
229 if(!sm.occlusion_map.source_fn.empty())
230 ++obj.occlusion_array.max_layers;
231 if(!sm.emission_map.source_fn.empty())
232 ++obj.emission_array.max_layers;
236 DataFile::Loader::ActionMap SplatMaterial::SubMaterial::Loader::shared_actions;
238 SplatMaterial::SubMaterial::Loader::Loader(SubMaterial &s):
239 ObjectLoader<SubMaterial>(s)
241 set_actions(shared_actions);
244 void SplatMaterial::SubMaterial::Loader::init_actions()
246 add("base_color", &Loader::base_color);
247 add("base_color_map", &Loader::map, &SubMaterial::base_color_map);
248 add("emission", &Loader::emission);
249 add("emission_map", &Loader::map, &SubMaterial::emission_map);
250 add("metalness", &SubMaterial::metalness);
251 add("metalness_map", &Loader::map, &SubMaterial::metalness_map);
252 add("normal_map", &Loader::map, &SubMaterial::normal_map);
253 add("occlusion_map", &Loader::map, &SubMaterial::occlusion_map);
254 add("roughness", &SubMaterial::roughness);
255 add("roughness_map", &Loader::map, &SubMaterial::roughness_map);
256 add("tint", &Loader::tint);
259 void SplatMaterial::SubMaterial::Loader::base_color(float r, float g, float b)
261 obj.base_color = Color(r, g, b);
264 void SplatMaterial::SubMaterial::Loader::emission(float r, float g, float b)
266 obj.emission = Color(r, g, b);
269 void SplatMaterial::SubMaterial::Loader::map(SubMap SubMaterial::*m, const string &fn)
271 (obj.*m).source_fn = fn;
274 void SplatMaterial::SubMaterial::Loader::tint(float r, float g, float b, float a)
276 obj.tint = Color(r, g, b, a);