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 "assembly.h"
32 
33 // appleseed.renderer headers.
34 #include "renderer/modeling/bsdf/bsdf.h"
35 #include "renderer/modeling/bssrdf/bssrdf.h"
36 #include "renderer/modeling/color/colorentity.h"
37 #include "renderer/modeling/edf/edf.h"
38 #include "renderer/modeling/light/light.h"
39 #include "renderer/modeling/material/material.h"
40 #include "renderer/modeling/object/object.h"
41 #include "renderer/modeling/object/proceduralobject.h"
42 #include "renderer/modeling/scene/assemblyinstance.h"
43 #include "renderer/modeling/scene/objectinstance.h"
44 #include "renderer/modeling/scene/textureinstance.h"
45 #include "renderer/modeling/shadergroup/shadergroup.h"
46 #include "renderer/modeling/surfaceshader/surfaceshader.h"
47 #include "renderer/modeling/texture/texture.h"
48 #include "renderer/modeling/volume/volume.h"
49 #include "renderer/utility/bbox.h"
50 #include "renderer/utility/paramarray.h"
51 
52 // appleseed.foundation headers.
53 #include "foundation/utility/api/specializedapiarrays.h"
54 #include "foundation/utility/containers/dictionary.h"
55 #include "foundation/utility/job/abortswitch.h"
56 
57 using namespace foundation;
58 using namespace std;
59 
60 namespace renderer
61 {
62 
63 APPLESEED_DEFINE_APIARRAY(IndexedObjectInstanceArray);
64 
65 
66 //
67 // Assembly class implementation.
68 //
69 
70 const char* Model = "generic_assembly";
71 
72 namespace
73 {
74     const UniqueID g_class_uid = new_guid();
75 }
76 
get_class_uid()77 UniqueID Assembly::get_class_uid()
78 {
79     return g_class_uid;
80 }
81 
82 struct Assembly::Impl
83 {
84     BSDFContainer               m_bsdfs;
85     BSSRDFContainer             m_bssrdfs;
86     EDFContainer                m_edfs;
87     SurfaceShaderContainer      m_surface_shaders;
88     MaterialContainer           m_materials;
89     LightContainer              m_lights;
90     ObjectContainer             m_objects;
91     ObjectInstanceContainer     m_object_instances;
92     VolumeContainer             m_volumes;
93 
Implrenderer::Assembly::Impl94     explicit Impl(Entity* parent)
95       : m_bsdfs(parent)
96       , m_bssrdfs(parent)
97       , m_edfs(parent)
98       , m_surface_shaders(parent)
99       , m_materials(parent)
100       , m_lights(parent)
101       , m_objects(parent)
102       , m_object_instances(parent)
103       , m_volumes(parent)
104     {
105     }
106 };
107 
Assembly(const char * name,const ParamArray & params)108 Assembly::Assembly(
109     const char*         name,
110     const ParamArray&   params)
111   : Entity(g_class_uid, params)
112   , BaseGroup(this)
113   , impl(new Impl(this))
114   , m_has_render_data(false)
115 {
116     set_name(name);
117 }
118 
~Assembly()119 Assembly::~Assembly()
120 {
121     delete impl;
122 }
123 
release()124 void Assembly::release()
125 {
126     delete this;
127 }
128 
get_model() const129 const char* Assembly::get_model() const
130 {
131     return Model;
132 }
133 
bsdfs() const134 BSDFContainer& Assembly::bsdfs() const
135 {
136     return impl->m_bsdfs;
137 }
138 
bssrdfs() const139 BSSRDFContainer& Assembly::bssrdfs() const
140 {
141     return impl->m_bssrdfs;
142 }
143 
edfs() const144 EDFContainer& Assembly::edfs() const
145 {
146     return impl->m_edfs;
147 }
148 
surface_shaders() const149 SurfaceShaderContainer& Assembly::surface_shaders() const
150 {
151     return impl->m_surface_shaders;
152 }
153 
materials() const154 MaterialContainer& Assembly::materials() const
155 {
156     return impl->m_materials;
157 }
158 
lights() const159 LightContainer& Assembly::lights() const
160 {
161     return impl->m_lights;
162 }
163 
objects() const164 ObjectContainer& Assembly::objects() const
165 {
166     return impl->m_objects;
167 }
168 
object_instances() const169 ObjectInstanceContainer& Assembly::object_instances() const
170 {
171     return impl->m_object_instances;
172 }
173 
volumes() const174 VolumeContainer& Assembly::volumes() const
175 {
176     return impl->m_volumes;
177 }
178 
clear()179 void Assembly::clear()
180 {
181     BaseGroup::clear();
182 
183     impl->m_bsdfs.clear();
184     impl->m_bssrdfs.clear();
185     impl->m_edfs.clear();
186     impl->m_surface_shaders.clear();
187     impl->m_materials.clear();
188     impl->m_lights.clear();
189     impl->m_objects.clear();
190     impl->m_object_instances.clear();
191     impl->m_volumes.clear();
192 }
193 
compute_local_bbox() const194 GAABB3 Assembly::compute_local_bbox() const
195 {
196     GAABB3 bbox = compute_non_hierarchical_local_bbox();
197 
198     bbox.insert(
199         compute_parent_bbox<GAABB3>(
200             assembly_instances().begin(),
201             assembly_instances().end()));
202 
203     return bbox;
204 }
205 
compute_non_hierarchical_local_bbox() const206 GAABB3 Assembly::compute_non_hierarchical_local_bbox() const
207 {
208     return
209         compute_parent_bbox<GAABB3>(
210             impl->m_object_instances.begin(),
211             impl->m_object_instances.end());
212 }
213 
collect_asset_paths(StringArray & paths) const214 void Assembly::collect_asset_paths(StringArray& paths) const
215 {
216     BaseGroup::collect_asset_paths(paths);
217 
218     invoke_collect_asset_paths(bsdfs(), paths);
219     invoke_collect_asset_paths(bssrdfs(), paths);
220     invoke_collect_asset_paths(edfs(), paths);
221     invoke_collect_asset_paths(surface_shaders(), paths);
222     invoke_collect_asset_paths(materials(), paths);
223     invoke_collect_asset_paths(lights(), paths);
224     invoke_collect_asset_paths(objects(), paths);
225     invoke_collect_asset_paths(object_instances(), paths);
226     invoke_collect_asset_paths(volumes(), paths);
227 }
228 
update_asset_paths(const StringDictionary & mappings)229 void Assembly::update_asset_paths(const StringDictionary& mappings)
230 {
231     BaseGroup::update_asset_paths(mappings);
232 
233     invoke_update_asset_paths(bsdfs(), mappings);
234     invoke_update_asset_paths(bssrdfs(), mappings);
235     invoke_update_asset_paths(edfs(), mappings);
236     invoke_update_asset_paths(surface_shaders(), mappings);
237     invoke_update_asset_paths(materials(), mappings);
238     invoke_update_asset_paths(lights(), mappings);
239     invoke_update_asset_paths(objects(), mappings);
240     invoke_update_asset_paths(object_instances(), mappings);
241     invoke_update_asset_paths(volumes(), mappings);
242 }
243 
on_render_begin(const Project & project,const BaseGroup * parent,OnRenderBeginRecorder & recorder,IAbortSwitch * abort_switch)244 bool Assembly::on_render_begin(
245     const Project&          project,
246     const BaseGroup*        parent,
247     OnRenderBeginRecorder&  recorder,
248     IAbortSwitch*           abort_switch)
249 {
250     if (!Entity::on_render_begin(project, parent, recorder, abort_switch))
251         return false;
252 
253     if (!BaseGroup::on_render_begin(project, parent, recorder, abort_switch))
254         return false;
255 
256     bool success = true;
257     success = success && invoke_on_render_begin(bsdfs(), project, this, recorder, abort_switch);
258     success = success && invoke_on_render_begin(bssrdfs(), project, this, recorder, abort_switch);
259     success = success && invoke_on_render_begin(edfs(), project, this, recorder, abort_switch);
260     success = success && invoke_on_render_begin(surface_shaders(), project, this, recorder, abort_switch);
261     success = success && invoke_on_render_begin(materials(), project, this, recorder, abort_switch);
262     success = success && invoke_on_render_begin(lights(), project, this, recorder, abort_switch);
263     success = success && invoke_on_render_begin(objects(), project, this, recorder, abort_switch);
264     success = success && invoke_on_render_begin(object_instances(), project, this, recorder, abort_switch);
265     success = success && invoke_on_render_begin(volumes(), project, this, recorder, abort_switch);
266 
267     return success;
268 }
269 
on_frame_begin(const Project & project,const BaseGroup * parent,OnFrameBeginRecorder & recorder,IAbortSwitch * abort_switch)270 bool Assembly::on_frame_begin(
271     const Project&          project,
272     const BaseGroup*        parent,
273     OnFrameBeginRecorder&   recorder,
274     IAbortSwitch*           abort_switch)
275 {
276     if (!Entity::on_frame_begin(project, parent, recorder, abort_switch))
277         return false;
278 
279     if (!BaseGroup::on_frame_begin(project, parent, recorder, abort_switch))
280         return false;
281 
282     bool success = true;
283     success = success && invoke_on_frame_begin(bsdfs(), project, this, recorder, abort_switch);
284     success = success && invoke_on_frame_begin(bssrdfs(), project, this, recorder, abort_switch);
285     success = success && invoke_on_frame_begin(edfs(), project, this, recorder, abort_switch);
286     success = success && invoke_on_frame_begin(surface_shaders(), project, this, recorder, abort_switch);
287     success = success && invoke_on_frame_begin(materials(), project, this, recorder, abort_switch);
288     success = success && invoke_on_frame_begin(lights(), project, this, recorder, abort_switch);
289     success = success && invoke_on_frame_begin(objects(), project, this, recorder, abort_switch);
290     success = success && invoke_on_frame_begin(object_instances(), project, this, recorder, abort_switch);
291     success = success && invoke_on_frame_begin(volumes(), project, this, recorder, abort_switch);
292     if (!success)
293         return false;
294 
295     // Collect procedural object instances.
296     assert(!m_has_render_data);
297     for (size_t i = 0, e = object_instances().size(); i < e; ++i)
298     {
299         const ObjectInstance* object_instance = object_instances().get_by_index(i);
300         const Object& object = object_instance->get_object();
301         if (dynamic_cast<const ProceduralObject*>(&object) != nullptr)
302             m_render_data.m_procedural_object_instances.push_back(make_pair(object_instance, i));
303     }
304     m_has_render_data = true;
305 
306     return true;
307 }
308 
on_frame_end(const Project & project,const BaseGroup * parent)309 void Assembly::on_frame_end(
310     const Project&          project,
311     const BaseGroup*        parent)
312 {
313     // `m_has_render_data` may be false if `on_frame_begin()` failed.
314     if (m_has_render_data)
315     {
316         m_render_data.m_procedural_object_instances.clear();
317         m_has_render_data = false;
318     }
319 
320     Entity::on_frame_end(project, parent);
321 }
322 
323 
324 //
325 // AssemblyFactory class implementation.
326 //
327 
release()328 void AssemblyFactory::release()
329 {
330     delete this;
331 }
332 
get_model() const333 const char* AssemblyFactory::get_model() const
334 {
335     return Model;
336 }
337 
get_model_metadata() const338 Dictionary AssemblyFactory::get_model_metadata() const
339 {
340     return
341         Dictionary()
342             .insert("name", Model)
343             .insert("label", "Generic Assembly");
344 }
345 
get_input_metadata() const346 DictionaryArray AssemblyFactory::get_input_metadata() const
347 {
348     DictionaryArray metadata;
349     return metadata;
350 }
351 
create(const char * name,const ParamArray & params) const352 auto_release_ptr<Assembly> AssemblyFactory::create(
353     const char*         name,
354     const ParamArray&   params) const
355 {
356     return auto_release_ptr<Assembly>(new Assembly(name, params));
357 }
358 
359 }   // namespace renderer
360