1 | |
2 | // |
3 | // This source file is part of appleseed. |
4 | // Visit http://appleseedhq.net/ for additional information and resources. |
5 | // |
6 | // This software is released under the MIT license. |
7 | // |
8 | // Copyright (c) 2012-2013 Esteban Tovagliari, Jupiter Jazz Limited |
9 | // Copyright (c) 2014-2017 Esteban Tovagliari, 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 | // appleseed.python headers. |
31 | #include "pyseed.h" // has to be first, to avoid redefinition warnings |
32 | #include "bindentitycontainers.h" |
33 | #include "dict2dict.h" |
34 | |
35 | // appleseed.renderer headers. |
36 | #include "renderer/api/display.h" |
37 | #include "renderer/api/frame.h" |
38 | #include "renderer/api/project.h" |
39 | #include "renderer/api/scene.h" |
40 | |
41 | // appleseed.foundation headers. |
42 | #include "foundation/utility/searchpaths.h" |
43 | |
44 | // Standard headers. |
45 | #include <cstddef> |
46 | #include <string> |
47 | |
48 | namespace bpy = boost::python; |
49 | using namespace foundation; |
50 | using namespace renderer; |
51 | using namespace std; |
52 | |
53 | // Work around a regression in Visual Studio 2015 Update 3. |
54 | #if defined(_MSC_VER) && _MSC_VER == 1900 |
55 | namespace boost |
56 | { |
57 | template <> Configuration const volatile* get_pointer<Configuration const volatile>(Configuration const volatile* p) { return p; } |
58 | template <> Project const volatile* get_pointer<Project const volatile>(Project const volatile* p) { return p; } |
59 | } |
60 | #endif |
61 | |
62 | namespace |
63 | { |
64 | auto_release_ptr<Project> create_project(const string& name) |
65 | { |
66 | return ProjectFactory::create(name.c_str()); |
67 | } |
68 | |
69 | bpy::object create_default_project() |
70 | { |
71 | auto_release_ptr<Project> project(DefaultProjectFactory::create()); |
72 | return bpy::object(project); |
73 | } |
74 | |
75 | bpy::object create_cornell_box_project() |
76 | { |
77 | auto_release_ptr<Project> project(CornellBoxProjectFactory::create()); |
78 | return bpy::object(project); |
79 | } |
80 | |
81 | bpy::list project_get_search_paths(const Project* project) |
82 | { |
83 | bpy::list paths; |
84 | |
85 | const SearchPaths& search_paths = project->search_paths(); |
86 | |
87 | for (size_t i = 0; i < search_paths.size(); ++i) |
88 | paths.append(search_paths[i]); |
89 | |
90 | return paths; |
91 | } |
92 | |
93 | void project_set_search_paths(Project* project, const bpy::list& paths) |
94 | { |
95 | project->search_paths().clear(); |
96 | |
97 | for (bpy::ssize_t i = 0, e = bpy::len(paths); i < e; ++i) |
98 | { |
99 | const bpy::extract<const char*> (paths[i]); |
100 | if (extractor.check()) |
101 | project->search_paths().push_back(extractor()); |
102 | else |
103 | { |
104 | PyErr_SetString(PyExc_TypeError, "Incompatible type. Only strings accepted." ); |
105 | bpy::throw_error_already_set(); |
106 | } |
107 | } |
108 | } |
109 | |
110 | ConfigurationContainer* project_get_configs(Project* project) |
111 | { |
112 | return &(project->configurations()); |
113 | } |
114 | |
115 | bool write_project_default_opts( |
116 | const ProjectFileWriter* writer, |
117 | const Project* project, |
118 | const char* filepath) |
119 | { |
120 | return ProjectFileWriter::write(*project, filepath); |
121 | } |
122 | |
123 | bool write_project_with_opts( |
124 | const ProjectFileWriter* writer, |
125 | const Project* project, |
126 | const char* filepath, |
127 | int opts) |
128 | { |
129 | return ProjectFileWriter::write(*project, filepath, opts); |
130 | } |
131 | |
132 | auto_release_ptr<Configuration> create_config(const string& name) |
133 | { |
134 | return ConfigurationFactory::create(name.c_str()); |
135 | } |
136 | |
137 | auto_release_ptr<Configuration> create_config_with_params( |
138 | const string& name, |
139 | const bpy::dict& params) |
140 | { |
141 | return ConfigurationFactory::create(name.c_str(), bpy_dict_to_param_array(params)); |
142 | } |
143 | |
144 | bpy::object create_base_final_config() |
145 | { |
146 | auto_release_ptr<Configuration> config(BaseConfigurationFactory::create_base_final()); |
147 | return bpy::object(config); |
148 | } |
149 | |
150 | bpy::object create_base_interactive_config() |
151 | { |
152 | auto_release_ptr<Configuration> config(BaseConfigurationFactory::create_base_interactive()); |
153 | return bpy::object(config); |
154 | } |
155 | |
156 | bpy::dict config_get_inherited_parameters(const Configuration* config) |
157 | { |
158 | ParamArray params(config->get_inherited_parameters()); |
159 | return param_array_to_bpy_dict(params); |
160 | } |
161 | |
162 | void config_insert_path(Configuration* config, const char* path, const bpy::object& value) |
163 | { |
164 | { |
165 | bpy::extract<const char*> (value); |
166 | if (extractor.check()) |
167 | { |
168 | config->get_parameters().insert_path(path, extractor()); |
169 | return; |
170 | } |
171 | } |
172 | |
173 | if (PyBool_Check(value.ptr())) |
174 | { |
175 | bpy::extract<bool> (value); |
176 | if (extractor.check()) |
177 | { |
178 | config->get_parameters().insert_path(path, extractor()); |
179 | return; |
180 | } |
181 | } |
182 | |
183 | #if PY_MAJOR_VERSION == 2 |
184 | if (PyInt_Check(value.ptr())) |
185 | { |
186 | bpy::extract<int> extractor(value); |
187 | if (extractor.check()) |
188 | { |
189 | config->get_parameters().insert_path(path, extractor()); |
190 | return; |
191 | } |
192 | } |
193 | #endif |
194 | |
195 | if (PyLong_Check(value.ptr())) |
196 | { |
197 | bpy::extract<int> (value); |
198 | if (extractor.check()) |
199 | { |
200 | config->get_parameters().insert_path(path, extractor()); |
201 | return; |
202 | } |
203 | } |
204 | |
205 | if (PyFloat_Check(value.ptr())) |
206 | { |
207 | bpy::extract<double> (value); |
208 | if (extractor.check()) |
209 | { |
210 | config->get_parameters().insert_path(path, extractor()); |
211 | return; |
212 | } |
213 | } |
214 | |
215 | PyErr_SetString(PyExc_TypeError, "Unsupported value type." ); |
216 | bpy::throw_error_already_set(); |
217 | } |
218 | |
219 | void config_remove_path(Configuration* config, const char* path) |
220 | { |
221 | config->get_parameters().remove_path(path); |
222 | } |
223 | |
224 | bpy::dict config_get_metadata() |
225 | { |
226 | return dictionary_to_bpy_dict(Configuration::get_metadata()); |
227 | } |
228 | |
229 | bpy::object project_file_reader_read_default_opts( |
230 | ProjectFileReader* reader, |
231 | const char* project_filename, |
232 | const char* schema_filename) |
233 | { |
234 | auto_release_ptr<Project> project(reader->read(project_filename, schema_filename)); |
235 | return bpy::object(project); |
236 | } |
237 | |
238 | bpy::object project_file_reader_read_with_opts( |
239 | ProjectFileReader* reader, |
240 | const char* project_filename, |
241 | const char* schema_filename, |
242 | const ProjectFileReader::Options opts) |
243 | { |
244 | auto_release_ptr<Project> project(reader->read(project_filename, schema_filename, opts)); |
245 | return bpy::object(project); |
246 | } |
247 | |
248 | bpy::object project_file_reader_load_builtin(ProjectFileReader* reader, const char* project_name) |
249 | { |
250 | auto_release_ptr<Project> project(reader->load_builtin(project_name)); |
251 | return bpy::object(project); |
252 | } |
253 | } |
254 | |
255 | void bind_project() |
256 | { |
257 | bpy::class_<Configuration, auto_release_ptr<Configuration>, bpy::bases<Entity>, boost::noncopyable>("Configuration" , bpy::no_init) |
258 | .def("create_base_final" , create_base_final_config).staticmethod("create_base_final" ) |
259 | .def("create_base_interactive" , create_base_interactive_config).staticmethod("create_base_interactive" ) |
260 | |
261 | .def("__init__" , bpy::make_constructor(create_config)) |
262 | .def("__init__" , bpy::make_constructor(create_config_with_params)) |
263 | |
264 | .def("set_base" , &Configuration::set_base) |
265 | .def("get_base" , &Configuration::get_base, bpy::return_value_policy<bpy::reference_existing_object>()) |
266 | .def("get_inherited_parameters" , config_get_inherited_parameters) |
267 | |
268 | .def("insert_path" , config_insert_path) |
269 | .def("remove_path" , config_remove_path) |
270 | |
271 | .def("get_metadata" , config_get_metadata).staticmethod("get_metadata" ); |
272 | |
273 | bind_typed_entity_map<Configuration>("ConfigurationContainer" ); |
274 | |
275 | bpy::class_<Project, auto_release_ptr<Project>, bpy::bases<Entity>, boost::noncopyable>("Project" , bpy::no_init) |
276 | .def("create_default" , create_default_project).staticmethod("create_default" ) |
277 | .def("create_cornell_box" , create_cornell_box_project).staticmethod("create_cornell_box" ) |
278 | |
279 | .def("__init__" , bpy::make_constructor(create_project)) |
280 | |
281 | .def("add_default_configurations" , &Project::add_default_configurations) |
282 | |
283 | .def("has_path" , &Project::has_path) |
284 | .def("set_path" , &Project::set_path) |
285 | .def("get_path" , &Project::get_path) |
286 | |
287 | .def("get_search_paths" , project_get_search_paths) |
288 | .def("set_search_paths" , project_set_search_paths) |
289 | |
290 | .def("set_scene" , &Project::set_scene) |
291 | .def("get_scene" , &Project::get_scene, bpy::return_value_policy<bpy::reference_existing_object>()) |
292 | |
293 | .def("set_frame" , &Project::set_frame) |
294 | .def("get_frame" , &Project::get_frame, bpy::return_value_policy<bpy::reference_existing_object>()) |
295 | |
296 | .def("get_display" , &Project::get_display, bpy::return_value_policy<bpy::reference_existing_object>()) |
297 | .def("set_display" , &Project::set_display) |
298 | |
299 | .def("get_active_camera" , &Project::get_uncached_active_camera, bpy::return_value_policy<bpy::reference_existing_object>()) |
300 | |
301 | .def("configurations" , project_get_configs, bpy::return_value_policy<bpy::reference_existing_object>()) |
302 | |
303 | .def("create_aov_images" , &Project::create_aov_images); |
304 | |
305 | bpy::enum_<ProjectFileReader::Options>("ProjectFileReaderOptions" ) |
306 | .value("Defaults" , ProjectFileReader::Defaults) |
307 | .value("OmitReadingMeshFiles" , ProjectFileReader::OmitReadingMeshFiles) |
308 | .value("OmitProjectFileUpdate" , ProjectFileReader::OmitProjectFileUpdate) |
309 | .value("OmitSearchPaths" , ProjectFileReader::OmitSearchPaths) |
310 | .value("OmitProjectSchemaValidation" , ProjectFileReader::OmitProjectSchemaValidation); |
311 | |
312 | bpy::class_<ProjectFileReader>("ProjectFileReader" ) |
313 | .def("read" , &project_file_reader_read_default_opts) |
314 | .def("read" , &project_file_reader_read_with_opts) |
315 | .def("load_builtin" , &project_file_reader_load_builtin); |
316 | |
317 | bpy::enum_<ProjectFileWriter::Options>("ProjectFileWriterOptions" ) |
318 | .value("Defaults" , ProjectFileWriter::Defaults) |
319 | .value("OmitHeaderComment" , ProjectFileWriter::OmitHeaderComment) |
320 | .value("OmitWritingGeometryFiles" , ProjectFileWriter::OmitWritingGeometryFiles) |
321 | .value("OmitHandlingAssetFiles" , ProjectFileWriter::OmitHandlingAssetFiles) |
322 | .value("CopyAllAssets" , ProjectFileWriter::CopyAllAssets); |
323 | |
324 | bpy::class_<ProjectFileWriter>("ProjectFileWriter" ) |
325 | // These methods are static but for symmetry with ProjectFileReader we're exposing them as non-static. |
326 | .def("write" , write_project_default_opts) |
327 | .def("write" , write_project_with_opts); |
328 | } |
329 | |