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 "unalignedmatrix44.h" |
33 | |
34 | // Standard headers. |
35 | #include <cstddef> |
36 | #include <memory> |
37 | |
38 | namespace bpy = boost::python; |
39 | using namespace foundation; |
40 | using namespace std; |
41 | |
42 | namespace |
43 | { |
44 | template <typename T> |
45 | UnalignedMatrix44<T>* construct_matrix_from_list(bpy::list l) |
46 | { |
47 | if (bpy::len(l) != 4 * 4) |
48 | { |
49 | PyErr_SetString(PyExc_RuntimeError, "Invalid list length given to appleseed.Matrix.__init__" ); |
50 | bpy::throw_error_already_set(); |
51 | } |
52 | |
53 | auto_ptr<UnalignedMatrix44<T> > r(new UnalignedMatrix44<T>()); |
54 | |
55 | for (size_t i = 0; i < 4 * 4; ++i) |
56 | { |
57 | bpy::extract<T> ex(l[i]); |
58 | if (!ex.check()) |
59 | { |
60 | PyErr_SetString(PyExc_TypeError, "Incompatible type." ); |
61 | bpy::throw_error_already_set(); |
62 | } |
63 | |
64 | (*r)[i] = ex(); |
65 | } |
66 | |
67 | return r.release(); |
68 | } |
69 | |
70 | template <typename T> |
71 | struct MatrixIndexer |
72 | { |
73 | static T get(const UnalignedMatrix44<T>& mat, bpy::tuple indices) |
74 | { |
75 | if (bpy::len(indices) != 2) |
76 | { |
77 | PyErr_SetString(PyExc_RuntimeError, "Invalid tuple length given to appleseed.Matrix.__get_item__" ); |
78 | bpy::throw_error_already_set(); |
79 | } |
80 | |
81 | int i = 0, j = 0; |
82 | |
83 | bpy::extract<int> ex0(indices[0]); |
84 | if (!ex0.check()) |
85 | { |
86 | PyErr_SetString(PyExc_TypeError, "Incompatible index type. Only ints." ); |
87 | bpy::throw_error_already_set(); |
88 | } |
89 | else |
90 | i = ex0(); |
91 | |
92 | bpy::extract<int> ex1(indices[1]); |
93 | if (!ex1.check()) |
94 | { |
95 | PyErr_SetString(PyExc_TypeError, "Incompatible index type. Only ints." ); |
96 | bpy::throw_error_already_set(); |
97 | } |
98 | else |
99 | j = ex1(); |
100 | |
101 | if (i < 0) |
102 | i = 4 + i; |
103 | |
104 | if (j < 0) |
105 | j = 4 + j; |
106 | |
107 | if (i >= 0 && i < 4 && j >= 0 && j < 4) |
108 | return mat(i, j); |
109 | |
110 | PyErr_SetString(PyExc_IndexError, "Out of bounds access in appleseed.Matrix.__get_item__" ); |
111 | boost::python::throw_error_already_set(); |
112 | return T(); |
113 | } |
114 | |
115 | static void set(UnalignedMatrix44<T>& mat, bpy::tuple indices, const T v) |
116 | { |
117 | if (bpy::len(indices) != 2) |
118 | { |
119 | PyErr_SetString(PyExc_RuntimeError, "Invalid tuple length given to appleseed.Matrix.__set_item__" ); |
120 | bpy::throw_error_already_set(); |
121 | } |
122 | |
123 | int i = 0, j = 0; |
124 | |
125 | bpy::extract<int> ex0(indices[0]); |
126 | if (!ex0.check()) |
127 | { |
128 | PyErr_SetString(PyExc_TypeError, "Incompatible index type. Only ints." ); |
129 | bpy::throw_error_already_set(); |
130 | } |
131 | else |
132 | i = ex0(); |
133 | |
134 | bpy::extract<int> ex1(indices[1]); |
135 | if (!ex1.check()) |
136 | { |
137 | PyErr_SetString(PyExc_TypeError, "Incompatible index type. Only ints." ); |
138 | bpy::throw_error_already_set(); |
139 | } |
140 | else |
141 | j = ex1(); |
142 | |
143 | if (i < 0) |
144 | i = 4 + i; |
145 | |
146 | if (j < 0) |
147 | j = 4 + j; |
148 | |
149 | if (i >= 0 && i < 4 && j >= 0 && j < 4) |
150 | mat(i, j) = v; |
151 | else |
152 | { |
153 | PyErr_SetString(PyExc_IndexError, "Out of bounds access in appleseed.Matrix.__set_item__" ); |
154 | boost::python::throw_error_already_set(); |
155 | } |
156 | } |
157 | }; |
158 | |
159 | template <typename T> |
160 | UnalignedMatrix44<T> transpose_matrix(const UnalignedMatrix44<T>& mat) |
161 | { |
162 | return UnalignedMatrix44<T>(transpose(mat.as_foundation_matrix())); |
163 | } |
164 | |
165 | template <typename T> |
166 | bpy::tuple (const UnalignedMatrix44<T>& mat) |
167 | { |
168 | T yaw, pitch, roll; |
169 | mat.as_foundation_matrix().extract_euler_angles(yaw, pitch, roll); |
170 | return bpy::make_tuple(yaw, pitch, roll); |
171 | } |
172 | |
173 | void (bpy::class_<UnalignedMatrix44<float> >& X) |
174 | { |
175 | X.def(bpy::init<UnalignedMatrix44<double> >()); |
176 | } |
177 | |
178 | void (bpy::class_<UnalignedMatrix44<double> >& X) |
179 | { |
180 | X.def(bpy::init<UnalignedMatrix44<float> >()); |
181 | } |
182 | |
183 | template <typename T> |
184 | void bind_typed_matrix4(const char* class_name) |
185 | { |
186 | UnalignedMatrix44<T>(*rot1)(T, T, T) = &UnalignedMatrix44<T>::make_rotation; |
187 | UnalignedMatrix44<T>(*rot2)(const Vector<T, 3>&, T) = &UnalignedMatrix44<T>::make_rotation; |
188 | UnalignedMatrix44<T>(*rot3)(const Quaternion<T>&) = &UnalignedMatrix44<T>::make_rotation; |
189 | |
190 | bpy::class_<UnalignedMatrix44<T> > X(class_name); |
191 | |
192 | X.def("identity" , &UnalignedMatrix44<T>::identity).staticmethod("identity" ) |
193 | .def("make_translation" , &UnalignedMatrix44<T>::make_translation).staticmethod("make_translation" ) |
194 | .def("make_scaling" , &UnalignedMatrix44<T>::make_scaling).staticmethod("make_scaling" ) |
195 | .def("make_rotation_x" , &UnalignedMatrix44<T>::make_rotation_x).staticmethod("make_rotation_x" ) |
196 | .def("make_rotation_y" , &UnalignedMatrix44<T>::make_rotation_y).staticmethod("make_rotation_y" ) |
197 | .def("make_rotation_z" , &UnalignedMatrix44<T>::make_rotation_z).staticmethod("make_rotation_z" ) |
198 | .def("make_lookat" , &UnalignedMatrix44<T>::make_lookat).staticmethod("make_lookat" ) |
199 | .def("make_rotation" , rot1).def("make_rotation" , rot2).def("make_rotation" , rot3).staticmethod("make_rotation" ) |
200 | |
201 | .def(bpy::init<T>()) |
202 | .def("__init__" , bpy::make_constructor(&construct_matrix_from_list<T>)) |
203 | |
204 | // operator[] |
205 | .def("__getitem__" , &MatrixIndexer<T>::get) |
206 | .def("__setitem__" , &MatrixIndexer<T>::set) |
207 | |
208 | .def("transpose" , &transpose_matrix<T>) |
209 | .def("inverse" , &invert_matrix<T>) |
210 | |
211 | .def(bpy::self * bpy::self) |
212 | .def(bpy::self * Vector<T, 4>()) |
213 | |
214 | // Because of a bug in Boost.Python, this needs the extra self_ns qualification. |
215 | .def(bpy::self_ns::str(bpy::self)) |
216 | .def(bpy::self_ns::repr(bpy::self)) |
217 | |
218 | .def("extract_matrix3" , &UnalignedMatrix44<T>::extract_matrix3) |
219 | .def("extract_translation" , &UnalignedMatrix44<T>::extract_translation); |
220 | |
221 | bind_typed_matrix4_extra(X); |
222 | } |
223 | } |
224 | |
225 | void bind_matrix() |
226 | { |
227 | bind_typed_matrix4<float>("Matrix4f" ); |
228 | bind_typed_matrix4<double>("Matrix4d" ); |
229 | |
230 | #ifdef APPLESEED_ENABLE_IMATH_INTEROP |
231 | bpy::implicitly_convertible<UnalignedMatrix44<float>, Imath::M44f>(); |
232 | bpy::implicitly_convertible<Imath::M44f, UnalignedMatrix44<float> >(); |
233 | |
234 | bpy::implicitly_convertible<UnalignedMatrix44<double>, Imath::M44d>(); |
235 | bpy::implicitly_convertible<Imath::M44d, UnalignedMatrix44<double> >(); |
236 | #endif |
237 | } |
238 | |