1
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9 // Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29
30 // Interface header.
31 #include "projectfileupdater.h"
32
33 // appleseed.renderer headers.
34 #include "renderer/global/globallogger.h"
35 #include "renderer/modeling/bsdf/bsdf.h"
36 #include "renderer/modeling/bsdf/disneybrdf.h"
37 #include "renderer/modeling/bsdf/glassbsdf.h"
38 #include "renderer/modeling/bsdf/glossybrdf.h"
39 #include "renderer/modeling/bsdf/metalbrdf.h"
40 #include "renderer/modeling/bsdf/specularbtdf.h"
41 #include "renderer/modeling/bssrdf/bssrdf.h"
42 #include "renderer/modeling/bssrdf/gaussianbssrdf.h"
43 #include "renderer/modeling/camera/camera.h"
44 #include "renderer/modeling/color/colorentity.h"
45 #include "renderer/modeling/edf/diffuseedf.h"
46 #include "renderer/modeling/edf/edf.h"
47 #include "renderer/modeling/entity/entity.h"
48 #include "renderer/modeling/environmentedf/constantenvironmentedf.h"
49 #include "renderer/modeling/environmentedf/constanthemisphereenvironmentedf.h"
50 #include "renderer/modeling/environmentedf/environmentedf.h"
51 #include "renderer/modeling/environmentedf/gradientenvironmentedf.h"
52 #include "renderer/modeling/environmentedf/latlongmapenvironmentedf.h"
53 #include "renderer/modeling/environmentedf/mirrorballmapenvironmentedf.h"
54 #include "renderer/modeling/environmentshader/environmentshader.h"
55 #include "renderer/modeling/frame/frame.h"
56 #include "renderer/modeling/input/colorsource.h"
57 #include "renderer/modeling/light/directionallight.h"
58 #include "renderer/modeling/light/light.h"
59 #include "renderer/modeling/light/pointlight.h"
60 #include "renderer/modeling/light/spotlight.h"
61 #include "renderer/modeling/light/sunlight.h"
62 #include "renderer/modeling/material/material.h"
63 #include "renderer/modeling/object/object.h"
64 #include "renderer/modeling/postprocessingstage/renderstamppostprocessingstage.h"
65 #include "renderer/modeling/project/configuration.h"
66 #include "renderer/modeling/project/eventcounters.h"
67 #include "renderer/modeling/project/project.h"
68 #include "renderer/modeling/project/projectformatrevision.h"
69 #include "renderer/modeling/scene/assembly.h"
70 #include "renderer/modeling/scene/assemblyinstance.h"
71 #include "renderer/modeling/scene/containers.h"
72 #include "renderer/modeling/scene/objectinstance.h"
73 #include "renderer/modeling/scene/scene.h"
74 #include "renderer/modeling/surfaceshader/physicalsurfaceshader.h"
75 #include "renderer/modeling/surfaceshader/surfaceshader.h"
76 #include "renderer/utility/paramarray.h"
77
78 // appleseed.foundation headers.
79 #include "foundation/core/concepts/noncopyable.h"
80 #include "foundation/math/root.h"
81 #include "foundation/math/scalar.h"
82 #include "foundation/platform/compiler.h"
83 #include "foundation/platform/types.h"
84 #include "foundation/utility/api/apistring.h"
85 #include "foundation/utility/autoreleaseptr.h"
86 #include "foundation/utility/containers/dictionary.h"
87 #include "foundation/utility/foreach.h"
88 #include "foundation/utility/iterators.h"
89 #include "foundation/utility/string.h"
90
91 // Standard headers.
92 #include <algorithm>
93 #include <cassert>
94 #include <cmath>
95 #include <cstring>
96 #include <limits>
97 #include <string>
98 #include <vector>
99
100 using namespace foundation;
101 using namespace std;
102
103 namespace renderer
104 {
105
106 namespace
107 {
108 //
109 // Base updater class.
110 //
111
112 class Updater
113 : public NonCopyable
114 {
115 public:
Updater(Project & project,const size_t from_revision)116 Updater(Project& project, const size_t from_revision)
117 : m_project(project)
118 , m_from_revision(from_revision)
119 , m_to_revision(from_revision + 1)
120 {
121 assert(m_project.get_format_revision() == m_from_revision);
122
123 RENDERER_LOG_INFO(
124 "migrating project format from revision " FMT_SIZE_T " to revision " FMT_SIZE_T "...",
125 m_from_revision,
126 m_to_revision);
127 }
128
~Updater()129 virtual ~Updater()
130 {
131 m_project.set_format_revision(m_to_revision);
132 }
133
134 virtual void update() = 0;
135
136 protected:
137 Project& m_project;
138 const size_t m_from_revision;
139 const size_t m_to_revision;
140
141 // Copy a key from one dictionary to another.
copy_if_exist(Dictionary & dest,const Dictionary & src,const char * key)142 static void copy_if_exist(
143 Dictionary& dest,
144 const Dictionary& src,
145 const char* key)
146 {
147 if (src.strings().exist(key))
148 dest.strings().insert(key, src.strings().get(key));
149 }
150
151 // Copy a key from one dictionary to another, and rename the key.
copy_if_exist(Dictionary & dest,const char * dest_key,const Dictionary & src,const char * src_key)152 static void copy_if_exist(
153 Dictionary& dest,
154 const char* dest_key,
155 const Dictionary& src,
156 const char* src_key)
157 {
158 if (src.strings().exist(src_key))
159 dest.strings().insert(dest_key, src.strings().get(src_key));
160 }
161
162 // Copy a key from one dictionary to same dictionary.
copy_if_exist_no_overwrite(Dictionary & dict,const char * dest_key,const char * src_key)163 static void copy_if_exist_no_overwrite(
164 Dictionary& dict,
165 const char* dest_key,
166 const char* src_key)
167 {
168 if (!dict.strings().exist(dest_key))
169 copy_if_exist(dict, dest_key, dict, src_key);
170 }
171
172 // Move a key from one dictionary to another at a given key.
move_if_exist(Dictionary & dest,const char * dest_key,Dictionary & src,const char * src_key)173 static void move_if_exist(
174 Dictionary& dest,
175 const char* dest_key,
176 Dictionary& src,
177 const char* src_key)
178 {
179 if (src.strings().exist(src_key))
180 {
181 dest.strings().insert(dest_key, src.strings().get(src_key));
182 src.strings().remove(src_key);
183 }
184 }
185
186 // Move a key from one dictionary to another at a given path.
move_if_exist(ParamArray & dest,const char * dest_path,Dictionary & src,const char * src_key)187 static void move_if_exist(
188 ParamArray& dest,
189 const char* dest_path,
190 Dictionary& src,
191 const char* src_key)
192 {
193 if (src.strings().exist(src_key))
194 {
195 dest.insert_path(dest_path, src.strings().get(src_key));
196 src.strings().remove(src_key);
197 }
198 }
199
200 // Move a key to a new path in the same parameter array.
move_if_exist(ParamArray & params,const char * dest_path,const char * src_key)201 static void move_if_exist(
202 ParamArray& params,
203 const char* dest_path,
204 const char* src_key)
205 {
206 move_if_exist(params, dest_path, params, src_key);
207 }
208
209 // Helper function, same functionality as above.
move_if_exist(Entity & entity,const char * dest_path,const char * src_key)210 static void move_if_exist(
211 Entity& entity,
212 const char* dest_path,
213 const char* src_key)
214 {
215 move_if_exist(entity.get_parameters(), dest_path, src_key);
216 }
217 };
218
219
220 //
221 // Update from revision 0 to revision 1.
222 //
223
224 class UpdateFromRevision_0
225 : public Updater
226 {
227 public:
UpdateFromRevision_0(Project & project)228 explicit UpdateFromRevision_0(Project& project)
229 : Updater(project, 0)
230 {
231 }
232
update()233 void update() override
234 {
235 // Nothing to do.
236 }
237 };
238
239
240 //
241 // Update from revision 1 to revision 2.
242 //
243
244 class UpdateFromRevision_1
245 : public Updater
246 {
247 public:
UpdateFromRevision_1(Project & project)248 explicit UpdateFromRevision_1(Project& project)
249 : Updater(project, 1)
250 {
251 }
252
update()253 void update() override
254 {
255 // Nothing to do.
256 }
257 };
258
259
260 //
261 // Update from revision 2 to revision 3.
262 //
263
264 class UpdateFromRevision_2
265 : public Updater
266 {
267 public:
UpdateFromRevision_2(Project & project)268 explicit UpdateFromRevision_2(Project& project)
269 : Updater(project, 2)
270 {
271 }
272
update()273 void update() override
274 {
275 introduce_pixel_renderers();
276 move_filter_parameters_from_configurations_to_frame();
277 }
278
279 private:
max_variation_to_quality(const float variation)280 static float max_variation_to_quality(const float variation)
281 {
282 const float q = -log(variation, 10.0f);
283 const int n = static_cast<int>(q * 10.0f);
284 return static_cast<float>(n) / 10.0f;
285 }
286
introduce_pixel_renderers()287 void introduce_pixel_renderers()
288 {
289 for (each<ConfigurationContainer> i = m_project.configurations(); i; ++i)
290 {
291 Dictionary& root = i->get_parameters();
292
293 if (!root.dictionaries().exist("generic_tile_renderer"))
294 continue;
295
296 Dictionary& gtr = root.dictionary("generic_tile_renderer");
297
298 copy_if_exist(root, "pixel_renderer", gtr, "sampler");
299
300 {
301 Dictionary upr;
302 copy_if_exist(upr, "samples", gtr, "max_samples");
303 root.insert("uniform_pixel_renderer", upr);
304 }
305
306 {
307 Dictionary apr;
308 copy_if_exist(apr, gtr, "min_samples");
309 copy_if_exist(apr, gtr, "max_samples");
310 if (gtr.strings().exist("max_variation"))
311 apr.insert("quality", max_variation_to_quality(gtr.get<float>("max_variation")));
312 copy_if_exist(apr, "enable_diagnostics", gtr, "enable_adaptive_sampler_diagnostics");
313 root.insert("adaptive_pixel_renderer", apr);
314 }
315
316 gtr.strings().remove("sampler");
317 gtr.strings().remove("min_samples");
318 gtr.strings().remove("max_samples");
319 gtr.strings().remove("max_contrast");
320 gtr.strings().remove("max_variation");
321 gtr.strings().remove("enable_adaptive_sampler_diagnostics");
322 }
323 }
324
move_filter_parameters_from_configurations_to_frame()325 void move_filter_parameters_from_configurations_to_frame()
326 {
327 Frame* frame = m_project.get_frame();
328
329 for (each<ConfigurationContainer> i = m_project.configurations(); i; ++i)
330 {
331 Dictionary& root = i->get_parameters();
332
333 if (!root.dictionaries().exist("generic_tile_renderer"))
334 continue;
335
336 Dictionary& gtr = root.dictionary("generic_tile_renderer");
337
338 if (frame && strcmp(i->get_name(), "final") == 0)
339 {
340 copy_if_exist(frame->get_parameters(), gtr, "filter");
341 copy_if_exist(frame->get_parameters(), gtr, "filter_size");
342 }
343
344 gtr.strings().remove("filter");
345 gtr.strings().remove("filter_size");
346 }
347 }
348 };
349
350
351 //
352 // Update from revision 3 to revision 4.
353 //
354
355 class UpdateFromRevision_3
356 : public Updater
357 {
358 public:
UpdateFromRevision_3(Project & project)359 explicit UpdateFromRevision_3(Project& project)
360 : Updater(project, 3)
361 {
362 }
363
update()364 void update() override
365 {
366 if (Scene* scene = m_project.get_scene())
367 {
368 for (each<EnvironmentEDFContainer> i = scene->environment_edfs(); i; ++i)
369 rename_exitance_inputs(*i);
370
371 rename_exitance_inputs(scene->assemblies());
372 }
373 }
374
375 private:
rename_exitance_inputs(AssemblyContainer & assemblies)376 static void rename_exitance_inputs(AssemblyContainer& assemblies)
377 {
378 for (each<AssemblyContainer> i = assemblies; i; ++i)
379 {
380 rename_exitance_inputs(*i);
381 rename_exitance_inputs(i->assemblies());
382 }
383 }
384
rename_exitance_inputs(Assembly & assembly)385 static void rename_exitance_inputs(Assembly& assembly)
386 {
387 for (each<EDFContainer> i = assembly.edfs(); i; ++i)
388 rename_exitance_inputs(*i);
389
390 for (each<LightContainer> i = assembly.lights(); i; ++i)
391 rename_exitance_inputs(*i);
392 }
393
rename_exitance_inputs(EDF & edf)394 static void rename_exitance_inputs(EDF& edf)
395 {
396 if (strcmp(edf.get_model(), DiffuseEDFFactory().get_model()) == 0)
397 {
398 move_if_exist(edf, "radiance", "exitance");
399 move_if_exist(edf, "radiance_multiplier", "exitance_multiplier");
400 }
401 }
402
rename_exitance_inputs(Light & light)403 static void rename_exitance_inputs(Light& light)
404 {
405 if (strcmp(light.get_model(), DirectionalLightFactory().get_model()) == 0 ||
406 strcmp(light.get_model(), PointLightFactory().get_model()) == 0 ||
407 strcmp(light.get_model(), SpotLightFactory().get_model()) == 0)
408 {
409 move_if_exist(light, "radiance", "exitance");
410 move_if_exist(light, "radiance_multiplier", "exitance_multiplier");
411 }
412 else if (strcmp(light.get_model(), SunLightFactory().get_model()) == 0)
413 {
414 move_if_exist(light, "radiance_multiplier", "exitance_multiplier");
415 }
416 }
417
rename_exitance_inputs(EnvironmentEDF & edf)418 static void rename_exitance_inputs(EnvironmentEDF& edf)
419 {
420 if (strcmp(edf.get_model(), ConstantEnvironmentEDFFactory().get_model()) == 0)
421 {
422 move_if_exist(edf, "radiance", "exitance");
423 }
424 else if (strcmp(edf.get_model(), ConstantHemisphereEnvironmentEDFFactory().get_model()) == 0)
425 {
426 move_if_exist(edf, "upper_hemi_radiance", "upper_hemi_exitance");
427 move_if_exist(edf, "lower_hemi_radiance", "lower_hemi_exitance");
428 }
429 else if (strcmp(edf.get_model(), GradientEnvironmentEDFFactory().get_model()) == 0)
430 {
431 move_if_exist(edf, "horizon_radiance", "horizon_exitance");
432 move_if_exist(edf, "zenith_radiance", "zenith_exitance");
433 }
434 else if (strcmp(edf.get_model(), LatLongMapEnvironmentEDFFactory().get_model()) == 0 ||
435 strcmp(edf.get_model(), MirrorBallMapEnvironmentEDFFactory().get_model()) == 0)
436 {
437 move_if_exist(edf, "radiance", "exitance");
438 move_if_exist(edf, "radiance_multiplier", "exitance_multiplier");
439 }
440 }
441 };
442
443
444 //
445 // Update from revision 4 to revision 5.
446 //
447
448 class UpdateFromRevision_4
449 : public Updater
450 {
451 public:
UpdateFromRevision_4(Project & project)452 explicit UpdateFromRevision_4(Project& project)
453 : Updater(project, 4)
454 {
455 }
456
update()457 void update() override
458 {
459 for (each<ConfigurationContainer> i = m_project.configurations(); i; ++i)
460 {
461 ParamArray& root = i->get_parameters();
462 move_if_exist(root, "texture_store.max_size", "texture_cache_size");
463 }
464 }
465 };
466
467
468 //
469 // Update from revision 5 to revision 6.
470 //
471
472 class UpdateFromRevision_5
473 : public Updater
474 {
475 public:
UpdateFromRevision_5(Project & project)476 explicit UpdateFromRevision_5(Project& project)
477 : Updater(project, 5)
478 {
479 }
480
update()481 void update() override
482 {
483 if (Scene* scene = m_project.get_scene())
484 update_assemblies(scene->assemblies());
485 }
486
487 private:
488 class BlinnExponentFunction
489 {
490 public:
BlinnExponentFunction(const float e)491 explicit BlinnExponentFunction(const float e)
492 : m_e(e)
493 {
494 }
495
operator ()(const float x) const496 float operator()(const float x) const
497 {
498 return 100.0f * pow_int<3>(x) + 9900.0f * pow_int<30>(x) - m_e;
499 }
500
501 private:
502 const float m_e;
503 };
504
update_assemblies(const AssemblyContainer & assemblies)505 static void update_assemblies(const AssemblyContainer& assemblies)
506 {
507 for (const_each<AssemblyContainer> i = assemblies; i; ++i)
508 {
509 update_bsdfs(*i, i->bsdfs());
510 update_assemblies(i->assemblies());
511 }
512 }
513
update_bsdfs(const Assembly & assembly,BSDFContainer & bsdfs)514 static void update_bsdfs(const Assembly& assembly, BSDFContainer& bsdfs)
515 {
516 for (each<BSDFContainer> i = bsdfs; i; ++i)
517 {
518 BSDF& bsdf = *i;
519
520 if (strcmp(bsdf.get_model(), "microfacet_brdf"))
521 continue;
522
523 ParamArray& params = bsdf.get_parameters();
524
525 const string mdf = params.get_optional<string>("mdf", "");
526 const string mdf_param = params.get_optional<string>("mdf_parameter", "");
527
528 if (mdf_param.empty())
529 continue;
530
531 float mdf_param_value;
532 if (try_parse_scalar(mdf_param, mdf_param_value))
533 {
534 float glossiness;
535 if (!mdf_param_to_glossiness(mdf, mdf_param_value, glossiness))
536 {
537 RENDERER_LOG_ERROR(
538 "while updating bsdf \"%s\", failed to convert mdf parameter %f.",
539 bsdf.get_path().c_str(),
540 mdf_param_value);
541 continue;
542 }
543
544 params.insert("glossiness", glossiness);
545 }
546 else
547 {
548 ColorEntity* color = find_color_entity(assembly, mdf_param);
549
550 if (color)
551 {
552 const ColorSource source(*color);
553
554 float mdf_param_value;
555 source.evaluate_uniform(mdf_param_value);
556
557 float glossiness;
558 if (!mdf_param_to_glossiness(mdf, mdf_param_value, glossiness))
559 {
560 RENDERER_LOG_ERROR(
561 "while updating bsdf \"%s\", failed to convert mdf parameter %f in color entity \"%s\".",
562 bsdf.get_path().c_str(),
563 mdf_param_value,
564 color->get_path().c_str());
565 continue;
566 }
567
568 ParamArray new_color_params = color->get_parameters();
569 new_color_params.remove_path("multiplier");
570
571 ColorValueArray new_color_values;
572 new_color_values.push_back(glossiness);
573
574 auto_release_ptr<ColorEntity> new_color_entity(
575 ColorEntityFactory::create(
576 color->get_name(),
577 new_color_params,
578 new_color_values));
579
580 Assembly* parent_assembly = dynamic_cast<Assembly*>(color->get_parent());
581
582 if (parent_assembly)
583 {
584 parent_assembly->colors().remove(color);
585 parent_assembly->colors().insert(new_color_entity);
586 }
587 else
588 {
589 Scene* parent_scene = dynamic_cast<Scene*>(color->get_parent());
590 assert(parent_scene);
591
592 parent_scene->colors().remove(color);
593 parent_scene->colors().insert(new_color_entity);
594 }
595 }
596
597 move_if_exist(params, "glossiness", "mdf_parameter");
598 }
599 }
600 }
601
try_parse_scalar(const string & s,float & value)602 static bool try_parse_scalar(const string& s, float& value)
603 {
604 try
605 {
606 value = from_string<float>(s);
607 return true;
608 }
609 catch (const ExceptionStringConversionError&)
610 {
611 return false;
612 }
613 }
614
find_color_entity(const Assembly & assembly,const string & name)615 static ColorEntity* find_color_entity(const Assembly& assembly, const string& name)
616 {
617 for (each<ColorContainer> i = assembly.colors(); i; ++i)
618 {
619 if (i->get_name() == name)
620 return &*i;
621 }
622
623 Assembly* parent_assembly = dynamic_cast<Assembly*>(assembly.get_parent());
624
625 if (parent_assembly)
626 return find_color_entity(*parent_assembly, name);
627
628 Scene* parent_scene = dynamic_cast<Scene*>(assembly.get_parent());
629 assert(parent_scene);
630
631 return find_color_entity(*parent_scene, name);
632 }
633
find_color_entity(const Scene & scene,const string & name)634 static ColorEntity* find_color_entity(const Scene& scene, const string& name)
635 {
636 for (each<ColorContainer> i = scene.colors(); i; ++i)
637 {
638 if (i->get_name() == name)
639 return &*i;
640 }
641
642 return nullptr;
643 }
644
mdf_param_to_glossiness(const string & mdf,const float mdf_param,float & glossiness)645 static bool mdf_param_to_glossiness(const string& mdf, const float mdf_param, float& glossiness)
646 {
647 if (mdf == "blinn")
648 {
649 const BlinnExponentFunction f(mdf_param);
650 return find_root_bisection(f, 0.0f, 1.0f, 1.0e-6f, 100, glossiness);
651 }
652 else
653 {
654 glossiness = saturate(1.0f - mdf_param);
655 return true;
656 }
657 }
658 };
659
660
661 //
662 // Update from revision 6 to revision 7.
663 //
664
665 class UpdateFromRevision_6
666 : public Updater
667 {
668 public:
UpdateFromRevision_6(Project & project)669 explicit UpdateFromRevision_6(Project& project)
670 : Updater(project, 6)
671 {
672 }
673
update()674 void update() override
675 {
676 // Here, we used to update render layer rules
677 // but render layers were removed in appleseed 1.7.0-beta.
678 }
679 };
680
681
682 //
683 // Update from revision 7 to revision 8.
684 //
685
686 class UpdateFromRevision_7
687 : public Updater
688 {
689 public:
UpdateFromRevision_7(Project & project)690 explicit UpdateFromRevision_7(Project& project)
691 : Updater(project, 7)
692 {
693 }
694
update()695 void update() override
696 {
697 if (Scene* scene = m_project.get_scene())
698 update_collection(scene->assemblies());
699 }
700
701 private:
702 template <typename Collection>
update_collection(Collection & collection)703 static void update_collection(Collection& collection)
704 {
705 for (each<Collection> i = collection; i; ++i)
706 update_entity(*i);
707 }
708
update_entity(Assembly & assembly)709 static void update_entity(Assembly& assembly)
710 {
711 update_collection(assembly.object_instances());
712 update_collection(assembly.assemblies());
713 }
714
update_entity(ObjectInstance & object_instance)715 static void update_entity(ObjectInstance& object_instance)
716 {
717 const Object* object = object_instance.find_object();
718
719 if (object && object->get_material_slot_count() == 1)
720 {
721 const string slot_name = object->get_material_slot(0);
722
723 rebuild_material_mappings(object_instance.get_front_material_mappings(), slot_name);
724 rebuild_material_mappings(object_instance.get_back_material_mappings(), slot_name);
725 }
726 }
727
rebuild_material_mappings(StringDictionary & mappings,const string & slot_name)728 static void rebuild_material_mappings(StringDictionary& mappings, const string& slot_name)
729 {
730 if (!mappings.empty())
731 {
732 const string material_name = mappings.begin().value();
733
734 mappings.clear();
735 mappings.insert(slot_name, material_name);
736 }
737 }
738 };
739
740
741 //
742 // Update from revision 8 to revision 9.
743 //
744
745 class UpdateFromRevision_8
746 : public Updater
747 {
748 public:
UpdateFromRevision_8(Project & project)749 explicit UpdateFromRevision_8(Project& project)
750 : Updater(project, 8)
751 {
752 }
753
update()754 void update() override
755 {
756 if (Scene* scene = m_project.get_scene())
757 rename_radiance_inputs(scene->assemblies());
758 }
759
760 private:
rename_radiance_inputs(AssemblyContainer & assemblies)761 static void rename_radiance_inputs(AssemblyContainer& assemblies)
762 {
763 for (each<AssemblyContainer> i = assemblies; i; ++i)
764 {
765 rename_radiance_inputs(*i);
766 rename_radiance_inputs(i->assemblies());
767 }
768 }
769
rename_radiance_inputs(Assembly & assembly)770 static void rename_radiance_inputs(Assembly& assembly)
771 {
772 for (each<LightContainer> i = assembly.lights(); i; ++i)
773 rename_radiance_inputs(*i);
774 }
775
rename_radiance_inputs(Light & light)776 static void rename_radiance_inputs(Light& light)
777 {
778 if (strcmp(light.get_model(), DirectionalLightFactory().get_model()) == 0)
779 {
780 move_if_exist(light, "irradiance", "radiance");
781 move_if_exist(light, "irradiance_multiplier", "radiance_multiplier");
782 }
783 else if (strcmp(light.get_model(), PointLightFactory().get_model()) == 0 ||
784 strcmp(light.get_model(), SpotLightFactory().get_model()) == 0)
785 {
786 move_if_exist(light, "intensity", "radiance");
787 move_if_exist(light, "intensity_multiplier", "radiance_multiplier");
788 }
789 }
790 };
791
792
793 //
794 // Update from revision 9 to revision 10.
795 //
796
797 class UpdateFromRevision_9
798 : public Updater
799 {
800 public:
UpdateFromRevision_9(Project & project)801 explicit UpdateFromRevision_9(Project& project)
802 : Updater(project, 9)
803 {
804 }
805
update()806 void update() override
807 {
808 if (Scene* scene = m_project.get_scene())
809 visit(scene->assemblies());
810 }
811
812 private:
813 struct MaterialInfo
814 {
815 bool m_updated;
816 Material* m_material;
817 BSDF* m_bsdf;
818 string m_bsdf_reflectance;
819 string m_bsdf_reflectance_multiplier;
820 string m_bsdf_transmittance;
821 string m_bsdf_transmittance_multiplier;
822 string m_bsdf_fresnel_multiplier;
823 float m_bsdf_from_ior;
824 float m_bsdf_to_ior;
825 string m_bssrdf;
826 string m_edf;
827 string m_alpha_map;
828 string m_displacement_map;
829 string m_displacement_method;
830 string m_bump_amplitude;
831 string m_normal_map_up;
832 };
833
visit(AssemblyContainer & assemblies)834 static void visit(AssemblyContainer& assemblies)
835 {
836 for (each<AssemblyContainer> i = assemblies; i; ++i)
837 visit(*i);
838 }
839
visit(Assembly & assembly)840 static void visit(Assembly& assembly)
841 {
842 visit(assembly.assemblies());
843 update(assembly);
844 }
845
update(Assembly & assembly)846 static void update(Assembly& assembly)
847 {
848 vector<MaterialInfo> materials;
849 collect_refractive_materials(assembly, materials);
850
851 for (each<vector<MaterialInfo>> i = materials; i; ++i)
852 {
853 if (i->m_updated)
854 continue;
855
856 for (each<vector<MaterialInfo>> j = succ(i); j; ++j)
857 {
858 if (j->m_updated)
859 continue;
860
861 MaterialInfo& mat1 = *i;
862 MaterialInfo& mat2 = *j;
863
864 if (are_paired(mat1, mat2))
865 {
866 // Extract mat1 from the assembly.
867 auto_release_ptr<Material> mat1_owner = assembly.materials().remove(mat1.m_material);
868
869 // Extract mat1's BSDF from the assembly.
870 auto_release_ptr<BSDF> bsdf_owner = assembly.bsdfs().remove(mat1.m_bsdf);
871
872 // Update mat1's BSDF.
873 // todo: make sure the BSDF is not used in another material.
874 update_bsdf(mat1);
875 assert(assembly.bsdfs().get_by_name(bsdf_owner->get_name()) == nullptr);
876
877 // Insert mat1's BSDF back into the assembly.
878 assembly.bsdfs().insert(bsdf_owner);
879
880 // Rename mat1.
881 const string old_mat1_name = mat1.m_material->get_name();
882 cleanup_entity_name(*mat1.m_material);
883 update_material_mappings(
884 assembly.object_instances(),
885 old_mat1_name.c_str(),
886 mat1.m_material->get_name());
887 update_material_mappings(
888 assembly.object_instances(),
889 mat2.m_material->get_name(),
890 mat1.m_material->get_name());
891
892 // Insert mat1 back into the assembly.
893 assembly.materials().insert(mat1_owner);
894
895 // Remove mat2.
896 assembly.bsdfs().remove(mat2.m_bsdf);
897 assembly.materials().remove(mat2.m_material);
898
899 mat1.m_updated = true;
900 mat2.m_updated = true;
901 break;
902 }
903 }
904
905 if (!i->m_updated)
906 {
907 // Extract the material's BSDF from the assembly.
908 auto_release_ptr<BSDF> bsdf_owner = assembly.bsdfs().remove(i->m_bsdf);
909
910 // Update the material's BSDF.
911 // todo: make sure the BSDF is not used in another material.
912 update_bsdf(*i);
913
914 // Insert the material's BSDF back into the assembly.
915 if (assembly.bsdfs().get_by_name(bsdf_owner->get_name()) == nullptr)
916 assembly.bsdfs().insert(bsdf_owner);
917
918 i->m_updated = true;
919 }
920 }
921 }
922
collect_refractive_materials(Assembly & assembly,vector<MaterialInfo> & materials)923 static void collect_refractive_materials(Assembly& assembly, vector<MaterialInfo>& materials)
924 {
925 for (each<MaterialContainer> i = assembly.materials(); i; ++i)
926 {
927 Material& material = *i;
928
929 if (strcmp(material.get_model(), "generic_material"))
930 continue;
931
932 const ParamArray& material_params = material.get_parameters();
933
934 if (!material_params.strings().exist("bsdf"))
935 continue;
936
937 const string bsdf_name = material_params.get<string>("bsdf");
938 BSDF* bsdf = assembly.bsdfs().get_by_name(bsdf_name.c_str());
939
940 if (bsdf == nullptr)
941 continue;
942
943 if (strcmp(bsdf->get_model(), "specular_btdf"))
944 continue;
945
946 const ParamArray& bsdf_params = bsdf->get_parameters();
947
948 if (!bsdf_params.strings().exist("from_ior") ||
949 !bsdf_params.strings().exist("to_ior") ||
950 !bsdf_params.strings().exist("reflectance") ||
951 !bsdf_params.strings().exist("transmittance"))
952 continue;
953
954 // At this point we have found a material that needs to be updated.
955
956 MaterialInfo info;
957 info.m_updated = false;
958 info.m_material = &material;
959 info.m_bsdf = bsdf;
960 info.m_bsdf_reflectance = bsdf_params.get<string>("reflectance");
961 info.m_bsdf_reflectance_multiplier = bsdf_params.get_optional<string>("reflectance_multiplier", "1.0");
962 info.m_bsdf_transmittance = bsdf_params.get<string>("transmittance");
963 info.m_bsdf_transmittance_multiplier = bsdf_params.get_optional<string>("transmittance_multiplier", "1.0");
964 info.m_bsdf_fresnel_multiplier = bsdf_params.get_optional<string>("fresnel_multiplier", "1.0");
965 info.m_bsdf_from_ior = bsdf_params.get<float>("from_ior");
966 info.m_bsdf_to_ior = bsdf_params.get<float>("to_ior");
967 info.m_bssrdf = material_params.get_optional<string>("bssrdf", "");
968 info.m_edf = material_params.get_optional<string>("edf", "");
969 info.m_alpha_map = material_params.get_optional<string>("alpha_map", "");
970 info.m_displacement_map = material_params.get_optional<string>("displacement_map", "");
971 info.m_displacement_method = material_params.get_optional<string>("displacement_method", "");
972 info.m_bump_amplitude = material_params.get_optional<string>("bump_amplitude", "");
973 info.m_normal_map_up = material_params.get_optional<string>("normal_map_up", "");
974
975 materials.push_back(info);
976 }
977 }
978
are_paired(const MaterialInfo & lhs,const MaterialInfo & rhs)979 static bool are_paired(const MaterialInfo& lhs, const MaterialInfo& rhs)
980 {
981 assert(!lhs.m_updated && !rhs.m_updated);
982
983 return
984 lhs.m_bsdf_reflectance == rhs.m_bsdf_reflectance &&
985 lhs.m_bsdf_reflectance_multiplier == rhs.m_bsdf_reflectance_multiplier &&
986 lhs.m_bsdf_transmittance == rhs.m_bsdf_transmittance &&
987 lhs.m_bsdf_transmittance_multiplier == rhs.m_bsdf_transmittance_multiplier &&
988 lhs.m_bsdf_fresnel_multiplier == rhs.m_bsdf_fresnel_multiplier &&
989 feq(lhs.m_bsdf_from_ior, rhs.m_bsdf_to_ior) &&
990 feq(lhs.m_bsdf_to_ior, rhs.m_bsdf_from_ior) &&
991 lhs.m_bssrdf == rhs.m_bssrdf &&
992 lhs.m_edf == rhs.m_edf &&
993 lhs.m_alpha_map == rhs.m_alpha_map &&
994 lhs.m_displacement_map == rhs.m_displacement_map &&
995 lhs.m_displacement_method == rhs.m_displacement_method &&
996 lhs.m_bump_amplitude == rhs.m_bump_amplitude &&
997 lhs.m_normal_map_up == rhs.m_normal_map_up;
998 }
999
cleanup_entity_name(Entity & entity)1000 static void cleanup_entity_name(Entity& entity)
1001 {
1002 string name = entity.get_name();
1003 name = replace(name, "_front_", "");
1004 name = replace(name, "_front", "");
1005 name = replace(name, "front_", "");
1006 name = replace(name, "_back_", "");
1007 name = replace(name, "_back", "");
1008 name = replace(name, "back_", "");
1009 entity.set_name(name.c_str());
1010 }
1011
update_material_mappings(ObjectInstanceContainer & object_instances,const char * old_material_name,const char * new_material_name)1012 static void update_material_mappings(
1013 ObjectInstanceContainer& object_instances,
1014 const char* old_material_name,
1015 const char* new_material_name)
1016 {
1017 for (each<ObjectInstanceContainer> i = object_instances; i; ++i)
1018 {
1019 update_material_mappings(i->get_front_material_mappings(), old_material_name, new_material_name);
1020 update_material_mappings(i->get_back_material_mappings(), old_material_name, new_material_name);
1021 }
1022 }
1023
update_material_mappings(StringDictionary & mappings,const char * old_material_name,const char * new_material_name)1024 static void update_material_mappings(
1025 StringDictionary& mappings,
1026 const char* old_material_name,
1027 const char* new_material_name)
1028 {
1029 for (const_each<StringDictionary> i = mappings; i; ++i)
1030 {
1031 if (strcmp(i->value(), old_material_name) == 0)
1032 mappings.set(i->key(), new_material_name);
1033 }
1034 }
1035
update_bsdf(const MaterialInfo & info)1036 static void update_bsdf(const MaterialInfo& info)
1037 {
1038 ParamArray& bsdf_params = info.m_bsdf->get_parameters();
1039
1040 bsdf_params.strings().remove("from_ior");
1041 bsdf_params.strings().remove("to_ior");
1042
1043 const float ior =
1044 feq(info.m_bsdf_from_ior, 1.0f) ? info.m_bsdf_to_ior : info.m_bsdf_from_ior;
1045 bsdf_params.strings().insert("ior", ior);
1046
1047 cleanup_entity_name(*info.m_bsdf);
1048 info.m_material->get_parameters().insert("bsdf", info.m_bsdf->get_name());
1049 }
1050 };
1051
1052
1053 //
1054 // Update from revision 10 to revision 11.
1055 //
1056
1057 class UpdateFromRevision_10
1058 : public Updater
1059 {
1060 public:
UpdateFromRevision_10(Project & project)1061 explicit UpdateFromRevision_10(Project& project)
1062 : Updater(project, 10)
1063 {
1064 }
1065
update()1066 void update() override
1067 {
1068 if (Scene* scene = m_project.get_scene())
1069 update_bssrdf_ior_inputs(scene->assemblies());
1070 }
1071
1072 private:
update_bssrdf_ior_inputs(AssemblyContainer & assemblies)1073 static void update_bssrdf_ior_inputs(AssemblyContainer& assemblies)
1074 {
1075 for (each<AssemblyContainer> i = assemblies; i; ++i)
1076 {
1077 update_bssrdf_ior_inputs(*i);
1078 update_bssrdf_ior_inputs(i->assemblies());
1079 }
1080 }
1081
update_bssrdf_ior_inputs(Assembly & assembly)1082 static void update_bssrdf_ior_inputs(Assembly& assembly)
1083 {
1084 for (each<BSSRDFContainer> i = assembly.bssrdfs(); i; ++i)
1085 update_bssrdf_ior_inputs(*i);
1086 }
1087
update_bssrdf_ior_inputs(BSSRDF & bssrdf)1088 static void update_bssrdf_ior_inputs(BSSRDF& bssrdf)
1089 {
1090 move_if_exist(bssrdf, "ior", "inside_ior");
1091 bssrdf.get_parameters().remove_path("outside_ior");
1092 }
1093 };
1094
1095
1096 //
1097 // Update from revision 11 to revision 12.
1098 //
1099
1100 class UpdateFromRevision_11
1101 : public Updater
1102 {
1103 public:
UpdateFromRevision_11(Project & project)1104 explicit UpdateFromRevision_11(Project& project)
1105 : Updater(project, 11)
1106 {
1107 }
1108
update()1109 void update() override
1110 {
1111 if (Scene* scene = m_project.get_scene())
1112 update_bssrdf_mfp_inputs(scene->assemblies());
1113 }
1114
1115 private:
update_bssrdf_mfp_inputs(AssemblyContainer & assemblies)1116 static void update_bssrdf_mfp_inputs(AssemblyContainer& assemblies)
1117 {
1118 for (each<AssemblyContainer> i = assemblies; i; ++i)
1119 {
1120 update_bssrdf_mfp_inputs(*i);
1121 update_bssrdf_mfp_inputs(i->assemblies());
1122 }
1123 }
1124
update_bssrdf_mfp_inputs(Assembly & assembly)1125 static void update_bssrdf_mfp_inputs(Assembly& assembly)
1126 {
1127 for (each<BSSRDFContainer> i = assembly.bssrdfs(); i; ++i)
1128 update_bssrdf_mfp_inputs(*i);
1129 }
1130
update_bssrdf_mfp_inputs(BSSRDF & bssrdf)1131 static void update_bssrdf_mfp_inputs(BSSRDF& bssrdf)
1132 {
1133 move_if_exist(bssrdf, "mfp", "dmfp");
1134 move_if_exist(bssrdf, "mfp_multiplier", "dmfp_multiplier");
1135 }
1136 };
1137
1138
1139 //
1140 // Update from revision 12 to revision 13.
1141 //
1142
1143 class UpdateFromRevision_12
1144 : public Updater
1145 {
1146 public:
UpdateFromRevision_12(Project & project)1147 explicit UpdateFromRevision_12(Project& project)
1148 : Updater(project, 12)
1149 {
1150 }
1151
update()1152 void update() override
1153 {
1154 Frame* frame = m_project.get_frame();
1155 const Scene* scene = m_project.get_scene();
1156
1157 if (frame == nullptr || scene == nullptr || scene->cameras().empty())
1158 return;
1159
1160 ParamArray& frame_params = frame->get_parameters();
1161
1162 if (!frame_params.strings().exist("camera"))
1163 {
1164 // The frame does not reference any camera: use the first camera.
1165 frame_params.insert(
1166 "camera",
1167 scene->cameras().get_by_index(0)->get_name());
1168 }
1169 else
1170 {
1171 const char* camera_name = frame_params.strings().get("camera");
1172 if (scene->cameras().get_by_name(camera_name) == nullptr)
1173 {
1174 // The frame references a non-existing camera: use the first camera.
1175 frame_params.insert(
1176 "camera",
1177 scene->cameras().get_by_index(0)->get_name());
1178 }
1179 }
1180 }
1181 };
1182
1183
1184 //
1185 // Update from revision 13 to revision 14.
1186 //
1187
1188 class UpdateFromRevision_13
1189 : public Updater
1190 {
1191 public:
UpdateFromRevision_13(Project & project)1192 explicit UpdateFromRevision_13(Project& project)
1193 : Updater(project, 13)
1194 {
1195 }
1196
update()1197 void update() override
1198 {
1199 if (Scene* scene = m_project.get_scene())
1200 {
1201 update_bsdfs_inputs(scene->assemblies());
1202 update_gaussian_bssrdfs(scene->assemblies());
1203 }
1204 }
1205
1206 private:
update_bsdfs_inputs(AssemblyContainer & assemblies)1207 static void update_bsdfs_inputs(AssemblyContainer& assemblies)
1208 {
1209 for (each<AssemblyContainer> i = assemblies; i; ++i)
1210 {
1211 update_bsdfs_inputs(*i);
1212 update_bsdfs_inputs(i->assemblies());
1213 }
1214 }
1215
update_bsdfs_inputs(Assembly & assembly)1216 static void update_bsdfs_inputs(Assembly& assembly)
1217 {
1218 for (each<BSDFContainer> i = assembly.bsdfs(); i; ++i)
1219 update_bsdf_inputs(*i);
1220 }
1221
update_bsdf_inputs(BSDF & bsdf)1222 static void update_bsdf_inputs(BSDF& bsdf)
1223 {
1224 if (strcmp(bsdf.get_model(), GlassBSDFFactory().get_model()) == 0)
1225 {
1226 bsdf.get_parameters().insert("volume_parameterization", "transmittance");
1227 move_if_exist(bsdf, "anisotropy", "anisotropic");
1228 }
1229 else if (strcmp(bsdf.get_model(), GlossyBRDFFactory().get_model()) == 0 ||
1230 strcmp(bsdf.get_model(), MetalBRDFFactory().get_model()) == 0)
1231 {
1232 move_if_exist(bsdf, "anisotropy", "anisotropic");
1233 }
1234 else if (strcmp(bsdf.get_model(), SpecularBTDFFactory().get_model()) == 0)
1235 {
1236 move_if_exist(bsdf, "volume_density", "density");
1237 move_if_exist(bsdf, "volume_scale", "scale");
1238 }
1239 }
1240
update_gaussian_bssrdfs(AssemblyContainer & assemblies)1241 static void update_gaussian_bssrdfs(AssemblyContainer& assemblies)
1242 {
1243 for (each<AssemblyContainer> i = assemblies; i; ++i)
1244 {
1245 update_gaussian_bssrdfs(*i);
1246 update_gaussian_bssrdfs(i->assemblies());
1247 }
1248 }
1249
update_gaussian_bssrdfs(Assembly & assembly)1250 static void update_gaussian_bssrdfs(Assembly& assembly)
1251 {
1252 for (each<BSSRDFContainer> i = assembly.bssrdfs(); i; ++i)
1253 {
1254 if (strcmp(i->get_model(), GaussianBSSRDFFactory().get_model()) == 0)
1255 update_gaussian_bssrdf(*i);
1256 }
1257 }
1258
update_gaussian_bssrdf(BSSRDF & bssrdf)1259 static void update_gaussian_bssrdf(BSSRDF& bssrdf)
1260 {
1261 ParamArray& params = bssrdf.get_parameters();
1262
1263 try
1264 {
1265 const float v = params.get<float>("v");
1266 const float mfp = sqrt(v * 16.0f) / 7.0f;
1267 params.insert("mfp", mfp);
1268 params.remove_path("v");
1269 }
1270 catch (const Exception&)
1271 {
1272 RENDERER_LOG_ERROR(
1273 "while updating gaussian bssrdf \"%s\": failed to convert v parameter.",
1274 bssrdf.get_name());
1275 }
1276 }
1277 };
1278
1279
1280 //
1281 // Update from revision 14 to revision 15.
1282 //
1283
1284 class UpdateFromRevision_14
1285 : public Updater
1286 {
1287 public:
UpdateFromRevision_14(Project & project)1288 explicit UpdateFromRevision_14(Project& project)
1289 : Updater(project, 14)
1290 {
1291 }
1292
update()1293 void update() override
1294 {
1295 if (Scene* scene = m_project.get_scene())
1296 update_entities(scene->assemblies());
1297 }
1298
1299 private:
update_entities(AssemblyContainer & assemblies)1300 static void update_entities(AssemblyContainer& assemblies)
1301 {
1302 for (each<AssemblyContainer> i = assemblies; i; ++i)
1303 {
1304 update_entities(*i);
1305 update_entities(i->assemblies());
1306 }
1307 }
1308
update_entities(Assembly & assembly)1309 static void update_entities(Assembly& assembly)
1310 {
1311 for (each<BSDFContainer> i = assembly.bsdfs(); i; ++i)
1312 update_bsdf_inputs(*i);
1313
1314 for (each<MaterialContainer> i = assembly.materials(); i; ++i)
1315 update_material_inputs(*i);
1316 }
1317
update_bsdf_inputs(BSDF & bsdf)1318 static void update_bsdf_inputs(BSDF& bsdf)
1319 {
1320 if (strcmp(bsdf.get_model(), DisneyBRDFFactory().get_model()) == 0)
1321 {
1322 ParamArray& params = bsdf.get_parameters();
1323 if (!params.strings().exist("specular"))
1324 params.insert("specular", 0.5f);
1325 if (!params.strings().exist("roughness"))
1326 params.insert("roughness", 0.5f);
1327 if (!params.strings().exist("sheen_tint"))
1328 params.insert("sheen_tint", 0.5f);
1329 }
1330 }
1331
update_material_inputs(Material & material)1332 static void update_material_inputs(Material& material)
1333 {
1334 // Don't rely on DisneyMaterialFactory().get_model() because appleseed needs
1335 // to be able to update projects even when built without Disney material support
1336 // (i.e. the APPLESEED_WITH_DISNEY_MATERIAL preprocessor symbol is undefined).
1337 if (strcmp(material.get_model(), "disney_material") == 0)
1338 {
1339 ParamArray& params = material.get_parameters();
1340 for (each<DictionaryDictionary> i = params.dictionaries(); i; ++i)
1341 {
1342 Dictionary& layer_params = i->value();
1343 if (!layer_params.strings().exist("roughness"))
1344 layer_params.insert("roughness", 0.5f);
1345 }
1346 }
1347 }
1348 };
1349
1350
1351 //
1352 // Update from revision 15 to revision 16.
1353 //
1354
1355 class UpdateFromRevision_15
1356 : public Updater
1357 {
1358 public:
UpdateFromRevision_15(Project & project)1359 explicit UpdateFromRevision_15(Project& project)
1360 : Updater(project, 15)
1361 {
1362 }
1363
update()1364 void update() override
1365 {
1366 if (Scene* scene = m_project.get_scene())
1367 update_physical_surface_shader_inputs(scene->assemblies());
1368 }
1369
1370 private:
update_physical_surface_shader_inputs(AssemblyContainer & assemblies)1371 static void update_physical_surface_shader_inputs(AssemblyContainer& assemblies)
1372 {
1373 for (each<AssemblyContainer> i = assemblies; i; ++i)
1374 {
1375 update_physical_surface_shader_inputs(*i);
1376 update_physical_surface_shader_inputs(i->assemblies());
1377 }
1378 }
1379
update_physical_surface_shader_inputs(Assembly & assembly)1380 static void update_physical_surface_shader_inputs(Assembly& assembly)
1381 {
1382 for (each<SurfaceShaderContainer> i = assembly.surface_shaders(); i; ++i)
1383 update_physical_surface_shader_inputs(*i);
1384 }
1385
update_physical_surface_shader_inputs(SurfaceShader & surface_shader)1386 static void update_physical_surface_shader_inputs(SurfaceShader& surface_shader)
1387 {
1388 if (strcmp(surface_shader.get_model(), PhysicalSurfaceShaderFactory().get_model()) == 0)
1389 {
1390 move_if_exist(surface_shader, "lighting_samples", "front_lighting_samples");
1391
1392 ParamArray& params = surface_shader.get_parameters();
1393 params.strings().remove("translucency");
1394 params.strings().remove("back_lighting_samples");
1395 params.strings().remove("aerial_persp_sky_color");
1396 params.strings().remove("aerial_persp_mode");
1397 params.strings().remove("aerial_persp_distance");
1398 params.strings().remove("aerial_persp_intensity");
1399 }
1400 }
1401 };
1402
1403
1404 //
1405 // Update from revision 16 to revision 17.
1406 //
1407
1408 class UpdateFromRevision_16
1409 : public Updater
1410 {
1411 public:
UpdateFromRevision_16(Project & project)1412 explicit UpdateFromRevision_16(Project& project)
1413 : Updater(project, 16)
1414 {
1415 }
1416
update()1417 void update() override
1418 {
1419 for (each<ConfigurationContainer> i = m_project.configurations(); i; ++i)
1420 update(*i);
1421 }
1422
1423 private:
update(Configuration & configuration)1424 static void update(Configuration& configuration)
1425 {
1426 ParamArray& params = configuration.get_parameters();
1427
1428 if (params.get_optional<string>("lighting_engine") == "drt")
1429 {
1430 // The project was using DRT: switch to PT.
1431 params.insert_path("lighting_engine", "pt");
1432
1433 // If they exist, replace DRT parameters by PT ones.
1434 if (params.dictionaries().exist("drt"))
1435 params.insert("pt", params.child("drt"));
1436
1437 // Set PT parameters to emulate DRT.
1438 params.insert_path("pt.max_diffuse_bounces", 0);
1439 }
1440
1441 // Remove DRT parameters.
1442 if (params.dictionaries().exist("drt"))
1443 params.dictionaries().remove("drt");
1444 }
1445 };
1446
1447
1448 //
1449 // Update from revision 17 to revision 18.
1450 //
1451
1452 class UpdateFromRevision_17
1453 : public Updater
1454 {
1455 public:
UpdateFromRevision_17(Project & project)1456 explicit UpdateFromRevision_17(Project& project)
1457 : Updater(project, 17)
1458 {
1459 }
1460
update()1461 void update() override
1462 {
1463 for (each<ConfigurationContainer> i = m_project.configurations(); i; ++i)
1464 update(*i);
1465 }
1466
1467 private:
update(Configuration & configuration)1468 static void update(Configuration& configuration)
1469 {
1470 ParamArray& params = configuration.get_parameters();
1471
1472 if (params.dictionaries().exist("pt"))
1473 {
1474 Dictionary& pt_params = params.dictionary("pt");
1475 convert_max_path_length_to_max_bounces(pt_params, "max_path_length", "max_bounces");
1476 }
1477
1478 if (params.dictionaries().exist("sppm"))
1479 {
1480 Dictionary& sppm_params = params.dictionary("sppm");
1481 convert_max_path_length_to_max_bounces(sppm_params, "photon_tracing_max_path_length", "photon_tracing_max_bounces");
1482 convert_max_path_length_to_max_bounces(sppm_params, "path_tracing_max_path_length", "path_tracing_max_bounces");
1483 }
1484
1485 if (params.dictionaries().exist("lighttracing"))
1486 {
1487 Dictionary& lt_params = params.dictionary("lighttracing");
1488 convert_max_path_length_to_max_bounces(lt_params, "max_path_length", "max_bounces");
1489 }
1490 }
1491
convert_max_path_length_to_max_bounces(Dictionary & params,const char * max_path_length_param_name,const char * max_bounces_param_name)1492 static void convert_max_path_length_to_max_bounces(
1493 Dictionary& params,
1494 const char* max_path_length_param_name,
1495 const char* max_bounces_param_name)
1496 {
1497 if (params.strings().exist(max_path_length_param_name))
1498 {
1499 const size_t max_path_length = params.get<size_t>(max_path_length_param_name);
1500 const int max_bounces =
1501 max_path_length == 0
1502 ? -1
1503 : static_cast<int>(max_path_length - 1);
1504
1505 params.strings().remove(max_path_length_param_name);
1506 params.insert(max_bounces_param_name, max_bounces);
1507 }
1508 }
1509 };
1510
1511
1512 //
1513 // Update from revision 18 to revision 19.
1514 //
1515
1516 class UpdateFromRevision_18
1517 : public Updater
1518 {
1519 public:
UpdateFromRevision_18(Project & project)1520 explicit UpdateFromRevision_18(Project& project)
1521 : Updater(project, 18)
1522 {
1523 }
1524
update()1525 void update() override
1526 {
1527 if (m_project.get_frame())
1528 update_frame(*m_project.get_frame());
1529 }
1530
1531 private:
update_frame(Frame & frame)1532 static void update_frame(Frame& frame)
1533 {
1534 ParamArray& params = frame.get_parameters();
1535 params.remove_path("pixel_format");
1536 params.remove_path("color_space");
1537 params.remove_path("gamma_correction");
1538 params.remove_path("clamping");
1539 params.remove_path("premultiplied_alpha");
1540 }
1541 };
1542
1543
1544 //
1545 // Update from revision 19 to revision 20.
1546 //
1547
1548 class UpdateFromRevision_19
1549 : public Updater
1550 {
1551 public:
UpdateFromRevision_19(Project & project)1552 explicit UpdateFromRevision_19(Project& project)
1553 : Updater(project, 19)
1554 {
1555 }
1556
update()1557 void update() override
1558 {
1559 if (Scene* scene = m_project.get_scene())
1560 update_material_and_object_inputs(scene->assemblies());
1561 }
1562
1563 private:
update_material_and_object_inputs(AssemblyContainer & assemblies)1564 static void update_material_and_object_inputs(AssemblyContainer& assemblies)
1565 {
1566 for (each<AssemblyContainer> i = assemblies; i; ++i)
1567 {
1568 update_material_and_object_inputs(*i);
1569 update_material_and_object_inputs(i->assemblies());
1570 }
1571 }
1572
update_material_and_object_inputs(Assembly & assembly)1573 static void update_material_and_object_inputs(Assembly& assembly)
1574 {
1575 for (each<MaterialContainer> i = assembly.materials(); i; ++i)
1576 remove_shade_alpha_cutouts(*i);
1577
1578 for (each<ObjectContainer> i = assembly.objects(); i; ++i)
1579 remove_shade_alpha_cutouts(*i);
1580 }
1581
1582 template <typename EntityType>
remove_shade_alpha_cutouts(EntityType & entity)1583 static void remove_shade_alpha_cutouts(EntityType& entity)
1584 {
1585 ParamArray& params = entity.get_parameters();
1586 params.remove_path("shade_alpha_cutouts");
1587 }
1588 };
1589
1590
1591 //
1592 // Update from revision 20 to revision 21.
1593 //
1594
1595 class UpdateFromRevision_20
1596 : public Updater
1597 {
1598 public:
UpdateFromRevision_20(Project & project)1599 explicit UpdateFromRevision_20(Project& project)
1600 : Updater(project, 20)
1601 {
1602 }
1603
update()1604 void update() override
1605 {
1606 if (Scene* scene = m_project.get_scene())
1607 update_physical_surface_shader_inputs(scene->assemblies());
1608 }
1609
1610 private:
update_physical_surface_shader_inputs(AssemblyContainer & assemblies)1611 static void update_physical_surface_shader_inputs(AssemblyContainer& assemblies)
1612 {
1613 for (each<AssemblyContainer> i = assemblies; i; ++i)
1614 {
1615 update_physical_surface_shader_inputs(*i);
1616 update_physical_surface_shader_inputs(i->assemblies());
1617 }
1618 }
1619
update_physical_surface_shader_inputs(Assembly & assembly)1620 static void update_physical_surface_shader_inputs(Assembly& assembly)
1621 {
1622 for (each<SurfaceShaderContainer> i = assembly.surface_shaders(); i; ++i)
1623 update_physical_surface_shader_inputs(*i);
1624 }
1625
update_physical_surface_shader_inputs(SurfaceShader & surface_shader)1626 static void update_physical_surface_shader_inputs(SurfaceShader& surface_shader)
1627 {
1628 if (strcmp(surface_shader.get_model(), PhysicalSurfaceShaderFactory().get_model()) == 0)
1629 {
1630 ParamArray& params = surface_shader.get_parameters();
1631 params.strings().remove("color_multiplier");
1632 params.strings().remove("alpha_multiplier");
1633 }
1634 }
1635 };
1636
1637
1638 //
1639 // Update from revision 21 to revision 22.
1640 //
1641
1642 class UpdateFromRevision_21
1643 : public Updater
1644 {
1645 public:
UpdateFromRevision_21(Project & project)1646 explicit UpdateFromRevision_21(Project& project)
1647 : Updater(project, 21)
1648 {
1649 }
1650
update()1651 void update() override
1652 {
1653 if (Scene* scene = m_project.get_scene())
1654 {
1655 for (each<CameraContainer> i = scene->cameras(); i; ++i)
1656 {
1657 Dictionary& camera_params = i->get_parameters();
1658
1659 copy_if_exist_no_overwrite(
1660 camera_params,
1661 "shutter_open_end_time",
1662 "shutter_open_time");
1663
1664 copy_if_exist_no_overwrite(
1665 camera_params,
1666 "shutter_close_start_time",
1667 "shutter_close_time");
1668 }
1669 }
1670 }
1671 };
1672
1673
1674 //
1675 // Update from revision 22 to revision 23.
1676 //
1677
1678 class UpdateFromRevision_22
1679 : public Updater
1680 {
1681 public:
UpdateFromRevision_22(Project & project)1682 explicit UpdateFromRevision_22(Project& project)
1683 : Updater(project, 22)
1684 {
1685 }
1686
update()1687 void update() override
1688 {
1689 if (Scene* scene = m_project.get_scene())
1690 {
1691 for (each<CameraContainer> i = scene->cameras(); i; ++i)
1692 {
1693 Dictionary& camera_params = i->get_parameters();
1694
1695 if (camera_params.strings().exist("autofocus_target"))
1696 camera_params.strings().insert("autofocus_enabled", true);
1697 else
1698 {
1699 // camera_params include "focal_distance".
1700 camera_params.strings().insert("autofocus_enabled", false);
1701 }
1702 }
1703 }
1704 }
1705 };
1706
1707
1708 //
1709 // Update from revision 23 to revision 24.
1710 //
1711
1712 class UpdateFromRevision_23
1713 : public Updater
1714 {
1715 public:
UpdateFromRevision_23(Project & project)1716 explicit UpdateFromRevision_23(Project& project)
1717 : Updater(project, 23)
1718 {
1719 }
1720
update()1721 void update() override
1722 {
1723 for (each<ConfigurationContainer> i = m_project.configurations(); i; ++i)
1724 update(*i);
1725 }
1726
1727 private:
update(Configuration & configuration)1728 static void update(Configuration& configuration)
1729 {
1730 ParamArray& params = configuration.get_parameters();
1731
1732 if (params.dictionaries().exist("pt"))
1733 {
1734 Dictionary& pt_params = params.dictionary("pt");
1735
1736 if (!pt_params.strings().exist("max_bounces"))
1737 pt_params.insert("max_bounces", -1);
1738
1739 if (!pt_params.strings().exist("max_diffuse_bounces"))
1740 pt_params.insert("max_diffuse_bounces", -1);
1741
1742 if (!pt_params.strings().exist("max_glossy_bounces"))
1743 pt_params.insert("max_glossy_bounces", -1);
1744
1745 if (!pt_params.strings().exist("max_specular_bounces"))
1746 pt_params.insert("max_specular_bounces", -1);
1747 }
1748 else
1749 {
1750 params.insert("pt", ParamArray()
1751 .insert("max_bounces", -1)
1752 .insert("max_diffuse_bounces", -1)
1753 .insert("max_glossy_bounces", -1)
1754 .insert("max_specular_bounces", -1));
1755 }
1756 }
1757 };
1758
1759
1760 //
1761 // Update from revision 24 to revision 25.
1762 //
1763
1764 class UpdateFromRevision_24
1765 : public Updater
1766 {
1767 public:
UpdateFromRevision_24(Project & project)1768 explicit UpdateFromRevision_24(Project& project)
1769 : Updater(project, 24)
1770 {
1771 }
1772
update()1773 void update() override
1774 {
1775 if (Scene* scene = m_project.get_scene())
1776 {
1777 for (each<CameraContainer> i = scene->cameras(); i; ++i)
1778 {
1779 ParamArray& camera_params = i->get_parameters();
1780 move_if_exist(camera_params, "shutter_open_begin_time", "shutter_open_time");
1781 move_if_exist(camera_params, "shutter_close_begin_time", "shutter_close_start_time");
1782 move_if_exist(camera_params, "shutter_close_end_time", "shutter_close_time");
1783 }
1784 }
1785 }
1786 };
1787
1788
1789 //
1790 // Update from revision 25 to revision 26.
1791 //
1792
1793 class UpdateFromRevision_25
1794 : public Updater
1795 {
1796 public:
UpdateFromRevision_25(Project & project)1797 explicit UpdateFromRevision_25(Project& project)
1798 : Updater(project, 25)
1799 {
1800 }
1801
update()1802 void update() override
1803 {
1804 if (m_project.get_frame())
1805 update_frame(*m_project.get_frame());
1806 }
1807
1808 private:
update_frame(Frame & frame)1809 static void update_frame(Frame& frame)
1810 {
1811 ParamArray& params = frame.get_parameters();
1812
1813 if (params.get_optional<bool>("enable_render_stamp"))
1814 {
1815 // There cannot be any other post-processing stage at this point.
1816 assert(frame.post_processing_stages().empty());
1817
1818 const string format_string = params.get_optional<string>("render_stamp_format");
1819 frame.post_processing_stages().insert(
1820 RenderStampPostProcessingStageFactory().create(
1821 "render_stamp",
1822 ParamArray()
1823 .insert("order", 0)
1824 .insert("format_string", format_string)));
1825 }
1826
1827 params.remove_path("enable_render_stamp");
1828 params.remove_path("render_stamp_format");
1829 }
1830 };
1831
1832
1833 //
1834 // Update from revision 26 to revision 27.
1835 //
1836
1837 class UpdateFromRevision_26
1838 : public Updater
1839 {
1840 public:
UpdateFromRevision_26(Project & project)1841 explicit UpdateFromRevision_26(Project& project)
1842 : Updater(project, 26)
1843 {
1844 }
1845
update()1846 void update() override
1847 {
1848 remove_diagnostic_option();
1849 update_passes_path();
1850 }
1851
1852 private:
1853 // Remove pixel_renderer::enable_diagnostics and frame::save_extra_aovs.
remove_diagnostic_option()1854 void remove_diagnostic_option()
1855 {
1856 for (Configuration& config : m_project.configurations())
1857 {
1858 Dictionary& root = config.get_parameters();
1859
1860 if (root.dictionaries().exist("uniform_pixel_renderer"))
1861 {
1862 Dictionary& upr = root.dictionary("uniform_pixel_renderer");
1863 upr.strings().remove("enable_diagnostics");
1864 }
1865
1866 if (root.dictionaries().exist("adaptive_pixel_renderer"))
1867 {
1868 Dictionary& apr = root.dictionary("adaptive_pixel_renderer");
1869 apr.strings().remove("enable_diagnostics");
1870 }
1871 }
1872
1873 Frame* frame = m_project.get_frame();
1874
1875 if (frame == nullptr)
1876 return;
1877
1878 ParamArray& frame_params = frame->get_parameters();
1879 frame_params.strings().remove("save_extra_aovs");
1880 }
1881
1882 // Move generic_frame_renderer::passes to the root configuration.
update_passes_path()1883 void update_passes_path()
1884 {
1885 for (Configuration& config : m_project.configurations())
1886 {
1887 Dictionary& root = config.get_parameters();
1888
1889 if (root.dictionaries().exist("generic_frame_renderer"))
1890 {
1891 Dictionary& gfr = root.dictionary("generic_frame_renderer");
1892
1893 move_if_exist(root, "passes", gfr, "passes");
1894
1895 // Remove the dictionnary from the root if it's empty.
1896 if (gfr.empty())
1897 root.dictionaries().remove("generic_frame_renderer");
1898 }
1899 }
1900 }
1901 };
1902
1903
1904 //
1905 // Update from revision 27 to revision 28.
1906 //
1907
1908 class UpdateFromRevision_27
1909 : public Updater
1910 {
1911 public:
UpdateFromRevision_27(Project & project)1912 explicit UpdateFromRevision_27(Project& project)
1913 : Updater(project, 27)
1914 {
1915 }
1916
update()1917 void update() override
1918 {
1919 if (Scene* scene = m_project.get_scene())
1920 update_assembly_inputs(scene->assemblies());
1921 }
1922
1923 private:
update_assembly_inputs(AssemblyContainer & assemblies)1924 static void update_assembly_inputs(AssemblyContainer& assemblies)
1925 {
1926 for (each<AssemblyContainer> i = assemblies; i; ++i)
1927 {
1928 update_assembly_inputs(*i);
1929 update_assembly_inputs(i->assemblies());
1930 }
1931 }
1932
update_assembly_inputs(Assembly & assembly)1933 static void update_assembly_inputs(Assembly& assembly)
1934 {
1935 assembly.get_parameters().remove_path("flushable");
1936 }
1937 };
1938
1939
1940 //
1941 // Update from revision 28 to revision 29.
1942 //
1943
1944 class UpdateFromRevision_28
1945 : public Updater
1946 {
1947 public:
UpdateFromRevision_28(Project & project)1948 explicit UpdateFromRevision_28(Project& project)
1949 : Updater(project, 28)
1950 {
1951 }
1952
update()1953 void update() override
1954 {
1955 if (m_project.get_frame())
1956 update_frame(*m_project.get_frame());
1957 }
1958
1959 private:
update_frame(Frame & frame)1960 static void update_frame(Frame& frame)
1961 {
1962 for (PostProcessingStage& stage : frame.post_processing_stages())
1963 {
1964 if (strcmp(stage.get_model(), RenderStampPostProcessingStageFactory().get_model()) == 0)
1965 {
1966 ParamArray& params = stage.get_parameters();
1967 if (params.strings().exist("format_string"))
1968 {
1969 string format_string = params.get<string>("format_string");
1970 format_string = replace(format_string, "{lib-variant}", "{lib-cpu-features}");
1971 params.set("format_string", format_string);
1972 }
1973 }
1974 }
1975 }
1976 };
1977
1978
1979 //
1980 // Update from revision 29 to revision 30.
1981 //
1982
1983 class UpdateFromRevision_29
1984 : public Updater
1985 {
1986 public:
UpdateFromRevision_29(Project & project)1987 explicit UpdateFromRevision_29(Project& project)
1988 : Updater(project, 29)
1989 {
1990 }
1991
update()1992 void update() override
1993 {
1994 remove_adaptive_pixel_renderer_settings();
1995 remove_decorrelate_pixels_setting();
1996
1997 if (m_project.get_frame())
1998 update_frame_filter(*m_project.get_frame());
1999 }
2000
2001 private:
update_frame_filter(Frame & frame)2002 static void update_frame_filter(Frame& frame)
2003 {
2004 const char* DefaultFilterName = "blackman-harris";
2005
2006 ParamArray& params = frame.get_parameters();
2007 const string filter_name = params.get_optional<string>("filter", DefaultFilterName);
2008
2009 const bool update_filter =
2010 filter_name == "mitchell" ||
2011 filter_name == "bspline" ||
2012 filter_name == "catmull" ||
2013 filter_name == "lanczos";
2014
2015 if (update_filter)
2016 {
2017 RENDERER_LOG_WARNING(
2018 "with the introduction of filter importance sampling, some reconstruction filters were removed; "
2019 "migrating this project to use the default reconstruction filter instead (%s).",
2020 DefaultFilterName);
2021
2022 params.insert_path("filter", DefaultFilterName);
2023 }
2024 }
2025
remove_decorrelate_pixels_setting()2026 void remove_decorrelate_pixels_setting()
2027 {
2028 for (Configuration& config : m_project.configurations())
2029 {
2030 Dictionary& root = config.get_parameters();
2031
2032 if (root.dictionaries().exist("uniform_pixel_renderer"))
2033 {
2034 Dictionary& d = root.dictionary("uniform_pixel_renderer");
2035
2036 if (d.strings().exist("decorrelate_pixels"))
2037 {
2038 if (d.strings().get<bool>("decorrelate_pixels") == false)
2039 {
2040 RENDERER_LOG_WARNING(
2041 "with the introduction of filter importance sampling, the option to disable pixel decorrelation was removed; "
2042 "migrating this project to use pixel decorrelation instead.");
2043 }
2044
2045 d.strings().remove("decorrelate_pixels");
2046 }
2047 }
2048 }
2049 }
2050
remove_adaptive_pixel_renderer_settings()2051 void remove_adaptive_pixel_renderer_settings()
2052 {
2053 for (Configuration& config : m_project.configurations())
2054 {
2055 Dictionary& root = config.get_parameters();
2056
2057 if (root.dictionaries().exist("adaptive_pixel_renderer"))
2058 root.dictionaries().remove("adaptive_pixel_renderer");
2059
2060 if (root.strings().exist("pixel_renderer"))
2061 {
2062 const char* pixel_renderer = root.strings().get("pixel_renderer");
2063 if (strcmp(pixel_renderer, "adaptive") == 0)
2064 {
2065 RENDERER_LOG_WARNING(
2066 "with the introduction of a new adaptive tile renderer, the adaptive pixel renderer was removed; "
2067 "migrating this project to use the uniform pixel renderer instead.");
2068
2069 root.strings().set("pixel_renderer", "uniform");
2070 }
2071 }
2072 }
2073 }
2074 };
2075
2076
2077 //
2078 // Update from revision 30 to revision 31.
2079 //
2080
2081 class UpdateFromRevision_30
2082 : public Updater
2083 {
2084 public:
UpdateFromRevision_30(Project & project)2085 explicit UpdateFromRevision_30(Project& project)
2086 : Updater(project, 30)
2087 {
2088 }
2089
update()2090 void update() override
2091 {
2092 replace_max_samples_interactive_renderer_setting();
2093
2094 if (Scene* scene = m_project.get_scene())
2095 update_assemblies(scene->assemblies());
2096 }
2097
2098 private:
replace_max_samples_interactive_renderer_setting()2099 void replace_max_samples_interactive_renderer_setting()
2100 {
2101 for (Configuration& config : m_project.configurations())
2102 {
2103 Dictionary& root = config.get_parameters();
2104
2105 if (root.dictionaries().exist("progressive_frame_renderer"))
2106 {
2107 Dictionary& pfr = root.dictionaries().get("progressive_frame_renderer");
2108
2109 if (pfr.strings().exist("max_samples"))
2110 {
2111 const uint64 max_samples = pfr.strings().get<uint64>("max_samples");
2112 pfr.strings().remove("max_samples");
2113
2114 if (max_samples < numeric_limits<uint64>::max())
2115 {
2116 Frame* frame = m_project.get_frame();
2117 if (frame)
2118 {
2119 // If max samples was previously set then preserve the nearest max average spp count.
2120 const uint64 pixel_count = frame->get_crop_window().volume();
2121 const uint64 max_average_spp =
2122 static_cast<uint64>(
2123 ceil(
2124 static_cast<double>(max_samples) / pixel_count));
2125 pfr.strings().insert("max_average_spp", max_average_spp);
2126 }
2127 }
2128 }
2129 }
2130 }
2131 }
2132
update_assemblies(const AssemblyContainer & assemblies)2133 static void update_assemblies(const AssemblyContainer& assemblies)
2134 {
2135 for (const auto& assembly : assemblies)
2136 {
2137 update_bsdfs(assembly.bsdfs());
2138 update_assemblies(assembly.assemblies());
2139 }
2140 }
2141
update_bsdfs(BSDFContainer & bsdfs)2142 static void update_bsdfs(BSDFContainer& bsdfs)
2143 {
2144 for (auto& bsdf : bsdfs)
2145 {
2146 if (strcmp(bsdf.get_model(), "glass_bsdf") == 0)
2147 update_microfacet_params(bsdf);
2148 else if (strcmp(bsdf.get_model(), "metal_brdf") == 0)
2149 update_microfacet_params(bsdf);
2150 else if (strcmp(bsdf.get_model(), "glossy_brdf") == 0)
2151 update_microfacet_params(bsdf);
2152 else if (strcmp(bsdf.get_model(), "plastic_brdf") == 0)
2153 update_microfacet_params(bsdf);
2154 }
2155 }
2156
update_microfacet_params(BSDF & bsdf)2157 static void update_microfacet_params(BSDF& bsdf)
2158 {
2159 ParamArray& params = bsdf.get_parameters();
2160
2161 if (params.strings().exist("mdf"))
2162 {
2163 const string mdf = params.strings().get<string>("mdf");
2164 params.strings().remove("mdf");
2165 if (mdf != "ggx")
2166 {
2167 RENDERER_LOG_WARNING(
2168 "the %s microfacet distribution used by BSDF \"%s\" was removed; "
2169 "the GGX distribution will be used instead.",
2170 mdf.c_str(),
2171 bsdf.get_name());
2172 }
2173 }
2174
2175 params.strings().remove("highlight_falloff");
2176 }
2177 };
2178 }
2179
update(Project & project,const size_t to_revision)2180 bool ProjectFileUpdater::update(
2181 Project& project,
2182 const size_t to_revision)
2183 {
2184 EventCounters event_counters;
2185 update(project, event_counters, to_revision);
2186 return event_counters.get_error_count() == 0;
2187 }
2188
update(Project & project,EventCounters & event_counters,const size_t to_revision)2189 void ProjectFileUpdater::update(
2190 Project& project,
2191 EventCounters& event_counters,
2192 const size_t to_revision)
2193 {
2194 size_t format_revision = project.get_format_revision();
2195
2196 #define CASE_UPDATE_FROM_REVISION(from) \
2197 case from: \
2198 { \
2199 if (format_revision >= to_revision) \
2200 break; \
2201 \
2202 UpdateFromRevision_##from updater(project); \
2203 updater.update(); \
2204 \
2205 format_revision = from + 1; \
2206 }
2207
2208 switch (format_revision)
2209 {
2210 CASE_UPDATE_FROM_REVISION(0);
2211 CASE_UPDATE_FROM_REVISION(1);
2212 CASE_UPDATE_FROM_REVISION(2);
2213 CASE_UPDATE_FROM_REVISION(3);
2214 CASE_UPDATE_FROM_REVISION(4);
2215 CASE_UPDATE_FROM_REVISION(5);
2216 CASE_UPDATE_FROM_REVISION(6);
2217 CASE_UPDATE_FROM_REVISION(7);
2218 CASE_UPDATE_FROM_REVISION(8);
2219 CASE_UPDATE_FROM_REVISION(9);
2220 CASE_UPDATE_FROM_REVISION(10);
2221 CASE_UPDATE_FROM_REVISION(11);
2222 CASE_UPDATE_FROM_REVISION(12);
2223 CASE_UPDATE_FROM_REVISION(13);
2224 CASE_UPDATE_FROM_REVISION(14);
2225 CASE_UPDATE_FROM_REVISION(15);
2226 CASE_UPDATE_FROM_REVISION(16);
2227 CASE_UPDATE_FROM_REVISION(17);
2228 CASE_UPDATE_FROM_REVISION(18);
2229 CASE_UPDATE_FROM_REVISION(19);
2230 CASE_UPDATE_FROM_REVISION(20);
2231 CASE_UPDATE_FROM_REVISION(21);
2232 CASE_UPDATE_FROM_REVISION(22);
2233 CASE_UPDATE_FROM_REVISION(23);
2234 CASE_UPDATE_FROM_REVISION(24);
2235 CASE_UPDATE_FROM_REVISION(25);
2236 CASE_UPDATE_FROM_REVISION(26);
2237 CASE_UPDATE_FROM_REVISION(27);
2238 CASE_UPDATE_FROM_REVISION(28);
2239 CASE_UPDATE_FROM_REVISION(29);
2240 CASE_UPDATE_FROM_REVISION(30);
2241
2242 case ProjectFormatRevision:
2243 // Project is up-to-date.
2244 break;
2245
2246 default:
2247 if (format_revision > ProjectFormatRevision)
2248 {
2249 RENDERER_LOG_ERROR(
2250 "cannot update project in format revision " FMT_SIZE_T ", latest supported revision is " FMT_SIZE_T ".",
2251 format_revision,
2252 ProjectFormatRevision);
2253 event_counters.signal_error();
2254 }
2255 else
2256 {
2257 RENDERER_LOG_ERROR(
2258 "cannot update project format from revision " FMT_SIZE_T " to revision " FMT_SIZE_T ", one or more update steps are missing.",
2259 format_revision,
2260 ProjectFormatRevision);
2261 event_counters.signal_error();
2262 }
2263 break;
2264 }
2265
2266 #undef CASE_UPDATE_FROM_REVISION
2267 }
2268
2269 } // namespace renderer
2270