windowsnumerics.impl.h (48101B) - Raw
1 /** 2 * This file has no copyright assigned and is placed in the Public Domain. 3 * This file is part of the mingw-w64 runtime package. 4 * No warranty is given; refer to the file DISCLAIMER.PD within this package. 5 */ 6 7 /** 8 * Normal users should include `windowsnumerics.h` instead of this header. 9 * However, the cppwinrt headers set `_WINDOWS_NUMERICS_NAMESPACE_`, 10 * `_WINDOWS_NUMERICS_BEGIN_NAMESPACE_` and `_WINDOWS_NUMERICS_END_NAMESPACE_` 11 * to custom values and include `windowsnumerics.impl.h`. Therefore this shall 12 * be considered a public header, and these macros are public API. 13 */ 14 15 16 #ifdef min 17 # pragma push_macro("min") 18 # undef min 19 # define _WINDOWS_NUMERICS_IMPL_PUSHED_MIN_ 20 #endif 21 22 #ifdef max 23 # pragma push_macro("max") 24 # undef max 25 # define _WINDOWS_NUMERICS_IMPL_PUSHED_MAX_ 26 #endif 27 28 #include <algorithm> 29 #include <cmath> 30 31 #include "directxmath.h" 32 33 34 // === Internal macros === 35 #define _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(_ty1, _op, _ty2) \ 36 inline _ty1 &operator _op ## =(_ty1 &val1, _ty2 val2) { \ 37 val1 = operator _op (val1, val2); \ 38 return val1; \ 39 } 40 41 42 // === Internal functions === 43 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 44 namespace _impl { 45 46 #if 0 && defined(__cpp_lib_clamp) 47 using std::clamp; 48 #else 49 constexpr const float &clamp(const float &val, const float &min, const float &max) { 50 return val < min ? min : (val > max ? max : val); 51 } 52 #endif 53 54 #if 0 && defined(__cpp_lib_interpolate) 55 using std::lerp; 56 #else 57 constexpr float lerp(float val1, float val2, float amount) { 58 // Don't do (val2 - val1) * amount + val1 as it has worse precision. 59 return val2 * amount + val1 * (1.0f - amount); 60 } 61 #endif 62 63 } 64 } _WINDOWS_NUMERICS_END_NAMESPACE_ 65 66 67 // === Forward decls === 68 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 69 70 struct float2; 71 struct float3; 72 struct float4; 73 struct float3x2; 74 struct float4x4; 75 struct plane; 76 struct quaternion; 77 78 } _WINDOWS_NUMERICS_END_NAMESPACE_ 79 80 81 // === float2: Struct and function defs === 82 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 83 84 struct float2 { 85 float2() = default; 86 constexpr float2(float x, float y) 87 : x(x), y(y) 88 {} 89 constexpr explicit float2(float val) 90 : x(val), y(val) 91 {} 92 93 static constexpr float2 zero() { 94 return float2(0.0f); 95 } 96 static constexpr float2 one() { 97 return float2(1.0f); 98 } 99 static constexpr float2 unit_x() { 100 return { 1.0f, 0.0f }; 101 } 102 static constexpr float2 unit_y() { 103 return { 0.0f, 1.0f }; 104 } 105 106 float x; 107 float y; 108 }; 109 110 // Forward decl functions 111 inline float length(const float2 &val); 112 inline float length_squared(const float2 &val); 113 inline float distance(const float2 &val1, const float2 &val2); 114 inline float distance_squared(const float2 &val1, const float2 &val2); 115 inline float dot(const float2 &val1, const float2 &val2); 116 inline float2 normalize(const float2 &val); 117 inline float2 reflect(const float2 &vec, const float2 &norm); 118 inline float2 min(const float2 &val1, const float2 &val2); 119 inline float2 max(const float2 &val1, const float2 &val2); 120 inline float2 clamp(const float2 &val, const float2 &min, const float2 &max); 121 inline float2 lerp(const float2 &val1, const float2 &val2, float amount); 122 inline float2 transform(const float2 &pos, const float3x2 &mat); 123 inline float2 transform(const float2 &pos, const float4x4 &mat); 124 inline float2 transform_normal(const float2 &norm, const float3x2 &mat); 125 inline float2 transform_normal(const float2 &norm, const float4x4 &mat); 126 inline float2 transform(const float2 &val, const quaternion &rot); 127 128 // Define operators 129 #define _WINDOWS_NUMERICS_IMPL_BINARY_OP(_ty, _op) \ 130 inline _ty operator _op(const _ty &val1, const _ty &val2) { \ 131 return { val1.x _op val2.x, val1.y _op val2.y }; \ 132 } 133 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float2, +) 134 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float2, -) 135 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float2, *) 136 inline float2 operator*(const float2 &val1, float val2) { 137 return { val1.x * val2, val1.y * val2 }; 138 } 139 inline float2 operator*(float val1, const float2 &val2) { 140 return operator*(val2, val1); 141 } 142 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float2, /) 143 inline float2 operator/(const float2 &val1, float val2) { 144 return operator*(val1, 1.0f / val2); 145 } 146 inline float2 operator-(const float2 &val) { 147 return { -val.x, -val.y }; 148 } 149 #undef _WINDOWS_NUMERICS_IMPL_BINARY_OP 150 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float2, +, const float2 &) 151 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float2, -, const float2 &) 152 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float2, *, const float2 &) 153 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float2, *, float) 154 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float2, /, const float2 &) 155 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float2, /, float) 156 inline bool operator==(const float2 &val1, const float2 &val2) { 157 return val1.x == val2.x && val1.y == val2.y; 158 } 159 inline bool operator!=(const float2 &val1, const float2 &val2) { 160 return !operator==(val1, val2); 161 } 162 163 } _WINDOWS_NUMERICS_END_NAMESPACE_ 164 165 166 // === float3: Struct and function defs === 167 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 168 169 struct float3 { 170 float3() = default; 171 constexpr float3(float x, float y, float z) 172 : x(x), y(y), z(z) 173 {} 174 constexpr float3(float2 val, float z) 175 : x(val.x), y(val.y), z(z) 176 {} 177 constexpr explicit float3(float val) 178 : x(val), y(val), z(val) 179 {} 180 181 static constexpr float3 zero() { 182 return float3(0.0); 183 } 184 static constexpr float3 one() { 185 return float3(1.0); 186 } 187 static constexpr float3 unit_x() { 188 return { 1.0f, 0.0f, 0.0f }; 189 } 190 static constexpr float3 unit_y() { 191 return { 0.0f, 1.0f, 0.0f }; 192 } 193 static constexpr float3 unit_z() { 194 return { 0.0f, 0.0f, 1.0f }; 195 } 196 197 float x; 198 float y; 199 float z; 200 }; 201 202 // Forward decl functions 203 inline float length(const float3 &val); 204 inline float length_squared(const float3 &val); 205 inline float distance(const float3 &val1, const float3 &val2); 206 inline float distance_squared(const float3 &val1, const float3 &val2); 207 inline float dot(const float3 &val1, const float3 &val2); 208 inline float3 normalize(const float3 &val); 209 inline float3 cross(const float3 &val1, const float3 &val2); 210 inline float3 reflect(const float3 &vec, const float3 &norm); 211 inline float3 min(const float3 &val1, const float3 &val2); 212 inline float3 max(const float3 &val1, const float3 &val2); 213 inline float3 clamp(const float3 &val, const float3 &min, const float3 &max); 214 inline float3 lerp(const float3 &val1, const float3 &val2, float amount); 215 inline float3 transform(const float3 &pos, const float4x4 &mat); 216 inline float3 transform_normal(const float3 &norm, const float4x4 &mat); 217 inline float3 transform(const float3 &val, const quaternion &rot); 218 219 // Define operators 220 #define _WINDOWS_NUMERICS_IMPL_BINARY_OP(_ty, _op) \ 221 inline _ty operator _op(const _ty &val1, const _ty &val2) { \ 222 return { val1.x _op val2.x, val1.y _op val2.y, val1.z _op val2.z }; \ 223 } 224 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float3, +) 225 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float3, -) 226 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float3, *) 227 inline float3 operator*(const float3 &val1, float val2) { 228 return { val1.x * val2, val1.y * val2, val1.z * val2 }; 229 } 230 inline float3 operator*(float val1, const float3 &val2) { 231 return operator*(val2, val1); 232 } 233 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float3, /) 234 inline float3 operator/(const float3 &val1, float val2) { 235 return operator*(val1, 1.0f / val2); 236 } 237 inline float3 operator-(const float3 &val) { 238 return { -val.x, -val.y, -val.z }; 239 } 240 #undef _WINDOWS_NUMERICS_IMPL_BINARY_OP 241 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float3, +, const float3 &) 242 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float3, -, const float3 &) 243 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float3, *, const float3 &) 244 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float3, *, float) 245 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float3, /, const float3 &) 246 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float3, /, float) 247 inline bool operator==(const float3 &val1, const float3 &val2) { 248 return val1.x == val2.x && val1.y == val2.y && val1.z == val2.z; 249 } 250 inline bool operator!=(const float3 &val1, const float3 &val2) { 251 return !operator==(val1, val2); 252 } 253 254 } _WINDOWS_NUMERICS_END_NAMESPACE_ 255 256 257 // === float4: Struct and function defs === 258 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 259 260 struct float4 { 261 float4() = default; 262 constexpr float4(float x, float y, float z, float w) 263 : x(x), y(y), z(z), w(w) 264 {} 265 constexpr float4(float2 val, float z, float w) 266 : x(val.x), y(val.y), z(z), w(w) 267 {} 268 constexpr float4(float3 val, float w) 269 : x(val.x), y(val.y), z(val.z), w(w) 270 {} 271 constexpr explicit float4(float val) 272 : x(val), y(val), z(val), w(val) 273 {} 274 275 static constexpr float4 zero() { 276 return float4(0.0); 277 } 278 static constexpr float4 one() { 279 return float4(1.0); 280 } 281 static constexpr float4 unit_x() { 282 return { 1.0f, 0.0f, 0.0f, 0.0f }; 283 } 284 static constexpr float4 unit_y() { 285 return { 0.0f, 1.0f, 0.0f, 0.0f }; 286 } 287 static constexpr float4 unit_z() { 288 return { 0.0f, 0.0f, 1.0f, 0.0f }; 289 } 290 static constexpr float4 unit_w() { 291 return { 0.0f, 0.0f, 0.0f, 1.0f }; 292 } 293 294 float x; 295 float y; 296 float z; 297 float w; 298 }; 299 300 // Forward decl functions 301 inline float length(const float4 &val); 302 inline float length_squared(const float4 &val); 303 inline float distance(const float4 &val1, const float4 &val2); 304 inline float distance_squared(const float4 &val1, const float4 &val2); 305 inline float dot(const float4 &val1, const float4 &val2); 306 inline float4 normalize(const float4 &val); 307 inline float4 min(const float4 &val1, const float4 &val2); 308 inline float4 max(const float4 &val1, const float4 &val2); 309 inline float4 clamp(const float4 &val, const float4 &min, const float4 &max); 310 inline float4 lerp(const float4 &val1, const float4 &val2, float amount); 311 inline float4 transform(const float4 &pos, const float4x4 &mat); 312 inline float4 transform4(const float3 &pos, const float4x4 &mat); 313 inline float4 transform4(const float2 &pos, const float4x4 &mat); 314 inline float4 transform(const float4 &val, const quaternion &rot); 315 inline float4 transform4(const float3 &val, const quaternion &rot); 316 inline float4 transform4(const float2 &val, const quaternion &rot); 317 318 // Define operators 319 #define _WINDOWS_NUMERICS_IMPL_BINARY_OP(_ty, _op) \ 320 inline _ty operator _op(const _ty &val1, const _ty &val2) { \ 321 return { val1.x _op val2.x, val1.y _op val2.y, val1.z _op val2.z, val1.w _op val2.w }; \ 322 } 323 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float4, +) 324 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float4, -) 325 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float4, *) 326 inline float4 operator*(const float4 &val1, float val2) { 327 return { val1.x * val2, val1.y * val2, val1.z * val2, val1.w * val2 }; 328 } 329 inline float4 operator*(float val1, const float4 &val2) { 330 return operator*(val2, val1); 331 } 332 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float4, /) 333 inline float4 operator/(const float4 &val1, float val2) { 334 return operator*(val1, 1.0f / val2); 335 } 336 inline float4 operator-(const float4 &val) { 337 return { -val.x, -val.y, -val.z, -val.w }; 338 } 339 #undef _WINDOWS_NUMERICS_IMPL_BINARY_OP 340 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float4, +, const float4 &) 341 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float4, -, const float4 &) 342 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float4, *, const float4 &) 343 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float4, *, float) 344 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float4, /, const float4 &) 345 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float4, /, float) 346 inline bool operator==(const float4 &val1, const float4 &val2) { 347 return val1.x == val2.x && val1.y == val2.y && val1.z == val2.z && val2.w == val2.w; 348 } 349 inline bool operator!=(const float4 &val1, const float4 &val2) { 350 return !operator==(val1, val2); 351 } 352 353 } _WINDOWS_NUMERICS_END_NAMESPACE_ 354 355 356 // === float3x2: Struct and function defs === 357 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 358 359 struct float3x2 { 360 float3x2() = default; 361 constexpr float3x2( 362 float m11, float m12, 363 float m21, float m22, 364 float m31, float m32 365 ) 366 : m11(m11), m12(m12) 367 , m21(m21), m22(m22) 368 , m31(m31), m32(m32) 369 {} 370 371 static constexpr float3x2 identity() { 372 return { 373 1.0f, 0.0f, 374 0.0f, 1.0f, 375 0.0f, 0.0f 376 }; 377 } 378 379 float m11; float m12; 380 float m21; float m22; 381 float m31; float m32; 382 }; 383 384 // Forward decl functions 385 inline float3x2 make_float3x2_translation(const float2 &pos); 386 inline float3x2 make_float3x2_translation(float xpos, float ypos); 387 inline float3x2 make_float3x2_scale(float xscale, float yscale); 388 inline float3x2 make_float3x2_scale(float xscale, float yscale, const float2 ¢er); 389 inline float3x2 make_float3x2_scale(const float2 &xyscale); 390 inline float3x2 make_float3x2_scale(const float2 &xyscale, const float2 ¢er); 391 inline float3x2 make_float3x2_scale(float scale); 392 inline float3x2 make_float3x2_scale(float scale, const float2 ¢er); 393 inline float3x2 make_float3x2_skew(float xrad, float yrad); 394 inline float3x2 make_float3x2_skew(float xrad, float yrad, const float2 ¢er); 395 inline float3x2 make_float3x2_rotation(float rad); 396 inline float3x2 make_float3x2_rotation(float rad, const float2 ¢er); 397 inline bool is_identity(const float3x2 &val); 398 inline float determinant(const float3x2 &val); 399 inline float2 translation(const float3x2 &val); 400 inline bool invert(const float3x2 &val, float3x2 *out); 401 inline float3x2 lerp(const float3x2 &mat1, const float3x2 &mat2, float amount); 402 403 // Define operators 404 #define _WINDOWS_NUMERICS_IMPL_BINARY_OP(_ty, _op) \ 405 inline _ty operator _op(const _ty &val1, const _ty &val2) { \ 406 return { \ 407 val1.m11 _op val2.m11, val1.m12 _op val2.m12, \ 408 val1.m21 _op val2.m21, val1.m22 _op val2.m22, \ 409 val1.m31 _op val2.m31, val1.m32 _op val2.m32, \ 410 }; \ 411 } 412 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float3x2, +) 413 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float3x2, -) 414 inline float3x2 operator*(const float3x2 &val1, const float3x2 &val2) { 415 // 2D transformation matrix has an implied 3rd column with (0, 0, 1) 416 const float3 v1r1(val1.m11, val1.m12, 0.0f); 417 const float3 v1r2(val1.m21, val1.m22, 0.0f); 418 const float3 v1r3(val1.m31, val1.m32, 1.0f); 419 const float3 v2c1(val2.m11, val2.m21, val2.m31); 420 const float3 v2c2(val2.m12, val2.m22, val2.m32); 421 // const float3 v2c3(0.0f, 0.0f, 1.0f); 422 return { 423 dot(v1r1, v2c1), dot(v1r1, v2c2), 424 dot(v1r2, v2c1), dot(v1r2, v2c2), 425 dot(v1r3, v2c1), dot(v1r3, v2c2) 426 }; 427 } 428 inline float3x2 operator*(const float3x2 &val1, float val2) { 429 return { 430 val1.m11 * val2, val1.m12 * val2, 431 val1.m21 * val2, val1.m22 * val2, 432 val1.m31 * val2, val1.m32 * val2 433 }; 434 } 435 inline float3x2 operator-(const float3x2 &val) { 436 return { 437 -val.m11, -val.m12, 438 -val.m21, -val.m22, 439 -val.m31, -val.m32 440 }; 441 } 442 #undef _WINDOWS_NUMERICS_IMPL_BINARY_OP 443 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float3x2, +, const float3x2 &) 444 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float3x2, -, const float3x2 &) 445 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float3x2, *, const float3x2 &) 446 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float3x2, *, float) 447 inline bool operator==(const float3x2 &val1, const float3x2 &val2) { 448 return 449 val1.m11 == val2.m11 && val1.m12 == val2.m12 && 450 val1.m21 == val2.m21 && val1.m22 == val2.m22 && 451 val1.m31 == val2.m31 && val1.m32 == val2.m32; 452 } 453 inline bool operator!=(const float3x2 &val1, const float3x2 &val2) { 454 return !operator==(val1, val2); 455 } 456 457 } _WINDOWS_NUMERICS_END_NAMESPACE_ 458 459 460 // === float4x4: Struct and function defs === 461 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 462 463 struct float4x4 { 464 float4x4() = default; 465 constexpr float4x4( 466 float m11, float m12, float m13, float m14, 467 float m21, float m22, float m23, float m24, 468 float m31, float m32, float m33, float m34, 469 float m41, float m42, float m43, float m44 470 ) 471 : m11(m11), m12(m12), m13(m13), m14(m14) 472 , m21(m21), m22(m22), m23(m23), m24(m24) 473 , m31(m31), m32(m32), m33(m33), m34(m34) 474 , m41(m41), m42(m42), m43(m43), m44(m44) 475 {} 476 477 static constexpr float4x4 identity() { 478 return { 479 1.0f, 0.0f, 0.0f, 0.0f, 480 0.0f, 1.0f, 0.0f, 0.0f, 481 0.0f, 0.0f, 1.0f, 0.0f, 482 0.0f, 0.0f, 0.0f, 1.0f 483 }; 484 } 485 486 float m11; float m12; float m13; float m14; 487 float m21; float m22; float m23; float m24; 488 float m31; float m32; float m33; float m34; 489 float m41; float m42; float m43; float m44; 490 }; 491 492 // Forward decl functions 493 inline float4x4 make_float4x4_billboard(const float3 &objpos, const float3 &camerapos, const float3 &cameraup, const float3 &camerafwd); 494 inline float4x4 make_float4x4_constrained_billboard(const float3 &objpos, const float3 &camerapos, const float3 &rotateaxis, const float3 &camerafwd, const float3 &objfwd); 495 inline float4x4 make_float4x4_translation(const float3 &pos); 496 inline float4x4 make_float4x4_translation(float xpos, float ypos, float zpos); 497 inline float4x4 make_float4x4_scale(float xscale, float yscale, float zscale); 498 inline float4x4 make_float4x4_scale(float xscale, float yscale, float zscale, const float3 ¢er); 499 inline float4x4 make_float4x4_scale(const float3 &xyzscale); 500 inline float4x4 make_float4x4_scale(const float3 &xyzscale, const float3 ¢er); 501 inline float4x4 make_float4x4_scale(float scale); 502 inline float4x4 make_float4x4_scale(float scale, const float3 ¢er); 503 inline float4x4 make_float4x4_rotation_x(float rad); 504 inline float4x4 make_float4x4_rotation_x(float rad, const float3 ¢er); 505 inline float4x4 make_float4x4_rotation_y(float rad); 506 inline float4x4 make_float4x4_rotation_y(float rad, const float3 ¢er); 507 inline float4x4 make_float4x4_rotation_z(float rad); 508 inline float4x4 make_float4x4_rotation_z(float rad, const float3 ¢er); 509 inline float4x4 make_float4x4_from_axis_angle(const float3 &axis, float angle); 510 inline float4x4 make_float4x4_perspective_field_of_view(float fov, float aspect, float nearplane, float farplane); 511 inline float4x4 make_float4x4_perspective(float w, float h, float nearplane, float farplane); 512 inline float4x4 make_float4x4_perspective_off_center(float left, float right, float bottom, float top, float nearplane, float farplane); 513 inline float4x4 make_float4x4_orthographic(float w, float h, float znearplane, float zfarplane); 514 inline float4x4 make_float4x4_orthographic_off_center(float left, float right, float bottom, float top, float znearplane, float zfarplane); 515 inline float4x4 make_float4x4_look_at(const float3 &camerapos, const float3 &target, const float3 &cameraup); 516 inline float4x4 make_float4x4_world(const float3 &pos, const float3 &fwd, const float3 &up); 517 inline float4x4 make_float4x4_from_quaternion(const quaternion &quat); 518 inline float4x4 make_float4x4_from_yaw_pitch_roll(float yaw, float pitch, float roll); 519 inline float4x4 make_float4x4_shadow(const float3 &lightdir, const plane &plane); 520 inline float4x4 make_float4x4_reflection(const plane &plane); 521 inline bool is_identity(const float4x4 &val); 522 inline float determinant(const float4x4 &val); 523 inline float3 translation(const float4x4 &val); 524 inline bool invert(const float4x4 &mat, float4x4 *out); 525 inline bool decompose(const float4x4 &mat, float3 *out_scale, quaternion *out_rot, float3 *out_translate); 526 inline float4x4 transform(const float4x4 &val, const quaternion &rot); 527 inline float4x4 transpose(const float4x4 &val); 528 inline float4x4 lerp(const float4x4 &val1, const float4x4 &val2, float amount); 529 530 // Define operators 531 #define _WINDOWS_NUMERICS_IMPL_BINARY_OP(_ty, _op) \ 532 inline _ty operator _op(const _ty &val1, const _ty &val2) { \ 533 return { \ 534 val1.m11 _op val2.m11, val1.m12 _op val2.m12, val1.m13 _op val2.m13, val1.m14 _op val2.m14, \ 535 val1.m21 _op val2.m21, val1.m22 _op val2.m22, val1.m23 _op val2.m23, val1.m24 _op val2.m24, \ 536 val1.m31 _op val2.m31, val1.m32 _op val2.m32, val1.m33 _op val2.m33, val1.m34 _op val2.m34, \ 537 val1.m41 _op val2.m41, val1.m42 _op val2.m42, val1.m43 _op val2.m43, val1.m44 _op val2.m44, \ 538 }; \ 539 } 540 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float4x4, +) 541 _WINDOWS_NUMERICS_IMPL_BINARY_OP(float4x4, -) 542 inline float4x4 operator*(const float4x4 &val1, const float4x4 &val2) { 543 const float4 v1r1(val1.m11, val1.m12, val1.m13, val1.m14); 544 const float4 v1r2(val1.m21, val1.m22, val1.m23, val1.m24); 545 const float4 v1r3(val1.m31, val1.m32, val1.m33, val1.m34); 546 const float4 v1r4(val1.m41, val1.m42, val1.m43, val1.m44); 547 const float4 v2c1(val2.m11, val2.m21, val2.m31, val2.m41); 548 const float4 v2c2(val2.m12, val2.m22, val2.m32, val2.m42); 549 const float4 v2c3(val2.m13, val2.m23, val2.m33, val2.m43); 550 const float4 v2c4(val2.m14, val2.m24, val2.m34, val2.m44); 551 return { 552 dot(v1r1, v2c1), dot(v1r1, v2c2), dot(v1r1, v2c3), dot(v1r1, v2c4), 553 dot(v1r2, v2c1), dot(v1r2, v2c2), dot(v1r2, v2c3), dot(v1r2, v2c4), 554 dot(v1r3, v2c1), dot(v1r3, v2c2), dot(v1r3, v2c3), dot(v1r3, v2c4), 555 dot(v1r4, v2c1), dot(v1r4, v2c2), dot(v1r4, v2c3), dot(v1r4, v2c4) 556 }; 557 } 558 inline float4x4 operator*(const float4x4 &val1, float val2) { 559 return { 560 val1.m11 * val2, val1.m12 * val2, val1.m13 * val2, val1.m14 * val2, 561 val1.m21 * val2, val1.m22 * val2, val1.m23 * val2, val1.m24 * val2, 562 val1.m31 * val2, val1.m32 * val2, val1.m33 * val2, val1.m34 * val2, 563 val1.m41 * val2, val1.m42 * val2, val1.m43 * val2, val1.m44 * val2 564 }; 565 } 566 inline float4x4 operator-(const float4x4 &val) { 567 return { 568 -val.m11, -val.m12, -val.m13, -val.m14, 569 -val.m21, -val.m22, -val.m23, -val.m24, 570 -val.m31, -val.m32, -val.m33, -val.m34, 571 -val.m41, -val.m42, -val.m43, -val.m44 572 }; 573 } 574 #undef _WINDOWS_NUMERICS_IMPL_BINARY_OP 575 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float4x4, +, const float4x4 &) 576 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float4x4, -, const float4x4 &) 577 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float4x4, *, const float4x4 &) 578 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(float4x4, *, float) 579 inline bool operator==(const float4x4 &val1, const float4x4 &val2) { 580 return 581 val1.m11 == val2.m11 && val1.m12 == val2.m12 && val1.m13 == val2.m13 && val1.m14 == val2.m14 && 582 val1.m21 == val2.m21 && val1.m22 == val2.m22 && val1.m23 == val2.m23 && val1.m24 == val2.m24 && 583 val1.m31 == val2.m31 && val1.m32 == val2.m32 && val1.m33 == val2.m33 && val1.m34 == val2.m34 && 584 val1.m41 == val2.m41 && val1.m42 == val2.m42 && val1.m43 == val2.m43 && val1.m44 == val2.m44; 585 } 586 inline bool operator!=(const float4x4 &val1, const float4x4 &val2) { 587 return !operator==(val1, val2); 588 } 589 590 } _WINDOWS_NUMERICS_END_NAMESPACE_ 591 592 593 // === plane: Struct and function defs === 594 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 595 596 struct plane { 597 plane() = default; 598 constexpr plane(float x, float y, float z, float d) 599 : normal(float3(x, y, z)), d(d) 600 {} 601 constexpr plane(float3 normal, float d) 602 : normal(normal), d(d) 603 {} 604 constexpr explicit plane(float4 val) 605 : normal(float3(val.x, val.y, val.z)), d(val.w) 606 {} 607 608 float3 normal; 609 float d; 610 }; 611 612 // Forward decl functions 613 inline plane make_plane_from_vertices(const float3 &pt1, const float3 &pt2, const float3 &pt3); 614 inline plane normalize(const plane &val); 615 inline plane transform(const plane &plane, const float4x4 &mat); 616 inline plane transform(const plane &plane, const quaternion &rot); 617 inline float dot(const plane &plane, const float4 &val); 618 inline float dot_coordinate(const plane &plane, const float3 &val); 619 inline float dot_normal(const plane &plane, const float3 &val); 620 621 // Define operators 622 inline bool operator==(const plane &val1, const plane &val2) { 623 return val1.normal == val2.normal && val1.d == val2.d; 624 } 625 inline bool operator!=(const plane &val1, const plane &val2) { 626 return !operator==(val1, val2); 627 } 628 629 } _WINDOWS_NUMERICS_END_NAMESPACE_ 630 631 632 // === quaternion: Struct and function defs === 633 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 634 635 struct quaternion { 636 quaternion() = default; 637 constexpr quaternion(float x, float y, float z, float w) 638 : x(x), y(y), z(z), w(w) 639 {} 640 constexpr quaternion(float3 vecPart, float scalarPart) 641 : x(vecPart.x), y(vecPart.y), z(vecPart.z), w(scalarPart) 642 {} 643 644 static constexpr quaternion identity() { 645 return { 0.0f, 0.0f, 0.0f, 1.0f }; 646 } 647 648 float x; 649 float y; 650 float z; 651 float w; 652 }; 653 654 // Forward decl functions 655 inline quaternion make_quaternion_from_axis_angle(const float3 &axis, float angle); 656 inline quaternion make_quaternion_from_yaw_pitch_roll(float yaw, float pitch, float roll); 657 inline quaternion make_quaternion_from_rotation_matrix(const float4x4 &mat); 658 inline bool is_identity(const quaternion &val); 659 inline float length(const quaternion &val); 660 inline float length_squared(const quaternion &val); 661 inline float dot(const quaternion &val1, const quaternion &val2); 662 inline quaternion normalize(const quaternion &val); 663 inline quaternion conjugate(const quaternion &val); 664 inline quaternion inverse(const quaternion &val); 665 inline quaternion slerp(const quaternion &val1, const quaternion &val2, float amount); 666 inline quaternion lerp(const quaternion &val1, const quaternion &val2, float amount); 667 inline quaternion concatenate(const quaternion &val1, const quaternion &val2); 668 669 // Define operators 670 #define _WINDOWS_NUMERICS_IMPL_BINARY_OP(_ty, _op) \ 671 inline _ty operator _op(const _ty &val1, const _ty &val2) { \ 672 return { val1.x _op val2.x, val1.y _op val2.y, val1.z _op val2.z, val1.w _op val2.w }; \ 673 } 674 _WINDOWS_NUMERICS_IMPL_BINARY_OP(quaternion, +) 675 _WINDOWS_NUMERICS_IMPL_BINARY_OP(quaternion, -) 676 inline quaternion operator*(const quaternion &val1, const quaternion &val2) { 677 return { 678 val1.w * val2.x + val1.x * val2.w + val1.y * val2.z - val1.z * val2.y, 679 val1.w * val2.y - val1.x * val2.z + val1.y * val2.w + val1.z * val2.x, 680 val1.w * val2.z + val1.x * val2.y - val1.y * val2.x + val1.z * val2.w, 681 val1.w * val2.w - val1.x * val2.x - val1.y * val2.y - val1.z * val2.z 682 }; } 683 inline quaternion operator*(const quaternion &val1, float val2) { 684 return { val1.x * val2, val1.y * val2, val1.z * val2, val1.w * val2 }; 685 } 686 inline quaternion operator/(const quaternion &val1, const quaternion &val2) { 687 return operator*(val1, inverse(val2)); 688 } 689 inline quaternion operator-(const quaternion &val) { 690 return { -val.x, -val.y, -val.z, -val.w }; 691 } 692 #undef _WINDOWS_NUMERICS_IMPL_BINARY_OP 693 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(quaternion, +, const quaternion &) 694 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(quaternion, -, const quaternion &) 695 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(quaternion, *, const quaternion &) 696 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(quaternion, *, float) 697 _WINDOWS_NUMERICS_IMPL_ASSIGN_OP(quaternion, /, const quaternion &) 698 inline bool operator==(const quaternion &val1, const quaternion &val2) { 699 return val1.x == val2.x && val1.y == val2.y && val1.z == val2.z && val2.w == val2.w; 700 } 701 inline bool operator!=(const quaternion &val1, const quaternion &val2) { 702 return !operator==(val1, val2); 703 } 704 705 } _WINDOWS_NUMERICS_END_NAMESPACE_ 706 707 708 // === Function definitions === 709 710 // Define float2 functions 711 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 712 713 inline float length(const float2 &val) { 714 return ::std::sqrt(length_squared(val)); 715 } 716 inline float length_squared(const float2 &val) { 717 return val.x * val.x + val.y * val.y; 718 } 719 inline float distance(const float2 &val1, const float2 &val2) { 720 return length(val2 - val1); 721 } 722 inline float distance_squared(const float2 &val1, const float2 &val2) { 723 return length_squared(val2 - val1); 724 } 725 inline float dot(const float2 &val1, const float2 &val2) { 726 return val1.x * val2.x + val1.y * val2.y; 727 } 728 inline float2 normalize(const float2 &val) { 729 return val / length(val); 730 } 731 inline float2 reflect(const float2 &vec, const float2 &norm) { 732 // norm is assumed to be normalized. 733 return vec - 2.0f * dot(vec, norm) * norm; 734 } 735 inline float2 min(const float2 &val1, const float2 &val2) { 736 return { ::std::min(val1.x, val2.x), ::std::min(val1.y, val2.y) }; 737 } 738 inline float2 max(const float2 &val1, const float2 &val2) { 739 return { ::std::max(val1.x, val2.x), ::std::max(val1.y, val2.y) }; 740 } 741 inline float2 clamp(const float2 &val, const float2 &min, const float2 &max) { 742 return { _impl::clamp(val.x, min.x, max.x), _impl::clamp(val.y, min.y, max.y) }; 743 } 744 inline float2 lerp(const float2 &val1, const float2 &val2, float amount) { 745 return { _impl::lerp(val1.x, val2.x, amount), _impl::lerp(val1.y, val2.y, amount) }; 746 } 747 // TODO: impl 748 inline float2 transform(const float2 &pos, const float3x2 &mat); 749 inline float2 transform(const float2 &pos, const float4x4 &mat); 750 inline float2 transform_normal(const float2 &norm, const float3x2 &mat); 751 inline float2 transform_normal(const float2 &norm, const float4x4 &mat); 752 inline float2 transform(const float2 &val, const quaternion &rot) { 753 // See comments in the float3 transform function. 754 quaternion result = rot * quaternion(float3(val.x, val.y, 0.0f), 0.0f) * inverse(rot); 755 return { result.x, result.y }; 756 } 757 758 } _WINDOWS_NUMERICS_END_NAMESPACE_ 759 760 761 // Define float3 functions 762 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 763 764 inline float length(const float3 &val) { 765 return ::std::sqrt(length_squared(val)); 766 } 767 inline float length_squared(const float3 &val) { 768 return val.x * val.x + val.y * val.y + val.z * val.z; 769 } 770 inline float distance(const float3 &val1, const float3 &val2) { 771 return length(val2 - val1); 772 } 773 inline float distance_squared(const float3 &val1, const float3 &val2) { 774 return length_squared(val2 - val1); 775 } 776 inline float dot(const float3 &val1, const float3 &val2) { 777 return val1.x * val2.x + val1.y * val2.y + val1.z * val2.z; 778 } 779 inline float3 normalize(const float3 &val) { 780 return val / length(val); 781 } 782 inline float3 cross(const float3 &val1, const float3 &val2) { 783 return { 784 val1.y * val2.z - val2.y * val1.z, 785 val1.z * val2.x - val2.z * val1.x, 786 val1.x * val2.y - val2.x * val1.y 787 }; 788 } 789 inline float3 reflect(const float3 &vec, const float3 &norm) { 790 // norm is assumed to be normalized. 791 return vec - 2.0f * dot(vec, norm) * norm; 792 } 793 inline float3 min(const float3 &val1, const float3 &val2) { 794 return { ::std::min(val1.x, val2.x), ::std::min(val1.y, val2.y), ::std::min(val1.z, val2.z) }; 795 } 796 inline float3 max(const float3 &val1, const float3 &val2) { 797 return { ::std::max(val1.x, val2.x), ::std::max(val1.y, val2.y), ::std::max(val1.z, val2.z) }; 798 } 799 inline float3 clamp(const float3 &val, const float3 &min, const float3 &max) { 800 return { _impl::clamp(val.x, min.x, max.x), _impl::clamp(val.y, min.y, max.y), _impl::clamp(val.z, min.z, max.z) }; 801 } 802 inline float3 lerp(const float3 &val1, const float3 &val2, float amount) { 803 return { _impl::lerp(val1.x, val2.x, amount), _impl::lerp(val1.y, val2.y, amount), _impl::lerp(val1.z, val2.z, amount) }; 804 } 805 // TODO: impl 806 inline float3 transform(const float3 &pos, const float4x4 &mat); 807 inline float3 transform_normal(const float3 &norm, const float4x4 &mat); 808 inline float3 transform(const float3 &val, const quaternion &rot) { 809 // https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Using_quaternions_as_rotations 810 // If assuming rot is a unit quaternion, this could use 811 // conjugate() instead of inverse() too. 812 // This can be expressed as a matrix operation too, with 813 // https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix 814 // (see make_float4x4_from_quaternion). 815 quaternion result = rot * quaternion(val, 0.0f) * inverse(rot); 816 return { result.x, result.y, result.z }; 817 } 818 819 } _WINDOWS_NUMERICS_END_NAMESPACE_ 820 821 822 // Define float4 functions 823 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 824 825 inline float length(const float4 &val) { 826 return ::std::sqrt(length_squared(val)); 827 } 828 inline float length_squared(const float4 &val) { 829 return val.x * val.x + val.y * val.y + val.z * val.z + val.w * val.w; 830 } 831 inline float distance(const float4 &val1, const float4 &val2) { 832 return length(val2 - val1); 833 } 834 inline float distance_squared(const float4 &val1, const float4 &val2) { 835 return length_squared(val2 - val1); 836 } 837 inline float dot(const float4 &val1, const float4 &val2) { 838 return val1.x * val2.x + val1.y * val2.y + val1.z * val2.z + val1.w * val2.w; 839 } 840 inline float4 normalize(const float4 &val) { 841 return val / length(val); 842 } 843 inline float4 min(const float4 &val1, const float4 &val2) { 844 return { 845 ::std::min(val1.x, val2.x), 846 ::std::min(val1.y, val2.y), 847 ::std::min(val1.z, val2.z), 848 ::std::min(val1.w, val2.w) 849 }; 850 } 851 inline float4 max(const float4 &val1, const float4 &val2) { 852 return { 853 ::std::max(val1.x, val2.x), 854 ::std::max(val1.y, val2.y), 855 ::std::max(val1.z, val2.z), 856 ::std::max(val1.w, val2.w) 857 }; 858 } 859 inline float4 clamp(const float4 &val, const float4 &min, const float4 &max) { 860 return { 861 _impl::clamp(val.x, min.x, max.x), 862 _impl::clamp(val.y, min.y, max.y), 863 _impl::clamp(val.z, min.z, max.z), 864 _impl::clamp(val.w, min.w, max.w) 865 }; 866 } 867 inline float4 lerp(const float4 &val1, const float4 &val2, float amount) { 868 return { 869 _impl::lerp(val1.x, val2.x, amount), 870 _impl::lerp(val1.y, val2.y, amount), 871 _impl::lerp(val1.z, val2.z, amount), 872 _impl::lerp(val1.w, val2.w, amount) 873 }; 874 } 875 // TODO: impl 876 inline float4 transform(const float4 &pos, const float4x4 &mat); 877 inline float4 transform4(const float3 &pos, const float4x4 &mat); 878 inline float4 transform4(const float2 &pos, const float4x4 &mat); 879 inline float4 transform(const float4 &val, const quaternion &rot) { 880 // See comments in the float3 transform function. 881 quaternion result = rot * quaternion(float3(val.x, val.y, val.z), 0.0f) * inverse(rot); 882 return { result.x, result.y, result.z, val.w }; 883 } 884 inline float4 transform4(const float3 &val, const quaternion &rot) { 885 quaternion result = rot * quaternion(val, 0.0f) * inverse(rot); 886 return { result.x, result.y, result.z, 1.0f }; 887 } 888 inline float4 transform4(const float2 &val, const quaternion &rot) { 889 quaternion result = rot * quaternion(float3(val.x, val.y, 0.0f), 0.0f) * inverse(rot); 890 return { result.x, result.y, result.z, 1.0f }; 891 } 892 893 } _WINDOWS_NUMERICS_END_NAMESPACE_ 894 895 896 // Define float3x2 functions 897 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 898 899 // TODO: impl 900 inline float3x2 make_float3x2_translation(const float2 &pos); 901 inline float3x2 make_float3x2_translation(float xpos, float ypos); 902 inline float3x2 make_float3x2_scale(float xscale, float yscale); 903 inline float3x2 make_float3x2_scale(float xscale, float yscale, const float2 ¢er); 904 inline float3x2 make_float3x2_scale(const float2 &xyscale); 905 inline float3x2 make_float3x2_scale(const float2 &xyscale, const float2 ¢er); 906 inline float3x2 make_float3x2_scale(float scale); 907 inline float3x2 make_float3x2_scale(float scale, const float2 ¢er); 908 inline float3x2 make_float3x2_skew(float xrad, float yrad); 909 inline float3x2 make_float3x2_skew(float xrad, float yrad, const float2 ¢er); 910 inline float3x2 make_float3x2_rotation(float rad); 911 inline float3x2 make_float3x2_rotation(float rad, const float2 ¢er); 912 inline bool is_identity(const float3x2 &val) { 913 return val == float3x2::identity(); 914 } 915 inline float determinant(const float3x2 &val) { 916 // 2D transformation matrix has an implied 3rd column with (0, 0, 1) 917 // det = m11 * m22 * m33 + m12 * m23 * m31 + m13 * m21 * m32 918 // - m31 * m22 * m13 - m21 * m12 * m33 - m11 * m32 * m23; 919 return val.m11 * val.m22 - val.m21 * val.m12; 920 } 921 inline float2 translation(const float3x2 &val) { 922 return { val.m31, val.m32 }; 923 } 924 inline bool invert(const float3x2 &val, float3x2 *out); 925 inline float3x2 lerp(const float3x2 &mat1, const float3x2 &mat2, float amount); 926 927 } _WINDOWS_NUMERICS_END_NAMESPACE_ 928 929 930 // Define float4x4 functions 931 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 932 933 // TODO: impl 934 inline float4x4 make_float4x4_billboard(const float3 &objpos, const float3 &camerapos, const float3 &cameraup, const float3 &camerafwd); 935 inline float4x4 make_float4x4_constrained_billboard(const float3 &objpos, const float3 &camerapos, const float3 &rotateaxis, const float3 &camerafwd, const float3 &objfwd); 936 inline float4x4 make_float4x4_translation(const float3 &pos) { 937 return { 938 1.0f, 0.0f, 0.0f, 0.0f, 939 0.0f, 1.0f, 0.0f, 0.0f, 940 0.0f, 0.0f, 1.0f, 0.0f, 941 pos.x, pos.y, pos.z, 1.0f 942 }; 943 } 944 inline float4x4 make_float4x4_translation(float xpos, float ypos, float zpos); 945 inline float4x4 make_float4x4_scale(float xscale, float yscale, float zscale); 946 inline float4x4 make_float4x4_scale(float xscale, float yscale, float zscale, const float3 ¢er); 947 inline float4x4 make_float4x4_scale(const float3 &xyzscale) { 948 return { 949 xyzscale.x, 0.0f, 0.0f, 0.0f, 950 0.0f, xyzscale.y, 0.0f, 0.0f, 951 0.0f, 0.0f, xyzscale.z, 0.0f, 952 0.0f, 0.0f, 0.0f, 1.0f 953 }; 954 } 955 inline float4x4 make_float4x4_scale(const float3 &xyzscale, const float3 ¢er); 956 inline float4x4 make_float4x4_scale(float scale); 957 inline float4x4 make_float4x4_scale(float scale, const float3 ¢er); 958 inline float4x4 make_float4x4_rotation_x(float rad); 959 inline float4x4 make_float4x4_rotation_x(float rad, const float3 ¢er); 960 inline float4x4 make_float4x4_rotation_y(float rad); 961 inline float4x4 make_float4x4_rotation_y(float rad, const float3 ¢er); 962 inline float4x4 make_float4x4_rotation_z(float rad); 963 inline float4x4 make_float4x4_rotation_z(float rad, const float3 ¢er); 964 inline float4x4 make_float4x4_from_axis_angle(const float3 &axis, float angle); 965 inline float4x4 make_float4x4_perspective_field_of_view(float fov, float aspect, float nearplane, float farplane); 966 inline float4x4 make_float4x4_perspective(float w, float h, float nearplane, float farplane); 967 inline float4x4 make_float4x4_perspective_off_center(float left, float right, float bottom, float top, float nearplane, float farplane); 968 inline float4x4 make_float4x4_orthographic(float w, float h, float znearplane, float zfarplane); 969 inline float4x4 make_float4x4_orthographic_off_center(float left, float right, float bottom, float top, float znearplane, float zfarplane); 970 inline float4x4 make_float4x4_look_at(const float3 &camerapos, const float3 &target, const float3 &cameraup); 971 inline float4x4 make_float4x4_world(const float3 &pos, const float3 &fwd, const float3 &up); 972 inline float4x4 make_float4x4_from_quaternion(const quaternion &quat) { 973 // https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion 974 float xx = quat.x * quat.x; 975 float yy = quat.y * quat.y; 976 float zz = quat.z * quat.z; 977 float xy = quat.x * quat.y; 978 float xz = quat.x * quat.z; 979 float xw = quat.x * quat.w; 980 float yz = quat.y * quat.z; 981 float yw = quat.y * quat.w; 982 float zw = quat.z * quat.w; 983 return { 984 1.0f - 2.0f*yy - 2.0f*zz, 2.0f*xy + 2.0f*zw, 2.0f*xz - 2.0f*yw, 0.0f, 985 2.0f*xy - 2.0f*zw, 1.0f - 2.0f*xx - 2.0f*zz, 2.0f*yz + 2.0f*xw, 0.0f, 986 2.0f*xz + 2.0f*yw, 2.0f*yz - 2.0f*xw, 1.0f - 2.0f*xx - 2.0f*yy, 0.0f, 987 0.0f, 0.0f, 0.0f, 1.0f 988 }; 989 } 990 inline float4x4 make_float4x4_from_yaw_pitch_roll(float yaw, float pitch, float roll); 991 inline float4x4 make_float4x4_shadow(const float3 &lightdir, const plane &plane); 992 inline float4x4 make_float4x4_reflection(const plane &plane); 993 inline bool is_identity(const float4x4 &val) { 994 return val == float4x4::identity(); 995 } 996 inline float determinant(const float4x4 &val) { 997 const float det_33_44 = (val.m33 * val.m44 - val.m34 * val.m43); 998 const float det_32_44 = (val.m32 * val.m44 - val.m34 * val.m42); 999 const float det_32_43 = (val.m32 * val.m43 - val.m33 * val.m42); 1000 const float det_31_44 = (val.m31 * val.m44 - val.m34 * val.m41); 1001 const float det_31_43 = (val.m31 * val.m43 - val.m33 * val.m41); 1002 const float det_31_42 = (val.m31 * val.m42 - val.m32 * val.m41); 1003 return val.m11 * (val.m22 * det_33_44 - val.m23 * det_32_44 + val.m24 * det_32_43) 1004 - val.m12 * (val.m21 * det_33_44 - val.m23 * det_31_44 + val.m24 * det_31_43) 1005 + val.m13 * (val.m21 * det_32_44 - val.m22 * det_31_44 + val.m24 * det_31_42) 1006 - val.m14 * (val.m21 * det_32_43 - val.m22 * det_31_43 + val.m23 * det_31_42); 1007 } 1008 inline float3 translation(const float4x4 &val) { 1009 return { val.m41, val.m42, val.m43 }; 1010 } 1011 inline bool invert(const float4x4 &mat, float4x4 *out); 1012 inline bool decompose(const float4x4 &mat, float3 *out_scale, quaternion *out_rot, float3 *out_translate); 1013 inline float4x4 transform(const float4x4 &val, const quaternion &rot) { 1014 return val * make_float4x4_from_quaternion(rot); 1015 } 1016 inline float4x4 transpose(const float4x4 &val) { 1017 return { 1018 val.m11, val.m21, val.m31, val.m41, 1019 val.m12, val.m22, val.m32, val.m42, 1020 val.m13, val.m23, val.m33, val.m43, 1021 val.m14, val.m24, val.m34, val.m44 1022 }; 1023 } 1024 inline float4x4 lerp(const float4x4 &val1, const float4x4 &val2, float amount); 1025 1026 } _WINDOWS_NUMERICS_END_NAMESPACE_ 1027 1028 1029 // Define plane functions 1030 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 1031 1032 // TODO: impl 1033 inline plane make_plane_from_vertices(const float3 &pt1, const float3 &pt2, const float3 &pt3); 1034 inline plane normalize(const plane &val) { 1035 const float invlen = 1.0f / length(val.normal); 1036 return { val.normal * invlen, val.d * invlen }; 1037 } 1038 inline plane transform(const plane &plane, const float4x4 &mat); 1039 inline plane transform(const plane &plane, const quaternion &rot) { 1040 quaternion result = rot * quaternion(plane.normal, 0.0f) * inverse(rot); 1041 return { float3(result.x, result.y, result.z), plane.d }; 1042 } 1043 inline float dot(const plane &plane, const float4 &val); 1044 inline float dot_coordinate(const plane &plane, const float3 &val); 1045 inline float dot_normal(const plane &plane, const float3 &val); 1046 1047 } _WINDOWS_NUMERICS_END_NAMESPACE_ 1048 1049 1050 // Define quaternion functions 1051 _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ { 1052 1053 inline quaternion make_quaternion_from_axis_angle(const float3 &axis, float angle) { 1054 return quaternion(axis * ::std::sin(angle * 0.5f), ::std::cos(angle * 0.5f)); 1055 } 1056 inline quaternion make_quaternion_from_yaw_pitch_roll(float yaw, float pitch, float roll) { 1057 quaternion yq = make_quaternion_from_axis_angle(float3(0.0f, 1.0f, 0.0f), yaw); 1058 quaternion pq = make_quaternion_from_axis_angle(float3(1.0f, 0.0f, 0.0f), pitch); 1059 quaternion rq = make_quaternion_from_axis_angle(float3(0.0f, 0.0f, 1.0f), roll); 1060 return concatenate(concatenate(rq, pq), yq); 1061 } 1062 inline quaternion make_quaternion_from_rotation_matrix(const float4x4 &mat) { 1063 // https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion 1064 float t = mat.m11 + mat.m22 + mat.m33; 1065 if (t > 0) { 1066 float r = ::std::sqrt(1.0f + t); 1067 float s = 1.0f / (2.0f * r); 1068 return { (mat.m23 - mat.m32) * s, (mat.m31 - mat.m13) * s, 1069 (mat.m12 - mat.m21) * s, r * 0.5f }; 1070 } else if (mat.m11 >= mat.m22 && mat.m11 >= mat.m33) { 1071 float r = ::std::sqrt(1.0f + mat.m11 - mat.m22 - mat.m33); 1072 float s = 1.0f / (2.0f * r); 1073 return { r * 0.5f, (mat.m21 + mat.m12) * s, 1074 (mat.m13 + mat.m31) * s, (mat.m23 - mat.m32) * s }; 1075 } else if (mat.m22 >= mat.m11 && mat.m22 >= mat.m33) { 1076 float r = ::std::sqrt(1.0f + mat.m22 - mat.m11 - mat.m33); 1077 float s = 1.0f / (2.0f * r); 1078 return { (mat.m21 + mat.m12) * s, r * 0.5f, 1079 (mat.m32 + mat.m23) * s, (mat.m31 - mat.m13) * s }; 1080 } else { 1081 float r = ::std::sqrt(1.0f + mat.m33 - mat.m11 - mat.m22); 1082 float s = 1.0f / (2.0f * r); 1083 return { (mat.m13 + mat.m31) * s, (mat.m32 + mat.m23) * s, 1084 r * 0.5f, (mat.m12 - mat.m21) * s }; 1085 } 1086 } 1087 inline bool is_identity(const quaternion &val) { 1088 return val == quaternion::identity(); 1089 } 1090 inline float length(const quaternion &val) { 1091 return ::std::sqrt(length_squared(val)); 1092 } 1093 inline float length_squared(const quaternion &val) { 1094 return dot(val, val); 1095 } 1096 inline float dot(const quaternion &val1, const quaternion &val2) { 1097 return val1.x * val2.x + val1.y * val2.y + val1.z * val2.z + val1.w * val2.w; 1098 } 1099 inline quaternion normalize(const quaternion &val) { 1100 return operator*(val, 1.0f / length(val)); 1101 } 1102 inline quaternion conjugate(const quaternion &val) { 1103 return { -val.x, -val.y, -val.z, val.w}; 1104 } 1105 inline quaternion inverse(const quaternion &val) { 1106 return operator*(conjugate(val), 1.0f / length_squared(val)); 1107 } 1108 inline quaternion slerp(const quaternion &val1, const quaternion &val2, float amount) { 1109 // https://en.wikipedia.org/wiki/Slerp#Geometric_Slerp 1110 float cosangle = dot(val1, val2); 1111 quaternion end = val2; 1112 if (cosangle < 0.0f) { 1113 end = -val2; 1114 cosangle = -cosangle; 1115 } 1116 float fact1, fact2; 1117 const float epsilon = 1.0e-6f; 1118 if (cosangle > 1.0f - epsilon) { 1119 // Very small rotation range, or non-normalized input quaternions. 1120 fact1 = (1.0f - amount); 1121 fact2 = amount; 1122 } else { 1123 float angle = ::std::acos(cosangle); 1124 float sinangle = ::std::sin(angle); 1125 fact1 = ::std::sin((1.0f - amount) * angle) / sinangle; 1126 fact2 = ::std::sin(amount * angle) / sinangle; 1127 } 1128 return val1 * fact1 + end * fact2; 1129 } 1130 inline quaternion lerp(const quaternion &val1, const quaternion &val2, float amount) { 1131 quaternion end = val2; 1132 if (dot(val1, val2) < 0.0f) 1133 end = -val2; 1134 return normalize(quaternion( 1135 _impl::lerp(val1.x, end.x, amount), _impl::lerp(val1.y, end.y, amount), 1136 _impl::lerp(val1.z, end.z, amount), _impl::lerp(val1.w, end.w, amount) 1137 )); 1138 } 1139 inline quaternion concatenate(const quaternion &val1, const quaternion &val2) { 1140 return val2 * val1; 1141 } 1142 1143 } _WINDOWS_NUMERICS_END_NAMESPACE_ 1144 1145 1146 /** 1147 * FIXME: Implement interop functions with DirectXMath. 1148 * This is where we are supposed to define the functions to convert between 1149 * Windows::Foundation::Numerics types and XMVECTOR / XMMATRIX. But our 1150 * directxmath.h does not contain the definitions for these types... 1151 */ 1152 #if 0 1153 // === DirectXMath Interop === 1154 namespace DirectX { 1155 1156 // TODO: impl 1157 XMVECTOR XMLoadFloat2(const _WINDOWS_NUMERICS_NAMESPACE_::float2 *src); 1158 XMVECTOR XMLoadFloat3(const _WINDOWS_NUMERICS_NAMESPACE_::float3 *src); 1159 XMVECTOR XMLoadFloat4(const _WINDOWS_NUMERICS_NAMESPACE_::float4 *src); 1160 XMMATRIX XMLoadFloat3x2(const _WINDOWS_NUMERICS_NAMESPACE_::float3x2 *src); 1161 XMMATRIX XMLoadFloat4x4(const _WINDOWS_NUMERICS_NAMESPACE_::float4x4 *src); 1162 XMVECTOR XMLoadPlane(const _WINDOWS_NUMERICS_NAMESPACE_::plane *src); 1163 XMVECTOR XMLoadQuaternion(const _WINDOWS_NUMERICS_NAMESPACE_::quaternion *src); 1164 void XMStoreFloat2(_WINDOWS_NUMERICS_NAMESPACE_::float2 *out, FXMVECTOR in); 1165 void XMStoreFloat3(_WINDOWS_NUMERICS_NAMESPACE_::float3 *out, FXMVECTOR in); 1166 void XMStoreFloat4(_WINDOWS_NUMERICS_NAMESPACE_::float4 *out, FXMVECTOR in); 1167 void XMStoreFloat3x2(_WINDOWS_NUMERICS_NAMESPACE_::float3x2 *out, FXMMATRIX in); 1168 void XMStoreFloat4x4(_WINDOWS_NUMERICS_NAMESPACE_::float4x4 *out, FXMMATRIX in); 1169 void XMStorePlane(_WINDOWS_NUMERICS_NAMESPACE_::plane *out, FXMVECTOR in); 1170 void XMStoreQuaternion(_WINDOWS_NUMERICS_NAMESPACE_::quaternion *out, FXMVECTOR in); 1171 1172 } /* namespace DirectX */ 1173 #endif 1174 1175 1176 #undef _WINDOWS_NUMERICS_IMPL_ASSIGN_OP 1177 1178 #ifdef _WINDOWS_NUMERICS_IMPL_PUSHED_MIN_ 1179 # undef _WINDOWS_NUMERICS_IMPL_PUSHED_MIN_ 1180 # pragma pop_macro("min") 1181 #endif 1182 1183 #ifdef _WINDOWS_NUMERICS_IMPL_PUSHED_MAX_ 1184 # undef _WINDOWS_NUMERICS_IMPL_PUSHED_MAX_ 1185 # pragma pop_macro("max") 1186 #endif