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/modeling/entity/entity.h"
34 #include "renderer/modeling/entity/entitymap.h"
35 #include "renderer/modeling/entity/entityvector.h"
36 #include "renderer/utility/paramarray.h"
37 
38 // appleseed.foundation headers.
39 #include "foundation/core/exceptions/stringexception.h"
40 #include "foundation/utility/foreach.h"
41 #include "foundation/utility/string.h"
42 
43 // Standard headers.
44 #include <string>
45 #include <vector>
46 
47 // Forward declarations.
48 namespace renderer  { class Assembly; }
49 namespace renderer  { class AssemblyInstance; }
50 namespace renderer  { class BSDF; }
51 namespace renderer  { class BSSRDF; }
52 namespace renderer  { class Camera; }
53 namespace renderer  { class ColorEntity; }
54 namespace renderer  { class EDF; }
55 namespace renderer  { class EnvironmentEDF; }
56 namespace renderer  { class EnvironmentShader; }
57 namespace renderer  { class Light; }
58 namespace renderer  { class Material; }
59 namespace renderer  { class Object; }
60 namespace renderer  { class ObjectInstance; }
61 namespace renderer  { class Shader; }
62 namespace renderer  { class ShaderConnection; }
63 namespace renderer  { class ShaderGroup; }
64 namespace renderer  { class ShaderParam; }
65 namespace renderer  { class SurfaceShader; }
66 namespace renderer  { class Texture; }
67 namespace renderer  { class TextureInstance; }
68 namespace renderer  { class Volume; }
69 
70 namespace renderer
71 {
72 
73 //
74 // Entity containers.
75 //
76 
77 typedef TypedEntityMap<Assembly>                AssemblyContainer;
78 typedef TypedEntityMap<AssemblyInstance>        AssemblyInstanceContainer;
79 typedef TypedEntityVector<BSDF>                 BSDFContainer;
80 typedef TypedEntityVector<BSSRDF>               BSSRDFContainer;
81 typedef TypedEntityVector<Camera>               CameraContainer;
82 typedef TypedEntityVector<ColorEntity>          ColorContainer;
83 typedef TypedEntityVector<EDF>                  EDFContainer;
84 typedef TypedEntityVector<EnvironmentEDF>       EnvironmentEDFContainer;
85 typedef TypedEntityVector<EnvironmentShader>    EnvironmentShaderContainer;
86 typedef TypedEntityVector<Light>                LightContainer;
87 typedef TypedEntityVector<Material>             MaterialContainer;
88 typedef TypedEntityVector<Object>               ObjectContainer;
89 typedef TypedEntityVector<ObjectInstance>       ObjectInstanceContainer;
90 typedef TypedEntityVector<Shader>               ShaderContainer;
91 typedef TypedEntityVector<ShaderConnection>     ShaderConnectionContainer;
92 typedef TypedEntityVector<ShaderGroup>          ShaderGroupContainer;
93 typedef TypedEntityVector<ShaderParam>          ShaderParamContainer;
94 typedef TypedEntityVector<SurfaceShader>        SurfaceShaderContainer;
95 typedef TypedEntityVector<Texture>              TextureContainer;
96 typedef TypedEntityVector<TextureInstance>      TextureInstanceContainer;
97 typedef TypedEntityVector<Volume>               VolumeContainer;
98 
99 
100 //
101 // Exception thrown when an entity is not found.
102 //
103 
104 class ExceptionUnknownEntity
105   : public foundation::StringException
106 {
107   public:
108     explicit ExceptionUnknownEntity(
109         const char*                 entity_name,
110         const Entity*               context = nullptr);
111 
112     const std::string& get_context_path() const;
113 
114   private:
115     const std::string m_context_path;
116 };
117 
118 
119 //
120 // Retrieve a mandatory entity from a container.
121 // Returns nullptr if the parameter does not exist.
122 // Throws a renderer::ExceptionUnknownEntity exception if the requested entity does not exist.
123 //
124 
125 template <typename T, typename Container>
126 T* get_required_entity(
127     const Container&                container,
128     const ParamArray&               params,
129     const std::string&              param_name);
130 
131 
132 //
133 // Retrieve an optional entity from a container.
134 // Returns nullptr if the parameter does not exist.
135 // Throws a renderer::ExceptionUnknownEntity exception if the requested entity does not exist.
136 //
137 
138 template <typename T, typename Container>
139 T* get_optional_entity(
140     const Container&                container,
141     const ParamArray&               params,
142     const std::string&              param_name);
143 
144 
145 //
146 // Generate a new name for an entity in a collection.
147 //
148 
149 template <typename EntityContainer>
150 std::vector<std::string> collect_entity_names(
151     const EntityContainer&          entities);
152 
153 template <typename EntityContainer>
154 std::string make_unique_name(
155     const std::string&              prefix,
156     const EntityContainer&          entities);
157 
158 std::string make_unique_name(
159     const std::string&              prefix,
160     const std::vector<std::string>& entity_names);
161 
162 
163 //
164 // Implementation.
165 //
166 
167 template <typename T, typename Container>
get_required_entity(const Container & container,const ParamArray & params,const std::string & param_name)168 T* get_required_entity(
169     const Container&                container,
170     const ParamArray&               params,
171     const std::string&              param_name)
172 {
173     const std::string entity_name =
174         params.get_required<std::string>(param_name.c_str(), std::string());
175 
176     if (entity_name.empty())
177         return 0;
178 
179     T* entity = container.get_by_name(entity_name.c_str());
180 
181     if (entity == 0)
182         throw ExceptionUnknownEntity(entity_name.c_str());
183 
184     return entity;
185 }
186 
187 template <typename T, typename Container>
get_optional_entity(const Container & container,const ParamArray & params,const std::string & param_name)188 T* get_optional_entity(
189     const Container&                container,
190     const ParamArray&               params,
191     const std::string&              param_name)
192 {
193     const std::string entity_name =
194         params.get_optional<std::string>(param_name.c_str(), std::string());
195 
196     if (entity_name.empty())
197         return 0;
198 
199     T* entity = container.get_by_name(entity_name.c_str());
200 
201     if (entity == 0)
202         throw ExceptionUnknownEntity(entity_name.c_str());
203 
204     return entity;
205 }
206 
207 template <typename EntityContainer>
collect_entity_names(const EntityContainer & entities)208 std::vector<std::string> collect_entity_names(
209     const EntityContainer&          entities)
210 {
211     std::vector<std::string> names;
212 
213     names.reserve(entities.size());
214 
215     for (foundation::const_each<EntityContainer> i = entities; i; ++i)
216         names.push_back(i->get_name());
217 
218     return names;
219 }
220 
221 template <typename EntityContainer>
make_unique_name(const std::string & prefix,const EntityContainer & entities)222 std::string make_unique_name(
223     const std::string&              prefix,
224     const EntityContainer&          entities)
225 {
226     return
227         make_unique_name(
228             prefix,
229             collect_entity_names(entities));
230 }
231 
make_unique_name(const std::string & prefix,const std::vector<std::string> & entity_names)232 inline std::string make_unique_name(
233     const std::string&              prefix,
234     const std::vector<std::string>& entity_names)
235 {
236     int max_number = 0;
237 
238     for (size_t i = 0, e = entity_names.size(); i < e; ++i)
239     {
240         const std::string& entity_name = entity_names[i];
241 
242         if (foundation::starts_with(entity_name, prefix))
243         {
244             try
245             {
246                 const std::string entity_name_suffix = entity_name.substr(prefix.size());
247                 const int number = foundation::from_string<int>(entity_name_suffix);
248 
249                 if (max_number < number)
250                     max_number = number;
251             }
252             catch (const foundation::ExceptionStringConversionError&)
253             {
254             }
255         }
256     }
257 
258     return prefix + foundation::to_string(max_number + 1);
259 }
260 
261 }   // namespace renderer
262