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