1 module raymath; 2 3 import raylib; 4 5 /********************************************************************************************** 6 * 7 * raymath v1.2 - Math functions to work with Vector3, Matrix and Quaternions 8 * 9 * CONFIGURATION: 10 * 11 * #define RAYMATH_IMPLEMENTATION 12 * Generates the implementation of the library into the included file. 13 * If not defined, the library is in header only mode and can be included in other headers 14 * or source files without problems. But only ONE file should hold the implementation. 15 * 16 * #define RAYMATH_HEADER_ONLY 17 * Define static inline functions code, so #include header suffices for use. 18 * This may use up lots of memory. 19 * 20 * #define RAYMATH_STANDALONE 21 * Avoid raylib.h header inclusion in this file. 22 * Vector3 and Matrix data types are defined internally in raymath module. 23 * 24 * 25 * LICENSE: zlib/libpng 26 * 27 * Copyright (c) 2015-2020 Ramon Santamaria (@raysan5) 28 * 29 * This software is provided "as-is", without any express or implied warranty. In no event 30 * will the authors be held liable for any damages arising from the use of this software. 31 * 32 * Permission is granted to anyone to use this software for any purpose, including commercial 33 * applications, and to alter it and redistribute it freely, subject to the following restrictions: 34 * 35 * 1. The origin of this software must not be misrepresented; you must not claim that you 36 * wrote the original software. If you use this software in a product, an acknowledgment 37 * in the product documentation would be appreciated but is not required. 38 * 39 * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 40 * as being the original software. 41 * 42 * 3. This notice may not be removed or altered from any source distribution. 43 * 44 **********************************************************************************************/ 45 46 extern (C) @nogc nothrow: 47 48 //#define RAYMATH_STANDALONE // NOTE: To use raymath as standalone lib, just uncomment this line 49 //#define RAYMATH_HEADER_ONLY // NOTE: To compile functions as static inline, uncomment this line 50 51 import raylib; // Required for structs: Vector3, Matrix 52 53 //---------------------------------------------------------------------------------- 54 // Defines and Macros 55 //---------------------------------------------------------------------------------- 56 57 // Return float vector for Matrix 58 59 extern (D) auto MatrixToFloat(T)(auto ref T mat) 60 { 61 return MatrixToFloatV(mat).v; 62 } 63 64 // Return float vector for Vector3 65 66 extern (D) auto Vector3ToFloat(T)(auto ref T vec) 67 { 68 return Vector3ToFloatV(vec).v; 69 } 70 71 // NOTE: Helper types to be used instead of array return types for *ToFloat functions 72 struct float3 73 { 74 float[3] v; 75 } 76 77 struct float16 78 { 79 float[16] v; 80 } 81 82 import core.stdc.math; // Required for: sinf(), cosf(), sqrtf(), tan(), fabs() 83 84 pragma(inline, true): 85 86 //---------------------------------------------------------------------------------- 87 // Module Functions Definition - Utils math 88 //---------------------------------------------------------------------------------- 89 90 // Clamp float value 91 static float Clamp(float value, float min, float max) 92 { 93 float result = (value < min)? min : value; 94 95 if (result > max) result = max; 96 97 return result; 98 } 99 100 // Calculate linear interpolation between two floats 101 static float Lerp(float start, float end, float amount) 102 { 103 float result = start + amount*(end - start); 104 105 return result; 106 } 107 108 // Normalize input value within input range 109 static float Normalize(float value, float start, float end) 110 { 111 float result = (value - start)/(end - start); 112 113 return result; 114 } 115 116 // Remap input value within input range to output range 117 static float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) 118 { 119 float result =(value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart; 120 121 return result; 122 } 123 124 //---------------------------------------------------------------------------------- 125 // Module Functions Definition - Vector2 math 126 //---------------------------------------------------------------------------------- 127 128 // Vector with components value 0.0f 129 static Vector2 Vector2Zero() 130 { 131 Vector2 result = { 0.0f, 0.0f }; 132 133 return result; 134 } 135 136 // Vector with components value 1.0f 137 static Vector2 Vector2One() 138 { 139 Vector2 result = { 1.0f, 1.0f }; 140 141 return result; 142 } 143 144 // Add two vectors (v1 + v2) 145 static Vector2 Vector2Add(Vector2 v1, Vector2 v2) 146 { 147 Vector2 result = { v1.x + v2.x, v1.y + v2.y }; 148 149 return result; 150 } 151 152 // Add vector and float value 153 static Vector2 Vector2AddValue(Vector2 v, float add) 154 { 155 Vector2 result = { v.x + add, v.y + add }; 156 157 return result; 158 } 159 160 // Subtract two vectors (v1 - v2) 161 static Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) 162 { 163 Vector2 result = { v1.x - v2.x, v1.y - v2.y }; 164 165 return result; 166 } 167 168 // Subtract vector by float value 169 static Vector2 Vector2SubtractValue(Vector2 v, float sub) 170 { 171 Vector2 result = { v.x - sub, v.y - sub }; 172 173 return result; 174 } 175 176 // Calculate vector length 177 static float Vector2Length(Vector2 v) 178 { 179 float result = sqrtf((v.x*v.x) + (v.y*v.y)); 180 181 return result; 182 } 183 184 // Calculate vector square length 185 static float Vector2LengthSqr(Vector2 v) 186 { 187 float result = (v.x*v.x) + (v.y*v.y); 188 189 return result; 190 } 191 192 // Calculate two vectors dot product 193 static float Vector2DotProduct(Vector2 v1, Vector2 v2) 194 { 195 float result = (v1.x*v2.x + v1.y*v2.y); 196 197 return result; 198 } 199 200 // Calculate distance between two vectors 201 static float Vector2Distance(Vector2 v1, Vector2 v2) 202 { 203 float result = sqrtf((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y)); 204 205 return result; 206 } 207 208 // Calculate angle from two vectors in X-axis 209 static float Vector2Angle(Vector2 v1, Vector2 v2) 210 { 211 float result = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI); 212 213 if (result < 0) result += 360.0f; 214 215 return result; 216 } 217 218 // Scale vector (multiply by value) 219 static Vector2 Vector2Scale(Vector2 v, float scale) 220 { 221 Vector2 result = { v.x*scale, v.y*scale }; 222 223 return result; 224 } 225 226 // Multiply vector by vector 227 static Vector2 Vector2Multiply(Vector2 v1, Vector2 v2) 228 { 229 Vector2 result = { v1.x*v2.x, v1.y*v2.y }; 230 231 return result; 232 } 233 234 // Negate vector 235 static Vector2 Vector2Negate(Vector2 v) 236 { 237 Vector2 result = { -v.x, -v.y }; 238 239 return result; 240 } 241 242 // Divide vector by vector 243 static Vector2 Vector2Divide(Vector2 v1, Vector2 v2) 244 { 245 Vector2 result = { v1.x/v2.x, v1.y/v2.y }; 246 247 return result; 248 } 249 250 // Normalize provided vector 251 static Vector2 Vector2Normalize(Vector2 v) 252 { 253 Vector2 result = { 0 }; 254 float length = sqrtf((v.x*v.x) + (v.y*v.y)); 255 256 if (length > 0) 257 { 258 result.x = v.x*1.0f/length; 259 result.y = v.y*1.0f/length; 260 } 261 262 return result; 263 } 264 265 // Calculate linear interpolation between two vectors 266 static Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount) 267 { 268 Vector2 result = { 0 }; 269 270 result.x = v1.x + amount*(v2.x - v1.x); 271 result.y = v1.y + amount*(v2.y - v1.y); 272 273 return result; 274 } 275 276 // Calculate reflected vector to normal 277 static Vector2 Vector2Reflect(Vector2 v, Vector2 normal) 278 { 279 Vector2 result = { 0 }; 280 281 float dotProduct = (v.x*normal.x + v.y*normal.y); // Dot product 282 283 result.x = v.x - (2.0f*normal.x)*dotProduct; 284 result.y = v.y - (2.0f*normal.y)*dotProduct; 285 286 return result; 287 } 288 289 // Rotate vector by angle 290 static Vector2 Vector2Rotate(Vector2 v, float angle) 291 { 292 Vector2 result = { 0 }; 293 294 result.x = v.x*cosf(angle) - v.y*sinf(angle); 295 result.y = v.x*sinf(angle) + v.y*cosf(angle); 296 297 return result; 298 } 299 300 // Move Vector towards target 301 static Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance) 302 { 303 Vector2 result = { 0 }; 304 305 float dx = target.x - v.x; 306 float dy = target.y - v.y; 307 float value = (dx*dx) + (dy*dy); 308 309 if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target; 310 311 float dist = sqrtf(value); 312 313 result.x = v.x + dx/dist*maxDistance; 314 result.y = v.y + dy/dist*maxDistance; 315 316 return result; 317 } 318 319 //---------------------------------------------------------------------------------- 320 // Module Functions Definition - Vector3 math 321 //---------------------------------------------------------------------------------- 322 323 // Vector with components value 0.0f 324 static Vector3 Vector3Zero() 325 { 326 Vector3 result = { 0.0f, 0.0f, 0.0f }; 327 328 return result; 329 } 330 331 // Vector with components value 1.0f 332 static Vector3 Vector3One() 333 { 334 Vector3 result = { 1.0f, 1.0f, 1.0f }; 335 336 return result; 337 } 338 339 // Add two vectors 340 static Vector3 Vector3Add(Vector3 v1, Vector3 v2) 341 { 342 Vector3 result = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; 343 344 return result; 345 } 346 347 // Add vector and float value 348 static Vector3 Vector3AddValue(Vector3 v, float add) 349 { 350 Vector3 result = { v.x + add, v.y + add, v.z + add }; 351 352 return result; 353 } 354 355 // Subtract two vectors 356 static Vector3 Vector3Subtract(Vector3 v1, Vector3 v2) 357 { 358 Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; 359 360 return result; 361 } 362 363 // Subtract vector by float value 364 static Vector3 Vector3SubtractValue(Vector3 v, float sub) 365 { 366 Vector3 result = { v.x - sub, v.y - sub, v.z - sub }; 367 368 return result; 369 } 370 371 // Multiply vector by scalar 372 static Vector3 Vector3Scale(Vector3 v, float scalar) 373 { 374 Vector3 result = { v.x*scalar, v.y*scalar, v.z*scalar }; 375 376 return result; 377 } 378 379 // Multiply vector by vector 380 static Vector3 Vector3Multiply(Vector3 v1, Vector3 v2) 381 { 382 Vector3 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z }; 383 384 return result; 385 } 386 387 // Calculate two vectors cross product 388 static Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2) 389 { 390 Vector3 result = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x }; 391 392 return result; 393 } 394 395 // Calculate one vector perpendicular vector 396 static Vector3 Vector3Perpendicular(Vector3 v) 397 { 398 Vector3 result = { 0 }; 399 400 float min = cast(float) fabs(v.x); 401 Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f}; 402 403 if (fabs(v.y) < min) 404 { 405 min = cast(float) fabs(v.y); 406 Vector3 tmp = {0.0f, 1.0f, 0.0f}; 407 cardinalAxis = tmp; 408 } 409 410 if (fabs(v.z) < min) 411 { 412 Vector3 tmp = {0.0f, 0.0f, 1.0f}; 413 cardinalAxis = tmp; 414 } 415 416 // Cross product between vectors 417 result.x = v.y*cardinalAxis.z - v.z*cardinalAxis.y; 418 result.y = v.z*cardinalAxis.x - v.x*cardinalAxis.z; 419 result.z = v.x*cardinalAxis.y - v.y*cardinalAxis.x; 420 421 return result; 422 } 423 424 // Calculate vector length 425 static float Vector3Length(const Vector3 v) 426 { 427 float result = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 428 429 return result; 430 } 431 432 // Calculate vector square length 433 static float Vector3LengthSqr(const Vector3 v) 434 { 435 float result = v.x*v.x + v.y*v.y + v.z*v.z; 436 437 return result; 438 } 439 440 // Calculate two vectors dot product 441 static float Vector3DotProduct(Vector3 v1, Vector3 v2) 442 { 443 float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); 444 445 return result; 446 } 447 448 // Calculate distance between two vectors 449 static float Vector3Distance(Vector3 v1, Vector3 v2) 450 { 451 float result = 0.0f; 452 453 float dx = v2.x - v1.x; 454 float dy = v2.y - v1.y; 455 float dz = v2.z - v1.z; 456 result = sqrtf(dx*dx + dy*dy + dz*dz); 457 458 return result; 459 } 460 461 // Calculate angle between two vectors in XY and XZ 462 static Vector2 Vector3Angle(Vector3 v1, Vector3 v2) 463 { 464 Vector2 result = { 0 }; 465 466 float dx = v2.x - v1.x; 467 float dy = v2.y - v1.y; 468 float dz = v2.z - v1.z; 469 470 result.x = atan2f(dx, dz); // Angle in XZ 471 result.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Angle in XY 472 473 return result; 474 } 475 476 // Negate provided vector (invert direction) 477 static Vector3 Vector3Negate(Vector3 v) 478 { 479 Vector3 result = { -v.x, -v.y, -v.z }; 480 481 return result; 482 } 483 484 // Divide vector by vector 485 static Vector3 Vector3Divide(Vector3 v1, Vector3 v2) 486 { 487 Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z }; 488 489 return result; 490 } 491 492 // Normalize provided vector 493 static Vector3 Vector3Normalize(Vector3 v) 494 { 495 Vector3 result = v; 496 497 float length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 498 if (length == 0.0f) length = 1.0f; 499 float ilength = 1.0f/length; 500 501 result.x *= ilength; 502 result.y *= ilength; 503 result.z *= ilength; 504 505 return result; 506 } 507 508 // Orthonormalize provided vectors 509 // Makes vectors normalized and orthogonal to each other 510 // Gram-Schmidt function implementation 511 static void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2) 512 { 513 float length = 0.0f; 514 float ilength = 0.0f; 515 516 // Vector3Normalize(*v1); 517 Vector3 v = *v1; 518 length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 519 if (length == 0.0f) length = 1.0f; 520 ilength = 1.0f/length; 521 v1.x *= ilength; 522 v1.y *= ilength; 523 v1.z *= ilength; 524 525 // Vector3CrossProduct(*v1, *v2) 526 Vector3 vn1 = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x }; 527 528 // Vector3Normalize(vn1); 529 v = vn1; 530 length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 531 if (length == 0.0f) length = 1.0f; 532 ilength = 1.0f/length; 533 vn1.x *= ilength; 534 vn1.y *= ilength; 535 vn1.z *= ilength; 536 537 // Vector3CrossProduct(vn1, *v1) 538 Vector3 vn2 = { vn1.y*v1.z - vn1.z*v1.y, vn1.z*v1.x - vn1.x*v1.z, vn1.x*v1.y - vn1.y*v1.x }; 539 540 *v2 = vn2; 541 } 542 543 // Transforms a Vector3 by a given Matrix 544 static Vector3 Vector3Transform(Vector3 v, Matrix mat) 545 { 546 Vector3 result = { 0 }; 547 548 float x = v.x; 549 float y = v.y; 550 float z = v.z; 551 552 result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12; 553 result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13; 554 result.z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14; 555 556 return result; 557 } 558 559 // Transform a vector by quaternion rotation 560 static Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q) 561 { 562 Vector3 result = { 0 }; 563 564 result.x = v.x*(q.x*q.x + q.w*q.w - q.y*q.y - q.z*q.z) + v.y*(2*q.x*q.y - 2*q.w*q.z) + v.z*(2*q.x*q.z + 2*q.w*q.y); 565 result.y = v.x*(2*q.w*q.z + 2*q.x*q.y) + v.y*(q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z) + v.z*(-2*q.w*q.x + 2*q.y*q.z); 566 result.z = v.x*(-2*q.w*q.y + 2*q.x*q.z) + v.y*(2*q.w*q.x + 2*q.y*q.z)+ v.z*(q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z); 567 568 return result; 569 } 570 571 // Calculate linear interpolation between two vectors 572 static Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount) 573 { 574 Vector3 result = { 0 }; 575 576 result.x = v1.x + amount*(v2.x - v1.x); 577 result.y = v1.y + amount*(v2.y - v1.y); 578 result.z = v1.z + amount*(v2.z - v1.z); 579 580 return result; 581 } 582 583 // Calculate reflected vector to normal 584 static Vector3 Vector3Reflect(Vector3 v, Vector3 normal) 585 { 586 Vector3 result = { 0 }; 587 588 // I is the original vector 589 // N is the normal of the incident plane 590 // R = I - (2*N*(DotProduct[I, N])) 591 592 float dotProduct = (v.x*normal.x + v.y*normal.y + v.z*normal.z); 593 594 result.x = v.x - (2.0f*normal.x)*dotProduct; 595 result.y = v.y - (2.0f*normal.y)*dotProduct; 596 result.z = v.z - (2.0f*normal.z)*dotProduct; 597 598 return result; 599 } 600 601 // Get min value for each pair of components 602 static Vector3 Vector3Min(Vector3 v1, Vector3 v2) 603 { 604 Vector3 result = { 0 }; 605 606 result.x = fminf(v1.x, v2.x); 607 result.y = fminf(v1.y, v2.y); 608 result.z = fminf(v1.z, v2.z); 609 610 return result; 611 } 612 613 // Get max value for each pair of components 614 static Vector3 Vector3Max(Vector3 v1, Vector3 v2) 615 { 616 Vector3 result = { 0 }; 617 618 result.x = fmaxf(v1.x, v2.x); 619 result.y = fmaxf(v1.y, v2.y); 620 result.z = fmaxf(v1.z, v2.z); 621 622 return result; 623 } 624 625 // Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c) 626 // NOTE: Assumes P is on the plane of the triangle 627 static Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) 628 { 629 Vector3 result = { 0 }; 630 631 Vector3 v0 = { b.x - a.x, b.y - a.y, b.z - a.z }; // Vector3Subtract(b, a) 632 Vector3 v1 = { c.x - a.x, c.y - a.y, c.z - a.z }; // Vector3Subtract(c, a) 633 Vector3 v2 = { p.x - a.x, p.y - a.y, p.z - a.z }; // Vector3Subtract(p, a) 634 float d00 = (v0.x*v0.x + v0.y*v0.y + v0.z*v0.z); // Vector3DotProduct(v0, v0) 635 float d01 = (v0.x*v1.x + v0.y*v1.y + v0.z*v1.z); // Vector3DotProduct(v0, v1) 636 float d11 = (v1.x*v1.x + v1.y*v1.y + v1.z*v1.z); // Vector3DotProduct(v1, v1) 637 float d20 = (v2.x*v0.x + v2.y*v0.y + v2.z*v0.z); // Vector3DotProduct(v2, v0) 638 float d21 = (v2.x*v1.x + v2.y*v1.y + v2.z*v1.z); // Vector3DotProduct(v2, v1) 639 640 float denom = d00*d11 - d01*d01; 641 642 result.y = (d11*d20 - d01*d21)/denom; 643 result.z = (d00*d21 - d01*d20)/denom; 644 result.x = 1.0f - (result.z + result.y); 645 646 return result; 647 } 648 649 // Projects a Vector3 from screen space into object space 650 // NOTE: We are avoiding calling other raymath functions despite available 651 static Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) 652 { 653 Vector3 result = { 0 }; 654 655 // Calculate unproject matrix (multiply view patrix by projection matrix) and invert it 656 Matrix matViewProj = { // MatrixMultiply(view, projection); 657 view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12, 658 view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13, 659 view.m0*projection.m2 + view.m1*projection.m6 + view.m2*projection.m10 + view.m3*projection.m14, 660 view.m0*projection.m3 + view.m1*projection.m7 + view.m2*projection.m11 + view.m3*projection.m15, 661 view.m4*projection.m0 + view.m5*projection.m4 + view.m6*projection.m8 + view.m7*projection.m12, 662 view.m4*projection.m1 + view.m5*projection.m5 + view.m6*projection.m9 + view.m7*projection.m13, 663 view.m4*projection.m2 + view.m5*projection.m6 + view.m6*projection.m10 + view.m7*projection.m14, 664 view.m4*projection.m3 + view.m5*projection.m7 + view.m6*projection.m11 + view.m7*projection.m15, 665 view.m8*projection.m0 + view.m9*projection.m4 + view.m10*projection.m8 + view.m11*projection.m12, 666 view.m8*projection.m1 + view.m9*projection.m5 + view.m10*projection.m9 + view.m11*projection.m13, 667 view.m8*projection.m2 + view.m9*projection.m6 + view.m10*projection.m10 + view.m11*projection.m14, 668 view.m8*projection.m3 + view.m9*projection.m7 + view.m10*projection.m11 + view.m11*projection.m15, 669 view.m12*projection.m0 + view.m13*projection.m4 + view.m14*projection.m8 + view.m15*projection.m12, 670 view.m12*projection.m1 + view.m13*projection.m5 + view.m14*projection.m9 + view.m15*projection.m13, 671 view.m12*projection.m2 + view.m13*projection.m6 + view.m14*projection.m10 + view.m15*projection.m14, 672 view.m12*projection.m3 + view.m13*projection.m7 + view.m14*projection.m11 + view.m15*projection.m15 }; 673 674 // Calculate inverted matrix . MatrixInvert(matViewProj); 675 // Cache the matrix values (speed optimization) 676 float a00 = matViewProj.m0, a01 = matViewProj.m1, a02 = matViewProj.m2, a03 = matViewProj.m3; 677 float a10 = matViewProj.m4, a11 = matViewProj.m5, a12 = matViewProj.m6, a13 = matViewProj.m7; 678 float a20 = matViewProj.m8, a21 = matViewProj.m9, a22 = matViewProj.m10, a23 = matViewProj.m11; 679 float a30 = matViewProj.m12, a31 = matViewProj.m13, a32 = matViewProj.m14, a33 = matViewProj.m15; 680 681 float b00 = a00*a11 - a01*a10; 682 float b01 = a00*a12 - a02*a10; 683 float b02 = a00*a13 - a03*a10; 684 float b03 = a01*a12 - a02*a11; 685 float b04 = a01*a13 - a03*a11; 686 float b05 = a02*a13 - a03*a12; 687 float b06 = a20*a31 - a21*a30; 688 float b07 = a20*a32 - a22*a30; 689 float b08 = a20*a33 - a23*a30; 690 float b09 = a21*a32 - a22*a31; 691 float b10 = a21*a33 - a23*a31; 692 float b11 = a22*a33 - a23*a32; 693 694 // Calculate the invert determinant (inlined to avoid double-caching) 695 float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); 696 697 Matrix matViewProjInv = { 698 (a11*b11 - a12*b10 + a13*b09)*invDet, 699 (-a01*b11 + a02*b10 - a03*b09)*invDet, 700 (a31*b05 - a32*b04 + a33*b03)*invDet, 701 (-a21*b05 + a22*b04 - a23*b03)*invDet, 702 (-a10*b11 + a12*b08 - a13*b07)*invDet, 703 (a00*b11 - a02*b08 + a03*b07)*invDet, 704 (-a30*b05 + a32*b02 - a33*b01)*invDet, 705 (a20*b05 - a22*b02 + a23*b01)*invDet, 706 (a10*b10 - a11*b08 + a13*b06)*invDet, 707 (-a00*b10 + a01*b08 - a03*b06)*invDet, 708 (a30*b04 - a31*b02 + a33*b00)*invDet, 709 (-a20*b04 + a21*b02 - a23*b00)*invDet, 710 (-a10*b09 + a11*b07 - a12*b06)*invDet, 711 (a00*b09 - a01*b07 + a02*b06)*invDet, 712 (-a30*b03 + a31*b01 - a32*b00)*invDet, 713 (a20*b03 - a21*b01 + a22*b00)*invDet }; 714 715 // Create quaternion from source point 716 Quaternion quat = { source.x, source.y, source.z, 1.0f }; 717 718 // Multiply quat point by unproject matrix 719 Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv) 720 matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w, 721 matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w, 722 matViewProjInv.m2*quat.x + matViewProjInv.m6*quat.y + matViewProjInv.m10*quat.z + matViewProjInv.m14*quat.w, 723 matViewProjInv.m3*quat.x + matViewProjInv.m7*quat.y + matViewProjInv.m11*quat.z + matViewProjInv.m15*quat.w }; 724 725 // Normalized world points in vectors 726 result.x = qtransformed.x/qtransformed.w; 727 result.y = qtransformed.y/qtransformed.w; 728 result.z = qtransformed.z/qtransformed.w; 729 730 return result; 731 } 732 733 // Get Vector3 as float array 734 static float3 Vector3ToFloatV(Vector3 v) 735 { 736 float3 buffer = { 0 }; 737 738 buffer.v[0] = v.x; 739 buffer.v[1] = v.y; 740 buffer.v[2] = v.z; 741 742 return buffer; 743 } 744 745 //---------------------------------------------------------------------------------- 746 // Module Functions Definition - Matrix math 747 //---------------------------------------------------------------------------------- 748 749 // Compute matrix determinant 750 static float MatrixDeterminant(Matrix mat) 751 { 752 float result = 0.0f; 753 754 // Cache the matrix values (speed optimization) 755 float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; 756 float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; 757 float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; 758 float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; 759 760 result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 + 761 a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 + 762 a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 + 763 a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + 764 a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + 765 a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; 766 767 return result; 768 } 769 770 // Get the trace of the matrix (sum of the values along the diagonal) 771 static float MatrixTrace(Matrix mat) 772 { 773 float result = (mat.m0 + mat.m5 + mat.m10 + mat.m15); 774 775 return result; 776 } 777 778 // Transposes provided matrix 779 static Matrix MatrixTranspose(Matrix mat) 780 { 781 Matrix result = { 0 }; 782 783 result.m0 = mat.m0; 784 result.m1 = mat.m4; 785 result.m2 = mat.m8; 786 result.m3 = mat.m12; 787 result.m4 = mat.m1; 788 result.m5 = mat.m5; 789 result.m6 = mat.m9; 790 result.m7 = mat.m13; 791 result.m8 = mat.m2; 792 result.m9 = mat.m6; 793 result.m10 = mat.m10; 794 result.m11 = mat.m14; 795 result.m12 = mat.m3; 796 result.m13 = mat.m7; 797 result.m14 = mat.m11; 798 result.m15 = mat.m15; 799 800 return result; 801 } 802 803 // Invert provided matrix 804 static Matrix MatrixInvert(Matrix mat) 805 { 806 Matrix result = { 0 }; 807 808 // Cache the matrix values (speed optimization) 809 float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; 810 float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; 811 float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; 812 float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; 813 814 float b00 = a00*a11 - a01*a10; 815 float b01 = a00*a12 - a02*a10; 816 float b02 = a00*a13 - a03*a10; 817 float b03 = a01*a12 - a02*a11; 818 float b04 = a01*a13 - a03*a11; 819 float b05 = a02*a13 - a03*a12; 820 float b06 = a20*a31 - a21*a30; 821 float b07 = a20*a32 - a22*a30; 822 float b08 = a20*a33 - a23*a30; 823 float b09 = a21*a32 - a22*a31; 824 float b10 = a21*a33 - a23*a31; 825 float b11 = a22*a33 - a23*a32; 826 827 // Calculate the invert determinant (inlined to avoid double-caching) 828 float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); 829 830 result.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet; 831 result.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet; 832 result.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet; 833 result.m3 = (-a21*b05 + a22*b04 - a23*b03)*invDet; 834 result.m4 = (-a10*b11 + a12*b08 - a13*b07)*invDet; 835 result.m5 = (a00*b11 - a02*b08 + a03*b07)*invDet; 836 result.m6 = (-a30*b05 + a32*b02 - a33*b01)*invDet; 837 result.m7 = (a20*b05 - a22*b02 + a23*b01)*invDet; 838 result.m8 = (a10*b10 - a11*b08 + a13*b06)*invDet; 839 result.m9 = (-a00*b10 + a01*b08 - a03*b06)*invDet; 840 result.m10 = (a30*b04 - a31*b02 + a33*b00)*invDet; 841 result.m11 = (-a20*b04 + a21*b02 - a23*b00)*invDet; 842 result.m12 = (-a10*b09 + a11*b07 - a12*b06)*invDet; 843 result.m13 = (a00*b09 - a01*b07 + a02*b06)*invDet; 844 result.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet; 845 result.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet; 846 847 return result; 848 } 849 850 // Normalize provided matrix 851 static Matrix MatrixNormalize(Matrix mat) 852 { 853 Matrix result = { 0 }; 854 855 // Cache the matrix values (speed optimization) 856 float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; 857 float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; 858 float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; 859 float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; 860 861 // MatrixDeterminant(mat) 862 float det = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 + 863 a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 + 864 a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 + 865 a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + 866 a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + 867 a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; 868 869 result.m0 = mat.m0/det; 870 result.m1 = mat.m1/det; 871 result.m2 = mat.m2/det; 872 result.m3 = mat.m3/det; 873 result.m4 = mat.m4/det; 874 result.m5 = mat.m5/det; 875 result.m6 = mat.m6/det; 876 result.m7 = mat.m7/det; 877 result.m8 = mat.m8/det; 878 result.m9 = mat.m9/det; 879 result.m10 = mat.m10/det; 880 result.m11 = mat.m11/det; 881 result.m12 = mat.m12/det; 882 result.m13 = mat.m13/det; 883 result.m14 = mat.m14/det; 884 result.m15 = mat.m15/det; 885 886 return result; 887 } 888 889 // Get identity matrix 890 static Matrix MatrixIdentity() 891 { 892 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 893 0.0f, 1.0f, 0.0f, 0.0f, 894 0.0f, 0.0f, 1.0f, 0.0f, 895 0.0f, 0.0f, 0.0f, 1.0f }; 896 897 return result; 898 } 899 900 // Add two matrices 901 static Matrix MatrixAdd(Matrix left, Matrix right) 902 { 903 Matrix result = { 0 }; 904 905 result.m0 = left.m0 + right.m0; 906 result.m1 = left.m1 + right.m1; 907 result.m2 = left.m2 + right.m2; 908 result.m3 = left.m3 + right.m3; 909 result.m4 = left.m4 + right.m4; 910 result.m5 = left.m5 + right.m5; 911 result.m6 = left.m6 + right.m6; 912 result.m7 = left.m7 + right.m7; 913 result.m8 = left.m8 + right.m8; 914 result.m9 = left.m9 + right.m9; 915 result.m10 = left.m10 + right.m10; 916 result.m11 = left.m11 + right.m11; 917 result.m12 = left.m12 + right.m12; 918 result.m13 = left.m13 + right.m13; 919 result.m14 = left.m14 + right.m14; 920 result.m15 = left.m15 + right.m15; 921 922 return result; 923 } 924 925 // Subtract two matrices (left - right) 926 static Matrix MatrixSubtract(Matrix left, Matrix right) 927 { 928 Matrix result = { 0 }; 929 930 result.m0 = left.m0 - right.m0; 931 result.m1 = left.m1 - right.m1; 932 result.m2 = left.m2 - right.m2; 933 result.m3 = left.m3 - right.m3; 934 result.m4 = left.m4 - right.m4; 935 result.m5 = left.m5 - right.m5; 936 result.m6 = left.m6 - right.m6; 937 result.m7 = left.m7 - right.m7; 938 result.m8 = left.m8 - right.m8; 939 result.m9 = left.m9 - right.m9; 940 result.m10 = left.m10 - right.m10; 941 result.m11 = left.m11 - right.m11; 942 result.m12 = left.m12 - right.m12; 943 result.m13 = left.m13 - right.m13; 944 result.m14 = left.m14 - right.m14; 945 result.m15 = left.m15 - right.m15; 946 947 return result; 948 } 949 950 // Get two matrix multiplication 951 // NOTE: When multiplying matrices... the order matters! 952 static Matrix MatrixMultiply(Matrix left, Matrix right) 953 { 954 Matrix result = { 0 }; 955 956 result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12; 957 result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13; 958 result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14; 959 result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15; 960 result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12; 961 result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13; 962 result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14; 963 result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15; 964 result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12; 965 result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13; 966 result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14; 967 result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15; 968 result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12; 969 result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13; 970 result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14; 971 result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15; 972 973 return result; 974 } 975 976 // Get translation matrix 977 static Matrix MatrixTranslate(float x, float y, float z) 978 { 979 Matrix result = { 1.0f, 0.0f, 0.0f, x, 980 0.0f, 1.0f, 0.0f, y, 981 0.0f, 0.0f, 1.0f, z, 982 0.0f, 0.0f, 0.0f, 1.0f }; 983 984 return result; 985 } 986 987 // Create rotation matrix from axis and angle 988 // NOTE: Angle should be provided in radians 989 static Matrix MatrixRotate(Vector3 axis, float angle) 990 { 991 Matrix result = { 0 }; 992 993 float x = axis.x, y = axis.y, z = axis.z; 994 995 float lengthSquared = x*x + y*y + z*z; 996 997 if ((lengthSquared != 1.0f) && (lengthSquared != 0.0f)) 998 { 999 float ilength = 1.0f/sqrtf(lengthSquared); 1000 x *= ilength; 1001 y *= ilength; 1002 z *= ilength; 1003 } 1004 1005 float sinres = sinf(angle); 1006 float cosres = cosf(angle); 1007 float t = 1.0f - cosres; 1008 1009 result.m0 = x*x*t + cosres; 1010 result.m1 = y*x*t + z*sinres; 1011 result.m2 = z*x*t - y*sinres; 1012 result.m3 = 0.0f; 1013 1014 result.m4 = x*y*t - z*sinres; 1015 result.m5 = y*y*t + cosres; 1016 result.m6 = z*y*t + x*sinres; 1017 result.m7 = 0.0f; 1018 1019 result.m8 = x*z*t + y*sinres; 1020 result.m9 = y*z*t - x*sinres; 1021 result.m10 = z*z*t + cosres; 1022 result.m11 = 0.0f; 1023 1024 result.m12 = 0.0f; 1025 result.m13 = 0.0f; 1026 result.m14 = 0.0f; 1027 result.m15 = 1.0f; 1028 1029 return result; 1030 } 1031 1032 // Get x-rotation matrix (angle in radians) 1033 static Matrix MatrixRotateX(float angle) 1034 { 1035 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 1036 0.0f, 1.0f, 0.0f, 0.0f, 1037 0.0f, 0.0f, 1.0f, 0.0f, 1038 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() 1039 1040 float cosres = cosf(angle); 1041 float sinres = sinf(angle); 1042 1043 result.m5 = cosres; 1044 result.m6 = -sinres; 1045 result.m9 = sinres; 1046 result.m10 = cosres; 1047 1048 return result; 1049 } 1050 1051 // Get y-rotation matrix (angle in radians) 1052 static Matrix MatrixRotateY(float angle) 1053 { 1054 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 1055 0.0f, 1.0f, 0.0f, 0.0f, 1056 0.0f, 0.0f, 1.0f, 0.0f, 1057 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() 1058 1059 float cosres = cosf(angle); 1060 float sinres = sinf(angle); 1061 1062 result.m0 = cosres; 1063 result.m2 = sinres; 1064 result.m8 = -sinres; 1065 result.m10 = cosres; 1066 1067 return result; 1068 } 1069 1070 // Get z-rotation matrix (angle in radians) 1071 static Matrix MatrixRotateZ(float angle) 1072 { 1073 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 1074 0.0f, 1.0f, 0.0f, 0.0f, 1075 0.0f, 0.0f, 1.0f, 0.0f, 1076 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() 1077 1078 float cosres = cosf(angle); 1079 float sinres = sinf(angle); 1080 1081 result.m0 = cosres; 1082 result.m1 = -sinres; 1083 result.m4 = sinres; 1084 result.m5 = cosres; 1085 1086 return result; 1087 } 1088 1089 1090 // Get xyz-rotation matrix (angles in radians) 1091 static Matrix MatrixRotateXYZ(Vector3 ang) 1092 { 1093 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 1094 0.0f, 1.0f, 0.0f, 0.0f, 1095 0.0f, 0.0f, 1.0f, 0.0f, 1096 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() 1097 1098 float cosz = cosf(-ang.z); 1099 float sinz = sinf(-ang.z); 1100 float cosy = cosf(-ang.y); 1101 float siny = sinf(-ang.y); 1102 float cosx = cosf(-ang.x); 1103 float sinx = sinf(-ang.x); 1104 1105 result.m0 = cosz*cosy; 1106 result.m4 = (cosz*siny*sinx) - (sinz*cosx); 1107 result.m8 = (cosz*siny*cosx) + (sinz*sinx); 1108 1109 result.m1 = sinz*cosy; 1110 result.m5 = (sinz*siny*sinx) + (cosz*cosx); 1111 result.m9 = (sinz*siny*cosx) - (cosz*sinx); 1112 1113 result.m2 = -siny; 1114 result.m6 = cosy*sinx; 1115 result.m10= cosy*cosx; 1116 1117 return result; 1118 } 1119 1120 // Get zyx-rotation matrix (angles in radians) 1121 static Matrix MatrixRotateZYX(Vector3 ang) 1122 { 1123 Matrix result = { 0 }; 1124 1125 float cz = cosf(ang.z); 1126 float sz = sinf(ang.z); 1127 float cy = cosf(ang.y); 1128 float sy = sinf(ang.y); 1129 float cx = cosf(ang.x); 1130 float sx = sinf(ang.x); 1131 1132 result.m0 = cz*cy; 1133 result.m1 = cz*sy*sx - cx*sz; 1134 result.m2 = sz*sx + cz*cx*sy; 1135 result.m3 = 0; 1136 1137 result.m4 = cy*sz; 1138 result.m5 = cz*cx + sz*sy*sx; 1139 result.m6 = cx*sz*sy - cz*sx; 1140 result.m7 = 0; 1141 1142 result.m8 = -sy; 1143 result.m9 = cy*sx; 1144 result.m10 = cy*cx; 1145 result.m11 = 0; 1146 1147 result.m12 = 0; 1148 result.m13 = 0; 1149 result.m14 = 0; 1150 result.m15 = 1; 1151 1152 return result; 1153 } 1154 1155 // Get scaling matrix 1156 static Matrix MatrixScale(float x, float y, float z) 1157 { 1158 Matrix result = { x, 0.0f, 0.0f, 0.0f, 1159 0.0f, y, 0.0f, 0.0f, 1160 0.0f, 0.0f, z, 0.0f, 1161 0.0f, 0.0f, 0.0f, 1.0f }; 1162 1163 return result; 1164 } 1165 1166 // Get perspective projection matrix 1167 static Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far) 1168 { 1169 Matrix result = { 0 }; 1170 1171 float rl = cast(float)(right - left); 1172 float tb = cast(float)(top - bottom); 1173 float fn = cast(float)(far - near); 1174 1175 result.m0 = (cast(float)near*2.0f)/rl; 1176 result.m1 = 0.0f; 1177 result.m2 = 0.0f; 1178 result.m3 = 0.0f; 1179 1180 result.m4 = 0.0f; 1181 result.m5 = (cast(float)near*2.0f)/tb; 1182 result.m6 = 0.0f; 1183 result.m7 = 0.0f; 1184 1185 result.m8 = (cast(float)right + cast(float)left)/rl; 1186 result.m9 = (cast(float)top + cast(float)bottom)/tb; 1187 result.m10 = -(cast(float)far + cast(float)near)/fn; 1188 result.m11 = -1.0f; 1189 1190 result.m12 = 0.0f; 1191 result.m13 = 0.0f; 1192 result.m14 = -(cast(float)far*cast(float)near*2.0f)/fn; 1193 result.m15 = 0.0f; 1194 1195 return result; 1196 } 1197 1198 // Get perspective projection matrix 1199 // NOTE: Angle should be provided in radians 1200 static Matrix MatrixPerspective(double fovy, double aspect, double near, double far) 1201 { 1202 Matrix result = { 0 }; 1203 1204 double top = near*tan(fovy*0.5); 1205 double bottom = -top; 1206 double right = top*aspect; 1207 double left = -right; 1208 1209 // MatrixFrustum(-right, right, -top, top, near, far); 1210 float rl = cast(float)(right - left); 1211 float tb = cast(float)(top - bottom); 1212 float fn = cast(float)(far - near); 1213 1214 result.m0 = (cast(float)near*2.0f)/rl; 1215 result.m5 = (cast(float)near*2.0f)/tb; 1216 result.m8 = (cast(float)right + cast(float)left)/rl; 1217 result.m9 = (cast(float)top + cast(float)bottom)/tb; 1218 result.m10 = -(cast(float)far + cast(float)near)/fn; 1219 result.m11 = -1.0f; 1220 result.m14 = -(cast(float)far*cast(float)near*2.0f)/fn; 1221 1222 return result; 1223 } 1224 1225 // Get orthographic projection matrix 1226 static Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far) 1227 { 1228 Matrix result = { 0 }; 1229 1230 float rl = cast(float)(right - left); 1231 float tb = cast(float)(top - bottom); 1232 float fn = cast(float)(far - near); 1233 1234 result.m0 = 2.0f/rl; 1235 result.m1 = 0.0f; 1236 result.m2 = 0.0f; 1237 result.m3 = 0.0f; 1238 result.m4 = 0.0f; 1239 result.m5 = 2.0f/tb; 1240 result.m6 = 0.0f; 1241 result.m7 = 0.0f; 1242 result.m8 = 0.0f; 1243 result.m9 = 0.0f; 1244 result.m10 = -2.0f/fn; 1245 result.m11 = 0.0f; 1246 result.m12 = -(cast(float)left + cast(float)right)/rl; 1247 result.m13 = -(cast(float)top + cast(float)bottom)/tb; 1248 result.m14 = -(cast(float)far + cast(float)near)/fn; 1249 result.m15 = 1.0f; 1250 1251 return result; 1252 } 1253 1254 // Get camera look-at matrix (view matrix) 1255 static Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up) 1256 { 1257 Matrix result = { 0 }; 1258 1259 float length = 0.0f; 1260 float ilength = 0.0f; 1261 1262 // Vector3Subtract(eye, target) 1263 Vector3 vz = { eye.x - target.x, eye.y - target.y, eye.z - target.z }; 1264 1265 // Vector3Normalize(vz) 1266 Vector3 v = vz; 1267 length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 1268 if (length == 0.0f) length = 1.0f; 1269 ilength = 1.0f/length; 1270 vz.x *= ilength; 1271 vz.y *= ilength; 1272 vz.z *= ilength; 1273 1274 // Vector3CrossProduct(up, vz) 1275 Vector3 vx = { up.y*vz.z - up.z*vz.y, up.z*vz.x - up.x*vz.z, up.x*vz.y - up.y*vz.x }; 1276 1277 // Vector3Normalize(x) 1278 v = vx; 1279 length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 1280 if (length == 0.0f) length = 1.0f; 1281 ilength = 1.0f/length; 1282 vx.x *= ilength; 1283 vx.y *= ilength; 1284 vx.z *= ilength; 1285 1286 // Vector3CrossProduct(vz, vx) 1287 Vector3 vy = { vz.y*vx.z - vz.z*vx.y, vz.z*vx.x - vz.x*vx.z, vz.x*vx.y - vz.y*vx.x }; 1288 1289 result.m0 = vx.x; 1290 result.m1 = vy.x; 1291 result.m2 = vz.x; 1292 result.m3 = 0.0f; 1293 result.m4 = vx.y; 1294 result.m5 = vy.y; 1295 result.m6 = vz.y; 1296 result.m7 = 0.0f; 1297 result.m8 = vx.z; 1298 result.m9 = vy.z; 1299 result.m10 = vz.z; 1300 result.m11 = 0.0f; 1301 result.m12 = -(vx.x*eye.x + vx.y*eye.y + vx.z*eye.z); // Vector3DotProduct(vx, eye) 1302 result.m13 = -(vy.x*eye.x + vy.y*eye.y + vy.z*eye.z); // Vector3DotProduct(vy, eye) 1303 result.m14 = -(vz.x*eye.x + vz.y*eye.y + vz.z*eye.z); // Vector3DotProduct(vz, eye) 1304 result.m15 = 1.0f; 1305 1306 return result; 1307 } 1308 1309 // Get float array of matrix data 1310 static float16 MatrixToFloatV(Matrix mat) 1311 { 1312 float16 result = { 0 }; 1313 1314 result.v[0] = mat.m0; 1315 result.v[1] = mat.m1; 1316 result.v[2] = mat.m2; 1317 result.v[3] = mat.m3; 1318 result.v[4] = mat.m4; 1319 result.v[5] = mat.m5; 1320 result.v[6] = mat.m6; 1321 result.v[7] = mat.m7; 1322 result.v[8] = mat.m8; 1323 result.v[9] = mat.m9; 1324 result.v[10] = mat.m10; 1325 result.v[11] = mat.m11; 1326 result.v[12] = mat.m12; 1327 result.v[13] = mat.m13; 1328 result.v[14] = mat.m14; 1329 result.v[15] = mat.m15; 1330 1331 return result; 1332 } 1333 1334 //---------------------------------------------------------------------------------- 1335 // Module Functions Definition - Quaternion math 1336 //---------------------------------------------------------------------------------- 1337 1338 // Add two quaternions 1339 static Quaternion QuaternionAdd(Quaternion q1, Quaternion q2) 1340 { 1341 Quaternion result = {q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w}; 1342 1343 return result; 1344 } 1345 1346 // Add quaternion and float value 1347 static Quaternion QuaternionAddValue(Quaternion q, float add) 1348 { 1349 Quaternion result = {q.x + add, q.y + add, q.z + add, q.w + add}; 1350 1351 return result; 1352 } 1353 1354 // Subtract two quaternions 1355 static Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2) 1356 { 1357 Quaternion result = {q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w}; 1358 1359 return result; 1360 } 1361 1362 // Subtract quaternion and float value 1363 static Quaternion QuaternionSubtractValue(Quaternion q, float sub) 1364 { 1365 Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub}; 1366 1367 return result; 1368 } 1369 1370 // Get identity quaternion 1371 static Quaternion QuaternionIdentity() 1372 { 1373 Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; 1374 1375 return result; 1376 } 1377 1378 // Computes the length of a quaternion 1379 static float QuaternionLength(Quaternion q) 1380 { 1381 float result = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 1382 1383 return result; 1384 } 1385 1386 // Normalize provided quaternion 1387 static Quaternion QuaternionNormalize(Quaternion q) 1388 { 1389 Quaternion result = { 0 }; 1390 1391 float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 1392 if (length == 0.0f) length = 1.0f; 1393 float ilength = 1.0f/length; 1394 1395 result.x = q.x*ilength; 1396 result.y = q.y*ilength; 1397 result.z = q.z*ilength; 1398 result.w = q.w*ilength; 1399 1400 return result; 1401 } 1402 1403 // Invert provided quaternion 1404 static Quaternion QuaternionInvert(Quaternion q) 1405 { 1406 Quaternion result = q; 1407 1408 float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 1409 float lengthSq = length*length; 1410 1411 if (lengthSq != 0.0) 1412 { 1413 float invLength = 1.0f/lengthSq; 1414 1415 result.x *= -invLength; 1416 result.y *= -invLength; 1417 result.z *= -invLength; 1418 result.w *= invLength; 1419 } 1420 1421 return result; 1422 } 1423 1424 // Calculate two quaternion multiplication 1425 static Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2) 1426 { 1427 Quaternion result = { 0 }; 1428 1429 float qax = q1.x, qay = q1.y, qaz = q1.z, qaw = q1.w; 1430 float qbx = q2.x, qby = q2.y, qbz = q2.z, qbw = q2.w; 1431 1432 result.x = qax*qbw + qaw*qbx + qay*qbz - qaz*qby; 1433 result.y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz; 1434 result.z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx; 1435 result.w = qaw*qbw - qax*qbx - qay*qby - qaz*qbz; 1436 1437 return result; 1438 } 1439 1440 // Scale quaternion by float value 1441 static Quaternion QuaternionScale(Quaternion q, float mul) 1442 { 1443 Quaternion result = { 0 }; 1444 1445 float qax = q.x, qay = q.y, qaz = q.z, qaw = q.w; 1446 1447 result.x = qax*mul + qaw*mul + qay*mul - qaz*mul; 1448 result.y = qay*mul + qaw*mul + qaz*mul - qax*mul; 1449 result.z = qaz*mul + qaw*mul + qax*mul - qay*mul; 1450 result.w = qaw*mul - qax*mul - qay*mul - qaz*mul; 1451 1452 return result; 1453 } 1454 1455 // Divide two quaternions 1456 static Quaternion QuaternionDivide(Quaternion q1, Quaternion q2) 1457 { 1458 Quaternion result = { q1.x/q2.x, q1.y/q2.y, q1.z/q2.z, q1.w/q2.w }; 1459 1460 return result; 1461 } 1462 1463 // Calculate linear interpolation between two quaternions 1464 static Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) 1465 { 1466 Quaternion result = { 0 }; 1467 1468 result.x = q1.x + amount*(q2.x - q1.x); 1469 result.y = q1.y + amount*(q2.y - q1.y); 1470 result.z = q1.z + amount*(q2.z - q1.z); 1471 result.w = q1.w + amount*(q2.w - q1.w); 1472 1473 return result; 1474 } 1475 1476 // Calculate slerp-optimized interpolation between two quaternions 1477 static Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount) 1478 { 1479 Quaternion result = { 0 }; 1480 1481 // QuaternionLerp(q1, q2, amount) 1482 result.x = q1.x + amount*(q2.x - q1.x); 1483 result.y = q1.y + amount*(q2.y - q1.y); 1484 result.z = q1.z + amount*(q2.z - q1.z); 1485 result.w = q1.w + amount*(q2.w - q1.w); 1486 1487 // QuaternionNormalize(q); 1488 Quaternion q = result; 1489 float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 1490 if (length == 0.0f) length = 1.0f; 1491 float ilength = 1.0f/length; 1492 1493 result.x = q.x*ilength; 1494 result.y = q.y*ilength; 1495 result.z = q.z*ilength; 1496 result.w = q.w*ilength; 1497 1498 return result; 1499 } 1500 1501 // Calculates spherical linear interpolation between two quaternions 1502 static Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) 1503 { 1504 Quaternion result = { 0 }; 1505 1506 float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w; 1507 1508 if (cosHalfTheta < 0) 1509 { 1510 q2.x = -q2.x; q2.y = -q2.y; q2.z = -q2.z; q2.w = -q2.w; 1511 cosHalfTheta = -cosHalfTheta; 1512 } 1513 1514 if (fabs(cosHalfTheta) >= 1.0f) result = q1; 1515 else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount); 1516 else 1517 { 1518 float halfTheta = acosf(cosHalfTheta); 1519 float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta); 1520 1521 if (fabs(sinHalfTheta) < 0.001f) 1522 { 1523 result.x = (q1.x*0.5f + q2.x*0.5f); 1524 result.y = (q1.y*0.5f + q2.y*0.5f); 1525 result.z = (q1.z*0.5f + q2.z*0.5f); 1526 result.w = (q1.w*0.5f + q2.w*0.5f); 1527 } 1528 else 1529 { 1530 float ratioA = sinf((1 - amount)*halfTheta)/sinHalfTheta; 1531 float ratioB = sinf(amount*halfTheta)/sinHalfTheta; 1532 1533 result.x = (q1.x*ratioA + q2.x*ratioB); 1534 result.y = (q1.y*ratioA + q2.y*ratioB); 1535 result.z = (q1.z*ratioA + q2.z*ratioB); 1536 result.w = (q1.w*ratioA + q2.w*ratioB); 1537 } 1538 } 1539 1540 return result; 1541 } 1542 1543 // Calculate quaternion based on the rotation from one vector to another 1544 static Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to) 1545 { 1546 Quaternion result = { 0 }; 1547 1548 float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to) 1549 Vector3 cross = { from.y*to.z - from.z*to.y, from.z*to.x - from.x*to.z, from.x*to.y - from.y*to.x }; // Vector3CrossProduct(from, to) 1550 1551 result.x = cross.x; 1552 result.y = cross.y; 1553 result.z = cross.z; 1554 result.w = 1.0f + cos2Theta; 1555 1556 // QuaternionNormalize(q); 1557 // NOTE: Normalize to essentially nlerp the original and identity to 0.5 1558 Quaternion q = result; 1559 float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 1560 if (length == 0.0f) length = 1.0f; 1561 float ilength = 1.0f/length; 1562 1563 result.x = q.x*ilength; 1564 result.y = q.y*ilength; 1565 result.z = q.z*ilength; 1566 result.w = q.w*ilength; 1567 1568 return result; 1569 } 1570 1571 // Get a quaternion for a given rotation matrix 1572 static Quaternion QuaternionFromMatrix(Matrix mat) 1573 { 1574 Quaternion result = { 0 }; 1575 1576 if ((mat.m0 > mat.m5) && (mat.m0 > mat.m10)) 1577 { 1578 float s = sqrtf(1.0f + mat.m0 - mat.m5 - mat.m10)*2; 1579 1580 result.x = 0.25f*s; 1581 result.y = (mat.m4 + mat.m1)/s; 1582 result.z = (mat.m2 + mat.m8)/s; 1583 result.w = (mat.m9 - mat.m6)/s; 1584 } 1585 else if (mat.m5 > mat.m10) 1586 { 1587 float s = sqrtf(1.0f + mat.m5 - mat.m0 - mat.m10)*2; 1588 result.x = (mat.m4 + mat.m1)/s; 1589 result.y = 0.25f*s; 1590 result.z = (mat.m9 + mat.m6)/s; 1591 result.w = (mat.m2 - mat.m8)/s; 1592 } 1593 else 1594 { 1595 float s = sqrtf(1.0f + mat.m10 - mat.m0 - mat.m5)*2; 1596 result.x = (mat.m2 + mat.m8)/s; 1597 result.y = (mat.m9 + mat.m6)/s; 1598 result.z = 0.25f*s; 1599 result.w = (mat.m4 - mat.m1)/s; 1600 } 1601 1602 return result; 1603 } 1604 1605 // Get a matrix for a given quaternion 1606 static Matrix QuaternionToMatrix(Quaternion q) 1607 { 1608 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 1609 0.0f, 1.0f, 0.0f, 0.0f, 1610 0.0f, 0.0f, 1.0f, 0.0f, 1611 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() 1612 1613 float a2 = q.x*q.x; 1614 float b2 = q.y*q.y; 1615 float c2 = q.z*q.z; 1616 float ac = q.x*q.z; 1617 float ab = q.x*q.y; 1618 float bc = q.y*q.z; 1619 float ad = q.w*q.x; 1620 float bd = q.w*q.y; 1621 float cd = q.w*q.z; 1622 1623 result.m0 = 1 - 2*(b2 + c2); 1624 result.m1 = 2*(ab + cd); 1625 result.m2 = 2*(ac - bd); 1626 1627 result.m4 = 2*(ab - cd); 1628 result.m5 = 1 - 2*(a2 + c2); 1629 result.m6 = 2*(bc + ad); 1630 1631 result.m8 = 2*(ac + bd); 1632 result.m9 = 2*(bc - ad); 1633 result.m10 = 1 - 2*(a2 + b2); 1634 1635 return result; 1636 } 1637 1638 // Get rotation quaternion for an angle and axis 1639 // NOTE: angle must be provided in radians 1640 static Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle) 1641 { 1642 Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; 1643 1644 float axisLength = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); 1645 1646 if (axisLength != 0.0f) 1647 { 1648 angle *= 0.5f; 1649 1650 float length = 0.0f; 1651 float ilength = 0.0f; 1652 1653 // Vector3Normalize(axis) 1654 Vector3 v = axis; 1655 length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 1656 if (length == 0.0f) length = 1.0f; 1657 ilength = 1.0f/length; 1658 axis.x *= ilength; 1659 axis.y *= ilength; 1660 axis.z *= ilength; 1661 1662 float sinres = sinf(angle); 1663 float cosres = cosf(angle); 1664 1665 result.x = axis.x*sinres; 1666 result.y = axis.y*sinres; 1667 result.z = axis.z*sinres; 1668 result.w = cosres; 1669 1670 // QuaternionNormalize(q); 1671 Quaternion q = result; 1672 length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 1673 if (length == 0.0f) length = 1.0f; 1674 ilength = 1.0f/length; 1675 result.x = q.x*ilength; 1676 result.y = q.y*ilength; 1677 result.z = q.z*ilength; 1678 result.w = q.w*ilength; 1679 } 1680 1681 return result; 1682 } 1683 1684 // Get the rotation angle and axis for a given quaternion 1685 static void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle) 1686 { 1687 if (fabs(q.w) > 1.0f) 1688 { 1689 // QuaternionNormalize(q); 1690 float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 1691 if (length == 0.0f) length = 1.0f; 1692 float ilength = 1.0f/length; 1693 1694 q.x = q.x*ilength; 1695 q.y = q.y*ilength; 1696 q.z = q.z*ilength; 1697 q.w = q.w*ilength; 1698 } 1699 1700 Vector3 resAxis = { 0.0f, 0.0f, 0.0f }; 1701 float resAngle = 2.0f*acosf(q.w); 1702 float den = sqrtf(1.0f - q.w*q.w); 1703 1704 if (den > 0.0001f) 1705 { 1706 resAxis.x = q.x/den; 1707 resAxis.y = q.y/den; 1708 resAxis.z = q.z/den; 1709 } 1710 else 1711 { 1712 // This occurs when the angle is zero. 1713 // Not a problem: just set an arbitrary normalized axis. 1714 resAxis.x = 1.0f; 1715 } 1716 1717 *outAxis = resAxis; 1718 *outAngle = resAngle; 1719 } 1720 1721 // Get the quaternion equivalent to Euler angles 1722 // NOTE: Rotation order is ZYX 1723 static Quaternion QuaternionFromEuler(float pitch, float yaw, float roll) 1724 { 1725 Quaternion result = { 0 }; 1726 1727 float x0 = cosf(pitch*0.5f); 1728 float x1 = sinf(pitch*0.5f); 1729 float y0 = cosf(yaw*0.5f); 1730 float y1 = sinf(yaw*0.5f); 1731 float z0 = cosf(roll*0.5f); 1732 float z1 = sinf(roll*0.5f); 1733 1734 result.x = x1*y0*z0 - x0*y1*z1; 1735 result.y = x0*y1*z0 + x1*y0*z1; 1736 result.z = x0*y0*z1 - x1*y1*z0; 1737 result.w = x0*y0*z0 + x1*y1*z1; 1738 1739 return result; 1740 } 1741 1742 // Get the Euler angles equivalent to quaternion (roll, pitch, yaw) 1743 // NOTE: Angles are returned in a Vector3 struct in radians 1744 static Vector3 QuaternionToEuler(Quaternion q) 1745 { 1746 Vector3 result = { 0 }; 1747 1748 // Roll (x-axis rotation) 1749 float x0 = 2.0f*(q.w*q.x + q.y*q.z); 1750 float x1 = 1.0f - 2.0f*(q.x*q.x + q.y*q.y); 1751 result.x = atan2f(x0, x1); 1752 1753 // Pitch (y-axis rotation) 1754 float y0 = 2.0f*(q.w*q.y - q.z*q.x); 1755 y0 = y0 > 1.0f ? 1.0f : y0; 1756 y0 = y0 < -1.0f ? -1.0f : y0; 1757 result.y = asinf(y0); 1758 1759 // Yaw (z-axis rotation) 1760 float z0 = 2.0f*(q.w*q.z + q.x*q.y); 1761 float z1 = 1.0f - 2.0f*(q.y*q.y + q.z*q.z); 1762 result.z = atan2f(z0, z1); 1763 1764 return result; 1765 } 1766 1767 // Transform a quaternion given a transformation matrix 1768 static Quaternion QuaternionTransform(Quaternion q, Matrix mat) 1769 { 1770 Quaternion result = { 0 }; 1771 1772 result.x = mat.m0*q.x + mat.m4*q.y + mat.m8*q.z + mat.m12*q.w; 1773 result.y = mat.m1*q.x + mat.m5*q.y + mat.m9*q.z + mat.m13*q.w; 1774 result.z = mat.m2*q.x + mat.m6*q.y + mat.m10*q.z + mat.m14*q.w; 1775 result.w = mat.m3*q.x + mat.m7*q.y + mat.m11*q.z + mat.m15*q.w; 1776 1777 return result; 1778 }