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#ifndef APPLESEED_PYTHON_UNALIGNEDMATRIX44_H
31#define APPLESEED_PYTHON_UNALIGNEDMATRIX44_H
32
33// appleseed.python headers.
34#include "pyseed.h" // has to be first, to avoid redefinition warnings
35
36// appleseed.foundation headers.
37#include "foundation/math/matrix.h"
38#include "foundation/math/quaternion.h"
39#include "foundation/math/vector.h"
40#include "foundation/utility/iostreamop.h"
41
42// Standard headers.
43#include <cstddef>
44
45namespace foundation
46{
47
48template <typename T>
49class UnalignedMatrix44
50{
51 public:
52 static UnalignedMatrix44<T> identity()
53 {
54 return UnalignedMatrix44<T>(Matrix<T, 4, 4>::identity());
55 }
56
57 static UnalignedMatrix44<T> make_translation(const Vector<T, 3>& v)
58 {
59 return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_translation(v));
60 }
61
62 static UnalignedMatrix44<T> make_scaling(const Vector<T, 3>& s)
63 {
64 return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_scaling(s));
65 }
66
67 static UnalignedMatrix44<T> make_rotation_x(const T angle)
68 {
69 return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation_x(angle));
70 }
71
72 static UnalignedMatrix44<T> make_rotation_y(const T angle)
73 {
74 return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation_y(angle));
75 }
76
77 static UnalignedMatrix44<T> make_rotation_z(const T angle)
78 {
79 return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation_z(angle));
80 }
81
82 static UnalignedMatrix44<T> make_rotation(const T yaw, const T pitch, const T roll)
83 {
84 return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation(yaw, pitch, roll));
85 }
86
87 static UnalignedMatrix44<T> make_rotation(const Vector<T, 3>& axis, const T angle)
88 {
89 return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation(axis, angle));
90 }
91
92 static UnalignedMatrix44<T> make_rotation(const Quaternion<T>& q)
93 {
94 return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_rotation(q));
95 }
96
97 static UnalignedMatrix44<T> make_lookat(const Vector<T, 3>& origin, const Vector<T, 3>& target, const Vector<T, 3>& up)
98 {
99 return UnalignedMatrix44<T>(Matrix<T, 4, 4>::make_lookat(origin, target, up));
100 }
101
102 UnalignedMatrix44() {}
103
104 explicit UnalignedMatrix44(const T x)
105 {
106 for (size_t i = 0; i < 16; ++i)
107 m_data[i] = x;
108 }
109
110 template <class U>
111 explicit UnalignedMatrix44(const Matrix<U, 4, 4>& m)
112 {
113 for (size_t i = 0; i < 16; ++i)
114 m_data[i] = static_cast<T>(m[i]);
115 }
116
117 template <class U>
118 explicit UnalignedMatrix44(const UnalignedMatrix44<U>& m)
119 {
120 for (size_t i = 0; i < 16; ++i)
121 m_data[i] = static_cast<T>(m[i]);
122 }
123
124#ifdef APPLESEED_ENABLE_IMATH_INTEROP
125
126 UnalignedMatrix44(const Imath::Matrix44<T>& rhs)
127 {
128 T *p = m_data;
129
130 for (int i = 0; i < 3; ++i)
131 {
132 for (int j = 0; j < 3; ++j)
133 *p++ = rhs[j][i];
134 }
135 }
136
137 operator Imath::Matrix44<T>() const
138 {
139 return as_foundation_matrix();
140 }
141
142#endif
143
144 template <class U>
145 UnalignedMatrix44<T>& operator=(const UnalignedMatrix44<U>& m)
146 {
147 for (size_t i = 0; i < 16; ++i)
148 m_data[i] = static_cast<T>(m[i]);
149
150 return *this;
151 }
152
153 Matrix<T, 4, 4> as_foundation_matrix() const
154 {
155 return Matrix<T, 4, 4>(m_data);
156 }
157
158 T operator[](const size_t index) const
159 {
160 return m_data[index];
161 }
162
163 T& operator[](const size_t index)
164 {
165 return m_data[index];
166 }
167
168 T operator()(const size_t row, const size_t col) const
169 {
170 return m_data[row * 4 + col];
171 }
172
173 T& operator()(const size_t row, const size_t col)
174 {
175 return m_data[row * 4 + col];
176 }
177
178 Matrix<T, 3, 3> extract_matrix3() const
179 {
180 return as_foundation_matrix().extract_matrix3();
181 }
182
183 Vector<T, 3> extract_translation() const
184 {
185 return as_foundation_matrix().extract_translation();
186 }
187
188 Vector<T, 3> transform_vector(const Vector<T, 3>& v) const
189 {
190 Vector<T, 3> res;
191
192 res[0] = m_data[0] * v[0] + m_data[1] * v[1] + m_data[ 2] * v[2];
193 res[1] = m_data[4] * v[0] + m_data[5] * v[1] + m_data[ 6] * v[2];
194 res[2] = m_data[8] * v[0] + m_data[9] * v[1] + m_data[10] * v[2];
195
196 return res;
197 }
198
199 Vector<T, 3> transform_normal(const Vector<T, 3>& n) const
200 {
201 Vector<T, 3> res;
202
203 res.x = m_data[ 0] * n.x +
204 m_data[ 4] * n.y +
205 m_data[ 8] * n.z;
206
207 res.y = m_data[ 1] * n.x +
208 m_data[ 5] * n.y +
209 m_data[ 9] * n.z;
210
211 res.z = m_data[ 2] * n.x +
212 m_data[ 6] * n.y +
213 m_data[10] * n.z;
214
215 return res;
216 }
217
218 Vector<T, 3> transform_point(const Vector<T, 3>& p) const
219 {
220 Vector<T, 3> res;
221
222 res.x = m_data[ 0] * p.x +
223 m_data[ 1] * p.y +
224 m_data[ 2] * p.z +
225 m_data[ 3];
226
227 res.y = m_data[ 4] * p.x +
228 m_data[ 5] * p.y +
229 m_data[ 6] * p.z +
230 m_data[ 7];
231
232 res.z = m_data[ 8] * p.x +
233 m_data[ 9] * p.y +
234 m_data[10] * p.z +
235 m_data[11];
236
237 const T w = m_data[12] * p.x +
238 m_data[13] * p.y +
239 m_data[14] * p.z +
240 m_data[15];
241
242 if (w == T(0.0))
243 {
244 PyErr_SetString(PyExc_RuntimeError, "Zero homogeneous coordinate in appleseed.Matrix44.transform_point");
245 boost::python::throw_error_already_set();
246 return res;
247 }
248
249 res /= w;
250
251 return res;
252 }
253
254 private:
255 T m_data[16];
256};
257
258template <typename T>
259UnalignedMatrix44<T> operator*(const UnalignedMatrix44<T>& a, const UnalignedMatrix44<T>& b)
260{
261 return UnalignedMatrix44<T>(a.as_foundation_matrix() * b.as_foundation_matrix());
262}
263
264template <typename T>
265Vector<T, 4> operator*(const UnalignedMatrix44<T>& a, const Vector<T, 4>& v)
266{
267 return a.as_foundation_matrix() * v;
268}
269
270template <typename T>
271UnalignedMatrix44<T> invert_matrix(const UnalignedMatrix44<T>& mat)
272{
273 try
274 {
275 return UnalignedMatrix44<T>(inverse(mat.as_foundation_matrix()));
276 }
277 catch (ExceptionSingularMatrix&)
278 {
279 PyErr_SetString(PyExc_RuntimeError, "Singular matrix in appleseed.Matrix.inverse");
280 boost::python::throw_error_already_set();
281 }
282
283 return UnalignedMatrix44<T>();
284}
285
286template <typename T>
287std::ostream& operator<<(std::ostream& s, const UnalignedMatrix44<T>& matrix)
288{
289 return s << matrix.as_foundation_matrix();
290}
291
292} // namespace foundation
293
294#endif // !APPLESEED_PYTHON_UNALIGNEDMATRIX44_H
295