]> git.tdb.fi Git - libs/gl.git/blob - source/materials/splatmaterial.cpp
Check the flat qualifier from the correct member
[libs/gl.git] / source / materials / splatmaterial.cpp
1 #include <msp/datafile/rawdata.h>
2 #include <msp/strings/format.h>
3 #include "pbrmaterial.h"
4 #include "resources.h"
5 #include "splatmaterial.h"
6 #include "texture2d.h"
7 #include "texture2darray.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace GL {
13
14 const Tag SplatMaterial::texture_tags[] =
15 {
16         Tag("base_color_array"),
17         Tag("normal_array"),
18         Tag("metalness_array"),
19         Tag("roughness_array"),
20         Tag("occlusion_array"),
21         Tag("emission_array"),
22         Tag("fresnel_lookup"),
23         Tag()
24 };
25
26 SplatMaterial::SplatMaterial():
27         fresnel_lookup(PbrMaterial::get_or_create_fresnel_lookup()),
28         fresnel_sampler(Resources::get_global().get<Sampler>("_linear_clamp.samp"))
29 {
30 }
31
32 SplatMaterial::~SplatMaterial()
33 {
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;
40 }
41
42 void SplatMaterial::fill_program_info(string &module_name, map<string, int> &spec_values) const
43 {
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);
55 }
56
57 const Texture *SplatMaterial::get_texture(Tag tag) const
58 {
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;
73         else
74                 return 0;
75 }
76
77 const Sampler *SplatMaterial::get_sampler(Tag tag) const
78 {
79         if(tag==texture_tags[6])
80                 return &fresnel_sampler;
81         else
82                 return sampler;
83 }
84
85 void SplatMaterial::set_sub_uniforms(unsigned index)
86 {
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);
94 }
95
96 void SplatMaterial::upload_sub(DataFile::Collection &coll, unsigned index)
97 {
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");
104 }
105
106 void SplatMaterial::upload_sub_map(DataFile::Collection &coll, unsigned index, SubMap SubMaterial::*map, MapArray &array, const char *name)
107 {
108         SubMap &sub = sub_materials[index].*map;
109         if(sub.source_fn.empty())
110                 return;
111
112         uint64_t layer_mask = 0;
113         for(const SubMaterial &s: sub_materials)
114         {
115                 int l = (s.*map).layer;
116                 if(l>=0)
117                         layer_mask |= 1<<l;
118         }
119
120         unsigned lowest_free_bit = (~layer_mask)&(layer_mask+1);
121         sub.layer = 0;
122         for(; lowest_free_bit>1; lowest_free_bit>>=1)
123                 ++sub.layer;
124
125         RefPtr<IO::Seekable> io = coll.open_raw(sub.source_fn);
126         char magic[4] = { };
127         io->read(magic, 4);
128         io->seek(0, IO::S_BEG);
129
130         if(DataFile::RawData::detect_signature(string(magic, 4)))
131         {
132                 DataFile::RawData raw_data;
133                 raw_data.open_io(*io, sub.source_fn);
134                 raw_data.load();
135                 array.texture->layer_image(0, sub.layer, raw_data.get_data());
136         }
137         else
138         {
139                 Graphics::Image image;
140                 image.load_io(*io);
141                 array.texture->layer_image(0, sub.layer, image);
142         }
143
144         shdata.uniform(format("splat_materials[%d].%s_layer", index, name), sub.layer);
145 }
146
147
148 void SplatMaterial::MapArray::create()
149 {
150         if(!texture && format!=NO_PIXELFORMAT && max_layers>0)
151         {
152                 texture = new Texture2DArray;
153                 texture->storage(format, width, height, max_layers);
154         }
155 }
156
157
158 DataFile::Loader::ActionMap SplatMaterial::Loader::shared_actions;
159
160 SplatMaterial::Loader::Loader(SplatMaterial &m, Collection &c):
161         DerivedObjectLoader<SplatMaterial, PropertyLoader<SplatMaterial>>(m, c)
162 {
163         set_actions(shared_actions);
164 }
165
166 void SplatMaterial::Loader::init_actions()
167 {
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);
176 }
177
178 void SplatMaterial::Loader::finish()
179 {
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();
186
187         DataFile::Collection &c = get_collection();
188         for(unsigned i=0; i<obj.sub_materials.size(); ++i)
189         {
190                 obj.set_sub_uniforms(i);
191                 obj.upload_sub(c, i);
192         }
193
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();
206 }
207
208 void SplatMaterial::Loader::map_storage(MapArray SplatMaterial::*array, PixelFormat f, unsigned w, unsigned h)
209 {
210         (obj.*array).format = f;
211         (obj.*array).width = w;
212         (obj.*array).height = h;
213 }
214
215 void SplatMaterial::Loader::sub()
216 {
217         SubMaterial sm;
218         load_sub(sm);
219         obj.sub_materials.push_back(sm);
220
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;
233 }
234
235
236 DataFile::Loader::ActionMap SplatMaterial::SubMaterial::Loader::shared_actions;
237
238 SplatMaterial::SubMaterial::Loader::Loader(SubMaterial &s):
239         ObjectLoader<SubMaterial>(s)
240 {
241         set_actions(shared_actions);
242 }
243
244 void SplatMaterial::SubMaterial::Loader::init_actions()
245 {
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);
257 }
258
259 void SplatMaterial::SubMaterial::Loader::base_color(float r, float g, float b)
260 {
261         obj.base_color = Color(r, g, b);
262 }
263
264 void SplatMaterial::SubMaterial::Loader::emission(float r, float g, float b)
265 {
266         obj.emission = Color(r, g, b);
267 }
268
269 void SplatMaterial::SubMaterial::Loader::map(SubMap SubMaterial::*m, const string &fn)
270 {
271         (obj.*m).source_fn = fn;
272 }
273
274 void SplatMaterial::SubMaterial::Loader::tint(float r, float g, float b, float a)
275 {
276         obj.tint = Color(r, g, b, a);
277 }
278
279 } // namespace GL
280 } // namespace Msp