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