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 #pragma once
31
32 // appleseed.renderer headers.
33 #include "renderer/utility/paramarray.h"
34
35 // appleseed.foundation headers.
36 #include "foundation/core/concepts/iunknown.h"
37 #include "foundation/platform/types.h"
38 #include "foundation/utility/job/iabortswitch.h"
39 #include "foundation/utility/siphash.h"
40 #include "foundation/utility/uid.h"
41 #include "foundation/utility/version.h"
42
43 // appleseed.main headers.
44 #include "main/dllsymbol.h"
45
46 // Standard headers.
47 #include <cstddef>
48 #include <string>
49
50 // Forward declarations.
51 namespace foundation { class APIString; }
52 namespace foundation { class IAbortSwitch; }
53 namespace foundation { class StringArray; }
54 namespace foundation { class StringDictionary; }
55 namespace renderer { class BaseGroup; }
56 namespace renderer { class OnFrameBeginRecorder; }
57 namespace renderer { class OnRenderBeginRecorder; }
58 namespace renderer { class Project; }
59
60 namespace renderer
61 {
62
63 //
64 // Base class for all entities in the scene.
65 //
66
67 class APPLESEED_DLLSYMBOL Entity
68 : public foundation::Identifiable
69 , public foundation::Versionable
70 , public foundation::IUnknown
71 {
72 public:
73 // Constructors.
74 explicit Entity(
75 const foundation::UniqueID class_uid);
76 Entity(
77 const foundation::UniqueID class_uid,
78 Entity* parent);
79 Entity(
80 const foundation::UniqueID class_uid,
81 const ParamArray& params);
82 Entity(
83 const foundation::UniqueID class_uid,
84 Entity* parent,
85 const ParamArray& params);
86
87 // Return the unique ID of this class of entities.
88 foundation::UniqueID get_class_uid() const;
89
90 // Compute and return the unique signature of this entity instance.
91 virtual foundation::uint64 compute_signature() const;
92
93 // Combine two entity signatures.
94 static foundation::uint64 combine_signatures(
95 const foundation::uint64 s1,
96 const foundation::uint64 s2);
97
98 // Set/get the parent of this entity.
99 void set_parent(Entity* parent);
100 Entity* get_parent() const;
101
102 // Set/get the name of this entity.
103 void set_name(const char* name);
104 const char* get_name() const;
105
106 // Return the name of the entity as a pointer to a OIIO::ustring for OSL.
107 const void* get_name_as_ustring() const;
108
109 // Get the full path from the scene entity to this entity in a human-readable format.
110 foundation::APIString get_path() const;
111
112 // Return the parameters of this entity.
113 ParamArray& get_parameters();
114 const ParamArray& get_parameters() const;
115
116 // Expose asset file paths referenced by this entity to the outside.
117 virtual void collect_asset_paths(foundation::StringArray& paths) const;
118 virtual void update_asset_paths(const foundation::StringDictionary& mappings);
119
120 //
121 // Rendering proceeds roughly as follow, both in final and interactive modes:
122 //
123 // Loop:
124 // [Bind scene entities inputs]
125 // on_render_begin()
126 //
127 // Loop:
128 // [Retrieve camera position]
129 // on_frame_begin()
130 // [Render frame]
131 // on_frame_end()
132 // Until an entity is edited
133 //
134 // on_render_end()
135 // Until rendering ends naturally or is aborted
136 //
137 // See the `MasterRenderer` class in masterrenderer.cpp for details.
138 //
139
140 // This method is called before rendering begins, and whenever rendering is reinitialized
141 // (i.e. because an entity has been edited). At this point, all entities inputs are bound.
142 // Returns true on success, or false if an error occurred or if the abort switch was triggered.
143 virtual bool on_render_begin(
144 const Project& project,
145 const BaseGroup* parent,
146 OnRenderBeginRecorder& recorder,
147 foundation::IAbortSwitch* abort_switch = nullptr);
148
149 // This method is called after rendering has ended. It is guaranteed to be called if
150 // `on_render_begin()` was called and was successful (i.e. returned true).
151 virtual void on_render_end(
152 const Project& project,
153 const BaseGroup* parent);
154
155 // This method is called before rendering a frame begins, and whenever rendering is restarted
156 // (i.e. because the camera has been moved). At this point, all entities inputs are bound.
157 // Returns true on success, or false if an error occurred or if the abort switch was triggered.
158 virtual bool on_frame_begin(
159 const Project& project,
160 const BaseGroup* parent,
161 OnFrameBeginRecorder& recorder,
162 foundation::IAbortSwitch* abort_switch = nullptr);
163
164 // This method is called after rendering a frame has ended. It is guaranteed to be called if
165 // `on_frame_begin()` was called and was successful (i.e. returned true).
166 virtual void on_frame_end(
167 const Project& project,
168 const BaseGroup* parent);
169
170 protected:
171 struct Impl;
172 Impl* impl;
173
174 const foundation::UniqueID m_class_uid;
175 Entity* m_parent;
176 ParamArray m_params;
177
178 // Destructor.
179 ~Entity() override;
180 };
181
182 // Utility function to invoke collect_asset_paths() on a collection of entities.
183 template <typename EntityCollection>
184 void invoke_collect_asset_paths(
185 const EntityCollection& entities,
186 foundation::StringArray& paths);
187
188 // Utility function to invoke update_asset_paths() on a collection of entities.
189 template <typename EntityCollection>
190 void invoke_update_asset_paths(
191 EntityCollection& entities,
192 const foundation::StringDictionary& mappings);
193
194 // Utility function to invoke on_render_begin() on a collection of entities.
195 // Returns true on success, or false if an error occurred or if the abort switch was triggered.
196 template <typename EntityCollection>
197 bool invoke_on_render_begin(
198 EntityCollection& entities,
199 const Project& project,
200 const BaseGroup* parent,
201 OnRenderBeginRecorder& recorder,
202 foundation::IAbortSwitch* abort_switch);
203
204 // Utility function to invoke on_frame_begin() on a collection of entities.
205 // Returns true on success, or false if an error occurred or if the abort switch was triggered.
206 template <typename EntityCollection>
207 bool invoke_on_frame_begin(
208 EntityCollection& entities,
209 const Project& project,
210 const BaseGroup* parent,
211 OnFrameBeginRecorder& recorder,
212 foundation::IAbortSwitch* abort_switch);
213
214
215 //
216 // Entity class implementation.
217 //
218
get_class_uid()219 inline foundation::UniqueID Entity::get_class_uid() const
220 {
221 return m_class_uid;
222 }
223
compute_signature()224 inline foundation::uint64 Entity::compute_signature() const
225 {
226 return foundation::siphash24(get_uid(), get_version_id());
227 }
228
combine_signatures(const foundation::uint64 s1,const foundation::uint64 s2)229 inline foundation::uint64 Entity::combine_signatures(
230 const foundation::uint64 s1,
231 const foundation::uint64 s2)
232 {
233 return foundation::siphash24(s1, s2);
234 }
235
set_parent(Entity * parent)236 inline void Entity::set_parent(Entity* parent)
237 {
238 m_parent = parent;
239 }
240
get_parent()241 inline Entity* Entity::get_parent() const
242 {
243 return m_parent;
244 }
245
get_parameters()246 inline ParamArray& Entity::get_parameters()
247 {
248 return m_params;
249 }
250
get_parameters()251 inline const ParamArray& Entity::get_parameters() const
252 {
253 return m_params;
254 }
255
256 template <typename EntityCollection>
invoke_collect_asset_paths(const EntityCollection & entities,foundation::StringArray & paths)257 void invoke_collect_asset_paths(
258 const EntityCollection& entities,
259 foundation::StringArray& paths)
260 {
261 for (const auto& entity : entities)
262 entity.collect_asset_paths(paths);
263 }
264
265 template <typename EntityCollection>
invoke_update_asset_paths(EntityCollection & entities,const foundation::StringDictionary & mappings)266 void invoke_update_asset_paths(
267 EntityCollection& entities,
268 const foundation::StringDictionary& mappings)
269 {
270 for (auto& entity : entities)
271 entity.update_asset_paths(mappings);
272 }
273
274 template <typename EntityCollection>
invoke_on_render_begin(EntityCollection & entities,const Project & project,const BaseGroup * parent,OnRenderBeginRecorder & recorder,foundation::IAbortSwitch * abort_switch)275 bool invoke_on_render_begin(
276 EntityCollection& entities,
277 const Project& project,
278 const BaseGroup* parent,
279 OnRenderBeginRecorder& recorder,
280 foundation::IAbortSwitch* abort_switch)
281 {
282 for (auto& entity : entities)
283 {
284 if (foundation::is_aborted(abort_switch))
285 return false;
286
287 if (!entity.on_render_begin(project, parent, recorder, abort_switch))
288 return false;
289 }
290
291 return true;
292 }
293
294 template <typename EntityCollection>
invoke_on_frame_begin(EntityCollection & entities,const Project & project,const BaseGroup * parent,OnFrameBeginRecorder & recorder,foundation::IAbortSwitch * abort_switch)295 bool invoke_on_frame_begin(
296 EntityCollection& entities,
297 const Project& project,
298 const BaseGroup* parent,
299 OnFrameBeginRecorder& recorder,
300 foundation::IAbortSwitch* abort_switch)
301 {
302 for (auto& entity : entities)
303 {
304 if (foundation::is_aborted(abort_switch))
305 return false;
306
307 if (!entity.on_frame_begin(project, parent, recorder, abort_switch))
308 return false;
309 }
310
311 return true;
312 }
313
314 } // namespace renderer
315