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) 2012-2013 Esteban Tovagliari, Jupiter Jazz Limited
9 // Copyright (c) 2014-2018 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 "bindentitycontainers.h"
32 #include "dict2dict.h"
33
34 // appleseed.renderer headers.
35 #include "renderer/api/object.h"
36
37 // appleseed.foundation headers.
38 #include "foundation/platform/python.h"
39 #include "foundation/utility/murmurhash.h"
40 #include "foundation/utility/searchpaths.h"
41
42 // Standard headers.
43 #include <cstddef>
44 #include <string>
45
46 namespace bpy = boost::python;
47 using namespace foundation;
48 using namespace renderer;
49 using namespace std;
50
51 // Work around a regression in Visual Studio 2015 Update 3.
52 #if defined(_MSC_VER) && _MSC_VER == 1900
53 namespace boost
54 {
get_pointer(MeshObject const volatile * p)55 template <> MeshObject const volatile* get_pointer<MeshObject const volatile>(MeshObject const volatile* p) { return p; }
56 }
57 #endif
58
59 namespace
60 {
create_mesh_obj(const string & name,const bpy::dict & params)61 auto_release_ptr<MeshObject> create_mesh_obj(
62 const string& name,
63 const bpy::dict& params)
64 {
65 return
66 auto_release_ptr<MeshObject>(
67 MeshObjectFactory().create(name.c_str(), bpy_dict_to_param_array(params)));
68 }
69
get_triangle(MeshObject * object,const size_t index)70 Triangle& get_triangle(MeshObject* object, const size_t index)
71 {
72 return object->get_triangle(index);
73 }
74
set_triangle(MeshObject * object,const size_t index,const Triangle & triangle)75 void set_triangle(MeshObject* object, const size_t index, const Triangle& triangle)
76 {
77 object->get_triangle(index) = triangle;
78 }
79
read_mesh_objects(const bpy::list & search_paths,const string & base_object_name,const bpy::dict & params)80 bpy::list read_mesh_objects(
81 const bpy::list& search_paths,
82 const string& base_object_name,
83 const bpy::dict& params)
84 {
85 SearchPaths paths;
86
87 for (bpy::ssize_t i = 0, e = bpy::len(search_paths); i < e; ++i)
88 {
89 bpy::extract<const char*> ex(search_paths[i]);
90 if (!ex.check())
91 {
92 PyErr_SetString(PyExc_TypeError, "Incompatible type. Only strings.");
93 bpy::throw_error_already_set();
94 }
95
96 paths.push_back_explicit_path(ex());
97 }
98
99 MeshObjectArray objs;
100 bpy::list py_objects;
101
102 if (MeshObjectReader::read(paths, base_object_name.c_str(), bpy_dict_to_param_array(params), objs))
103 {
104 for (size_t i = 0, e = objs.size(); i < e; ++i)
105 {
106 auto_release_ptr<MeshObject> object(objs[i]);
107 py_objects.append(object);
108 }
109 }
110 else
111 {
112 PyErr_SetString(PyExc_RuntimeError, "appleseed.MeshObjectReader failed");
113 bpy::throw_error_already_set();
114 return py_objects;
115 }
116
117 return py_objects;
118 }
119
write_mesh_object(const MeshObject * object,const string & object_name,const string & filename)120 bool write_mesh_object(
121 const MeshObject* object,
122 const string& object_name,
123 const string& filename)
124 {
125 return MeshObjectWriter::write(*object, object_name.c_str(), filename.c_str());
126 }
127
create_mesh_prim(const string & name,const bpy::dict & params)128 auto_release_ptr<MeshObject> create_mesh_prim(
129 const string& name,
130 const bpy::dict& params)
131 {
132 return create_primitive_mesh(name.c_str(), bpy_dict_to_param_array(params));
133 }
134
compute_mesh_signature(MurmurHash & hash,const MeshObject * mesh)135 void compute_mesh_signature(MurmurHash& hash, const MeshObject* mesh)
136 {
137 compute_signature(hash, *mesh);
138 }
139 }
140
bind_mesh_object()141 void bind_mesh_object()
142 {
143 bpy::class_<Triangle>("Triangle")
144 .def(bpy::init<size_t, size_t, size_t>())
145 .def(bpy::init<size_t, size_t, size_t, size_t>())
146 .def(bpy::init<size_t, size_t, size_t, size_t, size_t, size_t, size_t>())
147 .def(bpy::init<size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t>())
148
149 .def_readwrite("m_v0", &Triangle::m_v0)
150 .def_readwrite("m_v1", &Triangle::m_v1)
151 .def_readwrite("m_v2", &Triangle::m_v2)
152 .def_readwrite("m_n0", &Triangle::m_n0)
153 .def_readwrite("m_n1", &Triangle::m_n1)
154 .def_readwrite("m_n2", &Triangle::m_n2)
155 .def_readwrite("m_a0", &Triangle::m_a0)
156 .def_readwrite("m_a1", &Triangle::m_a1)
157 .def_readwrite("m_a2", &Triangle::m_a2)
158 .def_readwrite("m_pa", &Triangle::m_pa)
159
160 .def("has_vertex_attributes", &Triangle::has_vertex_attributes);
161
162 bpy::class_<MeshObject, auto_release_ptr<MeshObject>, bpy::bases<Object>, boost::noncopyable>("MeshObject", bpy::no_init)
163 .def("__init__", bpy::make_constructor(create_mesh_obj))
164
165 .def("reserve_vertices", &MeshObject::reserve_vertices)
166 .def("push_vertex", &MeshObject::push_vertex)
167 .def("get_vertex_count", &MeshObject::get_vertex_count)
168 .def("get_vertex", &MeshObject::get_vertex, bpy::return_value_policy<bpy::reference_existing_object>())
169
170 .def("reserve_vertex_normals", &MeshObject::reserve_vertex_normals)
171 .def("push_vertex_normal", &MeshObject::push_vertex_normal)
172 .def("get_vertex_normal_count", &MeshObject::get_vertex_normal_count)
173 .def("get_vertex_normal", &MeshObject::get_vertex_normal, bpy::return_value_policy<bpy::reference_existing_object>())
174
175 .def("reserve_vertex_tangents", &MeshObject::reserve_vertex_tangents)
176 .def("push_vertex_tangent", &MeshObject::push_vertex_tangent)
177 .def("get_vertex_tangent_count", &MeshObject::get_vertex_tangent_count)
178 .def("get_vertex_tangent", &MeshObject::get_vertex_tangent)
179
180 .def("reserve_tex_coords", &MeshObject::reserve_tex_coords)
181 .def("push_tex_coords", &MeshObject::push_tex_coords)
182 .def("get_tex_coords_count", &MeshObject::get_tex_coords_count)
183 .def("get_tex_coords", &MeshObject::get_tex_coords)
184
185 .def("reserve_triangles", &MeshObject::reserve_triangles)
186 .def("push_triangle", &MeshObject::push_triangle)
187 .def("get_triangle_count", &MeshObject::get_triangle_count)
188 .def("get_triangle", get_triangle, bpy::return_value_policy<bpy::reference_existing_object>())
189 .def("set_triangle", set_triangle)
190
191 .def("set_motion_segment_count", &MeshObject::set_motion_segment_count)
192 .def("get_motion_segment_count", &MeshObject::get_motion_segment_count)
193
194 .def("set_vertex_pose", &MeshObject::set_vertex_pose)
195 .def("get_vertex_pose", &MeshObject::get_vertex_pose)
196 .def("clear_vertex_poses", &MeshObject::clear_vertex_poses)
197
198 .def("set_vertex_normal_pose", &MeshObject::set_vertex_normal_pose)
199 .def("get_vertex_normal_pose", &MeshObject::get_vertex_normal_pose)
200 .def("clear_vertex_normal_poses", &MeshObject::clear_vertex_normal_poses)
201
202 .def("set_vertex_tangent_pose", &MeshObject::set_vertex_tangent_pose)
203 .def("get_vertex_tangent_pose", &MeshObject::get_vertex_tangent_pose)
204 .def("clear_vertex_tangent_poses", &MeshObject::clear_vertex_tangent_poses)
205
206 .def("reserve_material_slots", &MeshObject::reserve_material_slots)
207 .def("push_material_slot", &MeshObject::push_material_slot);
208
209 boost::python::implicitly_convertible<auto_release_ptr<MeshObject>, auto_release_ptr<Object>>();
210
211 bpy::class_<MeshObjectReader>("MeshObjectReader", bpy::no_init)
212 .def("read", read_mesh_objects).staticmethod("read");
213
214 bpy::class_<MeshObjectWriter>("MeshObjectWriter", bpy::no_init)
215 .def("write", write_mesh_object).staticmethod("write");
216
217 bpy::def("compute_smooth_vertex_normals", compute_smooth_vertex_normals);
218 bpy::def("compute_smooth_vertex_tangents", compute_smooth_vertex_tangents);
219 bpy::def("compute_signature", compute_mesh_signature);
220 bpy::def("create_primitive_mesh", create_mesh_prim);
221 }
222