neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
numerical.hpp
Go to the documentation of this file.
1// numerical.hpp
2/*
3 * Copyright (c) 2015, 2020 Leigh Johnston.
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * * Neither the name of Leigh Johnston nor the names of any
19 * other contributors to this software may be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#pragma once
37
38#include <neolib/neolib.hpp>
39#include <type_traits>
40#include <stdexcept>
41#include <vector>
42#include <utility>
43#include <array>
44#include <algorithm>
45#include <ostream>
46#include <istream>
47#include <boost/math/constants/constants.hpp>
50#include <neolib/core/simd.hpp>
53
54namespace neolib
55{
56 namespace math
57 {
58#define USE_AVX
59#define USE_EMM
60
61 using namespace boost::math::constants;
62
63 typedef double scalar;
64 typedef double angle;
65
66 namespace constants
67 {
68 template <typename T>
69 constexpr T zero = static_cast<T>(0.0);
70 template <typename T>
71 constexpr T one = static_cast<T>(1.0);
72 template <typename T>
73 constexpr T two = static_cast<T>(2.0);
74 template <typename T>
75 constexpr T three = static_cast<T>(3.0);
76 template <typename T>
77 constexpr T four = static_cast<T>(4.0);
78 }
79
80 template <typename T, typename SFINAE = std::enable_if_t<std::is_scalar_v<T>, sfinae>>
81 inline T lerp(T aX1, T aX2, double aAmount)
82 {
83 double x1 = aX1;
84 double x2 = aX2;
85 return static_cast<T>((x2 - x1) * aAmount + x1);
86 }
87
88 inline angle to_rad(angle aDegrees)
89 {
90 return aDegrees / 180.0 * pi<angle>();
91 }
92
93 inline angle to_deg(angle aRadians)
94 {
95 return aRadians * 180.0 / pi<angle>();
96 }
97
98 struct column_vector {};
99 struct row_vector {};
100
101 template <typename T, uint32_t _Size, typename Type = column_vector>
102 class basic_vector;
103 }
104
105 template <typename T, uint32_t _Size, typename Type>
106 bool constexpr vecarray_trivial_v<math::basic_vector<T, _Size, Type>> = true;
107
108 namespace math
109 {
110 template <typename T, uint32_t _Size, typename Type>
112 {
114 public:
115 typedef self_type abstract_type; // todo: abstract base; std::array?
116 public:
117 typedef Type type;
118 public:
119 typedef T value_type;
121 typedef uint32_t size_type;
122 typedef std::array<value_type, _Size> array_type;
123 typedef typename array_type::const_iterator const_iterator;
124 typedef typename array_type::iterator iterator;
125 public:
126 template <uint32_t Size2> struct rebind { typedef basic_vector<T, Size2, Type> type; };
127 public:
128 static constexpr uint32_t Size = _Size;
129 public:
131 template <typename SFINAE = int>
132 explicit basic_vector(value_type x, typename std::enable_if_t<Size == 1, SFINAE> = 0) : v{ {x} } {}
133 template <typename SFINAE = int>
134 explicit basic_vector(value_type x, value_type y, typename std::enable_if_t<Size == 2, SFINAE> = 0) : v{ {x, y} } {}
135 template <typename SFINAE = int>
136 explicit basic_vector(value_type x, value_type y, value_type z, typename std::enable_if_t<Size == 3, SFINAE> = 0) : v{ {x, y, z} } {}
137 template <typename SFINAE = int>
138 explicit basic_vector(value_type x, value_type y, value_type z, value_type w, typename std::enable_if_t<Size == 4, SFINAE> = 0) : v{ { x, y, z, w } } {}
139 template <typename... Arguments>
140 explicit basic_vector(const value_type& value, Arguments&&... aArguments) : v{ {value, std::forward<Arguments>(aArguments)...} } {}
141 template <typename... Arguments>
142 explicit basic_vector(value_type&& value, Arguments&&... aArguments) : v{ {std::move(value), std::forward<Arguments>(aArguments)...} } {}
143 explicit basic_vector(const array_type& v) : v{ v } {}
144 basic_vector(std::initializer_list<value_type> values) { if (values.size() > Size) throw std::out_of_range("neolib::basic_vector: initializer list too big"); std::uninitialized_copy(values.begin(), values.end(), v.begin()); std::uninitialized_fill(v.begin() + (values.end() - values.begin()), v.end(), value_type{}); }
145 template <typename V, typename A, uint32_t S, uint32_t... Indexes>
146 basic_vector(const swizzle<V, A, S, Indexes...>& aSwizzle) : self_type{ ~aSwizzle } {}
147 basic_vector(const self_type& other) : v{ other.v } {}
148 basic_vector(self_type&& other) : v{ std::move(other.v) } {}
149 template <typename T2>
150 basic_vector(const basic_vector<T2, Size, Type>& other) { std::transform(other.begin(), other.end(), v.begin(), [](T2 source) { return static_cast<value_type>(source); }); }
151 template <typename T2, uint32_t Size2, typename SFINAE = int>
152 basic_vector(const basic_vector<T2, Size2, Type>& other, typename std::enable_if_t<Size2 < Size, SFINAE> = 0) : v{} { std::transform(other.begin(), other.end(), v.begin(), [](T2 source) { return static_cast<value_type>(source); }); }
153 self_type& operator=(const self_type& other) { v = other.v; return *this; }
154 self_type& operator=(self_type&& other) { v = std::move(other.v); return *this; }
155 self_type& operator=(std::initializer_list<value_type> values) { if (values.size() > Size) throw std::out_of_range("neolib::basic_vector: initializer list too big"); std::copy(values.begin(), values.end(), v.begin()); std::fill(v.begin() + (values.end() - values.begin()), v.end(), value_type{}); return *this; }
156 public:
157 static uint32_t size() { return Size; }
158 value_type operator[](uint32_t aIndex) const { return v[aIndex]; }
159 value_type& operator[](uint32_t aIndex) { return v[aIndex]; }
160 const_iterator begin() const { return v.begin(); }
161 const_iterator end() const { return v.end(); }
162 iterator begin() { return v.begin(); }
163 iterator end() { return v.end(); }
164 operator const array_type&() const { return v; }
165 public:
166 template <typename T2>
168 {
169 return basic_vector<T2, Size, Type>{ *this };
170 }
171 public:
172 bool operator==(const self_type& right) const { return v == right.v; }
173 bool operator!=(const self_type& right) const { return v != right.v; }
174 self_type& operator+=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] += value; return *this; }
175 self_type& operator-=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] -= value; return *this; }
176 self_type& operator*=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] *= value; return *this; }
177 self_type& operator/=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] /= value; return *this; }
178 self_type& operator+=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] += right.v[index]; return *this; }
179 self_type& operator-=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] -= right.v[index]; return *this; }
180 self_type& operator*=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] *= right.v[index]; return *this; }
181 self_type& operator/=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] /= right.v[index]; return *this; }
182 self_type operator-() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result.v[index] = -v[index]; return result; }
183 self_type scale(const self_type& right) const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = v[index] * right[index]; return result; }
184 value_type magnitude() const { value_type ss = constants::zero<value_type>; for (uint32_t index = 0; index < Size; ++index) ss += (v[index] * v[index]); return std::sqrt(ss); }
185 self_type normalized() const { self_type result; value_type im = constants::one<value_type> / magnitude(); for (uint32_t index = 0; index < Size; ++index) result.v[index] = v[index] * im; return result; }
186 self_type min(const self_type& right) const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::min(v[index], right.v[index]); return result; }
187 self_type max(const self_type& right) const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::max(v[index], right.v[index]); return result; }
188 value_type min() const { value_type result = v[0]; for (uint32_t index = 1; index < Size; ++index) result = std::min(v[index], result); return result; }
189 self_type ceil() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::ceil(v[index]); return result; }
190 self_type floor() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::floor(v[index]); return result; }
191 self_type round() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::round(v[index]); return result; }
192 value_type distance(const self_type& right) const { value_type total = 0; for (uint32_t index = 0; index < Size; ++index) total += ((v[index] - right.v[index]) * (v[index] - right.v[index])); return std::sqrt(total); }
193 value_type dot(const self_type& right) const
194 {
195 value_type result = constants::zero<value_type>;
196 for (uint32_t index = 0; index < Size; ++index)
197 result += (v[index] * right[index]);
198 return result;
199 }
200 template <typename SFINAE = self_type>
201 std::enable_if_t<Size == 3, SFINAE> cross(const self_type& right) const
202 {
203 return self_type{
204 y * right.z - z * right.y,
205 z * right.x - x * right.z,
206 x * right.y - y * right.x };
207 }
209 {
210 self_type result = *this;
211 result *= right;
212 return result;
213 }
214 public:
215 friend void swap(self_type& a, self_type& b)
216 {
217 using std::swap;
218 swap(a.v, b.v);
219 }
220 public:
221 union
222 {
224 struct // todo: alignment, padding?
225 {
229 };
263 };
264 };
265
266 template <typename T, typename Type>
267 class basic_vector<T, 2, Type>
268 {
270 public:
271 typedef self_type abstract_type; // todo: abstract base; std::array?
272 public:
273 typedef Type type;
274 public:
275 typedef T value_type;
277 typedef uint32_t size_type;
278 typedef std::array<value_type, 2> array_type;
279 typedef typename array_type::const_iterator const_iterator;
280 typedef typename array_type::iterator iterator;
281 public:
282 template <uint32_t Size2> struct rebind { typedef basic_vector<T, Size2, Type> type; };
283 public:
284 static constexpr uint32_t Size = 2;
285 public:
286 basic_vector() : v{} {}
287 explicit basic_vector(value_type x, value_type y) : v{ {x, y} } {}
288 template <typename... Arguments>
289 explicit basic_vector(const value_type& value, Arguments&&... aArguments) : v{ {value, std::forward<Arguments>(aArguments)...} } {}
290 template <typename... Arguments>
291 explicit basic_vector(value_type&& value, Arguments&&... aArguments) : v{ {std::move(value), std::forward<Arguments>(aArguments)...} } {}
292 explicit basic_vector(const array_type& v) : v{ v } {}
293 basic_vector(std::initializer_list<value_type> values) { if (values.size() > Size) throw std::out_of_range("neolib::basic_vector: initializer list too big"); std::uninitialized_copy(values.begin(), values.end(), v.begin()); std::uninitialized_fill(v.begin() + (values.end() - values.begin()), v.end(), value_type{}); }
294 template <typename V, typename A, uint32_t S, uint32_t... Indexes>
295 basic_vector(const swizzle<V, A, S, Indexes...>& aSwizzle) : self_type{ ~aSwizzle } {}
296 basic_vector(const self_type& other) : v{ other.v } {}
297 basic_vector(self_type&& other) : v{ std::move(other.v) } {}
298 template <typename T2>
299 basic_vector(const basic_vector<T2, Size, Type>& other) { std::transform(other.begin(), other.end(), v.begin(), [](T2 source) { return static_cast<value_type>(source); }); }
300 template <typename T2, uint32_t Size2, typename SFINAE = int>
301 basic_vector(const basic_vector<T2, Size2, Type>& other, typename std::enable_if_t < Size2 < Size, SFINAE> = 0) : v{} { std::transform(other.begin(), other.end(), v.begin(), [](T2 source) { return static_cast<value_type>(source); }); }
302 self_type& operator=(const self_type& other) { v = other.v; return *this; }
303 self_type& operator=(self_type&& other) { v = std::move(other.v); return *this; }
304 self_type& operator=(std::initializer_list<value_type> values) { if (values.size() > Size) throw std::out_of_range("neolib::basic_vector: initializer list too big"); std::copy(values.begin(), values.end(), v.begin()); std::fill(v.begin() + (values.end() - values.begin()), v.end(), value_type{}); return *this; }
305 public:
306 static uint32_t size() { return Size; }
307 value_type operator[](uint32_t aIndex) const { return v[aIndex]; }
308 value_type& operator[](uint32_t aIndex) { return v[aIndex]; }
309 const_iterator begin() const { return v.begin(); }
310 const_iterator end() const { return v.end(); }
311 iterator begin() { return v.begin(); }
312 iterator end() { return v.end(); }
313 operator const array_type& () const { return v; }
314 public:
315 template <typename T2>
317 {
318 return basic_vector<T2, Size, Type>{ *this };
319 }
320 public:
321 bool operator==(const self_type& right) const { return v == right.v; }
322 bool operator!=(const self_type& right) const { return v != right.v; }
323 self_type& operator+=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] += value; return *this; }
324 self_type& operator-=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] -= value; return *this; }
325 self_type& operator*=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] *= value; return *this; }
326 self_type& operator/=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] /= value; return *this; }
327 self_type& operator+=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] += right.v[index]; return *this; }
328 self_type& operator-=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] -= right.v[index]; return *this; }
329 self_type& operator*=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] *= right.v[index]; return *this; }
330 self_type& operator/=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] /= right.v[index]; return *this; }
331 self_type operator-() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result.v[index] = -v[index]; return result; }
332 self_type scale(const self_type& right) const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = v[index] * right[index]; return result; }
333 value_type magnitude() const { value_type ss = constants::zero<value_type>; for (uint32_t index = 0; index < Size; ++index) ss += (v[index] * v[index]); return std::sqrt(ss); }
334 self_type normalized() const { self_type result; value_type im = constants::one<value_type> / magnitude(); for (uint32_t index = 0; index < Size; ++index) result.v[index] = v[index] * im; return result; }
335 self_type min(const self_type& right) const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::min(v[index], right.v[index]); return result; }
336 self_type max(const self_type& right) const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::max(v[index], right.v[index]); return result; }
337 value_type min() const { value_type result = v[0]; for (uint32_t index = 1; index < Size; ++index) result = std::min(v[index], result); return result; }
338 self_type ceil() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::ceil(v[index]); return result; }
339 self_type floor() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::floor(v[index]); return result; }
340 self_type round() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::round(v[index]); return result; }
341 value_type distance(const self_type& right) const { value_type total = 0; for (uint32_t index = 0; index < Size; ++index) total += ((v[index] - right.v[index]) * (v[index] - right.v[index])); return std::sqrt(total); }
342 value_type dot(const self_type& right) const
343 {
344 value_type result = constants::zero<value_type>;
345 for (uint32_t index = 0; index < Size; ++index)
346 result += (v[index] * right[index]);
347 return result;
348 }
350 {
351 self_type result = *this;
352 result *= right;
353 return result;
354 }
355 public:
356 friend void swap(self_type& a, self_type& b)
357 {
358 using std::swap;
359 swap(a.v, b.v);
360 }
361 public:
362 union
363 {
365 struct // todo: alignment, padding?
366 {
369 };
382 };
383 };
384
385 template <typename T, typename Type>
386 class basic_vector<T, 1, Type>
387 {
389 public:
390 typedef self_type abstract_type; // todo: abstract base; std::array?
391 public:
392 typedef Type type;
393 public:
394 typedef T value_type;
396 typedef uint32_t size_type;
397 typedef std::array<value_type, 1> array_type;
398 typedef typename array_type::const_iterator const_iterator;
399 typedef typename array_type::iterator iterator;
400 public:
401 template <uint32_t Size2> struct rebind { typedef basic_vector<T, Size2, Type> type; };
402 public:
403 static constexpr uint32_t Size = 1;
404 public:
405 basic_vector() : v{} {}
406 explicit basic_vector(value_type x) : v{ {x} } {}
407 template <typename... Arguments>
408 explicit basic_vector(const value_type& value, Arguments&&... aArguments) : v{ {value, std::forward<Arguments>(aArguments)...} } {}
409 template <typename... Arguments>
410 explicit basic_vector(value_type&& value, Arguments&&... aArguments) : v{ {std::move(value), std::forward<Arguments>(aArguments)...} } {}
411 explicit basic_vector(const array_type& v) : v{ v } {}
412 basic_vector(std::initializer_list<value_type> values) { if (values.size() > Size) throw std::out_of_range("neolib::basic_vector: initializer list too big"); std::uninitialized_copy(values.begin(), values.end(), v.begin()); std::uninitialized_fill(v.begin() + (values.end() - values.begin()), v.end(), value_type{}); }
413 template <typename V, typename A, uint32_t S, uint32_t... Indexes>
414 basic_vector(const swizzle<V, A, S, Indexes...>& aSwizzle) : self_type{ ~aSwizzle } {}
415 basic_vector(const self_type& other) : v{ other.v } {}
416 basic_vector(self_type&& other) : v{ std::move(other.v) } {}
417 template <typename T2>
418 basic_vector(const basic_vector<T2, Size, Type>& other) { std::transform(other.begin(), other.end(), v.begin(), [](T2 source) { return static_cast<value_type>(source); }); }
419 template <typename T2, uint32_t Size2, typename SFINAE = int>
420 basic_vector(const basic_vector<T2, Size2, Type>& other, typename std::enable_if_t < Size2 < Size, SFINAE> = 0) : v{} { std::transform(other.begin(), other.end(), v.begin(), [](T2 source) { return static_cast<value_type>(source); }); }
421 self_type& operator=(const self_type& other) { v = other.v; return *this; }
422 self_type& operator=(self_type&& other) { v = std::move(other.v); return *this; }
423 self_type& operator=(std::initializer_list<value_type> values) { if (values.size() > Size) throw std::out_of_range("neolib::basic_vector: initializer list too big"); std::copy(values.begin(), values.end(), v.begin()); std::fill(v.begin() + (values.end() - values.begin()), v.end(), value_type{}); return *this; }
424 public:
425 static uint32_t size() { return Size; }
426 value_type operator[](uint32_t aIndex) const { return v[aIndex]; }
427 value_type& operator[](uint32_t aIndex) { return v[aIndex]; }
428 const_iterator begin() const { return v.begin(); }
429 const_iterator end() const { return v.end(); }
430 iterator begin() { return v.begin(); }
431 iterator end() { return v.end(); }
432 operator const array_type& () const { return v; }
433 public:
434 template <typename T2>
436 {
437 return basic_vector<T2, Size, Type>{ *this };
438 }
439 public:
440 bool operator==(const self_type& right) const { return v == right.v; }
441 bool operator!=(const self_type& right) const { return v != right.v; }
442 self_type& operator+=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] += value; return *this; }
443 self_type& operator-=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] -= value; return *this; }
444 self_type& operator*=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] *= value; return *this; }
445 self_type& operator/=(value_type value) { for (uint32_t index = 0; index < Size; ++index) v[index] /= value; return *this; }
446 self_type& operator+=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] += right.v[index]; return *this; }
447 self_type& operator-=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] -= right.v[index]; return *this; }
448 self_type& operator*=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] *= right.v[index]; return *this; }
449 self_type& operator/=(const self_type& right) { for (uint32_t index = 0; index < Size; ++index) v[index] /= right.v[index]; return *this; }
450 self_type operator-() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result.v[index] = -v[index]; return result; }
451 self_type scale(const self_type& right) const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = v[index] * right[index]; return result; }
452 value_type magnitude() const { value_type ss = constants::zero<value_type>; for (uint32_t index = 0; index < Size; ++index) ss += (v[index] * v[index]); return std::sqrt(ss); }
453 self_type normalized() const { self_type result; value_type im = constants::one<value_type> / magnitude(); for (uint32_t index = 0; index < Size; ++index) result.v[index] = v[index] * im; return result; }
454 self_type min(const self_type& right) const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::min(v[index], right.v[index]); return result; }
455 self_type max(const self_type& right) const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::max(v[index], right.v[index]); return result; }
456 value_type min() const { value_type result = v[0]; for (uint32_t index = 1; index < Size; ++index) result = std::min(v[index], result); return result; }
457 self_type ceil() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::ceil(v[index]); return result; }
458 self_type floor() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::floor(v[index]); return result; }
459 self_type round() const { self_type result; for (uint32_t index = 0; index < Size; ++index) result[index] = std::round(v[index]); return result; }
460 value_type distance(const self_type& right) const { value_type total = 0; for (uint32_t index = 0; index < Size; ++index) total += ((v[index] - right.v[index]) * (v[index] - right.v[index])); return std::sqrt(total); }
461 value_type dot(const self_type& right) const
462 {
463 value_type result = constants::zero<value_type>;
464 for (uint32_t index = 0; index < Size; ++index)
465 result += (v[index] * right[index]);
466 return result;
467 }
469 {
470 self_type result = *this;
471 result *= right;
472 return result;
473 }
474 public:
475 friend void swap(self_type& a, self_type& b)
476 {
477 using std::swap;
478 swap(a.v, b.v);
479 }
480 public:
481 union
482 {
484 struct // todo: alignment, padding?
485 {
487 };
490 };
491 };
492
493 template <typename T, uint32_t Size, typename Type>
494 inline bool operator==(const basic_vector<T, Size, Type>& aLhs, const basic_vector<T, Size, Type>& aRhs)
495 {
496 return aLhs.v == aRhs.v;
497 }
498
499 template <typename T, uint32_t Size, typename Type>
500 inline bool operator<(const basic_vector<T, Size, Type>& aLhs, const basic_vector<T, Size, Type>& aRhs)
501 {
502 return aLhs.v < aRhs.v;
503 }
504
505 template <typename T, uint32_t Size, typename Type>
506 inline std::partial_ordering operator<=>(const basic_vector<T, Size, Type>& aLhs, const basic_vector<T, Size, Type>& aRhs)
507 {
508 return aLhs.v <=> aRhs.v;
509 }
510
515
516 typedef vector1 vec1;
517 typedef vector2 vec2;
518 typedef vector3 vec3;
519 typedef vector4 vec4;
520
521 typedef vec1 col_vec1;
522 typedef vec2 col_vec2;
523 typedef vec3 col_vec3;
524 typedef vec4 col_vec4;
525
530
535
540
545
550
551 typedef std::vector<vec2> vec2_list;
552 typedef std::vector<vec3> vec3_list;
553
556
559
562
567
572
573 typedef int32_t i32;
574 typedef int64_t i64;
575
580
585
586 typedef uint32_t u32;
587 typedef uint32_t u64;
588
593
598
599 template <std::size_t VertexCount>
601
602 template <std::size_t VertexCount>
604
605 typedef std::array<int8_t, 1> avec1i8;
606 typedef std::array<int8_t, 2> avec2i8;
607 typedef std::array<int8_t, 3> avec3i8;
608 typedef std::array<int8_t, 4> avec4i8;
609
610 typedef std::array<int16_t, 1> avec1i16;
611 typedef std::array<int16_t, 2> avec2i16;
612 typedef std::array<int16_t, 3> avec3i16;
613 typedef std::array<int16_t, 4> avec4i16;
614
615 typedef std::array<int32_t, 1> avec1i32;
616 typedef std::array<int32_t, 2> avec2i32;
617 typedef std::array<int32_t, 3> avec3i32;
618 typedef std::array<int32_t, 4> avec4i32;
619
620 typedef std::array<uint8_t, 1> avec1u8;
621 typedef std::array<uint8_t, 2> avec2u8;
622 typedef std::array<uint8_t, 3> avec3u8;
623 typedef std::array<uint8_t, 4> avec4u8;
624
625 typedef std::array<uint16_t, 1> avec1u16;
626 typedef std::array<uint16_t, 2> avec2u16;
627 typedef std::array<uint16_t, 3> avec3u16;
628 typedef std::array<uint16_t, 4> avec4u16;
629
630 typedef std::array<uint32_t, 1> avec1u32;
631 typedef std::array<uint32_t, 2> avec2u32;
632 typedef std::array<uint32_t, 3> avec3u32;
633 typedef std::array<uint32_t, 4> avec4u32;
634
635 typedef std::array<float, 1> avec1f;
636 typedef std::array<float, 2> avec2f;
637 typedef std::array<float, 3> avec3f;
638 typedef std::array<float, 4> avec4f;
639
640 typedef std::array<double, 1> avec1;
641 typedef std::array<double, 2> avec2;
642 typedef std::array<double, 3> avec3;
643 typedef std::array<double, 4> avec4;
644
645 typedef std::array<vec3, 3> triangle;
646 typedef std::array<vec3, 4> quad;
647
648 typedef std::array<vec2, 3> triangle_2d;
649 typedef std::array<vec2, 4> quad_2d;
650
651 typedef std::array<vec3f, 3> trianglef;
652 typedef std::array<vec3f, 4> quadf;
653
654 typedef std::array<vec2f, 3> trianglef_2d;
655 typedef std::array<vec2f, 4> quadf_2d;
656
657 template <typename T, uint32_t D, typename Type>
659 {
660 basic_vector<T, D, Type> result = left;
661 result += right;
662 return result;
663 }
664
665 template <typename T, uint32_t D, typename Type>
667 {
668 basic_vector<T, D, Type> result = left;
669 result -= right;
670 return result;
671 }
672
673 template <typename T, uint32_t D, typename Type, std::size_t VertexCount>
674 inline std::array<basic_vector<T, D, Type>, VertexCount> operator+(const basic_vector<T, D, Type>& left, const std::array<basic_vector<T, D, Type>, VertexCount>& right)
675 {
676 std::array<basic_vector<T, D, Type>, VertexCount> result = right;
677 for (auto& v : result)
678 v += left;
679 return result;
680 }
681
682 template <typename T, uint32_t D, typename Type, std::size_t VertexCount>
683 inline std::array<basic_vector<T, D, Type>, VertexCount> operator+(const std::array<basic_vector<T, D, Type>, VertexCount>& left, const basic_vector<T, D, Type>& right)
684 {
685 std::array<basic_vector<T, D, Type>, VertexCount> result = left;
686 for (auto& v : result)
687 v += right;
688 return result;
689 }
690
691 template <typename T, uint32_t D, typename Type, std::size_t VertexCount>
692 inline std::array<basic_vector<T, D, Type>, VertexCount>& operator+=(std::array<basic_vector<T, D, Type>, VertexCount>& left, const basic_vector<T, D, Type>& right)
693 {
694 for (auto& v : left)
695 v += right;
696 return left;
697 }
698
699 template <typename T, uint32_t D, typename Type, std::size_t VertexCount>
700 inline std::array<basic_vector<T, D, Type>, VertexCount> operator-(const basic_vector<T, D, Type>& left, const std::array<basic_vector<T, D, Type>, VertexCount>& right)
701 {
702 std::array<basic_vector<T, D, Type>, VertexCount> result = right;
703 for (auto& v : result)
704 v = left - v;
705 return result;
706 }
707
708 template <typename T, uint32_t D, typename Type, std::size_t VertexCount>
709 inline std::array<basic_vector<T, D, Type>, VertexCount> operator-(const std::array<basic_vector<T, D, Type>, VertexCount>& left, const basic_vector<T, D, Type>& right)
710 {
711 std::array<basic_vector<T, D, Type>, VertexCount> result = left;
712 for (auto& v : result)
713 v -= right;
714 return result;
715 }
716
717 template <typename T, uint32_t D, typename Type, std::size_t VertexCount>
718 inline std::array<basic_vector<T, D, Type>, VertexCount>& operator-=(std::array<basic_vector<T, D, Type>, VertexCount>& left, const basic_vector<T, D, Type>& right)
719 {
720 for (auto& v : left)
721 v -= right;
722 return left;
723 }
724
725 template <typename T, uint32_t D, typename Type>
726 inline basic_vector<T, D, Type> operator+(const basic_vector<T, D, Type>& left, const T& right)
727 {
728 basic_vector<T, D, Type> result = left;
729 for (uint32_t i = 0; i < D; ++i)
730 result[i] += right;
731 return result;
732 }
733
734 template <typename T, uint32_t D, typename Type>
735 inline basic_vector<T, D, Type> operator+(const T& left, const basic_vector<T, D, Type>& right)
736 {
737 basic_vector<T, D, Type> result = right;
738 for (uint32_t i = 0; i < D; ++i)
739 result[i] += left;
740 return result;
741 }
742
743 template <typename T, uint32_t D, typename Type>
744 inline basic_vector<T, D, Type> operator-(const basic_vector<T, D, Type>& left, const T& right)
745 {
746 basic_vector<T, D, Type> result = left;
747 for (uint32_t i = 0; i < D; ++i)
748 result[i] -= right;
749 return result;
750 }
751
752 template <typename T, uint32_t D, typename Type>
753 inline basic_vector<T, D, Type> operator-(const T& left, const basic_vector<T, D, Type>& right)
754 {
756 for (uint32_t i = 0; i < D; ++i)
757 result[i] = left - right[i];
758 return result;
759 }
760
761 template <typename T, uint32_t D, typename Type>
762 inline basic_vector<T, D, Type> operator*(const basic_vector<T, D, Type>& left, const T& right)
763 {
764 basic_vector<T, D, Type> result = left;
765 for (uint32_t i = 0; i < D; ++i)
766 result[i] *= right;
767 return result;
768 }
769
770 template <typename T, uint32_t D, typename Type>
771 inline basic_vector<T, D, Type> operator*(const T& left, const basic_vector<T, D, Type>& right)
772 {
773 basic_vector<T, D, Type> result = right;
774 for (uint32_t i = 0; i < D; ++i)
775 result[i] *= left;
776 return result;
777 }
778
779 template <typename T, uint32_t D, typename Type>
780 inline basic_vector<T, D, Type> operator/(const basic_vector<T, D, Type>& left, const T& right)
781 {
782 basic_vector<T, D, Type> result = left;
783 for (uint32_t i = 0; i < D; ++i)
784 result[i] /= right;
785 return result;
786 }
787
788 template <typename T, uint32_t D, typename Type>
789 inline basic_vector<T, D, Type> operator/(const T& left, const basic_vector<T, D, Type>& right)
790 {
792 for (uint32_t i = 0; i < D; ++i)
793 result[i] = left / right[i];
794 return result;
795 }
796
797 template <typename T, uint32_t D, typename Type>
799 {
801 for (uint32_t i = 0; i < D; ++i)
802 result[i] = std::fmod(left[i], right);
803 return result;
804 }
805
806 template <typename T, uint32_t D>
807 inline T operator*(const basic_vector<T, D, row_vector>& left, const basic_vector<T, D, column_vector>& right)
808 {
809 T result = {};
810 for (uint32_t index = 0; index < D; ++index)
811 result += (left[index] * right[index]);
812 return result;
813 }
814
815 template <typename T, typename Type>
817 {
818 return basic_vector<T, 3, Type>{ left[0] + right[0], left[1] + right[1], left[2] + right[2] };
819 }
820
821 template <typename T, typename Type>
823 {
824 return basic_vector<T, 3, Type>{ left[0] - right[0], left[1] - right[1], left[2] - right[2] };
825 }
826
827 template <typename T, typename Type>
828 inline basic_vector<T, 3, Type> operator+(const basic_vector<T, 3, Type>& left, const T& right)
829 {
830 return basic_vector<T, 3, Type>{ left[0] + right, left[1] + right, left[2] + right };
831 }
832
833 template <typename T, typename Type>
834 inline basic_vector<T, 3, Type> operator+(const T& left, const basic_vector<T, 3, Type>& right)
835 {
836 return basic_vector<T, 3, Type>{ left + right[0], left + right[1], left + right[2] };
837 }
838
839 template <typename T, typename Type>
840 inline basic_vector<T, 3, Type> operator-(const basic_vector<T, 3, Type>& left, const T& right)
841 {
842 return basic_vector<T, 3, Type>{ left[0] - right, left[1] - right, left[2] - right };
843 }
844
845 template <typename T, typename Type>
846 inline basic_vector<T, 3, Type> operator-(const T& left, const basic_vector<T, 3, Type>& right)
847 {
848 return basic_vector<T, 3, Type>{ left - right[0], left - right[1], left - right[2] };
849 }
850
851 template <typename T, typename Type>
852 inline basic_vector<T, 3, Type> operator*(const basic_vector<T, 3, Type>& left, const T& right)
853 {
854 return basic_vector<T, 3, Type>{ left[0] * right, left[1] * right, left[2] * right };
855 }
856
857 template <typename T, typename Type>
858 inline basic_vector<T, 3, Type> operator*(const T& left, const basic_vector<T, 3, Type>& right)
859 {
860 return basic_vector<T, 3, Type>{ left * right[0], left * right[1], left * right[2] };
861 }
862
863 template <typename T, typename Type>
864 inline basic_vector<T, 3, Type> operator/(const basic_vector<T, 3, Type>& left, const T& right)
865 {
866 return basic_vector<T, 3, Type>{ left[0] / right, left[1] / right, left[2] / right };
867 }
868
869 template <typename T, typename Type>
871 {
872 return basic_vector<T, 3, Type>{ std::fmod(left[0], right), std::fmod(left[1], right), std::fmod(left[2], right) };
873 }
874
875 template <typename T>
876 inline T operator*(const basic_vector<T, 3, row_vector>& left, const basic_vector<T, 3, column_vector>& right)
877 {
878 return left[0] * right[0] + left[1] * right[1] + left[2] * right[2];
879 }
880
881 template <typename T, typename Type>
883 {
884 return (left + right) / constants::two<T>;
885 }
886
887 template <typename T, uint32_t Size, typename Type>
889 {
891 for (uint32_t i = 0; i < Size; ++i)
892 {
893 double x1 = aV1[i];
894 double x2 = aV2[i];
895 result[i] = static_cast<T>((x2 - x1) * aAmount + x1);
896 }
897 return result;
898 }
899
900 /* todo: specializations that use SIMD intrinsics. */
901 template <typename T, uint32_t Rows, uint32_t Columns>
903 {
904 typedef basic_matrix<T, Rows, Columns> self_type;
905 public:
906 typedef self_type abstract_type; // todo: abstract base
907 public:
908 typedef T value_type;
911 typedef std::array<column_type, Columns> array_type;
912 public:
913 template <typename T2>
915 public:
916 basic_matrix() : m{ {} } {}
917 basic_matrix(std::initializer_list<std::initializer_list<value_type>> aColumns) { std::copy(aColumns.begin(), aColumns.end(), m.begin()); }
918 basic_matrix(const self_type& other) : m{ other.m }, isIdentity{ other.isIdentity } {}
919 basic_matrix(self_type&& other) : m{ std::move(other.m) }, isIdentity{ other.isIdentity } {}
920 template <typename T2>
922 {
923 for (uint32_t column = 0; column < Columns; ++column)
924 for (uint32_t row = 0; row < Rows; ++row)
925 (*this)[column][row] = static_cast<value_type>(other[column][row]);
926 isIdentity = other.maybe_identity();
927 }
928 self_type& operator=(const self_type& other) { m = other.m; isIdentity = other.isIdentity; return *this; }
929 self_type& operator=(self_type&& other) { m = std::move(other.m); isIdentity = other.isIdentity; return *this; }
930 public:
931 template <typename T2>
936 public:
937 std::pair<uint32_t, uint32_t> size() const { return std::make_pair(Rows, Columns); }
938 const column_type& operator[](uint32_t aColumn) const { return m[aColumn]; }
939 column_type& operator[](uint32_t aColumn) { isIdentity = std::nullopt; return m[aColumn]; }
940 const value_type* data() const { return &m[0].v[0]; }
941 public:
942 bool operator==(const self_type& right) const { return m == right.m; }
943 bool operator!=(const self_type& right) const { return m != right.m; }
944 self_type& operator+=(const self_type& right) { for (uint32_t column = 0; column < Columns; ++column) (*this)[column] += right[column]; return *this; }
945 self_type& operator-=(const self_type& right) { for (uint32_t column = 0; column < Columns; ++column) (*this)[column] -= right[column]; return *this; }
946 self_type& operator*=(const self_type& right)
947 {
948 self_type result;
949 for (uint32_t column = 0; column < Columns; ++column)
950 for (uint32_t row = 0; row < Rows; ++row)
951 for (uint32_t index = 0; index < Columns; ++index)
952 result[column][row] += ((*this)[index][row] * right[column][index]);
953 *this = result;
954 return *this;
955 }
956 self_type operator-() const
957 {
958 self_type result = *this;
959 for (uint32_t column = 0; column < Columns; ++column)
960 for (uint32_t row = 0; row < Rows; ++row)
961 result[column][row] = -result[column][row];
962 return result;
963 }
964 self_type round_to(value_type aEpsilon) const
965 {
966 self_type result;
967 for (uint32_t column = 0; column < Columns; ++column)
968 for (uint32_t row = 0; row < Rows; ++row)
969 {
970 std::modf((*this)[column][row] / aEpsilon + 0.5, &result[column][row]);
971 result[column][row] *= aEpsilon;
972 }
973 return result;
974 }
976 {
978 for (uint32_t column = 0; column < Columns; ++column)
979 for (uint32_t row = 0; row < Rows; ++row)
980 result[row][column] = (*this)[column][row];
981 return result;
982 }
983 template <typename SFINAE = self_type>
984 static const std::enable_if_t<Rows == Columns, SFINAE>& identity()
985 {
986 auto make_identity = []()
987 {
988 self_type result;
989 for (uint32_t diag = 0; diag < Rows; ++diag)
990 result[diag][diag] = static_cast<value_type>(1.0);
991 result.isIdentity = true;
992 return result;
993 };
994 static self_type const sIdentity = make_identity();
995 return sIdentity;
996 }
997 bool is_identity() const
998 {
999 if (isIdentity)
1000 return *isIdentity;
1001 else
1002 return *(isIdentity = ((*this) == identity()));
1003 }
1004 const std::optional<bool>& maybe_identity() const
1005 {
1006 return isIdentity;
1007 }
1008 public:
1009 friend void swap(self_type& a, self_type& b)
1010 {
1011 using std::swap;
1012 swap(a.m, b.m);
1013 swap(a.isIdentity, b.isIdentity);
1014 }
1015 private:
1016 array_type m;
1017 mutable std::optional<bool> isIdentity;
1018 };
1019
1036
1041
1058
1059 typedef mat11 mat1;
1060 typedef mat22 mat2;
1061 typedef mat33 mat3;
1062 typedef mat44 mat4;
1063
1080
1085
1102
1107
1124
1141
1146
1163
1168
1185
1190
1191 template <typename T, uint32_t Rows, uint32_t Columns>
1193 {
1194 basic_matrix<T, Rows, Columns> result = left;
1195 result += right;
1196 return result;
1197 }
1198
1199 template <typename T, uint32_t Rows, uint32_t Columns>
1201 {
1202 basic_matrix<T, Rows, Columns> result = left;
1203 result -= right;
1204 return result;
1205 }
1206
1207 template <typename T, uint32_t Rows, uint32_t Columns>
1209 {
1210 basic_matrix<T, Rows, Columns> result = left;
1211 result *= right;
1212 return result;
1213 }
1214
1215 template <typename T, uint32_t Rows, uint32_t Columns>
1217 {
1218 basic_matrix<T, Rows, Columns> result = left;
1219 result /= right;
1220 return result;
1221 }
1222
1223 template <typename T, uint32_t Rows, uint32_t Columns>
1225 {
1226 basic_matrix<T, Rows, Columns> result = right;
1227 result += left;
1228 return result;
1229 }
1230
1231 template <typename T, uint32_t Rows, uint32_t Columns>
1233 {
1234 return -right + left;
1235 }
1236
1237 template <typename T, uint32_t Rows, uint32_t Columns>
1239 {
1240 basic_matrix<T, Rows, Columns> result = right;
1241 result *= left;
1242 return result;
1243 }
1244
1245 template <typename T, uint32_t Rows, uint32_t Columns>
1247 {
1248 basic_matrix<T, Rows, Columns> result = left;
1249 result += right;
1250 return result;
1251 }
1252
1253 template <typename T, uint32_t Rows, uint32_t Columns>
1255 {
1256 basic_matrix<T, Rows, Columns> result = left;
1257 result -= right;
1258 return result;
1259 }
1260
1261 template <typename T, uint32_t D1, uint32_t D2>
1263 {
1264 if (left.is_identity())
1265 return right;
1266 if (right.is_identity())
1267 return left;
1269 for (uint32_t column = 0u; column < D1; ++column)
1270 for (uint32_t row = 0u; row < D1; ++row)
1271 for (uint32_t index = 0; index < D2; ++index)
1272 result[column][row] += (left[index][row] * right[column][index]);
1273 return result;
1274 }
1275
1276 template <typename T>
1278 {
1279 if (left.is_identity())
1280 return right;
1281 if (right.is_identity())
1282 return left;
1284 for (uint32_t column = 0u; column < 4u; ++column)
1285 for (uint32_t row = 0u; row < 4u; ++row)
1286 result[column][row] = simd_fma_4d(left[0u][row], right[column][0u], left[1u][row], right[column][1u], left[2u][row], right[column][2u], left[3u][row], right[column][3u]);
1287 return result;
1288 }
1289
1290 template <typename T, uint32_t D>
1292 {
1293 if (left.is_identity())
1294 return right;
1296 for (uint32_t row = 0; row < D; ++row)
1297 for (uint32_t index = 0; index < D; ++index)
1298 result[row] += (left[index][row] * right[index]);
1299 return result;
1300 }
1301
1302 template <typename T, uint32_t D, std::size_t VertexCount>
1303 inline std::array<basic_vector<T, D, column_vector>, VertexCount> operator*(const basic_matrix<T, D, D>& left, const std::array<basic_vector<T, D, column_vector>, VertexCount>& right)
1304 {
1305 if (left.is_identity())
1306 return right;
1307 std::array<basic_vector<T, D, column_vector>, VertexCount> result;
1308 for (std::size_t vector = 0; vector < VertexCount; ++vector)
1309 result[vector] = left * right[vector];
1310 return result;
1311 }
1312
1313 template <typename T>
1315 {
1316 if (left.is_identity())
1317 return right;
1319 for (uint32_t row = 0u; row < 4u; ++row)
1320 result[row] = simd_fma_4d(left[0][row], right[0], left[1][row], right[1], left[2][row], right[2], left[3][row], right[3]);
1321 return result;
1322 }
1323
1324 template <typename T, std::size_t VertexCount>
1325 inline std::array<basic_vector<T, 4u, column_vector>, VertexCount> operator*(const basic_matrix<T, 4u, 4u>& left, const std::array<basic_vector<T, 4u, column_vector>, VertexCount>& right)
1326 {
1327 if (left.is_identity())
1328 return right;
1329 std::array<basic_vector<T, 4u, column_vector>, VertexCount> result;
1330 for (std::size_t vector = 0; vector < VertexCount; ++vector)
1331 result[vector] = left * right[vector];
1332 return result;
1333 }
1334
1335 template <typename T, uint32_t D>
1337 {
1338 if (right.is_identity())
1339 return left;
1341 for (uint32_t column = 0; column < D; ++column)
1342 for (uint32_t index = 0; index < D; ++index)
1343 result[column] += (left[index] * right[column][index]);
1344 return result;
1345 }
1346
1347 template <typename T, uint32_t D, std::size_t VertexCount>
1348 inline std::array<basic_vector<T, D, row_vector>, VertexCount> operator*(const std::array<basic_vector<T, D, row_vector>, VertexCount>& left, const basic_matrix<T, D, D>& right)
1349 {
1350 if (right.is_identity())
1351 return left;
1352 std::array<basic_vector<T, D, row_vector>, VertexCount> result;
1353 for (std::size_t vector = 0; vector < VertexCount; ++vector)
1354 result[vector] = left[vector] * right;
1355 return result;
1356 }
1357
1358 template <typename T>
1360 {
1361 if (right.is_identity())
1362 return left;
1364 for (uint32_t column = 0u; column < 4u; ++column)
1365 result[column] = simd_fma_4d(left[0], right[column][0], left[1], right[column][1], left[2], right[column][2], left[3], right[column][3]);
1366 return result;
1367 }
1368
1369 template <typename T, std::size_t VertexCount>
1370 inline basic_vector<T, 4u, row_vector> operator*(const std::array<basic_vector<T, 4u, row_vector>, VertexCount>& left, const basic_matrix<T, 4u, 4u>& right)
1371 {
1372 if (right.is_identity())
1373 return left;
1374 std::array<basic_vector<T, 4u, row_vector>, VertexCount> result;
1375 for (std::size_t vector = 0; vector < VertexCount; ++vector)
1376 result[vector] = left[vector] * right;
1377 return result;
1378 }
1379
1380 template <typename T, uint32_t D>
1382 {
1383 basic_matrix<T, D, D> result;
1384 for (uint32_t column = 0; column < D; ++column)
1385 for (uint32_t row = 0; row < D; ++row)
1386 result[column][row] = (left[row] * right[column]);
1387 return result;
1388 }
1389
1390 template <typename T>
1392 {
1394 for (uint32_t column = 0; column < 4u; ++column)
1395 simd_mul_4d(left[0u], right[column], left[1u], right[column], left[2u], right[column], left[3u], right[column], result[column][0u], result[column][1u], result[column][2u], result[column][3u]);
1396 return result;
1397 }
1398
1399 template <typename T, uint32_t D>
1401 {
1402 auto result = matrix;
1403 for (uint32_t row = 0; row < D - 1; ++row)
1404 result[D - 1][row] = 0.0;
1405 return result;
1406 }
1407
1408 template <typename Elem, typename Traits, typename T, uint32_t Size, typename Type>
1409 inline std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& aStream, const basic_vector<T, Size, Type>& aVector)
1410 {
1411 aStream << "[";
1412 for (uint32_t i = 0; i < Size; ++i)
1413 {
1414 if (i != 0)
1415 aStream << ", ";
1416 aStream << aVector[i];
1417 }
1418 aStream << "]";
1419 return aStream;
1420 }
1421
1422 template <typename Elem, typename Traits, typename T, uint32_t Size, typename Type>
1423 inline std::basic_istream<Elem, Traits>& operator>>(std::basic_istream<Elem, Traits>& aStream, basic_vector<T, Size, Type>& aVector)
1424 {
1425 auto previousImbued = aStream.getloc();
1426 if (typeid(std::use_facet<std::ctype<char>>(previousImbued)) != typeid(neolib::comma_and_brackets_as_whitespace))
1427 aStream.imbue(std::locale{ previousImbued, new neolib::comma_and_brackets_as_whitespace{} });
1428 for (uint32_t i = 0; i < Size; ++i)
1429 aStream >> aVector[i];
1430 aStream.imbue(previousImbued);
1431 return aStream;
1432 }
1433
1434 template <typename Elem, typename Traits, typename T, uint32_t Rows, uint32_t Columns>
1435 inline std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& aStream, const basic_matrix<T, Rows, Columns>& aMatrix)
1436 {
1437 aStream << "[";
1438 for (uint32_t row = 0; row < Rows; ++row)
1439 {
1440 if (row != 0)
1441 aStream << ", ";
1442 aStream << "[";
1443 for (uint32_t column = 0; column < Columns; ++column)
1444 {
1445 if (column != 0)
1446 aStream << ", ";
1447 aStream << aMatrix[column][row];
1448 }
1449 aStream << "]";
1450 }
1451 aStream << "]";
1452 return aStream;
1453 }
1454
1455 template <typename Elem, typename Traits, typename T, uint32_t Rows, uint32_t Columns>
1456 inline std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& aStream, const optional<basic_matrix<T, Rows, Columns>>& aMatrix)
1457 {
1458 if (aMatrix != std::nullopt)
1459 aStream << *aMatrix;
1460 else
1461 aStream << "[null]";
1462 return aStream;
1463 }
1464
1465 template <typename Elem, typename Traits, typename T, uint32_t Rows, uint32_t Columns>
1466 inline std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& aStream, const std::optional<basic_matrix<T, Rows, Columns>>& aMatrix)
1467 {
1468 if (aMatrix != std::nullopt)
1469 aStream << *aMatrix;
1470 else
1471 aStream << "[null]";
1472 return aStream;
1473 }
1474
1475 // 3D helpers
1476
1477 template <typename T>
1479 {
1480 if (left.is_identity())
1481 return right;
1483 for (uint32_t row = 0u; row < 3u; ++row)
1484 result[row] = static_cast<T>(simd_fma_4d(left[0][row], right[0], left[1][row], right[1], left[2][row], right[2], left[3][row], 1.0));
1485 return result;
1486 }
1487
1488 template <typename T>
1489 inline std::vector<basic_vector<T, 3u, column_vector>> operator*(const basic_matrix<T, 4u, 4u>& left, const std::vector<basic_vector<T, 3u, column_vector>>& right)
1490 {
1491 if (left.is_identity())
1492 return right;
1493 std::vector<basic_vector<T, 3u, column_vector>> result;
1494 result.reserve(right.size());
1495 for (auto const& v : right)
1496 result.push_back(left * v);
1497 return result;
1498 }
1499
1500 inline mat33 rotation_matrix(const vec3& axis, scalar angle, scalar epsilon = 0.00001)
1501 {
1502 if (std::abs(angle) <= epsilon)
1503 return mat33::identity();
1504 else if (std::abs(angle - boost::math::constants::pi<scalar>()) <= epsilon)
1505 return -mat33::identity();
1506 scalar const s = std::sin(angle);
1507 scalar const c = std::cos(angle);
1508 scalar const a = 1.0 - c;
1509 scalar const ax = a * axis.x;
1510 scalar const ay = a * axis.y;
1511 scalar const az = a * axis.z;
1512 return mat33{
1513 { ax * axis.x + c, ax * axis.y + axis.z * s, ax * axis.z - axis.y * s },
1514 { ay * axis.x - axis.z * s, ay * axis.y + c, ay * axis.z + axis.x * s },
1515 { az * axis.x + axis.y * s, az * axis.y - axis.x * s, az * axis.z + c } }.round_to(epsilon);
1516 }
1517
1518 inline mat33 rotation_matrix(const vec3& vectorA, const vec3& vectorB, scalar epsilon = 0.00001)
1519 {
1520 auto const nva = vectorA.normalized();
1521 auto const nvb = vectorB.normalized();
1522 return rotation_matrix(nva.cross(nvb).normalized(), std::acos(nva.dot(nvb)), epsilon);
1523 }
1524
1525 inline mat33 rotation_matrix(const vec3& angles)
1526 {
1527 scalar ax = angles.x;
1528 scalar ay = angles.y;
1529 scalar az = angles.z;
1530 if (ax != 0.0 || ay != 0.0)
1531 {
1532 mat33 rx = { { 1.0, 0.0, 0.0 },{ 0.0, std::cos(ax), std::sin(ax) },{ 0.0, -std::sin(ax), std::cos(ax) } };
1533 mat33 ry = { { std::cos(ay), 0.0, -std::sin(ay) },{ 0.0, 1.0, 0.0 },{ std::sin(ay), 0.0, std::cos(ay) } };
1534 mat33 rz = { { std::cos(az), std::sin(az), 0.0 },{ -std::sin(az), std::cos(az), 0.0 },{ 0.0, 0.0, 1.0 } };
1535 return rz * ry * rx;
1536 }
1537 else
1538 {
1539 return mat33{ { std::cos(az), std::sin(az), 0.0 },{ -std::sin(az), std::cos(az), 0.0 },{ 0.0, 0.0, 1.0 } };
1540 }
1541 }
1542
1543 inline mat44 affine_rotation_matrix(const vec3& angles)
1544 {
1545 scalar ax = angles.x;
1546 scalar ay = angles.y;
1547 scalar az = angles.z;
1548 if (ax != 0.0 || ay != 0.0)
1549 {
1550 mat44 rx = { { 1.0, 0.0, 0.0, 0.0 },{ 0.0, std::cos(ax), std::sin(ax), 0.0 },{ 0.0, -std::sin(ax), std::cos(ax), 0.0 },{0.0, 0.0, 0.0, 1.0} };
1551 mat44 ry = { { std::cos(ay), 0.0, -std::sin(ay), 0.0 },{ 0.0, 1.0, 0.0, 0.0 },{ std::sin(ay), 0.0, std::cos(ay), 0.0 },{0.0, 0.0, 0.0, 1.0} };
1552 mat44 rz = { { std::cos(az), std::sin(az), 0.0, 0.0 },{ -std::sin(az), std::cos(az), 0.0, 0.0 },{ 0.0, 0.0, 1.0, 0.0 },{0.0, 0.0, 0.0, 1.0} };
1553 return rz * ry * rx;
1554 }
1555 else
1556 {
1557 return mat44{ { std::cos(az), std::sin(az), 0.0, 0.0 },{ -std::sin(az), std::cos(az), 0.0, 0.0 },{ 0.0, 0.0, 1.0, 0.0 },{0.0, 0.0, 0.0, 1.0} };
1558 }
1559 }
1560
1561 inline mat44& apply_translation(mat44& aMatrix, const vec3& aTranslation)
1562 {
1563 // todo: SIMD
1564 aMatrix[3][0] += aTranslation.x;
1565 aMatrix[3][1] += aTranslation.y;
1566 aMatrix[3][2] += aTranslation.z;
1567 return aMatrix;
1568 }
1569
1570 inline mat44& apply_scaling(mat44& aMatrix, const vec3& aScaling)
1571 {
1572 // todo: SIMD
1573 aMatrix[0][0] *= aScaling.x;
1574 aMatrix[1][1] *= aScaling.y;
1575 aMatrix[2][2] *= aScaling.z;
1576 return aMatrix;
1577 }
1578
1579 // Function
1580
1581 template <typename T>
1582 inline bool nearly_equal(T lhs, T rhs, scalar epsilon = 0.00001, std::enable_if_t<std::is_floating_point_v<T>, sfinae> = {})
1583 {
1584 return static_cast<double>(std::abs(lhs - rhs)) < epsilon;
1585 }
1586 template <typename T>
1587 inline bool nearly_equal(T lhs, T rhs, scalar epsilon = 0.00001, std::enable_if_t<std::is_integral_v<T>, sfinae> = {})
1588 {
1589 return lhs == rhs;
1590 }
1591 template <typename T, uint32_t Size, typename Type = column_vector>
1592 inline bool nearly_equal(basic_vector<T, Size, Type> const& lhs, basic_vector<T, Size, Type> const& rhs, scalar epsilon = 0.00001)
1593 {
1594 for (uint32_t index = 0; index < Size; ++index)
1595 if (!nearly_equal(lhs[index], rhs[index], epsilon))
1596 return false;
1597 return true;
1598 }
1599 template <typename T>
1600 inline bool nearly_equal(optional<T> const& lhs, optional<T> const& rhs, scalar epsilon = 0.00001)
1601 {
1602 if (!!lhs != !!rhs)
1603 return false;
1604 if (!lhs)
1605 return true;
1606 return nearly_equal(*lhs, *rhs, epsilon);
1607 }
1608 template <typename T>
1609 inline bool nearly_equal(std::optional<T> const& lhs, std::optional<T> const& rhs, scalar epsilon = 0.00001)
1610 {
1611 if (!!lhs != !!rhs)
1612 return false;
1613 if (!lhs)
1614 return true;
1615 return nearly_equal(*lhs, *rhs, epsilon);
1616 }
1617 template <typename T1, typename T2>
1618 inline bool nearly_equal(std::pair<T1, T2> const& lhs, std::pair<T1, T2> const& rhs, scalar epsilon = 0.00001)
1619 {
1620 return nearly_equal(lhs.first, rhs.first, epsilon) && nearly_equal(lhs.second, rhs.second, epsilon);
1621 }
1622 template <typename T>
1623 inline bool nearly_equal(std::vector<T> const& lhs, std::vector<T> const& rhs, scalar epsilon = 0.00001)
1624 {
1625 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(),
1626 [epsilon](auto const& lhs, auto const& rhs) { return nearly_equal(lhs, rhs, epsilon); });
1627 }
1628
1629 template <typename T, std::size_t D>
1631 {
1632 return basic_vector<T, D>{
1633 (aQuad[1].distance(aQuad[0]) + aQuad[3].distance(aQuad[2])) / static_cast<T>(2.0),
1634 (aQuad[0].distance(aQuad[3]) + aQuad[1].distance(aQuad[2])) / static_cast<T>(2.0)
1635 };
1636 }
1637
1638 // AABB
1639
1640 struct aabb
1641 {
1643
1646 aabb() : min{}, max{} {}
1647 aabb(const vec3& aMin, const vec3& aMax) : min{ aMin }, max{ aMax } {}
1648 };
1649
1650 inline vec3 aabb_origin(const aabb& aAabb)
1651 {
1652 return aAabb.min + (aAabb.max - aAabb.min) / 2.0;
1653 }
1654
1655 inline vec3 aabb_extents(const aabb& aAabb)
1656 {
1657 return aAabb.max - aAabb.min;
1658 }
1659
1660 template <typename... Transforms>
1661 inline aabb aabb_transform(const aabb& aAabb, const Transforms&... aTransforms)
1662 {
1663 std::array<vec3, 8> boxVertices =
1664 {
1665 (aTransforms * ... * vec3{ aAabb.min.x, aAabb.min.y, aAabb.min.z }),
1666 (aTransforms * ... * vec3{ aAabb.max.x, aAabb.min.y, aAabb.min.z }),
1667 (aTransforms * ... * vec3{ aAabb.min.x, aAabb.max.y, aAabb.min.z }),
1668 (aTransforms * ... * vec3{ aAabb.max.x, aAabb.max.y, aAabb.min.z }),
1669 (aTransforms * ... * vec3{ aAabb.min.x, aAabb.min.y, aAabb.max.z }),
1670 (aTransforms * ... * vec3{ aAabb.max.x, aAabb.min.y, aAabb.max.z }),
1671 (aTransforms * ... * vec3{ aAabb.min.x, aAabb.max.y, aAabb.max.z }),
1672 (aTransforms * ... * vec3{ aAabb.max.x, aAabb.max.y, aAabb.max.z })
1673 };
1674 aabb result{ boxVertices[0], boxVertices[0] };
1675 for (auto const& v : boxVertices)
1676 {
1677 result.min = result.min.min(v);
1678 result.max = result.max.max(v);
1679 }
1680 return result;
1681 }
1682
1683 inline aabb to_aabb(const vec3& aOrigin, scalar aSize)
1684 {
1685 return aabb{ aOrigin - aSize / 2.0, aOrigin + aSize / 2.0 };
1686 }
1687
1688 inline aabb to_aabb(const vec3& aOrigin, const vec3& aSize)
1689 {
1690 return aabb{ aOrigin - aSize / 2.0, aOrigin + aSize / 2.0 };
1691 }
1692
1693 template <typename VertexIter>
1694 inline aabb to_aabb(VertexIter aBegin, VertexIter aEnd, const mat44& aTransformation = mat44::identity())
1695 {
1696 if (aBegin == aEnd)
1697 return aabb_transform(aabb{}, aTransformation);
1698 aabb result{ aBegin->xyz, aBegin->xyz };
1699 for (auto i = std::next(aBegin); i != aEnd; ++i)
1700 {
1701 result.min = result.min.min(i->xyz);
1702 result.max = result.max.max(i->xyz);
1703 }
1704 return aabb_transform(result, aTransformation);
1705 }
1706
1707 inline aabb to_aabb(const vertices& aVertices, const mat44& aTransformation = mat44::identity())
1708 {
1709 return to_aabb(aVertices.begin(), aVertices.end(), aTransformation);
1710 }
1711
1712 inline bool operator==(const aabb& left, const aabb& right)
1713 {
1714 return left.min == right.min && left.max == right.max;
1715 }
1716
1717 inline bool operator<(const aabb& left, const aabb& right)
1718 {
1719 return std::forward_as_tuple(left.min.z, left.min.y, left.min.x, left.max.z, left.max.y, left.max.x) <
1720 std::forward_as_tuple(right.min.z, right.min.y, right.min.x, right.max.z, right.max.y, right.max.x);
1721 }
1722
1723 inline std::partial_ordering operator<=>(const aabb& left, const aabb& right)
1724 {
1725 return std::forward_as_tuple(left.min.z, left.min.y, left.min.x, left.max.z, left.max.y, left.max.x) <=>
1726 std::forward_as_tuple(right.min.z, right.min.y, right.min.x, right.max.z, right.max.y, right.max.x);
1727 }
1728
1730
1731 inline aabb aabb_union(const aabb& left, const aabb& right)
1732 {
1733 return aabb{ left.min.min(right.min), left.max.max(right.max) };
1734 }
1735
1736 inline scalar aabb_volume(const aabb& a)
1737 {
1738 auto extents = a.max - a.min;
1739 return extents.x * extents.y * (extents.z != 0.0 ? extents.z : 1.0);
1740 }
1741
1742 inline bool aabb_contains(const aabb& outer, const aabb& inner)
1743 {
1744 return inner.min >= outer.min && inner.max <= outer.max;
1745 }
1746
1747 inline bool aabb_contains(const aabb& outer, const vec3& point)
1748 {
1749 return point >= outer.min && point <= outer.max;
1750 }
1751
1752 inline bool aabb_intersects(const aabb& first, const aabb& second)
1753 {
1754 if (first.max.x < second.min.x)
1755 return false;
1756 if (first.min.x > second.max.x)
1757 return false;
1758 if (first.max.y < second.min.y)
1759 return false;
1760 if (first.min.y > second.max.y)
1761 return false;
1762 if (first.max.z < second.min.z)
1763 return false;
1764 if (first.min.z > second.max.z)
1765 return false;
1766 return true;
1767 }
1768
1769 inline bool aabb_intersects(const optional<aabb>& first, const std::optional<aabb>& second)
1770 {
1771 if (first == std::nullopt || second == std::nullopt)
1772 return false;
1773 return aabb_intersects(*first, *second);
1774 }
1775
1776 inline bool aabb_intersects(const optional<aabb>& first, const aabb& second)
1777 {
1778 if (first == std::nullopt)
1779 return false;
1780 return aabb_intersects(*first, second);
1781 }
1782
1783 inline bool aabb_intersects(const aabb& first, const std::optional<aabb>& second)
1784 {
1785 if (second == std::nullopt)
1786 return false;
1787 return aabb_intersects(first, *second);
1788 }
1789
1790 struct aabb_2d
1791 {
1793
1796 aabb_2d() : min{}, max{} {}
1797 aabb_2d(const vec2& aMin, const vec2& aMax) : min{ aMin }, max{ aMax } {}
1798 aabb_2d(const aabb& aAabb) : min{ aAabb.min.xy }, max{ aAabb.max.xy } {}
1799 };
1800
1801 inline vec2 aabb_origin(const aabb_2d& aAabb)
1802 {
1803 return aAabb.min + (aAabb.max - aAabb.min) / 2.0;
1804 }
1805
1806 inline vec2 aabb_extents(const aabb_2d& aAabb)
1807 {
1808 return aAabb.max - aAabb.min;
1809 }
1810
1811 template <typename... Transforms>
1812 inline aabb_2d aabb_transform(const aabb_2d& aAabb, const Transforms&... aTransforms)
1813 {
1814 std::array<vec3, 4> boxVertices =
1815 {
1816 (aTransforms * ... * vec3{ aAabb.min.x, aAabb.min.y, 0.0 }),
1817 (aTransforms * ... * vec3{ aAabb.max.x, aAabb.min.y, 0.0 }),
1818 (aTransforms * ... * vec3{ aAabb.min.x, aAabb.max.y, 0.0 }),
1819 (aTransforms * ... * vec3{ aAabb.max.x, aAabb.max.y, 0.0 })
1820 };
1821 aabb_2d result{ boxVertices[0].xy, boxVertices[0].xy };
1822 for (auto const& v : boxVertices)
1823 {
1824 result.min = result.min.min(v.xy);
1825 result.max = result.max.max(v.xy);
1826 }
1827 return result;
1828 }
1829
1830 inline aabb_2d to_aabb_2d(const vec3& aOrigin, scalar aSize)
1831 {
1832 return aabb_2d{ (aOrigin - aSize / 2.0).xy, (aOrigin + aSize / 2.0).xy };
1833 }
1834
1835 inline aabb_2d to_aabb_2d(const vec3& aOrigin, const vec3& aSize)
1836 {
1837 return aabb_2d{ (aOrigin - aSize / 2.0).xy, (aOrigin + aSize / 2.0).xy };
1838 }
1839
1840 template <typename VertexIter>
1841 inline aabb_2d to_aabb_2d(VertexIter aBegin, VertexIter aEnd, const mat44& aTransformation = mat44::identity())
1842 {
1843 if (aBegin == aEnd)
1844 return aabb_transform(aabb_2d{}, aTransformation);
1845 aabb_2d result{ aBegin->xy, aBegin->xy };
1846 for (auto i = std::next(aBegin); i != aEnd; ++i)
1847 {
1848 result.min = result.min.min(i->xy);
1849 result.max = result.max.max(i->xy);
1850 }
1851 return aabb_transform(result, aTransformation);
1852 }
1853
1854 inline aabb_2d to_aabb_2d(const vertices& aVertices, const mat44& aTransformation = mat44::identity())
1855 {
1856 return to_aabb_2d(aVertices.begin(), aVertices.end(), aTransformation);
1857 }
1858
1859 inline bool operator==(const aabb_2d& left, const aabb_2d& right)
1860 {
1861 return left.min == right.min && left.max == right.max;
1862 }
1863
1864 inline bool operator<(const aabb_2d& left, const aabb_2d& right)
1865 {
1866 return std::forward_as_tuple(left.min.y, left.min.x, left.max.y, left.max.x) <
1867 std::forward_as_tuple(right.min.y, right.min.x, right.max.y, right.max.x);
1868 }
1869
1870 inline std::partial_ordering operator<=>(const aabb_2d& left, const aabb_2d& right)
1871 {
1872 return std::forward_as_tuple(left.min.y, left.min.x, left.max.y, left.max.x) <=>
1873 std::forward_as_tuple(right.min.y, right.min.x, right.max.y, right.max.x);
1874 }
1875
1877
1878 inline aabb_2d aabb_union(const aabb_2d& left, const aabb_2d& right)
1879 {
1880 return aabb_2d{ left.min.min(right.min), left.max.max(right.max) };
1881 }
1882
1883 inline scalar aabb_volume(const aabb_2d& a)
1884 {
1885 auto extents = a.max - a.min;
1886 return extents.x * extents.y;
1887 }
1888
1889 inline bool aabb_contains(const aabb_2d& outer, const aabb_2d& inner)
1890 {
1891 return inner.min >= outer.min && inner.max <= outer.max;
1892 }
1893
1894 inline bool aabb_contains(const aabb_2d& outer, const vec2& point)
1895 {
1896 return point >= outer.min && point <= outer.max;
1897 }
1898
1899 inline bool aabb_intersects(const aabb_2d& first, const aabb_2d& second)
1900 {
1901 if (first.max.x < second.min.x)
1902 return false;
1903 if (first.min.x > second.max.x)
1904 return false;
1905 if (first.max.y < second.min.y)
1906 return false;
1907 if (first.min.y > second.max.y)
1908 return false;
1909 return true;
1910 }
1911
1912 inline bool aabb_intersects(const optional<aabb_2d>& first, const std::optional<aabb_2d>& second)
1913 {
1914 if (first == std::nullopt || second == std::nullopt)
1915 return false;
1916 return aabb_intersects(*first, *second);
1917 }
1918
1919 inline bool aabb_intersects(const optional<aabb_2d>& first, const aabb_2d& second)
1920 {
1921 if (first == std::nullopt)
1922 return false;
1923 return aabb_intersects(*first, second);
1924 }
1925
1926 inline bool aabb_intersects(const aabb_2d& first, const std::optional<aabb_2d>& second)
1927 {
1928 if (second == std::nullopt)
1929 return false;
1930 return aabb_intersects(first, *second);
1931 }
1932
1933 inline vec2 bezier_cubic(vec2 const& p0, vec2 const& p1, vec2 const& p2, vec2 const& p3, scalar t)
1934 {
1935 return std::pow(1.0 - t, 3.0) * p0 + 3.0 * std::pow(1.0 - t, 2.0) * t * p1 + 3 * (1.0 - t) * std::pow(t, 2.0) * p2 + std::pow(t, 3.0) * p3;
1936 }
1937
1938 inline vec2 bezier_cubic_x(vec2 const& p0, vec2 const& p1, vec2 const& p2, vec2 const& p3, scalar x)
1939 {
1940 return bezier_cubic(p0, p1, p2, p3, (x - p0.x) / (p3.x - p0.x));
1941 }
1942
1943 inline vec2 bezier_cubic_y(vec2 const& p0, vec2 const& p1, vec2 const& p2, vec2 const& p3, scalar y)
1944 {
1945 return bezier_cubic(p0, p1, p2, p3, (y - p0.y) / (p3.y - p0.y));
1946 }
1947
1948 template <typename T>
1950 {
1951 return bezier_cubic(p0.template as<scalar>(), p1.template as<scalar>(), p2.template as<scalar>(), p3.template as<scalar>(), static_cast<scalar>(t)).template as<T>();
1952 }
1953
1954 template <typename T>
1956 {
1957 return bezier_cubic_x(p0.template as<scalar>(), p1.template as<scalar>(), p2.template as<scalar>(), p3.template as<scalar>(), static_cast<scalar>(x)).template as<T>();
1958 }
1959
1960 template <typename T>
1962 {
1963 return bezier_cubic_y(p0.template as<scalar>(), p1.template as<scalar>(), p2.template as<scalar>(), p3.template as<scalar>(), static_cast<scalar>(y)).template as<T>();
1964 }
1965 }
1966
1967 using namespace math;
1968}
self_type & operator-=(const self_type &right)
basic_vector< T, Rows, column_vector > column_type
bool operator!=(const self_type &right) const
self_type operator-() const
self_type round_to(value_type aEpsilon) const
const value_type * data() const
std::array< column_type, Columns > array_type
basic_matrix(const self_type &other)
std::pair< uint32_t, uint32_t > size() const
basic_matrix< T2, Rows, Columns > as() const
basic_vector< T, Columns, row_vector > row_type
self_type & operator+=(const self_type &right)
self_type & operator=(const self_type &other)
basic_matrix< T, Columns, Rows > transposed() const
static const std::enable_if_t< Rows==Columns, SFINAE > & identity()
basic_matrix(self_type &&other)
friend void swap(self_type &a, self_type &b)
bool operator==(const self_type &right) const
basic_matrix(const basic_matrix< T2, Rows, Columns > &other)
const std::optional< bool > & maybe_identity() const
column_type & operator[](uint32_t aColumn)
self_type & operator*=(const self_type &right)
basic_matrix(std::initializer_list< std::initializer_list< value_type > > aColumns)
const column_type & operator[](uint32_t aColumn) const
self_type & operator=(self_type &&other)
basic_vector(std::initializer_list< value_type > values)
self_type & operator+=(value_type value)
self_type & operator*=(const self_type &right)
value_type operator[](uint32_t aIndex) const
self_type & operator=(self_type &&other)
self_type & operator/=(const self_type &right)
self_type & operator/=(value_type value)
value_type dot(const self_type &right) const
basic_vector(const basic_vector< T2, Size, Type > &other)
std::array< value_type, 1 > array_type
basic_vector< value_type, 1, Type > vector_type
basic_vector< T2, Size, Type > as() const
array_type::const_iterator const_iterator
self_type & operator*=(value_type value)
self_type scale(const self_type &right) const
self_type & operator+=(const self_type &right)
basic_vector(const swizzle< V, A, S, Indexes... > &aSwizzle)
basic_vector(value_type &&value, Arguments &&... aArguments)
basic_vector(const basic_vector< T2, Size2, Type > &other, typename std::enable_if_t< Size2< Size, SFINAE >=0)
swizzle< vector_type, array_type, 2, 0, 0 > xx
self_type hadamard_product(const self_type &right) const
self_type & operator=(const self_type &other)
bool operator==(const self_type &right) const
self_type & operator=(std::initializer_list< value_type > values)
friend void swap(self_type &a, self_type &b)
self_type & operator-=(value_type value)
self_type min(const self_type &right) const
basic_vector(const value_type &value, Arguments &&... aArguments)
value_type & operator[](uint32_t aIndex)
swizzle< vector_type, array_type, 3, 0, 0, 0 > xxx
self_type & operator-=(const self_type &right)
value_type distance(const self_type &right) const
self_type max(const self_type &right) const
bool operator!=(const self_type &right) const
swizzle< vector_type, array_type, 3, 0, 1, 0 > xyx
self_type & operator/=(value_type value)
swizzle< vector_type, array_type, 3, 1, 1, 0 > yyx
bool operator!=(const self_type &right) const
basic_vector(const basic_vector< T2, Size2, Type > &other, typename std::enable_if_t< Size2< Size, SFINAE >=0)
swizzle< vector_type, array_type, 2, 0, 1 > xy
value_type dot(const self_type &right) const
swizzle< vector_type, array_type, 3, 0, 0, 1 > xxy
std::array< value_type, 2 > array_type
self_type & operator*=(const self_type &right)
self_type & operator=(std::initializer_list< value_type > values)
array_type::const_iterator const_iterator
self_type & operator+=(const self_type &right)
value_type operator[](uint32_t aIndex) const
swizzle< vector_type, array_type, 2, 0, 0 > xx
self_type & operator/=(const self_type &right)
basic_vector< value_type, 2, Type > vector_type
swizzle< vector_type, array_type, 2, 1, 0 > yx
basic_vector(value_type &&value, Arguments &&... aArguments)
self_type & operator*=(value_type value)
self_type scale(const self_type &right) const
self_type hadamard_product(const self_type &right) const
basic_vector(const swizzle< V, A, S, Indexes... > &aSwizzle)
basic_vector(std::initializer_list< value_type > values)
basic_vector< T2, Size, Type > as() const
self_type & operator=(const self_type &other)
basic_vector(const value_type &value, Arguments &&... aArguments)
value_type distance(const self_type &right) const
swizzle< vector_type, array_type, 3, 1, 0, 1 > yxy
self_type & operator=(self_type &&other)
self_type & operator+=(value_type value)
self_type max(const self_type &right) const
value_type & operator[](uint32_t aIndex)
swizzle< vector_type, array_type, 3, 0, 0, 0 > xxx
friend void swap(self_type &a, self_type &b)
swizzle< vector_type, array_type, 3, 1, 0, 0 > yxx
basic_vector(value_type x, value_type y)
swizzle< vector_type, array_type, 3, 1, 1, 1 > yyy
swizzle< vector_type, array_type, 3, 0, 1, 1 > xyy
swizzle< vector_type, array_type, 2, 1, 1 > yy
self_type & operator-=(const self_type &right)
basic_vector(const basic_vector< T2, Size, Type > &other)
self_type min(const self_type &right) const
self_type & operator-=(value_type value)
bool operator==(const self_type &right) const
const_iterator begin() const
swizzle< vector_type, array_type, 2, 2, 1 > zy
self_type hadamard_product(const self_type &right) const
basic_vector(const swizzle< V, A, S, Indexes... > &aSwizzle)
self_type max(const self_type &right) const
self_type operator-() const
swizzle< vector_type, array_type, 2, 1, 0 > yx
basic_vector(const basic_vector< T2, Size2, Type > &other, typename std::enable_if_t< Size2< Size, SFINAE >=0)
swizzle< vector_type, array_type, 2, 0, 2 > xz
self_type & operator=(const self_type &other)
swizzle< vector_type, array_type, 2, 0, 0 > xx
static uint32_t size()
swizzle< vector_type, array_type, 3, 1, 1, 2 > yyz
std::enable_if_t< Size==3, SFINAE > cross(const self_type &right) const
swizzle< vector_type, array_type, 3, 1, 0, 1 > yxy
swizzle< vector_type, array_type, 3, 2, 0, 0 > zxx
swizzle< vector_type, array_type, 3, 0, 0, 0 > xxx
const_iterator end() const
self_type scale(const self_type &right) const
basic_vector(const value_type &value, Arguments &&... aArguments)
swizzle< vector_type, array_type, 3, 2, 0, 1 > zxy
value_type & operator[](uint32_t aIndex)
self_type & operator-=(const self_type &right)
swizzle< vector_type, array_type, 3, 0, 1, 1 > xyy
self_type & operator*=(const self_type &right)
swizzle< vector_type, array_type, 2, 2, 0 > zx
swizzle< vector_type, array_type, 3, 1, 2, 2 > yzz
swizzle< vector_type, array_type, 3, 1, 1, 0 > yyx
self_type & operator+=(const self_type &right)
swizzle< vector_type, array_type, 3, 0, 0, 1 > xxy
self_type normalized() const
swizzle< vector_type, array_type, 3, 2, 1, 1 > zyy
basic_vector(const array_type &v)
self_type ceil() const
basic_vector(value_type x, value_type y, value_type z, typename std::enable_if_t< Size==3, SFINAE >=0)
array_type::const_iterator const_iterator
basic_vector(std::initializer_list< value_type > values)
basic_vector(value_type x, typename std::enable_if_t< Size==1, SFINAE >=0)
std::array< value_type, _Size > array_type
self_type & operator*=(value_type value)
static constexpr uint32_t Size
swizzle< vector_type, array_type, 3, 2, 1, 0 > zyx
bool operator==(const self_type &right) const
swizzle< vector_type, array_type, 3, 1, 0, 0 > yxx
value_type magnitude() const
basic_vector< value_type, _Size, Type > vector_type
value_type operator[](uint32_t aIndex) const
swizzle< vector_type, array_type, 2, 0, 1 > xy
value_type distance(const self_type &right) const
swizzle< vector_type, array_type, 2, 1, 1 > yy
swizzle< vector_type, array_type, 2, 1, 2 > yz
self_type min(const self_type &right) const
self_type & operator/=(const self_type &right)
array_type::iterator iterator
swizzle< vector_type, array_type, 3, 0, 1, 0 > xyx
basic_vector(const self_type &other)
value_type dot(const self_type &right) const
swizzle< vector_type, array_type, 3, 1, 2, 1 > yzy
swizzle< vector_type, array_type, 3, 2, 2, 0 > zzx
swizzle< vector_type, array_type, 3, 1, 1, 1 > yyy
self_type & operator=(self_type &&other)
friend void swap(self_type &a, self_type &b)
swizzle< vector_type, array_type, 3, 1, 2, 0 > yzx
self_type floor() const
self_type & operator+=(value_type value)
swizzle< vector_type, array_type, 3, 2, 2, 1 > zzy
basic_vector< T2, Size, Type > as() const
swizzle< vector_type, array_type, 3, 0, 1, 2 > xyz
self_type & operator/=(value_type value)
basic_vector(value_type x, value_type y, value_type z, value_type w, typename std::enable_if_t< Size==4, SFINAE >=0)
swizzle< vector_type, array_type, 3, 2, 0, 2 > zxz
swizzle< vector_type, array_type, 3, 2, 2, 2 > zzz
self_type round() const
swizzle< vector_type, array_type, 3, 0, 0, 2 > xxz
basic_vector(value_type x, value_type y, typename std::enable_if_t< Size==2, SFINAE >=0)
swizzle< vector_type, array_type, 3, 1, 0, 2 > yxz
self_type & operator-=(value_type value)
bool operator!=(const self_type &right) const
basic_vector(value_type &&value, Arguments &&... aArguments)
value_type min() const
self_type & operator=(std::initializer_list< value_type > values)
swizzle< vector_type, array_type, 3, 2, 1, 2 > zyz
basic_vector(const basic_vector< T2, Size, Type > &other)
swizzle< vector_type, array_type, 2, 2, 2 > zz
basic_vector(self_type &&other)
std::basic_ostream< Elem, Traits > & operator<<(std::basic_ostream< Elem, Traits > &aStream, const basic_point< T > &aPoint)
std::array< double, 3 > avec3
optional< row_vec4 > optional_row_vec4
matrix41 mat41
basic_matrix< double, 4, 3 > matrix43
optional< vector3 > optional_vector3
optional< matrix32f > optional_matrix32f
basic_matrix< float, 1, 1 > matrix11f
basic_matrix< double, 1, 1 > matrix11
basic_matrix< double, 2, 4 > matrix24
matrix11 matrix1
basic_vector< i32, 1 > vector1i32
angle to_deg(angle aRadians)
Definition numerical.hpp:93
optional< mat11f > optional_mat11f
optional< matrix44f > optional_matrix44f
optional< mat11f > optional_mat1f
matrix22 matrix2
aabb to_aabb(const vec3 &aOrigin, scalar aSize)
vec3_list vertices
matrix24f mat24f
basic_matrix< double, 3, 4 > matrix34
optional< mat41f > optional_mat41f
std::array< vec2f, 3 > trianglef_2d
matrix24 mat24
optional< vector1 > optional_vector1
basic_matrix< double, 3, 3 > matrix33
optional< matrix22f > optional_matrix22f
std::array< uint8_t, 3 > avec3u8
matrix31f mat31f
std::array< vec3f, 3 > trianglef
optional< mat13 > optional_mat13
optional< mat11 > optional_mat11
basic_vector< T, 3, Type > midpoint(const basic_vector< T, 3, Type > &left, const basic_vector< T, 3, Type > &right)
vec2 bezier_cubic_y(vec2 const &p0, vec2 const &p1, vec2 const &p2, vec2 const &p3, scalar y)
vector1i32 vec1i32
optional< matrix11 > optional_matrix11
optional< vector2 > optional_vector2
basic_vector< double, 1, row_vector > row_vec1
vec2_list vertices_2d
scalar aabb_volume(const aabb &a)
std::array< int8_t, 2 > avec2i8
matrix12 mat12
std::array< vec2, 4 > quad_2d
matrix33 mat33
basic_matrix< float, 2, 3 > matrix23f
std::array< double, 2 > avec2
angle to_rad(angle aDegrees)
Definition numerical.hpp:88
optional< mat33f > optional_mat3f
optional< mat43 > optional_mat43
optional< mat33f > optional_mat33f
optional< matrix31f > optional_matrix31f
optional< vec2_list > optional_vec2_list
optional< vector4 > optional_vector4
optional< mat22f > optional_mat2f
std::array< int16_t, 3 > avec3i16
basic_matrix< double, 2, 3 > matrix23
optional< mat33 > optional_mat33
optional< col_vec2 > optional_col_vec2
optional_vec3_list optional_vertices_t
basic_vector< u32, 1 > vector1u32
basic_matrix< double, 3, 2 > matrix32
matrix33 matrix3
basic_vector< T, D, Type > operator%(const basic_vector< T, D, Type > &left, const T &right)
std::array< int32_t, 1 > avec1i32
optional< mat14f > optional_mat14f
std::array< uint8_t, 4 > avec4u8
matrix44f mat44f
mat33 rotation_matrix(const vec3 &axis, scalar angle, scalar epsilon=0.00001)
std::array< float, 1 > avec1f
optional< matrix42 > optional_matrix42
std::array< int16_t, 1 > avec1i16
optional< mat12f > optional_mat12f
std::array< vec3, 4 > quad
optional< matrix13 > optional_matrix13
vec3 aabb_extents(const aabb &aAabb)
std::array< uint16_t, 1 > avec1u16
basic_vector< u32, 4 > vector4u32
basic_vector< i32, 4 > vector4i32
matrix41f mat41f
optional< matrix21 > optional_matrix21
optional< matrix31 > optional_matrix31
basic_matrix< T, D, D > without_translation(const basic_matrix< T, D, D > &matrix)
basic_matrix< float, 1, 3 > matrix13f
matrix34f mat34f
optional< mat32 > optional_mat32
optional< vec1 > optional_vec1
optional< mat42f > optional_mat42f
optional< col_vec3 > optional_col_vec3
bool aabb_contains(const aabb &outer, const aabb &inner)
std::array< uint16_t, 2 > avec2u16
vector4u32 vec4u32
basic_matrix< double, 2, 2 > matrix22
matrix32f mat32f
basic_matrix< double, 3, 1 > matrix31
matrix31 mat31
optional< matrix41 > optional_matrix41
basic_matrix< double, 1, 4 > matrix14
basic_vector< double, 4, row_vector > row_vec4
std::array< double, 4 > avec4
std::array< int16_t, 2 > avec2i16
std::array< float, 3 > avec3f
std::array< basic_vector< T, D, Type >, VertexCount > & operator-=(std::array< basic_vector< T, D, Type >, VertexCount > &left, const basic_vector< T, D, Type > &right)
matrix14f mat14f
optional< mat33 > optional_mat3
matrix43f mat43f
vector4f vec4f
aabb aabb_union(const aabb &left, const aabb &right)
matrix43 mat43
matrix22f mat22f
optional< matrix43f > optional_matrix43f
vector4i32 vec4i32
std::array< uint8_t, 2 > avec2u8
basic_vector< i32, 2 > vector2i32
optional< matrix34 > optional_matrix34
matrix32 mat32
std::array< uint8_t, 1 > avec1u8
optional_vec2_list optional_vertices_2d_t
std::vector< vec2 > vec2_list
std::array< uint16_t, 3 > avec3u16
optional< mat21 > optional_mat21
matrix34 mat34
optional< vec3_list > optional_vec3_list
matrix13f mat13f
optional< matrix24f > optional_matrix24f
basic_vector< double, 2, row_vector > row_vec2
mat44 affine_rotation_matrix(const vec3 &angles)
matrix21f mat21f
optional< mat32f > optional_mat32f
optional< mat22f > optional_mat22f
std::array< vec3f, 4 > quadf
T lerp(T aX1, T aX2, double aAmount)
Definition numerical.hpp:81
std::array< uint32_t, 1 > avec1u32
basic_vector< float, 1 > vector1f
bool aabb_intersects(const aabb &first, const aabb &second)
basic_matrix< float, 3, 4 > matrix34f
matrix14 mat14
mat44 & apply_translation(mat44 &aMatrix, const vec3 &aTranslation)
optional< mat12 > optional_mat12
optional< matrix33f > optional_matrix33f
optional< matrix14 > optional_matrix14
optional< col_vec1 > optional_col_vec1
vec2 bezier_cubic_x(vec2 const &p0, vec2 const &p1, vec2 const &p2, vec2 const &p3, scalar x)
optional< matrix13f > optional_matrix13f
optional< mat13f > optional_mat13f
vector2u32 vec2u32
optional< matrix11 > optional_matrix1
matrix23 mat23
std::array< float, 2 > avec2f
optional< mat31 > optional_mat31
optional< matrix14f > optional_matrix14f
matrix13 mat13
optional< matrix42f > optional_matrix42f
optional< mat24f > optional_mat24f
std::array< int32_t, 4 > avec4i32
std::array< int8_t, 4 > avec4i8
std::array< int8_t, 1 > avec1i8
optional< matrix33 > optional_matrix3
matrix42f mat42f
basic_vector< float, 3 > vector3f
matrix12f mat12f
optional< vec3 > optional_vec3
matrix33f mat3f
double scalar
Definition numerical.hpp:63
basic_vector< T, D > quad_extents(std::array< basic_vector< T, D >, 4 > const &aQuad)
optional< mat23f > optional_mat23f
vector2i32 vec2i32
optional< mat44f > optional_mat4f
basic_vector< float, 4 > vector4f
vector2f vec2f
matrix11f mat1f
optional< matrix23f > optional_matrix23f
std::array< double, 1 > avec1
optional< row_vec2 > optional_row_vec2
optional< mat21f > optional_mat21f
vector3i32 vec3i32
std::array< uint32_t, 2 > avec2u32
std::array< float, 4 > avec4f
basic_matrix< double, 2, 1 > matrix21
basic_matrix< float, 4, 3 > matrix43f
optional< mat14 > optional_mat14
std::array< vec2, 3 > triangle_2d
basic_matrix< float, 4, 1 > matrix41f
vector1u32 vec1u32
matrix22 mat22
optional< matrix44 > optional_matrix44
vec3 aabb_origin(const aabb &aAabb)
basic_matrix< float, 2, 4 > matrix24f
optional< matrix43 > optional_matrix43
std::array< uint32_t, 4 > avec4u32
matrix23f mat23f
optional< mat22 > optional_mat2
std::array< int32_t, 3 > avec3i32
optional< matrix44f > optional_matrix4f
optional< mat34f > optional_mat34f
matrix44f mat4f
basic_matrix< float, 1, 2 > matrix12f
optional< matrix21f > optional_matrix21f
std::array< vec2f, 4 > quadf_2d
basic_matrix< float, 3, 3 > matrix33f
basic_vector< double, 1 > vector1
optional< mat22 > optional_mat22
optional< mat34 > optional_mat34
matrix42 mat42
matrix11f mat11f
optional< matrix33f > optional_matrix3f
optional< matrix22f > optional_matrix2f
basic_vector< i32, 3 > vector3i32
optional< mat31f > optional_mat31f
optional< matrix22 > optional_matrix22
basic_matrix< float, 4, 4 > matrix44f
uint32_t u64
matrix11 mat11
basic_matrix< double, 4, 2 > matrix42
optional< matrix12f > optional_matrix12f
std::array< int8_t, 3 > avec3i8
matrix22f mat2f
optional< mat44f > optional_mat44f
optional< matrix23 > optional_matrix23
optional< matrix33 > optional_matrix33
optional< mat24 > optional_mat24
basic_matrix< float, 2, 2 > matrix22f
matrix33f mat33f
optional< col_vec4 > optional_col_vec4
optional< matrix11f > optional_matrix1f
std::array< uint32_t, 3 > avec3u32
optional< matrix12 > optional_matrix12
basic_vector< double, 3, row_vector > row_vec3
basic_matrix< float, 3, 2 > matrix32f
basic_vector< u32, 2 > vector2u32
basic_vector< u32, 3 > vector3u32
aabb aabb_transform(const aabb &aAabb, const Transforms &... aTransforms)
optional< matrix41f > optional_matrix41f
optional< mat23 > optional_mat23
uint32_t u32
basic_vector< float, 2 > vector2f
basic_matrix< float, 1, 4 > matrix14f
optional< matrix22 > optional_matrix2
aabb_2d to_aabb_2d(const vec3 &aOrigin, scalar aSize)
optional< row_vec1 > optional_row_vec1
std::array< uint16_t, 4 > avec4u16
std::array< int32_t, 2 > avec2i32
optional< mat41 > optional_mat41
optional< mat42 > optional_mat42
basic_matrix< double, 1, 2 > matrix12
basic_matrix< double, 4, 1 > matrix41
basic_matrix< double, 1, 3 > matrix13
optional< aabb > optional_aabb
std::vector< vec3 > vec3_list
optional< mat11 > optional_mat1
optional< matrix11f > optional_matrix11f
mat44 & apply_scaling(mat44 &aMatrix, const vec3 &aScaling)
optional< matrix44 > optional_matrix4
matrix21 mat21
optional< mat43f > optional_mat43f
basic_matrix< float, 3, 1 > matrix31f
vec2 bezier_cubic(vec2 const &p0, vec2 const &p1, vec2 const &p2, vec2 const &p3, scalar t)
optional< row_vec3 > optional_row_vec3
optional< matrix34f > optional_matrix34f
basic_matrix< float, 4, 2 > matrix42f
vector3u32 vec3u32
basic_matrix< float, 2, 1 > matrix21f
vector3f vec3f
std::array< vec3, 3 > triangle
std::array< int16_t, 4 > avec4i16
optional< matrix24 > optional_matrix24
optional< matrix32 > optional_matrix32
vector1f vec1f
i_string & operator+=(i_string &lhs, const i_string &rhs)
Definition i_string.hpp:89
Definition plf_hive.h:79
void swap(plf::hive< element_type, allocator_type > &a, plf::hive< element_type, allocator_type > &b) noexcept(std::allocator_traits< allocator_type >::propagate_on_container_swap::value||std::allocator_traits< allocator_type >::is_always_equal::value)
Definition plf_hive.h:4776
it_type next(it_type it, const typename iterator_traits< it_type >::difference_type distance=1)
Definition plf_hive.h:89
#define simd_fma_4d
Definition simd.hpp:108
#define simd_mul_4d
Definition simd.hpp:143
aabb_2d(const aabb &aAabb)
aabb_2d(const vec2 &aMin, const vec2 &aMax)
aabb(const vec3 &aMin, const vec3 &aMax)
basic_matrix< T2, Rows, Columns > type
basic_vector< T, Size2, Type > type