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