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