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