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