vector_math.h
1 // Licensed under GPLv2 or any later version 2 // Refer to the license.txt file included. 3 4 // Copyright 2014 Tony Wasserka 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 met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above copyright 13 // notice, this list of conditions and the following disclaimer in the 14 // documentation and/or other materials provided with the distribution. 15 // * Neither the name of the owner nor the names of its contributors may 16 // be used to endorse or promote products derived from this software 17 // without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 #pragma once 32 33 #include <cmath> 34 #include <cstring> 35 #include <type_traits> 36 #include <boost/serialization/access.hpp> 37 38 namespace Common { 39 40 template <typename T> 41 class Vec2; 42 template <typename T> 43 class Vec3; 44 template <typename T> 45 class Vec4; 46 47 template <typename T> 48 class Vec2 { 49 friend class boost::serialization::access; 50 template <class Archive> 51 void serialize(Archive& ar, const unsigned int file_version) { 52 ar& x; 53 ar& y; 54 } 55 56 public: 57 T x; 58 T y; 59 60 T* AsArray() { 61 return &x; 62 } 63 64 const T* AsArray() const { 65 return &x; 66 } 67 68 constexpr Vec2() = default; 69 constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {} 70 71 template <typename T2> 72 [[nodiscard]] constexpr Vec2<T2> Cast() const { 73 return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y)); 74 } 75 76 [[nodiscard]] static constexpr Vec2 AssignToAll(const T& f) { 77 return Vec2{f, f}; 78 } 79 80 [[nodiscard]] constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const { 81 return {x + other.x, y + other.y}; 82 } 83 constexpr Vec2& operator+=(const Vec2& other) { 84 x += other.x; 85 y += other.y; 86 return *this; 87 } 88 [[nodiscard]] constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const { 89 return {x - other.x, y - other.y}; 90 } 91 constexpr Vec2& operator-=(const Vec2& other) { 92 x -= other.x; 93 y -= other.y; 94 return *this; 95 } 96 97 template <typename U = T> 98 [[nodiscard]] constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const { 99 return {-x, -y}; 100 } 101 [[nodiscard]] constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const { 102 return {x * other.x, y * other.y}; 103 } 104 105 template <typename V> 106 [[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const { 107 return {x * f, y * f}; 108 } 109 110 template <typename V> 111 constexpr Vec2& operator*=(const V& f) { 112 *this = *this * f; 113 return *this; 114 } 115 116 template <typename V> 117 [[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const { 118 return {x / f, y / f}; 119 } 120 121 template <typename V> 122 constexpr Vec2& operator/=(const V& f) { 123 *this = *this / f; 124 return *this; 125 } 126 127 [[nodiscard]] constexpr T Length2() const { 128 return x * x + y * y; 129 } 130 131 [[nodiscard]] constexpr bool operator!=(const Vec2& other) const { 132 return std::memcmp(AsArray(), other.AsArray(), sizeof(Vec2)) != 0; 133 } 134 135 [[nodiscard]] constexpr bool operator==(const Vec2& other) const { 136 return std::memcmp(AsArray(), other.AsArray(), sizeof(Vec2)) == 0; 137 } 138 139 // Only implemented for T=float 140 [[nodiscard]] float Length() const; 141 float Normalize(); // returns the previous length, which is often useful 142 143 [[nodiscard]] constexpr T& operator[](std::size_t i) { 144 return *((&x) + i); 145 } 146 [[nodiscard]] constexpr const T& operator[](std::size_t i) const { 147 return *((&x) + i); 148 } 149 150 constexpr void SetZero() { 151 x = 0; 152 y = 0; 153 } 154 155 // Common aliases: UV (texel coordinates), ST (texture coordinates) 156 [[nodiscard]] constexpr T& u() { 157 return x; 158 } 159 [[nodiscard]] constexpr T& v() { 160 return y; 161 } 162 [[nodiscard]] constexpr T& s() { 163 return x; 164 } 165 [[nodiscard]] constexpr T& t() { 166 return y; 167 } 168 169 [[nodiscard]] constexpr const T& u() const { 170 return x; 171 } 172 [[nodiscard]] constexpr const T& v() const { 173 return y; 174 } 175 [[nodiscard]] constexpr const T& s() const { 176 return x; 177 } 178 [[nodiscard]] constexpr const T& t() const { 179 return y; 180 } 181 182 // swizzlers - create a subvector of specific components 183 [[nodiscard]] constexpr Vec2 yx() const { 184 return Vec2(y, x); 185 } 186 [[nodiscard]] constexpr Vec2 vu() const { 187 return Vec2(y, x); 188 } 189 [[nodiscard]] constexpr Vec2 ts() const { 190 return Vec2(y, x); 191 } 192 }; 193 194 template <typename T, typename V> 195 [[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) { 196 return Vec2<T>(f * vec.x, f * vec.y); 197 } 198 199 using Vec2f = Vec2<float>; 200 using Vec2i = Vec2<int>; 201 using Vec2u = Vec2<unsigned int>; 202 203 template <> 204 inline float Vec2<float>::Length() const { 205 return std::sqrt(x * x + y * y); 206 } 207 208 template <> 209 inline float Vec2<float>::Normalize() { 210 float length = Length(); 211 *this /= length; 212 return length; 213 } 214 215 template <typename T> 216 class Vec3 { 217 friend class boost::serialization::access; 218 template <class Archive> 219 void serialize(Archive& ar, const unsigned int file_version) { 220 ar& x; 221 ar& y; 222 ar& z; 223 } 224 225 public: 226 T x; 227 T y; 228 T z; 229 230 T* AsArray() { 231 return &x; 232 } 233 234 const T* AsArray() const { 235 return &x; 236 } 237 238 constexpr Vec3() = default; 239 constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {} 240 241 template <typename T2> 242 [[nodiscard]] constexpr Vec3<T2> Cast() const { 243 return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z)); 244 } 245 246 [[nodiscard]] static constexpr Vec3 AssignToAll(const T& f) { 247 return Vec3(f, f, f); 248 } 249 250 [[nodiscard]] constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const { 251 return {x + other.x, y + other.y, z + other.z}; 252 } 253 254 constexpr Vec3& operator+=(const Vec3& other) { 255 x += other.x; 256 y += other.y; 257 z += other.z; 258 return *this; 259 } 260 261 [[nodiscard]] constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const { 262 return {x - other.x, y - other.y, z - other.z}; 263 } 264 265 constexpr Vec3& operator-=(const Vec3& other) { 266 x -= other.x; 267 y -= other.y; 268 z -= other.z; 269 return *this; 270 } 271 272 template <typename U = T> 273 [[nodiscard]] constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const { 274 return {-x, -y, -z}; 275 } 276 277 [[nodiscard]] constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const { 278 return {x * other.x, y * other.y, z * other.z}; 279 } 280 281 template <typename V> 282 [[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const { 283 return {x * f, y * f, z * f}; 284 } 285 286 template <typename V> 287 constexpr Vec3& operator*=(const V& f) { 288 *this = *this * f; 289 return *this; 290 } 291 template <typename V> 292 [[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const { 293 return {x / f, y / f, z / f}; 294 } 295 296 template <typename V> 297 constexpr Vec3& operator/=(const V& f) { 298 *this = *this / f; 299 return *this; 300 } 301 302 [[nodiscard]] constexpr bool operator!=(const Vec3& other) const { 303 return std::memcmp(AsArray(), other.AsArray(), sizeof(Vec3)) != 0; 304 } 305 306 [[nodiscard]] constexpr bool operator==(const Vec3& other) const { 307 return std::memcmp(AsArray(), other.AsArray(), sizeof(Vec3)) == 0; 308 } 309 310 [[nodiscard]] constexpr T Length2() const { 311 return x * x + y * y + z * z; 312 } 313 314 // Only implemented for T=float 315 [[nodiscard]] float Length() const; 316 [[nodiscard]] Vec3 Normalized() const; 317 float Normalize(); // returns the previous length, which is often useful 318 319 [[nodiscard]] constexpr T& operator[](std::size_t i) { 320 return *((&x) + i); 321 } 322 323 [[nodiscard]] constexpr const T& operator[](std::size_t i) const { 324 return *((&x) + i); 325 } 326 327 constexpr void SetZero() { 328 x = 0; 329 y = 0; 330 z = 0; 331 } 332 333 // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates) 334 [[nodiscard]] constexpr T& u() { 335 return x; 336 } 337 [[nodiscard]] constexpr T& v() { 338 return y; 339 } 340 [[nodiscard]] constexpr T& w() { 341 return z; 342 } 343 344 [[nodiscard]] constexpr T& r() { 345 return x; 346 } 347 [[nodiscard]] constexpr T& g() { 348 return y; 349 } 350 [[nodiscard]] constexpr T& b() { 351 return z; 352 } 353 354 [[nodiscard]] constexpr T& s() { 355 return x; 356 } 357 [[nodiscard]] constexpr T& t() { 358 return y; 359 } 360 [[nodiscard]] constexpr T& q() { 361 return z; 362 } 363 364 [[nodiscard]] constexpr const T& u() const { 365 return x; 366 } 367 [[nodiscard]] constexpr const T& v() const { 368 return y; 369 } 370 [[nodiscard]] constexpr const T& w() const { 371 return z; 372 } 373 374 [[nodiscard]] constexpr const T& r() const { 375 return x; 376 } 377 [[nodiscard]] constexpr const T& g() const { 378 return y; 379 } 380 [[nodiscard]] constexpr const T& b() const { 381 return z; 382 } 383 384 [[nodiscard]] constexpr const T& s() const { 385 return x; 386 } 387 [[nodiscard]] constexpr const T& t() const { 388 return y; 389 } 390 [[nodiscard]] constexpr const T& q() const { 391 return z; 392 } 393 394 // swizzlers - create a subvector of specific components 395 // e.g. Vec2 uv() { return Vec2(x,y); } 396 // _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all 397 // component names (x<->r) and permutations (xy<->yx) 398 #define _DEFINE_SWIZZLER2(a, b, name) \ 399 [[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); } 400 #define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ 401 _DEFINE_SWIZZLER2(a, b, a##b); \ 402 _DEFINE_SWIZZLER2(a, b, a2##b2); \ 403 _DEFINE_SWIZZLER2(a, b, a3##b3); \ 404 _DEFINE_SWIZZLER2(a, b, a4##b4); \ 405 _DEFINE_SWIZZLER2(b, a, b##a); \ 406 _DEFINE_SWIZZLER2(b, a, b2##a2); \ 407 _DEFINE_SWIZZLER2(b, a, b3##a3); \ 408 _DEFINE_SWIZZLER2(b, a, b4##a4) 409 410 DEFINE_SWIZZLER2(x, y, r, g, u, v, s, t); 411 DEFINE_SWIZZLER2(x, z, r, b, u, w, s, q); 412 DEFINE_SWIZZLER2(y, z, g, b, v, w, t, q); 413 #undef DEFINE_SWIZZLER2 414 #undef _DEFINE_SWIZZLER2 415 }; 416 417 template <typename T, typename V> 418 [[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) { 419 return Vec3<T>(f * vec.x, f * vec.y, f * vec.z); 420 } 421 422 template <> 423 inline float Vec3<float>::Length() const { 424 return std::sqrt(x * x + y * y + z * z); 425 } 426 427 template <> 428 inline Vec3<float> Vec3<float>::Normalized() const { 429 return *this / Length(); 430 } 431 432 template <> 433 inline float Vec3<float>::Normalize() { 434 float length = Length(); 435 *this /= length; 436 return length; 437 } 438 439 using Vec3f = Vec3<float>; 440 using Vec3i = Vec3<int>; 441 using Vec3u = Vec3<unsigned int>; 442 443 template <typename T> 444 class Vec4 { 445 friend class boost::serialization::access; 446 template <class Archive> 447 void serialize(Archive& ar, const unsigned int file_version) { 448 ar& x; 449 ar& y; 450 ar& z; 451 ar& w; 452 } 453 454 public: 455 T x; 456 T y; 457 T z; 458 T w; 459 460 T* AsArray() { 461 return &x; 462 } 463 464 const T* AsArray() const { 465 return &x; 466 } 467 468 constexpr Vec4() = default; 469 constexpr Vec4(const T& x_, const T& y_, const T& z_, const T& w_) 470 : x(x_), y(y_), z(z_), w(w_) {} 471 472 template <typename T2> 473 [[nodiscard]] constexpr Vec4<T2> Cast() const { 474 return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z), 475 static_cast<T2>(w)); 476 } 477 478 [[nodiscard]] static constexpr Vec4 AssignToAll(const T& f) { 479 return Vec4(f, f, f, f); 480 } 481 482 [[nodiscard]] constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const { 483 return {x + other.x, y + other.y, z + other.z, w + other.w}; 484 } 485 486 constexpr Vec4& operator+=(const Vec4& other) { 487 x += other.x; 488 y += other.y; 489 z += other.z; 490 w += other.w; 491 return *this; 492 } 493 494 [[nodiscard]] constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const { 495 return {x - other.x, y - other.y, z - other.z, w - other.w}; 496 } 497 498 constexpr Vec4& operator-=(const Vec4& other) { 499 x -= other.x; 500 y -= other.y; 501 z -= other.z; 502 w -= other.w; 503 return *this; 504 } 505 506 template <typename U = T> 507 [[nodiscard]] constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const { 508 return {-x, -y, -z, -w}; 509 } 510 511 [[nodiscard]] constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const { 512 return {x * other.x, y * other.y, z * other.z, w * other.w}; 513 } 514 515 template <typename V> 516 [[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const { 517 return {x * f, y * f, z * f, w * f}; 518 } 519 520 template <typename V> 521 constexpr Vec4& operator*=(const V& f) { 522 *this = *this * f; 523 return *this; 524 } 525 526 template <typename V> 527 [[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const { 528 return {x / f, y / f, z / f, w / f}; 529 } 530 531 template <typename V> 532 constexpr Vec4& operator/=(const V& f) { 533 *this = *this / f; 534 return *this; 535 } 536 537 [[nodiscard]] constexpr bool operator!=(const Vec4& other) const { 538 return std::memcmp(AsArray(), other.AsArray(), sizeof(Vec4)) != 0; 539 } 540 541 [[nodiscard]] constexpr bool operator==(const Vec4& other) const { 542 return std::memcmp(AsArray(), other.AsArray(), sizeof(Vec4)) == 0; 543 } 544 545 [[nodiscard]] constexpr T Length2() const { 546 return x * x + y * y + z * z + w * w; 547 } 548 549 [[nodiscard]] constexpr T& operator[](std::size_t i) { 550 return *((&x) + i); 551 } 552 553 [[nodiscard]] constexpr const T& operator[](std::size_t i) const { 554 return *((&x) + i); 555 } 556 557 constexpr void SetZero() { 558 x = 0; 559 y = 0; 560 z = 0; 561 w = 0; 562 } 563 564 // Common alias: RGBA (colors) 565 [[nodiscard]] constexpr T& r() { 566 return x; 567 } 568 [[nodiscard]] constexpr T& g() { 569 return y; 570 } 571 [[nodiscard]] constexpr T& b() { 572 return z; 573 } 574 [[nodiscard]] constexpr T& a() { 575 return w; 576 } 577 578 [[nodiscard]] constexpr const T& r() const { 579 return x; 580 } 581 [[nodiscard]] constexpr const T& g() const { 582 return y; 583 } 584 [[nodiscard]] constexpr const T& b() const { 585 return z; 586 } 587 [[nodiscard]] constexpr const T& a() const { 588 return w; 589 } 590 591 // Swizzlers - Create a subvector of specific components 592 // e.g. Vec2 uv() { return Vec2(x,y); } 593 594 // _DEFINE_SWIZZLER2 defines a single such function 595 // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) 596 // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and 597 // permutations (xy<->yx) 598 #define _DEFINE_SWIZZLER2(a, b, name) \ 599 [[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); } 600 #define DEFINE_SWIZZLER2_COMP1(a, a2) \ 601 _DEFINE_SWIZZLER2(a, a, a##a); \ 602 _DEFINE_SWIZZLER2(a, a, a2##a2) 603 #define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \ 604 _DEFINE_SWIZZLER2(a, b, a##b); \ 605 _DEFINE_SWIZZLER2(a, b, a2##b2); \ 606 _DEFINE_SWIZZLER2(b, a, b##a); \ 607 _DEFINE_SWIZZLER2(b, a, b2##a2) 608 609 DEFINE_SWIZZLER2_COMP2(x, y, r, g); 610 DEFINE_SWIZZLER2_COMP2(x, z, r, b); 611 DEFINE_SWIZZLER2_COMP2(x, w, r, a); 612 DEFINE_SWIZZLER2_COMP2(y, z, g, b); 613 DEFINE_SWIZZLER2_COMP2(y, w, g, a); 614 DEFINE_SWIZZLER2_COMP2(z, w, b, a); 615 DEFINE_SWIZZLER2_COMP1(x, r); 616 DEFINE_SWIZZLER2_COMP1(y, g); 617 DEFINE_SWIZZLER2_COMP1(z, b); 618 DEFINE_SWIZZLER2_COMP1(w, a); 619 #undef DEFINE_SWIZZLER2_COMP1 620 #undef DEFINE_SWIZZLER2_COMP2 621 #undef _DEFINE_SWIZZLER2 622 623 #define _DEFINE_SWIZZLER3(a, b, c, name) \ 624 [[nodiscard]] constexpr Vec3<T> name() const { return Vec3<T>(a, b, c); } 625 #define DEFINE_SWIZZLER3_COMP1(a, a2) \ 626 _DEFINE_SWIZZLER3(a, a, a, a##a##a); \ 627 _DEFINE_SWIZZLER3(a, a, a, a2##a2##a2) 628 #define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \ 629 _DEFINE_SWIZZLER3(a, b, c, a##b##c); \ 630 _DEFINE_SWIZZLER3(a, c, b, a##c##b); \ 631 _DEFINE_SWIZZLER3(b, a, c, b##a##c); \ 632 _DEFINE_SWIZZLER3(b, c, a, b##c##a); \ 633 _DEFINE_SWIZZLER3(c, a, b, c##a##b); \ 634 _DEFINE_SWIZZLER3(c, b, a, c##b##a); \ 635 _DEFINE_SWIZZLER3(a, b, c, a2##b2##c2); \ 636 _DEFINE_SWIZZLER3(a, c, b, a2##c2##b2); \ 637 _DEFINE_SWIZZLER3(b, a, c, b2##a2##c2); \ 638 _DEFINE_SWIZZLER3(b, c, a, b2##c2##a2); \ 639 _DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \ 640 _DEFINE_SWIZZLER3(c, b, a, c2##b2##a2) 641 642 DEFINE_SWIZZLER3_COMP3(x, y, z, r, g, b); 643 DEFINE_SWIZZLER3_COMP3(x, y, w, r, g, a); 644 DEFINE_SWIZZLER3_COMP3(x, z, w, r, b, a); 645 DEFINE_SWIZZLER3_COMP3(y, z, w, g, b, a); 646 DEFINE_SWIZZLER3_COMP1(x, r); 647 DEFINE_SWIZZLER3_COMP1(y, g); 648 DEFINE_SWIZZLER3_COMP1(z, b); 649 DEFINE_SWIZZLER3_COMP1(w, a); 650 #undef DEFINE_SWIZZLER3_COMP1 651 #undef DEFINE_SWIZZLER3_COMP3 652 #undef _DEFINE_SWIZZLER3 653 }; 654 655 template <typename T, typename V> 656 [[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { 657 return {f * vec.x, f * vec.y, f * vec.z, f * vec.w}; 658 } 659 660 using Vec4f = Vec4<float>; 661 using Vec4i = Vec4<int>; 662 using Vec4u = Vec4<unsigned int>; 663 664 template <typename T> 665 constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) { 666 return a.x * b.x + a.y * b.y; 667 } 668 669 template <typename T> 670 [[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) { 671 return a.x * b.x + a.y * b.y + a.z * b.z; 672 } 673 674 template <typename T> 675 [[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) { 676 return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; 677 } 678 679 template <typename T> 680 [[nodiscard]] constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, 681 const Vec3<T>& b) { 682 return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; 683 } 684 685 // linear interpolation via float: 0.0=begin, 1.0=end 686 template <typename X> 687 [[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end, 688 const float t) { 689 return begin * (1.f - t) + end * t; 690 } 691 692 // linear interpolation via int: 0=begin, base=end 693 template <typename X, int base> 694 [[nodiscard]] constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, 695 const X& end, 696 const int t) { 697 return (begin * (base - t) + end * t) / base; 698 } 699 700 // bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second 701 // interpolation. 702 template <typename X> 703 [[nodiscard]] constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, 704 const float s, const float t) { 705 auto y0 = Lerp(x00, x01, s); 706 auto y1 = Lerp(x10, x11, s); 707 return Lerp(y0, y1, t); 708 } 709 710 // Utility vector factories 711 template <typename T> 712 [[nodiscard]] constexpr Vec2<T> MakeVec(const T& x, const T& y) { 713 return Vec2<T>{x, y}; 714 } 715 716 template <typename T> 717 [[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) { 718 return Vec3<T>{x, y, z}; 719 } 720 721 template <typename T> 722 [[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) { 723 return MakeVec(x, y, zw[0], zw[1]); 724 } 725 726 template <typename T> 727 [[nodiscard]] constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) { 728 return MakeVec(xy[0], xy[1], z); 729 } 730 731 template <typename T> 732 [[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) { 733 return MakeVec(x, yz[0], yz[1]); 734 } 735 736 template <typename T> 737 [[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) { 738 return Vec4<T>{x, y, z, w}; 739 } 740 741 template <typename T> 742 [[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) { 743 return MakeVec(xy[0], xy[1], z, w); 744 } 745 746 template <typename T> 747 [[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) { 748 return MakeVec(x, yz[0], yz[1], w); 749 } 750 751 // NOTE: This has priority over "Vec2<Vec2<T>> MakeVec(const Vec2<T>& x, const Vec2<T>& y)". 752 // Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error 753 // out soon enough due to misuse of the returned structure. 754 template <typename T> 755 [[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) { 756 return MakeVec(xy[0], xy[1], zw[0], zw[1]); 757 } 758 759 template <typename T> 760 [[nodiscard]] constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) { 761 return MakeVec(xyz[0], xyz[1], xyz[2], w); 762 } 763 764 template <typename T> 765 [[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) { 766 return MakeVec(x, yzw[0], yzw[1], yzw[2]); 767 } 768 769 } // namespace Common