└── dr_math.h /dr_math.h: -------------------------------------------------------------------------------- 1 | // Public Domain. See "unlicense" statement at the end of this file. 2 | 3 | // NOTE: This is still very much work in progress and is only being updated as I need it. You don't want to be using this library 4 | // in its current state. 5 | 6 | // QUICK NOTES 7 | // - This library does not use SSE for its basic types (vec4, etc.). Rationale: 1) It keeps things simple; 2) SSE is not always 8 | // faster than the FPU(s) on modern CPUs; 3) The library can always implement functions that work on __m128 variables directly 9 | // in the future if the need arises; 4) It doesn't work well with the pass-by-value API this library uses. 10 | // - Use DISABLE_SSE to disable SSE optimized functions. 11 | // - Angles are always specified in radians, unless otherwise noted. Rationale: Consistency with the standard library and most 12 | // other math libraries. 13 | // - Use radians() and degrees() to convert between the two. 14 | 15 | #ifndef dr_math_h 16 | #define dr_math_h 17 | 18 | #include 19 | 20 | #if defined(_MSC_VER) 21 | #define DR_MATHCALL static __forceinline 22 | #else 23 | #define DR_MATHCALL static inline 24 | #endif 25 | 26 | #define DR_PI 3.14159265358979323846 27 | #define DR_PIF 3.14159265358979323846f 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | typedef struct 34 | { 35 | float x; 36 | float y; 37 | float z; 38 | float w; 39 | } vec4; 40 | 41 | typedef struct 42 | { 43 | float x; 44 | float y; 45 | float z; 46 | } vec3; 47 | 48 | typedef struct 49 | { 50 | float x; 51 | float y; 52 | } vec2; 53 | 54 | typedef struct 55 | { 56 | vec4 col[4]; 57 | } mat4; 58 | 59 | typedef struct 60 | { 61 | float x; 62 | float y; 63 | float z; 64 | float w; 65 | } quat; 66 | 67 | 68 | // Radians to degrees. 69 | DR_MATHCALL float dr_degrees(float radians) 70 | { 71 | return radians * 57.29577951308232087685f; 72 | } 73 | 74 | // Degrees to radians. 75 | DR_MATHCALL float dr_radians(float degrees) 76 | { 77 | return degrees * 0.01745329251994329577f; 78 | } 79 | 80 | 81 | 82 | /////////////////////////////////////////////// 83 | // 84 | // VEC4 85 | // 86 | /////////////////////////////////////////////// 87 | 88 | DR_MATHCALL vec4 vec4f(float x, float y, float z, float w) 89 | { 90 | vec4 result; 91 | result.x = x; 92 | result.y = y; 93 | result.z = z; 94 | result.w = w; 95 | 96 | return result; 97 | } 98 | DR_MATHCALL vec4 vec4v(const float* v) 99 | { 100 | return vec4f(v[0], v[1], v[2], v[3]); 101 | } 102 | DR_MATHCALL vec4 vec4_zero() 103 | { 104 | return vec4f(0, 0, 0, 0); 105 | } 106 | DR_MATHCALL vec4 vec4_one() 107 | { 108 | return vec4f(1, 1, 1, 1); 109 | } 110 | 111 | 112 | 113 | DR_MATHCALL vec4 vec4_add(vec4 a, vec4 b) 114 | { 115 | return vec4f(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); 116 | } 117 | 118 | DR_MATHCALL vec4 vec4_sub(vec4 a, vec4 b) 119 | { 120 | return vec4f(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); 121 | } 122 | 123 | 124 | DR_MATHCALL vec4 vec4_mul(vec4 a, vec4 b) 125 | { 126 | return vec4f(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); 127 | } 128 | DR_MATHCALL vec4 vec4_mul_1f(vec4 a, float x) 129 | { 130 | return vec4f(a.x * x, a.y * x, a.z * x, a.w * x); 131 | } 132 | DR_MATHCALL vec4 vec4_mul_mat4(vec4 v, mat4 m) 133 | { 134 | const vec4 m0 = m.col[0]; 135 | const vec4 m1 = m.col[1]; 136 | const vec4 m2 = m.col[2]; 137 | const vec4 m3 = m.col[3]; 138 | 139 | return vec4f( 140 | m0.x*v.x + m0.y*v.y + m0.z*v.z + m0.w*v.w, 141 | m1.x*v.x + m1.y*v.y + m1.z*v.z + m1.w*v.w, 142 | m2.x*v.x + m2.y*v.y + m2.z*v.z + m2.w*v.w, 143 | m3.x*v.x + m3.y*v.y + m3.z*v.z + m3.w*v.w 144 | ); 145 | } 146 | 147 | 148 | DR_MATHCALL vec4 vec4_div(vec4 a, vec4 b) 149 | { 150 | return vec4f(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); 151 | } 152 | 153 | 154 | 155 | 156 | 157 | 158 | /////////////////////////////////////////////// 159 | // 160 | // VEC3 161 | // 162 | /////////////////////////////////////////////// 163 | 164 | DR_MATHCALL vec3 vec3f(float x, float y, float z) 165 | { 166 | vec3 result; 167 | result.x = x; 168 | result.y = y; 169 | result.z = z; 170 | 171 | return result; 172 | } 173 | DR_MATHCALL vec3 vec3v(const float* v) 174 | { 175 | return vec3f(v[0], v[1], v[2]); 176 | } 177 | DR_MATHCALL vec3 vec3_zero() 178 | { 179 | return vec3f(0, 0, 0); 180 | } 181 | DR_MATHCALL vec3 vec3_one() 182 | { 183 | return vec3f(1, 1, 1); 184 | } 185 | 186 | 187 | DR_MATHCALL vec3 vec3_add(vec3 a, vec3 b) 188 | { 189 | return vec3f(a.x + b.x, a.y + b.y, a.z + b.z); 190 | } 191 | 192 | DR_MATHCALL vec3 vec3_sub(vec3 a, vec3 b) 193 | { 194 | return vec3f(a.x - b.x, a.y - b.y, a.z - b.z); 195 | } 196 | 197 | 198 | DR_MATHCALL vec3 vec3_mul(vec3 a, vec3 b) 199 | { 200 | return vec3f(a.x * b.x, a.y * b.y, a.z * b.z); 201 | } 202 | DR_MATHCALL vec3 vec3_mul_1f(vec3 a, float x) 203 | { 204 | return vec3f(a.x * x, a.y * x, a.z * x); 205 | } 206 | 207 | 208 | DR_MATHCALL vec3 vec3_div(vec3 a, vec3 b) 209 | { 210 | return vec3f(a.x / b.x, a.y / b.y, a.z / b.z); 211 | } 212 | 213 | 214 | DR_MATHCALL float vec3_dot(vec3 a, vec3 b) 215 | { 216 | return a.x*b.x + a.y*b.y + a.z*b.z; 217 | } 218 | 219 | 220 | DR_MATHCALL float vec3_length2(vec3 a) 221 | { 222 | return vec3_dot(a, a); 223 | } 224 | 225 | DR_MATHCALL float vec3_length(vec3 a) 226 | { 227 | return sqrtf(vec3_length2(a)); 228 | } 229 | 230 | 231 | DR_MATHCALL vec3 vec3_normalize(vec3 a) 232 | { 233 | float len = vec3_length(a); 234 | 235 | return vec3f( 236 | a.x / len, 237 | a.y / len, 238 | a.z / len 239 | ); 240 | } 241 | 242 | DR_MATHCALL vec3 vec3_cross(vec3 a, vec3 b) 243 | { 244 | return vec3f( 245 | a.y*b.z - a.z*b.y, 246 | a.z*b.x - a.x*b.z, 247 | a.x*b.y - a.y*b.x 248 | ); 249 | } 250 | 251 | 252 | DR_MATHCALL vec3 vec3_triangle_normal(vec3 p1, vec3 p2, vec3 p3) 253 | { 254 | vec3 u = vec3_sub(p2, p1); 255 | vec3 v = vec3_sub(p3, p1); 256 | return vec3_normalize(vec3_cross(u, v)); 257 | } 258 | 259 | 260 | 261 | /////////////////////////////////////////////// 262 | // 263 | // VEC2 264 | // 265 | /////////////////////////////////////////////// 266 | 267 | DR_MATHCALL vec2 vec2f(float x, float y) 268 | { 269 | vec2 result; 270 | result.x = x; 271 | result.y = y; 272 | 273 | return result; 274 | } 275 | DR_MATHCALL vec2 vec2v(const float* v) 276 | { 277 | return vec2f(v[0], v[1]); 278 | } 279 | DR_MATHCALL vec2 vec2_zero() 280 | { 281 | return vec2f(0, 0); 282 | } 283 | DR_MATHCALL vec2 vec2_one() 284 | { 285 | return vec2f(1, 1); 286 | } 287 | 288 | 289 | DR_MATHCALL vec2 vec2_add(vec2 a, vec2 b) 290 | { 291 | return vec2f(a.x + b.x, a.y + b.y); 292 | } 293 | 294 | DR_MATHCALL vec2 vec2_sub(vec2 a, vec2 b) 295 | { 296 | return vec2f(a.x - b.x, a.y - b.y); 297 | } 298 | 299 | 300 | DR_MATHCALL vec2 vec2_mul(vec2 a, vec2 b) 301 | { 302 | return vec2f(a.x * b.x, a.y * b.y); 303 | } 304 | DR_MATHCALL vec2 vec2_mul_1f(vec2 a, float x) 305 | { 306 | return vec2f(a.x * x, a.y * x); 307 | } 308 | 309 | 310 | DR_MATHCALL vec2 vec2_div(vec2 a, vec2 b) 311 | { 312 | return vec2f(a.x / b.x, a.y / b.y); 313 | } 314 | 315 | 316 | DR_MATHCALL float vec2_dot(vec2 a, vec2 b) 317 | { 318 | return a.x*b.x + a.y*b.y; 319 | } 320 | 321 | 322 | DR_MATHCALL float vec2_length2(vec2 a) 323 | { 324 | return vec2_dot(a, a); 325 | } 326 | 327 | DR_MATHCALL float vec2_length(vec2 a) 328 | { 329 | return sqrtf(vec2_length2(a)); 330 | } 331 | 332 | 333 | DR_MATHCALL vec2 vec2_normalize(vec2 a) 334 | { 335 | float len = vec2_length(a); 336 | 337 | return vec2f( 338 | a.x / len, 339 | a.y / len 340 | ); 341 | } 342 | 343 | 344 | DR_MATHCALL float vec2_angle(vec2 a, vec2 b) 345 | { 346 | return atanf(a.y / a.x) - atanf(b.y / b.x); 347 | } 348 | 349 | DR_MATHCALL vec2 vec2_rotate(vec2 a, float angleInRadians) 350 | { 351 | float c = cosf(angleInRadians); 352 | float s = sinf(angleInRadians); 353 | 354 | return vec2f( 355 | a.x*c - a.y*s, 356 | a.x*s + a.y*c 357 | ); 358 | } 359 | 360 | 361 | /////////////////////////////////////////////// 362 | // 363 | // MAT4 364 | // 365 | /////////////////////////////////////////////// 366 | 367 | DR_MATHCALL mat4 mat4f(vec4 col0, vec4 col1, vec4 col2, vec4 col3) 368 | { 369 | mat4 result; 370 | result.col[0] = col0; 371 | result.col[1] = col1; 372 | result.col[2] = col2; 373 | result.col[3] = col3; 374 | 375 | return result; 376 | } 377 | 378 | DR_MATHCALL mat4 mat4_identity() 379 | { 380 | mat4 result; 381 | result.col[0] = vec4f(1, 0, 0, 0); 382 | result.col[1] = vec4f(0, 1, 0, 0); 383 | result.col[2] = vec4f(0, 0, 1, 0); 384 | result.col[3] = vec4f(0, 0, 0, 1); 385 | 386 | return result; 387 | } 388 | 389 | DR_MATHCALL mat4 mat4_ortho(float left, float right, float bottom, float top, float znear, float zfar) 390 | { 391 | float rml = right - left; 392 | float tmb = top - bottom; 393 | float fmn = zfar - znear; 394 | 395 | float rpl = right + left; 396 | float tpb = top + bottom; 397 | float fpn = zfar + znear; 398 | 399 | mat4 result; 400 | result.col[0] = vec4f(2/rml, 0, 0, 0); 401 | result.col[1] = vec4f(0, 2/tmb, 0, 0); 402 | result.col[2] = vec4f(0, 0, -2/fmn, 0); 403 | result.col[3] = vec4f(-(rpl/rml), -(tpb/tmb), -(fpn/fmn), 1); 404 | 405 | return result; 406 | } 407 | 408 | DR_MATHCALL mat4 mat4_perspective(float fovy, float aspect, float znear, float zfar) 409 | { 410 | float f = (float)tan(DR_PI/2 - fovy/2); 411 | 412 | mat4 result; 413 | result.col[0] = vec4f(f / aspect, 0, 0, 0); 414 | result.col[1] = vec4f(0, f, 0, 0); 415 | result.col[2] = vec4f(0, 0, (zfar + znear) / (znear - zfar), -1); 416 | result.col[3] = vec4f(0, 0, (2 * zfar * znear) / (znear - zfar), 0); 417 | 418 | return result; 419 | } 420 | 421 | DR_MATHCALL mat4 mat4_vulkan_clip_correction() 422 | { 423 | mat4 result; 424 | result.col[0] = vec4f(1, 0, 0, 0); 425 | result.col[1] = vec4f(0, -1, 0, 0); 426 | result.col[2] = vec4f(0, 0, 0.5f, 0); 427 | result.col[3] = vec4f(0, 0, 0.5f, 1); 428 | 429 | return result; 430 | } 431 | 432 | DR_MATHCALL mat4 mat4_translate(vec3 translation) 433 | { 434 | mat4 result; 435 | result.col[0] = vec4f(1, 0, 0, 0); 436 | result.col[1] = vec4f(0, 1, 0, 0); 437 | result.col[2] = vec4f(0, 0, 1, 0); 438 | result.col[3] = vec4f(translation.x, translation.y, translation.z, 1); 439 | 440 | return result; 441 | } 442 | 443 | DR_MATHCALL mat4 mat4_rotate(float angleInRadians, vec3 axis) 444 | { 445 | float c = cosf(angleInRadians); 446 | float s = sinf(angleInRadians); 447 | 448 | float x = axis.x; 449 | float y = axis.y; 450 | float z = axis.z; 451 | 452 | float xx = x*x; 453 | float xy = x*y; 454 | float xz = x*z; 455 | float yy = y*y; 456 | float yz = y*z; 457 | float zz = z*z; 458 | 459 | float xs = x*s; 460 | float ys = y*s; 461 | float zs = z*s; 462 | 463 | mat4 result; 464 | result.col[0] = vec4f(xx * (1 - c) + c, xy * (1 - c) - zs, xz * (1 - c) + ys, 0); 465 | result.col[1] = vec4f(xy * (1 - c) + zs, yy * (1 - c) + c, yz * (1 - c) - xs, 0); 466 | result.col[2] = vec4f(xz * (1 - c) - ys, yz * (1 - c) + xs, zz * (1 - c) + c, 0); 467 | result.col[3] = vec4f(0, 0, 0, 1); 468 | 469 | return result; 470 | } 471 | 472 | DR_MATHCALL mat4 mat4_scale(vec3 scale) 473 | { 474 | mat4 result; 475 | result.col[0] = vec4f(scale.x, 0, 0, 0); 476 | result.col[1] = vec4f(0, scale.y, 0, 0); 477 | result.col[2] = vec4f(0, 0, scale.z, 0); 478 | result.col[3] = vec4f(0, 0, 0, 1); 479 | 480 | return result; 481 | } 482 | 483 | 484 | DR_MATHCALL mat4 mat4_mul(mat4 a, mat4 b) 485 | { 486 | const vec4 a0 = a.col[0]; 487 | const vec4 a1 = a.col[1]; 488 | const vec4 a2 = a.col[2]; 489 | const vec4 a3 = a.col[3]; 490 | 491 | const vec4 b0 = b.col[0]; 492 | const vec4 b1 = b.col[1]; 493 | const vec4 b2 = b.col[2]; 494 | const vec4 b3 = b.col[3]; 495 | 496 | mat4 result; 497 | result.col[0] = vec4f( 498 | a0.x*b0.x + a1.x*b0.y + a2.x*b0.z + a3.x*b0.w, 499 | a0.y*b0.x + a1.y*b0.y + a2.y*b0.z + a3.y*b0.w, 500 | a0.z*b0.x + a1.z*b0.y + a2.z*b0.z + a3.z*b0.w, 501 | a0.w*b0.x + a1.w*b0.y + a2.w*b0.z + a3.w*b0.w 502 | ); 503 | 504 | result.col[1] = vec4f( 505 | a0.x*b1.x + a1.x*b1.y + a2.x*b1.z + a3.x*b1.w, 506 | a0.y*b1.x + a1.y*b1.y + a2.y*b1.z + a3.y*b1.w, 507 | a0.z*b1.x + a1.z*b1.y + a2.z*b1.z + a3.z*b1.w, 508 | a0.w*b1.x + a1.w*b1.y + a2.w*b1.z + a3.w*b1.w 509 | ); 510 | 511 | result.col[2] = vec4f( 512 | a0.x*b2.x + a1.x*b2.y + a2.x*b2.z + a3.x*b2.w, 513 | a0.y*b2.x + a1.y*b2.y + a2.y*b2.z + a3.y*b2.w, 514 | a0.z*b2.x + a1.z*b2.y + a2.z*b2.z + a3.z*b2.w, 515 | a0.w*b2.x + a1.w*b2.y + a2.w*b2.z + a3.w*b2.w 516 | ); 517 | 518 | result.col[3] = vec4f( 519 | a0.x*b3.x + a1.x*b3.y + a2.x*b3.z + a3.x*b3.w, 520 | a0.y*b3.x + a1.y*b3.y + a2.y*b3.z + a3.y*b3.w, 521 | a0.z*b3.x + a1.z*b3.y + a2.z*b3.z + a3.z*b3.w, 522 | a0.w*b3.x + a1.w*b3.y + a2.w*b3.z + a3.w*b3.w 523 | ); 524 | 525 | return result; 526 | } 527 | 528 | DR_MATHCALL vec4 mat4_mul_vec4(mat4 m, vec4 v) 529 | { 530 | const vec4 m0 = m.col[0]; 531 | const vec4 m1 = m.col[1]; 532 | const vec4 m2 = m.col[2]; 533 | const vec4 m3 = m.col[3]; 534 | 535 | return vec4f( 536 | m0.x*v.x + m1.x*v.y + m2.x*v.z + m3.x*v.w, 537 | m0.y*v.x + m1.y*v.y + m2.y*v.z + m3.y*v.w, 538 | m0.z*v.x + m1.z*v.y + m2.z*v.z + m3.z*v.w, 539 | m0.w*v.x + m1.w*v.y + m2.w*v.z + m3.w*v.w 540 | ); 541 | } 542 | 543 | 544 | /////////////////////////////////////////////// 545 | // 546 | // QUAT 547 | // 548 | /////////////////////////////////////////////// 549 | 550 | DR_MATHCALL quat quatf(float x, float y, float z, float w) 551 | { 552 | quat result; 553 | result.x = x; 554 | result.y = y; 555 | result.z = z; 556 | result.w = w; 557 | 558 | return result; 559 | } 560 | DR_MATHCALL quat quatv(const float* v) 561 | { 562 | return quatf(v[0], v[1], v[2], v[3]); 563 | } 564 | 565 | DR_MATHCALL quat quat_identity() 566 | { 567 | return quatf(0, 0, 0, 1); 568 | } 569 | 570 | 571 | 572 | 573 | 574 | /////////////////////////////////////////////// 575 | // 576 | // TRANSFORM 577 | // 578 | /////////////////////////////////////////////// 579 | 580 | typedef struct 581 | { 582 | vec3 position; 583 | quat rotation; 584 | vec3 scale; 585 | }transform_t; 586 | 587 | DR_MATHCALL transform_t transform_init(vec3 position, quat rotation, vec3 scale) 588 | { 589 | transform_t result; 590 | result.position = position; 591 | result.rotation = rotation; 592 | result.scale = scale; 593 | 594 | return result; 595 | } 596 | 597 | DR_MATHCALL transform_t transform_identity() 598 | { 599 | transform_t result; 600 | result.position = vec3_zero(); 601 | result.rotation = quat_identity(); 602 | result.scale = vec3_one(); 603 | 604 | return result; 605 | } 606 | 607 | 608 | DR_MATHCALL transform_t transform_translate(transform_t transform, vec3 offset) 609 | { 610 | transform_t result = transform; 611 | result.position = vec3_add(transform.position, offset); 612 | 613 | return result; 614 | } 615 | 616 | 617 | 618 | 619 | /////////////////////////////////////////////// 620 | // 621 | // SSE IMPLEMENTATION 622 | // 623 | /////////////////////////////////////////////// 624 | 625 | // Not supporting SSE on x86/MSVC due to pass-by-value errors with aligned types. 626 | #if (defined(_MSC_VER) && defined(_M_X64)) || defined(__SSE2__) 627 | #define SUPPORTS_SSE 628 | #endif 629 | 630 | #if !defined(DISABLE_SSE) && defined(SUPPORTS_SSE) 631 | #define ENABLE_SSE 632 | #endif 633 | 634 | #ifdef ENABLE_SSE 635 | #if defined(__MINGW32__) 636 | #include 637 | #endif 638 | #include 639 | #endif 640 | 641 | 642 | 643 | 644 | 645 | #ifdef __cplusplus 646 | } 647 | #endif 648 | 649 | #endif //dr_math_h 650 | 651 | /* 652 | This is free and unencumbered software released into the public domain. 653 | 654 | Anyone is free to copy, modify, publish, use, compile, sell, or 655 | distribute this software, either in source code form or as a compiled 656 | binary, for any purpose, commercial or non-commercial, and by any 657 | means. 658 | 659 | In jurisdictions that recognize copyright laws, the author or authors 660 | of this software dedicate any and all copyright interest in the 661 | software to the public domain. We make this dedication for the benefit 662 | of the public at large and to the detriment of our heirs and 663 | successors. We intend this dedication to be an overt act of 664 | relinquishment in perpetuity of all present and future rights to this 665 | software under copyright law. 666 | 667 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 668 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 669 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 670 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 671 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 672 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 673 | OTHER DEALINGS IN THE SOFTWARE. 674 | 675 | For more information, please refer to 676 | */ 677 | --------------------------------------------------------------------------------