0/**********************************************************************************************
1*
2* raymath v2.0 - Math functions to work with Vector2, Vector3, Matrix and Quaternions
3*
4* CONVENTIONS:
5* - Matrix structure is defined as row-major (memory layout) but parameters naming AND all
6* math operations performed by the library consider the structure as it was column-major
7* It is like transposed versions of the matrices are used for all the maths
8* It benefits some functions making them cache-friendly and also avoids matrix
9* transpositions sometimes required by OpenGL
10* Example: In memory order, row0 is [m0 m4 m8 m12] but in semantic math row0 is [m0 m1 m2 m3]
11* - Functions are always self-contained, no function use another raymath function inside,
12* required code is directly re-implemented inside
13* - Functions input parameters are always received by value (2 unavoidable exceptions)
14* - Functions use always a "result" variable for return (except C++ operators)
15* - Functions are always defined inline
16* - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience)
17* - No compound literals used to make sure libray is compatible with C++
18*
19* CONFIGURATION:
20* #define RAYMATH_IMPLEMENTATION
21* Generates the implementation of the library into the included file.
22* If not defined, the library is in header only mode and can be included in other headers
23* or source files without problems. But only ONE file should hold the implementation.
24*
25* #define RAYMATH_STATIC_INLINE
26* Define static inline functions code, so #include header suffices for use.
27* This may use up lots of memory.
28*
29* #define RAYMATH_DISABLE_CPP_OPERATORS
30* Disables C++ operator overloads for raymath types.
31*
32* LICENSE: zlib/libpng
33*
34* Copyright (c) 2015-2025 Ramon Santamaria (@raysan5)
35*
36* This software is provided "as-is", without any express or implied warranty. In no event
37* will the authors be held liable for any damages arising from the use of this software.
38*
39* Permission is granted to anyone to use this software for any purpose, including commercial
40* applications, and to alter it and redistribute it freely, subject to the following restrictions:
41*
42* 1. The origin of this software must not be misrepresented; you must not claim that you
43* wrote the original software. If you use this software in a product, an acknowledgment
44* in the product documentation would be appreciated but is not required.
45*
46* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
47* as being the original software.
48*
49* 3. This notice may not be removed or altered from any source distribution.
50*
51**********************************************************************************************/
53#ifndef RAYMATH_H
54#define RAYMATH_H
56#if defined(RAYMATH_IMPLEMENTATION) && defined(RAYMATH_STATIC_INLINE)
57 #error "Specifying both RAYMATH_IMPLEMENTATION and RAYMATH_STATIC_INLINE is contradictory"
58#endif
60// Function specifiers definition
61#if defined(RAYMATH_IMPLEMENTATION)
62 #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
63 #define RMAPI __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll)
64 #elif defined(BUILD_LIBTYPE_SHARED)
65 #define RMAPI __attribute__((visibility("default"))) // We are building raylib as a Unix shared library (.so/.dylib)
66 #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
67 #define RMAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
68 #else
69 #define RMAPI extern inline // Provide external definition
70 #endif
71#elif defined(RAYMATH_STATIC_INLINE)
72 #define RMAPI static inline // Functions may be inlined, no external out-of-line definition
73#else
74 #if defined(__TINYC__)
75 #define RMAPI static inline // plain inline not supported by tinycc (See issue #435)
76 #else
77 #define RMAPI inline // Functions may be inlined or external definition used
78 #endif
79#endif
82//----------------------------------------------------------------------------------
83// Defines and Macros
84//----------------------------------------------------------------------------------
85#ifndef PI
86 #define PI 3.14159265358979323846f
87#endif
89#ifndef EPSILON
90 #define EPSILON 0.000001f
91#endif
93#ifndef DEG2RAD
94 #define DEG2RAD (PI/180.0f)
95#endif
97#ifndef RAD2DEG
98 #define RAD2DEG (180.0f/PI)
99#endif
101// Get float vector for Matrix
102#ifndef MatrixToFloat
103 #define MatrixToFloat(mat) (MatrixToFloatV(mat).v)
104#endif
106// Get float vector for Vector3
107#ifndef Vector3ToFloat
108 #define Vector3ToFloat(vec) (Vector3ToFloatV(vec).v)
109#endif
111//----------------------------------------------------------------------------------
112// Types and Structures Definition
113//----------------------------------------------------------------------------------
114#if !defined(RL_VECTOR2_TYPE)
115// Vector2 type
116typedef struct Vector2 {
117 float x;
118 float y;
119} Vector2;
120#define RL_VECTOR2_TYPE
121#endif
123#if !defined(RL_VECTOR3_TYPE)
124// Vector3 type
125typedef struct Vector3 {
126 float x;
127 float y;
128 float z;
129} Vector3;
130#define RL_VECTOR3_TYPE
131#endif
133#if !defined(RL_VECTOR4_TYPE)
134// Vector4 type
135typedef struct Vector4 {
136 float x;
137 float y;
138 float z;
139 float w;
140} Vector4;
141#define RL_VECTOR4_TYPE
142#endif
144#if !defined(RL_QUATERNION_TYPE)
145// Quaternion type
146typedef Vector4 Quaternion;
147#define RL_QUATERNION_TYPE
148#endif
150#if !defined(RL_MATRIX_TYPE)
151// Matrix type (OpenGL style 4x4 - right handed, column major)
152typedef struct Matrix {
153 float m0, m4, m8, m12; // Matrix first row (4 components)
154 float m1, m5, m9, m13; // Matrix second row (4 components)
155 float m2, m6, m10, m14; // Matrix third row (4 components)
156 float m3, m7, m11, m15; // Matrix fourth row (4 components)
157} Matrix;
158#define RL_MATRIX_TYPE
159#endif
161// NOTE: Helper types to be used instead of array return types for *ToFloat functions
162typedef struct float3 {
163 float v[3];
164} float3;
166typedef struct float16 {
167 float v[16];
168} float16;
170#include <math.h> // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabsf()
172//----------------------------------------------------------------------------------
173// Module Functions Definition - Utils math
174//----------------------------------------------------------------------------------
176// Clamp float value
177RMAPI float Clamp(float value, float min, float max)
178{
179 float result = (value < min)? min : value;
181 if (result > max) result = max;
183 return result;
184}
186// Calculate linear interpolation between two floats
187RMAPI float Lerp(float start, float end, float amount)
188{
189 float result = start + amount*(end - start);
191 return result;
192}
194// Normalize input value within input range
195RMAPI float Normalize(float value, float start, float end)
196{
197 float result = (value - start)/(end - start);
199 return result;
200}
202// Remap input value within input range to output range
203RMAPI float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd)
204{
205 float result = (value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart;
207 return result;
208}
210// Wrap input value from min to max
211RMAPI float Wrap(float value, float min, float max)
212{
213 float result = value - (max - min)*floorf((value - min)/(max - min));
215 return result;
216}
218// Check whether two given floats are almost equal
219RMAPI int FloatEquals(float x, float y)
220{
221#if !defined(EPSILON)
222 #define EPSILON 0.000001f
223#endif
225 int result = (fabsf(x - y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(x), fabsf(y))));
227 return result;
228}
230//----------------------------------------------------------------------------------
231// Module Functions Definition - Vector2 math
232//----------------------------------------------------------------------------------
234// Vector with components value 0.0f
235RMAPI Vector2 Vector2Zero(void)
236{
237 Vector2 result = { 0.0f, 0.0f };
239 return result;
240}
242// Vector with components value 1.0f
243RMAPI Vector2 Vector2One(void)
244{
245 Vector2 result = { 1.0f, 1.0f };
247 return result;
248}
250// Add two vectors (v1 + v2)
251RMAPI Vector2 Vector2Add(Vector2 v1, Vector2 v2)
252{
253 Vector2 result = { v1.x + v2.x, v1.y + v2.y };
255 return result;
256}
258// Add vector and float value
259RMAPI Vector2 Vector2AddValue(Vector2 v, float add)
260{
261 Vector2 result = { v.x + add, v.y + add };
263 return result;
264}
266// Subtract two vectors (v1 - v2)
267RMAPI Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
268{
269 Vector2 result = { v1.x - v2.x, v1.y - v2.y };
271 return result;
272}
274// Subtract vector by float value
275RMAPI Vector2 Vector2SubtractValue(Vector2 v, float sub)
276{
277 Vector2 result = { v.x - sub, v.y - sub };
279 return result;
280}
282// Calculate vector length
283RMAPI float Vector2Length(Vector2 v)
284{
285 float result = sqrtf((v.x*v.x) + (v.y*v.y));
287 return result;
288}
290// Calculate vector square length
291RMAPI float Vector2LengthSqr(Vector2 v)
292{
293 float result = (v.x*v.x) + (v.y*v.y);
295 return result;
296}
298// Calculate two vectors dot product
299RMAPI float Vector2DotProduct(Vector2 v1, Vector2 v2)
300{
301 float result = (v1.x*v2.x + v1.y*v2.y);
303 return result;
304}
306// Calculate two vectors cross product
307RMAPI float Vector2CrossProduct(Vector2 v1, Vector2 v2)
308{
309 float result = (v1.x*v2.y - v1.y*v2.x);
311 return result;
312}
314// Calculate distance between two vectors
315RMAPI float Vector2Distance(Vector2 v1, Vector2 v2)
316{
317 float result = sqrtf((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y));
319 return result;
320}
322// Calculate square distance between two vectors
323RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2)
324{
325 float result = ((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y));
327 return result;
328}
330// Calculate the signed angle from v1 to v2, relative to the origin (0, 0)
331// NOTE: Coordinate system convention: positive X right, positive Y down
332// positive angles appear clockwise, and negative angles appear counterclockwise
333RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)
334{
335 float result = 0.0f;
337 float dot = v1.x*v2.x + v1.y*v2.y;
338 float det = v1.x*v2.y - v1.y*v2.x;
340 result = atan2f(det, dot);
342 return result;
343}
345// Calculate angle defined by a two vectors line
346// NOTE: Parameters need to be normalized
347// Current implementation should be aligned with glm::angle
348RMAPI float Vector2LineAngle(Vector2 start, Vector2 end)
349{
350 float result = 0.0f;
352 // TODO(10/9/2023): Currently angles move clockwise, determine if this is wanted behavior
353 result = -atan2f(end.y - start.y, end.x - start.x);
355 return result;
356}
358// Scale vector (multiply by value)
359RMAPI Vector2 Vector2Scale(Vector2 v, float scale)
360{
361 Vector2 result = { v.x*scale, v.y*scale };
363 return result;
364}
366// Multiply vector by vector
367RMAPI Vector2 Vector2Multiply(Vector2 v1, Vector2 v2)
368{
369 Vector2 result = { v1.x*v2.x, v1.y*v2.y };
371 return result;
372}
374// Negate vector
375RMAPI Vector2 Vector2Negate(Vector2 v)
376{
377 Vector2 result = { -v.x, -v.y };
379 return result;
380}
382// Divide vector by vector
383RMAPI Vector2 Vector2Divide(Vector2 v1, Vector2 v2)
384{
385 Vector2 result = { v1.x/v2.x, v1.y/v2.y };
387 return result;
388}
390// Normalize provided vector
391RMAPI Vector2 Vector2Normalize(Vector2 v)
392{
393 Vector2 result = { 0 };
394 float length = sqrtf((v.x*v.x) + (v.y*v.y));
396 if (length > 0)
397 {
398 float ilength = 1.0f/length;
399 result.x = v.x*ilength;
400 result.y = v.y*ilength;
401 }
403 return result;
404}
406// Transforms a Vector2 by a given Matrix
407RMAPI Vector2 Vector2Transform(Vector2 v, Matrix mat)
408{
409 Vector2 result = { 0 };
411 float x = v.x;
412 float y = v.y;
413 float z = 0;
415 result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12;
416 result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13;
418 return result;
419}
421// Calculate linear interpolation between two vectors
422RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount)
423{
424 Vector2 result = { 0 };
426 result.x = v1.x + amount*(v2.x - v1.x);
427 result.y = v1.y + amount*(v2.y - v1.y);
429 return result;
430}
432// Calculate reflected vector to normal
433RMAPI Vector2 Vector2Reflect(Vector2 v, Vector2 normal)
434{
435 Vector2 result = { 0 };
437 float dotProduct = (v.x*normal.x + v.y*normal.y); // Dot product
439 result.x = v.x - (2.0f*normal.x)*dotProduct;
440 result.y = v.y - (2.0f*normal.y)*dotProduct;
442 return result;
443}
445// Get min value for each pair of components
446RMAPI Vector2 Vector2Min(Vector2 v1, Vector2 v2)
447{
448 Vector2 result = { 0 };
450 result.x = fminf(v1.x, v2.x);
451 result.y = fminf(v1.y, v2.y);
453 return result;
454}
456// Get max value for each pair of components
457RMAPI Vector2 Vector2Max(Vector2 v1, Vector2 v2)
458{
459 Vector2 result = { 0 };
461 result.x = fmaxf(v1.x, v2.x);
462 result.y = fmaxf(v1.y, v2.y);
464 return result;
465}
467// Rotate vector by angle
468RMAPI Vector2 Vector2Rotate(Vector2 v, float angle)
469{
470 Vector2 result = { 0 };
472 float cosres = cosf(angle);
473 float sinres = sinf(angle);
475 result.x = v.x*cosres - v.y*sinres;
476 result.y = v.x*sinres + v.y*cosres;
478 return result;
479}
481// Move Vector towards target
482RMAPI Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance)
483{
484 Vector2 result = { 0 };
486 float dx = target.x - v.x;
487 float dy = target.y - v.y;
488 float value = (dx*dx) + (dy*dy);
490 if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target;
492 float dist = sqrtf(value);
494 result.x = v.x + dx/dist*maxDistance;
495 result.y = v.y + dy/dist*maxDistance;
497 return result;
498}
500// Invert the given vector
501RMAPI Vector2 Vector2Invert(Vector2 v)
502{
503 Vector2 result = { 1.0f/v.x, 1.0f/v.y };
505 return result;
506}
508// Clamp the components of the vector between
509// min and max values specified by the given vectors
510RMAPI Vector2 Vector2Clamp(Vector2 v, Vector2 min, Vector2 max)
511{
512 Vector2 result = { 0 };
514 result.x = fminf(max.x, fmaxf(min.x, v.x));
515 result.y = fminf(max.y, fmaxf(min.y, v.y));
517 return result;
518}
520// Clamp the magnitude of the vector between two min and max values
521RMAPI Vector2 Vector2ClampValue(Vector2 v, float min, float max)
522{
523 Vector2 result = v;
525 float length = (v.x*v.x) + (v.y*v.y);
526 if (length > 0.0f)
527 {
528 length = sqrtf(length);
530 float scale = 1; // By default, 1 as the neutral element.
531 if (length < min)
532 {
533 scale = min/length;
534 }
535 else if (length > max)
536 {
537 scale = max/length;
538 }
540 result.x = v.x*scale;
541 result.y = v.y*scale;
542 }
544 return result;
545}
547// Check whether two given vectors are almost equal
548RMAPI int Vector2Equals(Vector2 p, Vector2 q)
549{
550#if !defined(EPSILON)
551 #define EPSILON 0.000001f
552#endif
554 int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) &&
555 ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y)))));
557 return result;
558}
560// Compute the direction of a refracted ray
561// v: normalized direction of the incoming ray
562// n: normalized normal vector of the interface of two optical media
563// r: ratio of the refractive index of the medium from where the ray comes
564// to the refractive index of the medium on the other side of the surface
565RMAPI Vector2 Vector2Refract(Vector2 v, Vector2 n, float r)
566{
567 Vector2 result = { 0 };
569 float dot = v.x*n.x + v.y*n.y;
570 float d = 1.0f - r*r*(1.0f - dot*dot);
572 if (d >= 0.0f)
573 {
574 d = sqrtf(d);
575 v.x = r*v.x - (r*dot + d)*n.x;
576 v.y = r*v.y - (r*dot + d)*n.y;
578 result = v;
579 }
581 return result;
582}
585//----------------------------------------------------------------------------------
586// Module Functions Definition - Vector3 math
587//----------------------------------------------------------------------------------
589// Vector with components value 0.0f
590RMAPI Vector3 Vector3Zero(void)
591{
592 Vector3 result = { 0.0f, 0.0f, 0.0f };
594 return result;
595}
597// Vector with components value 1.0f
598RMAPI Vector3 Vector3One(void)
599{
600 Vector3 result = { 1.0f, 1.0f, 1.0f };
602 return result;
603}
605// Add two vectors
606RMAPI Vector3 Vector3Add(Vector3 v1, Vector3 v2)
607{
608 Vector3 result = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
610 return result;
611}
613// Add vector and float value
614RMAPI Vector3 Vector3AddValue(Vector3 v, float add)
615{
616 Vector3 result = { v.x + add, v.y + add, v.z + add };
618 return result;
619}
621// Subtract two vectors
622RMAPI Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
623{
624 Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
626 return result;
627}
629// Subtract vector by float value
630RMAPI Vector3 Vector3SubtractValue(Vector3 v, float sub)
631{
632 Vector3 result = { v.x - sub, v.y - sub, v.z - sub };
634 return result;
635}
637// Multiply vector by scalar
638RMAPI Vector3 Vector3Scale(Vector3 v, float scalar)
639{
640 Vector3 result = { v.x*scalar, v.y*scalar, v.z*scalar };
642 return result;
643}
645// Multiply vector by vector
646RMAPI Vector3 Vector3Multiply(Vector3 v1, Vector3 v2)
647{
648 Vector3 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z };
650 return result;
651}
653// Calculate two vectors cross product
654RMAPI Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2)
655{
656 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 };
658 return result;
659}
661// Calculate one vector perpendicular vector
662RMAPI Vector3 Vector3Perpendicular(Vector3 v)
663{
664 Vector3 result = { 0 };
666 float min = fabsf(v.x);
667 Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f};
669 if (fabsf(v.y) < min)
670 {
671 min = fabsf(v.y);
672 Vector3 tmp = {0.0f, 1.0f, 0.0f};
673 cardinalAxis = tmp;
674 }
676 if (fabsf(v.z) < min)
677 {
678 Vector3 tmp = {0.0f, 0.0f, 1.0f};
679 cardinalAxis = tmp;
680 }
682 // Cross product between vectors
683 result.x = v.y*cardinalAxis.z - v.z*cardinalAxis.y;
684 result.y = v.z*cardinalAxis.x - v.x*cardinalAxis.z;
685 result.z = v.x*cardinalAxis.y - v.y*cardinalAxis.x;
687 return result;
688}
690// Calculate vector length
691RMAPI float Vector3Length(const Vector3 v)
692{
693 float result = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
695 return result;
696}
698// Calculate vector square length
699RMAPI float Vector3LengthSqr(const Vector3 v)
700{
701 float result = v.x*v.x + v.y*v.y + v.z*v.z;
703 return result;
704}
706// Calculate two vectors dot product
707RMAPI float Vector3DotProduct(Vector3 v1, Vector3 v2)
708{
709 float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
711 return result;
712}
714// Calculate distance between two vectors
715RMAPI float Vector3Distance(Vector3 v1, Vector3 v2)
716{
717 float result = 0.0f;
719 float dx = v2.x - v1.x;
720 float dy = v2.y - v1.y;
721 float dz = v2.z - v1.z;
722 result = sqrtf(dx*dx + dy*dy + dz*dz);
724 return result;
725}
727// Calculate square distance between two vectors
728RMAPI float Vector3DistanceSqr(Vector3 v1, Vector3 v2)
729{
730 float result = 0.0f;
732 float dx = v2.x - v1.x;
733 float dy = v2.y - v1.y;
734 float dz = v2.z - v1.z;
735 result = dx*dx + dy*dy + dz*dz;
737 return result;
738}
740// Calculate angle between two vectors
741RMAPI float Vector3Angle(Vector3 v1, Vector3 v2)
742{
743 float result = 0.0f;
745 Vector3 cross = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x };
746 float len = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z);
747 float dot = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
748 result = atan2f(len, dot);
750 return result;
751}
753// Negate provided vector (invert direction)
754RMAPI Vector3 Vector3Negate(Vector3 v)
755{
756 Vector3 result = { -v.x, -v.y, -v.z };
758 return result;
759}
761// Divide vector by vector
762RMAPI Vector3 Vector3Divide(Vector3 v1, Vector3 v2)
763{
764 Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z };
766 return result;
767}
769// Normalize provided vector
770RMAPI Vector3 Vector3Normalize(Vector3 v)
771{
772 Vector3 result = v;
774 float length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
775 if (length != 0.0f)
776 {
777 float ilength = 1.0f/length;
779 result.x *= ilength;
780 result.y *= ilength;
781 result.z *= ilength;
782 }
784 return result;
785}
787//Calculate the projection of the vector v1 on to v2
788RMAPI Vector3 Vector3Project(Vector3 v1, Vector3 v2)
789{
790 Vector3 result = { 0 };
792 float v1dv2 = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
793 float v2dv2 = (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z);
795 float mag = v1dv2/v2dv2;
797 result.x = v2.x*mag;
798 result.y = v2.y*mag;
799 result.z = v2.z*mag;
801 return result;
802}
804//Calculate the rejection of the vector v1 on to v2
805RMAPI Vector3 Vector3Reject(Vector3 v1, Vector3 v2)
806{
807 Vector3 result = { 0 };
809 float v1dv2 = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
810 float v2dv2 = (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z);
812 float mag = v1dv2/v2dv2;
814 result.x = v1.x - (v2.x*mag);
815 result.y = v1.y - (v2.y*mag);
816 result.z = v1.z - (v2.z*mag);
818 return result;
819}
821// Orthonormalize provided vectors
822// Makes vectors normalized and orthogonal to each other
823// Gram-Schmidt function implementation
824RMAPI void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2)
825{
826 float length = 0.0f;
827 float ilength = 0.0f;
829 // Vector3Normalize(*v1);
830 Vector3 v = *v1;
831 length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
832 if (length == 0.0f) length = 1.0f;
833 ilength = 1.0f/length;
834 v1->x *= ilength;
835 v1->y *= ilength;
836 v1->z *= ilength;
838 // Vector3CrossProduct(*v1, *v2)
839 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 };
841 // Vector3Normalize(vn1);
842 v = vn1;
843 length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
844 if (length == 0.0f) length = 1.0f;
845 ilength = 1.0f/length;
846 vn1.x *= ilength;
847 vn1.y *= ilength;
848 vn1.z *= ilength;
850 // Vector3CrossProduct(vn1, *v1)
851 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 };
853 *v2 = vn2;
854}
856// Transforms a Vector3 by a given Matrix
857RMAPI Vector3 Vector3Transform(Vector3 v, Matrix mat)
858{
859 Vector3 result = { 0 };
861 float x = v.x;
862 float y = v.y;
863 float z = v.z;
865 result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12;
866 result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13;
867 result.z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14;
869 return result;
870}
872// Transform a vector by quaternion rotation
873RMAPI Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q)
874{
875 Vector3 result = { 0 };
877 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);
878 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);
879 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);
881 return result;
882}
884// Rotates a vector around an axis
885RMAPI Vector3 Vector3RotateByAxisAngle(Vector3 v, Vector3 axis, float angle)
886{
887 // Using Euler-Rodrigues Formula
888 // Ref.: https://en.wikipedia.org/w/index.php?title=Euler%E2%80%93Rodrigues_formula
890 Vector3 result = v;
892 // Vector3Normalize(axis);
893 float length = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);
894 if (length == 0.0f) length = 1.0f;
895 float ilength = 1.0f/length;
896 axis.x *= ilength;
897 axis.y *= ilength;
898 axis.z *= ilength;
900 angle /= 2.0f;
901 float a = sinf(angle);
902 float b = axis.x*a;
903 float c = axis.y*a;
904 float d = axis.z*a;
905 a = cosf(angle);
906 Vector3 w = { b, c, d };
908 // Vector3CrossProduct(w, v)
909 Vector3 wv = { w.y*v.z - w.z*v.y, w.z*v.x - w.x*v.z, w.x*v.y - w.y*v.x };
911 // Vector3CrossProduct(w, wv)
912 Vector3 wwv = { w.y*wv.z - w.z*wv.y, w.z*wv.x - w.x*wv.z, w.x*wv.y - w.y*wv.x };
914 // Vector3Scale(wv, 2*a)
915 a *= 2;
916 wv.x *= a;
917 wv.y *= a;
918 wv.z *= a;
920 // Vector3Scale(wwv, 2)
921 wwv.x *= 2;
922 wwv.y *= 2;
923 wwv.z *= 2;
925 result.x += wv.x;
926 result.y += wv.y;
927 result.z += wv.z;
929 result.x += wwv.x;
930 result.y += wwv.y;
931 result.z += wwv.z;
933 return result;
934}
936// Move Vector towards target
937RMAPI Vector3 Vector3MoveTowards(Vector3 v, Vector3 target, float maxDistance)
938{
939 Vector3 result = { 0 };
941 float dx = target.x - v.x;
942 float dy = target.y - v.y;
943 float dz = target.z - v.z;
944 float value = (dx*dx) + (dy*dy) + (dz*dz);
946 if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target;
948 float dist = sqrtf(value);
950 result.x = v.x + dx/dist*maxDistance;
951 result.y = v.y + dy/dist*maxDistance;
952 result.z = v.z + dz/dist*maxDistance;
954 return result;
955}
957// Calculate linear interpolation between two vectors
958RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount)
959{
960 Vector3 result = { 0 };
962 result.x = v1.x + amount*(v2.x - v1.x);
963 result.y = v1.y + amount*(v2.y - v1.y);
964 result.z = v1.z + amount*(v2.z - v1.z);
966 return result;
967}
969// Calculate cubic hermite interpolation between two vectors and their tangents
970// as described in the GLTF 2.0 specification: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#interpolation-cubic
971RMAPI Vector3 Vector3CubicHermite(Vector3 v1, Vector3 tangent1, Vector3 v2, Vector3 tangent2, float amount)
972{
973 Vector3 result = { 0 };
975 float amountPow2 = amount*amount;
976 float amountPow3 = amount*amount*amount;
978 result.x = (2*amountPow3 - 3*amountPow2 + 1)*v1.x + (amountPow3 - 2*amountPow2 + amount)*tangent1.x + (-2*amountPow3 + 3*amountPow2)*v2.x + (amountPow3 - amountPow2)*tangent2.x;
979 result.y = (2*amountPow3 - 3*amountPow2 + 1)*v1.y + (amountPow3 - 2*amountPow2 + amount)*tangent1.y + (-2*amountPow3 + 3*amountPow2)*v2.y + (amountPow3 - amountPow2)*tangent2.y;
980 result.z = (2*amountPow3 - 3*amountPow2 + 1)*v1.z + (amountPow3 - 2*amountPow2 + amount)*tangent1.z + (-2*amountPow3 + 3*amountPow2)*v2.z + (amountPow3 - amountPow2)*tangent2.z;
982 return result;
983}
985// Calculate reflected vector to normal
986RMAPI Vector3 Vector3Reflect(Vector3 v, Vector3 normal)
987{
988 Vector3 result = { 0 };
990 // I is the original vector
991 // N is the normal of the incident plane
992 // R = I - (2*N*(DotProduct[I, N]))
994 float dotProduct = (v.x*normal.x + v.y*normal.y + v.z*normal.z);
996 result.x = v.x - (2.0f*normal.x)*dotProduct;
997 result.y = v.y - (2.0f*normal.y)*dotProduct;
998 result.z = v.z - (2.0f*normal.z)*dotProduct;
1000 return result;
1001}
1003// Get min value for each pair of components
1004RMAPI Vector3 Vector3Min(Vector3 v1, Vector3 v2)
1005{
1006 Vector3 result = { 0 };
1008 result.x = fminf(v1.x, v2.x);
1009 result.y = fminf(v1.y, v2.y);
1010 result.z = fminf(v1.z, v2.z);
1012 return result;
1013}
1015// Get max value for each pair of components
1016RMAPI Vector3 Vector3Max(Vector3 v1, Vector3 v2)
1017{
1018 Vector3 result = { 0 };
1020 result.x = fmaxf(v1.x, v2.x);
1021 result.y = fmaxf(v1.y, v2.y);
1022 result.z = fmaxf(v1.z, v2.z);
1024 return result;
1025}
1027// Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c)
1028// NOTE: Assumes P is on the plane of the triangle
1029RMAPI Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
1030{
1031 Vector3 result = { 0 };
1033 Vector3 v0 = { b.x - a.x, b.y - a.y, b.z - a.z }; // Vector3Subtract(b, a)
1034 Vector3 v1 = { c.x - a.x, c.y - a.y, c.z - a.z }; // Vector3Subtract(c, a)
1035 Vector3 v2 = { p.x - a.x, p.y - a.y, p.z - a.z }; // Vector3Subtract(p, a)
1036 float d00 = (v0.x*v0.x + v0.y*v0.y + v0.z*v0.z); // Vector3DotProduct(v0, v0)
1037 float d01 = (v0.x*v1.x + v0.y*v1.y + v0.z*v1.z); // Vector3DotProduct(v0, v1)
1038 float d11 = (v1.x*v1.x + v1.y*v1.y + v1.z*v1.z); // Vector3DotProduct(v1, v1)
1039 float d20 = (v2.x*v0.x + v2.y*v0.y + v2.z*v0.z); // Vector3DotProduct(v2, v0)
1040 float d21 = (v2.x*v1.x + v2.y*v1.y + v2.z*v1.z); // Vector3DotProduct(v2, v1)
1042 float denom = d00*d11 - d01*d01;
1044 result.y = (d11*d20 - d01*d21)/denom;
1045 result.z = (d00*d21 - d01*d20)/denom;
1046 result.x = 1.0f - (result.z + result.y);
1048 return result;
1049}
1051// Projects a Vector3 from screen space into object space
1052// NOTE: We are avoiding calling other raymath functions despite available
1053RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
1054{
1055 Vector3 result = { 0 };
1057 // Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it
1058 Matrix matViewProj = { // MatrixMultiply(view, projection);
1059 view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12,
1060 view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13,
1061 view.m0*projection.m2 + view.m1*projection.m6 + view.m2*projection.m10 + view.m3*projection.m14,
1062 view.m0*projection.m3 + view.m1*projection.m7 + view.m2*projection.m11 + view.m3*projection.m15,
1063 view.m4*projection.m0 + view.m5*projection.m4 + view.m6*projection.m8 + view.m7*projection.m12,
1064 view.m4*projection.m1 + view.m5*projection.m5 + view.m6*projection.m9 + view.m7*projection.m13,
1065 view.m4*projection.m2 + view.m5*projection.m6 + view.m6*projection.m10 + view.m7*projection.m14,
1066 view.m4*projection.m3 + view.m5*projection.m7 + view.m6*projection.m11 + view.m7*projection.m15,
1067 view.m8*projection.m0 + view.m9*projection.m4 + view.m10*projection.m8 + view.m11*projection.m12,
1068 view.m8*projection.m1 + view.m9*projection.m5 + view.m10*projection.m9 + view.m11*projection.m13,
1069 view.m8*projection.m2 + view.m9*projection.m6 + view.m10*projection.m10 + view.m11*projection.m14,
1070 view.m8*projection.m3 + view.m9*projection.m7 + view.m10*projection.m11 + view.m11*projection.m15,
1071 view.m12*projection.m0 + view.m13*projection.m4 + view.m14*projection.m8 + view.m15*projection.m12,
1072 view.m12*projection.m1 + view.m13*projection.m5 + view.m14*projection.m9 + view.m15*projection.m13,
1073 view.m12*projection.m2 + view.m13*projection.m6 + view.m14*projection.m10 + view.m15*projection.m14,
1074 view.m12*projection.m3 + view.m13*projection.m7 + view.m14*projection.m11 + view.m15*projection.m15 };
1076 // Calculate inverted matrix -> MatrixInvert(matViewProj);
1077 // Cache the matrix values (speed optimization)
1078 float a00 = matViewProj.m0, a01 = matViewProj.m1, a02 = matViewProj.m2, a03 = matViewProj.m3;
1079 float a10 = matViewProj.m4, a11 = matViewProj.m5, a12 = matViewProj.m6, a13 = matViewProj.m7;
1080 float a20 = matViewProj.m8, a21 = matViewProj.m9, a22 = matViewProj.m10, a23 = matViewProj.m11;
1081 float a30 = matViewProj.m12, a31 = matViewProj.m13, a32 = matViewProj.m14, a33 = matViewProj.m15;
1083 float b00 = a00*a11 - a01*a10;
1084 float b01 = a00*a12 - a02*a10;
1085 float b02 = a00*a13 - a03*a10;
1086 float b03 = a01*a12 - a02*a11;
1087 float b04 = a01*a13 - a03*a11;
1088 float b05 = a02*a13 - a03*a12;
1089 float b06 = a20*a31 - a21*a30;
1090 float b07 = a20*a32 - a22*a30;
1091 float b08 = a20*a33 - a23*a30;
1092 float b09 = a21*a32 - a22*a31;
1093 float b10 = a21*a33 - a23*a31;
1094 float b11 = a22*a33 - a23*a32;
1096 // Calculate the invert determinant (inlined to avoid double-caching)
1097 float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
1099 Matrix matViewProjInv = {
1100 (a11*b11 - a12*b10 + a13*b09)*invDet,
1101 (-a01*b11 + a02*b10 - a03*b09)*invDet,
1102 (a31*b05 - a32*b04 + a33*b03)*invDet,
1103 (-a21*b05 + a22*b04 - a23*b03)*invDet,
1104 (-a10*b11 + a12*b08 - a13*b07)*invDet,
1105 (a00*b11 - a02*b08 + a03*b07)*invDet,
1106 (-a30*b05 + a32*b02 - a33*b01)*invDet,
1107 (a20*b05 - a22*b02 + a23*b01)*invDet,
1108 (a10*b10 - a11*b08 + a13*b06)*invDet,
1109 (-a00*b10 + a01*b08 - a03*b06)*invDet,
1110 (a30*b04 - a31*b02 + a33*b00)*invDet,
1111 (-a20*b04 + a21*b02 - a23*b00)*invDet,
1112 (-a10*b09 + a11*b07 - a12*b06)*invDet,
1113 (a00*b09 - a01*b07 + a02*b06)*invDet,
1114 (-a30*b03 + a31*b01 - a32*b00)*invDet,
1115 (a20*b03 - a21*b01 + a22*b00)*invDet };
1117 // Create quaternion from source point
1118 Quaternion quat = { source.x, source.y, source.z, 1.0f };
1120 // Multiply quat point by unprojecte matrix
1121 Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv)
1122 matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w,
1123 matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w,
1124 matViewProjInv.m2*quat.x + matViewProjInv.m6*quat.y + matViewProjInv.m10*quat.z + matViewProjInv.m14*quat.w,
1125 matViewProjInv.m3*quat.x + matViewProjInv.m7*quat.y + matViewProjInv.m11*quat.z + matViewProjInv.m15*quat.w };
1127 // Normalized world points in vectors
1128 result.x = qtransformed.x/qtransformed.w;
1129 result.y = qtransformed.y/qtransformed.w;
1130 result.z = qtransformed.z/qtransformed.w;
1132 return result;
1133}
1135// Get Vector3 as float array
1136RMAPI float3 Vector3ToFloatV(Vector3 v)
1137{
1138 float3 buffer = { 0 };
1140 buffer.v[0] = v.x;
1141 buffer.v[1] = v.y;
1142 buffer.v[2] = v.z;
1144 return buffer;
1145}
1147// Invert the given vector
1148RMAPI Vector3 Vector3Invert(Vector3 v)
1149{
1150 Vector3 result = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z };
1152 return result;
1153}
1155// Clamp the components of the vector between
1156// min and max values specified by the given vectors
1157RMAPI Vector3 Vector3Clamp(Vector3 v, Vector3 min, Vector3 max)
1158{
1159 Vector3 result = { 0 };
1161 result.x = fminf(max.x, fmaxf(min.x, v.x));
1162 result.y = fminf(max.y, fmaxf(min.y, v.y));
1163 result.z = fminf(max.z, fmaxf(min.z, v.z));
1165 return result;
1166}
1168// Clamp the magnitude of the vector between two values
1169RMAPI Vector3 Vector3ClampValue(Vector3 v, float min, float max)
1170{
1171 Vector3 result = v;
1173 float length = (v.x*v.x) + (v.y*v.y) + (v.z*v.z);
1174 if (length > 0.0f)
1175 {
1176 length = sqrtf(length);
1178 float scale = 1; // By default, 1 as the neutral element.
1179 if (length < min)
1180 {
1181 scale = min/length;
1182 }
1183 else if (length > max)
1184 {
1185 scale = max/length;
1186 }
1188 result.x = v.x*scale;
1189 result.y = v.y*scale;
1190 result.z = v.z*scale;
1191 }
1193 return result;
1194}
1196// Check whether two given vectors are almost equal
1197RMAPI int Vector3Equals(Vector3 p, Vector3 q)
1198{
1199#if !defined(EPSILON)
1200 #define EPSILON 0.000001f
1201#endif
1203 int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) &&
1204 ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) &&
1205 ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z)))));
1207 return result;
1208}
1210// Compute the direction of a refracted ray
1211// v: normalized direction of the incoming ray
1212// n: normalized normal vector of the interface of two optical media
1213// r: ratio of the refractive index of the medium from where the ray comes
1214// to the refractive index of the medium on the other side of the surface
1215RMAPI Vector3 Vector3Refract(Vector3 v, Vector3 n, float r)
1216{
1217 Vector3 result = { 0 };
1219 float dot = v.x*n.x + v.y*n.y + v.z*n.z;
1220 float d = 1.0f - r*r*(1.0f - dot*dot);
1222 if (d >= 0.0f)
1223 {
1224 d = sqrtf(d);
1225 v.x = r*v.x - (r*dot + d)*n.x;
1226 v.y = r*v.y - (r*dot + d)*n.y;
1227 v.z = r*v.z - (r*dot + d)*n.z;
1229 result = v;
1230 }
1232 return result;
1233}
1236//----------------------------------------------------------------------------------
1237// Module Functions Definition - Vector4 math
1238//----------------------------------------------------------------------------------
1240RMAPI Vector4 Vector4Zero(void)
1241{
1242 Vector4 result = { 0.0f, 0.0f, 0.0f, 0.0f };
1243 return result;
1244}
1246RMAPI Vector4 Vector4One(void)
1247{
1248 Vector4 result = { 1.0f, 1.0f, 1.0f, 1.0f };
1249 return result;
1250}
1252RMAPI Vector4 Vector4Add(Vector4 v1, Vector4 v2)
1253{
1254 Vector4 result = {
1255 v1.x + v2.x,
1256 v1.y + v2.y,
1257 v1.z + v2.z,
1258 v1.w + v2.w
1259 };
1260 return result;
1261}
1263RMAPI Vector4 Vector4AddValue(Vector4 v, float add)
1264{
1265 Vector4 result = {
1266 v.x + add,
1267 v.y + add,
1268 v.z + add,
1269 v.w + add
1270 };
1271 return result;
1272}
1274RMAPI Vector4 Vector4Subtract(Vector4 v1, Vector4 v2)
1275{
1276 Vector4 result = {
1277 v1.x - v2.x,
1278 v1.y - v2.y,
1279 v1.z - v2.z,
1280 v1.w - v2.w
1281 };
1282 return result;
1283}
1285RMAPI Vector4 Vector4SubtractValue(Vector4 v, float add)
1286{
1287 Vector4 result = {
1288 v.x - add,
1289 v.y - add,
1290 v.z - add,
1291 v.w - add
1292 };
1293 return result;
1294}
1296RMAPI float Vector4Length(Vector4 v)
1297{
1298 float result = sqrtf((v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w));
1299 return result;
1300}
1302RMAPI float Vector4LengthSqr(Vector4 v)
1303{
1304 float result = (v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w);
1305 return result;
1306}
1308RMAPI float Vector4DotProduct(Vector4 v1, Vector4 v2)
1309{
1310 float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w);
1311 return result;
1312}
1314// Calculate distance between two vectors
1315RMAPI float Vector4Distance(Vector4 v1, Vector4 v2)
1316{
1317 float result = sqrtf(
1318 (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y) +
1319 (v1.z - v2.z)*(v1.z - v2.z) + (v1.w - v2.w)*(v1.w - v2.w));
1320 return result;
1321}
1323// Calculate square distance between two vectors
1324RMAPI float Vector4DistanceSqr(Vector4 v1, Vector4 v2)
1325{
1326 float result =
1327 (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y) +
1328 (v1.z - v2.z)*(v1.z - v2.z) + (v1.w - v2.w)*(v1.w - v2.w);
1330 return result;
1331}
1333RMAPI Vector4 Vector4Scale(Vector4 v, float scale)
1334{
1335 Vector4 result = { v.x*scale, v.y*scale, v.z*scale, v.w*scale };
1336 return result;
1337}
1339// Multiply vector by vector
1340RMAPI Vector4 Vector4Multiply(Vector4 v1, Vector4 v2)
1341{
1342 Vector4 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z, v1.w*v2.w };
1343 return result;
1344}
1346// Negate vector
1347RMAPI Vector4 Vector4Negate(Vector4 v)
1348{
1349 Vector4 result = { -v.x, -v.y, -v.z, -v.w };
1350 return result;
1351}
1353// Divide vector by vector
1354RMAPI Vector4 Vector4Divide(Vector4 v1, Vector4 v2)
1355{
1356 Vector4 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z, v1.w/v2.w };
1357 return result;
1358}
1360// Normalize provided vector
1361RMAPI Vector4 Vector4Normalize(Vector4 v)
1362{
1363 Vector4 result = { 0 };
1364 float length = sqrtf((v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w));
1366 if (length > 0)
1367 {
1368 float ilength = 1.0f/length;
1369 result.x = v.x*ilength;
1370 result.y = v.y*ilength;
1371 result.z = v.z*ilength;
1372 result.w = v.w*ilength;
1373 }
1375 return result;
1376}
1378// Get min value for each pair of components
1379RMAPI Vector4 Vector4Min(Vector4 v1, Vector4 v2)
1380{
1381 Vector4 result = { 0 };
1383 result.x = fminf(v1.x, v2.x);
1384 result.y = fminf(v1.y, v2.y);
1385 result.z = fminf(v1.z, v2.z);
1386 result.w = fminf(v1.w, v2.w);
1388 return result;
1389}
1391// Get max value for each pair of components
1392RMAPI Vector4 Vector4Max(Vector4 v1, Vector4 v2)
1393{
1394 Vector4 result = { 0 };
1396 result.x = fmaxf(v1.x, v2.x);
1397 result.y = fmaxf(v1.y, v2.y);
1398 result.z = fmaxf(v1.z, v2.z);
1399 result.w = fmaxf(v1.w, v2.w);
1401 return result;
1402}
1404// Calculate linear interpolation between two vectors
1405RMAPI Vector4 Vector4Lerp(Vector4 v1, Vector4 v2, float amount)
1406{
1407 Vector4 result = { 0 };
1409 result.x = v1.x + amount*(v2.x - v1.x);
1410 result.y = v1.y + amount*(v2.y - v1.y);
1411 result.z = v1.z + amount*(v2.z - v1.z);
1412 result.w = v1.w + amount*(v2.w - v1.w);
1414 return result;
1415}
1417// Move Vector towards target
1418RMAPI Vector4 Vector4MoveTowards(Vector4 v, Vector4 target, float maxDistance)
1419{
1420 Vector4 result = { 0 };
1422 float dx = target.x - v.x;
1423 float dy = target.y - v.y;
1424 float dz = target.z - v.z;
1425 float dw = target.w - v.w;
1426 float value = (dx*dx) + (dy*dy) + (dz*dz) + (dw*dw);
1428 if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target;
1430 float dist = sqrtf(value);
1432 result.x = v.x + dx/dist*maxDistance;
1433 result.y = v.y + dy/dist*maxDistance;
1434 result.z = v.z + dz/dist*maxDistance;
1435 result.w = v.w + dw/dist*maxDistance;
1437 return result;
1438}
1440// Invert the given vector
1441RMAPI Vector4 Vector4Invert(Vector4 v)
1442{
1443 Vector4 result = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z, 1.0f/v.w };
1444 return result;
1445}
1447// Check whether two given vectors are almost equal
1448RMAPI int Vector4Equals(Vector4 p, Vector4 q)
1449{
1450#if !defined(EPSILON)
1451 #define EPSILON 0.000001f
1452#endif
1454 int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) &&
1455 ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) &&
1456 ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) &&
1457 ((fabsf(p.w - q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w)))));
1458 return result;
1459}
1462//----------------------------------------------------------------------------------
1463// Module Functions Definition - Matrix math
1464//----------------------------------------------------------------------------------
1466// Compute matrix determinant
1467RMAPI float MatrixDeterminant(Matrix mat)
1468{
1469 float result = 0.0f;
1470/*
1471 // Cache the matrix values (speed optimization)
1472 float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
1473 float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
1474 float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
1475 float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;
1477 // NOTE: It takes 72 multiplication to calculate 4x4 matrix determinant
1478 result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
1479 a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
1480 a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
1481 a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +
1482 a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +
1483 a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
1484*/
1485 // Using Laplace expansion (https://en.wikipedia.org/wiki/Laplace_expansion),
1486 // previous operation can be simplified to 40 multiplications, decreasing matrix
1487 // size from 4x4 to 2x2 using minors
1489 // Cache the matrix values (speed optimization)
1490 float m0 = mat.m0, m1 = mat.m1, m2 = mat.m2, m3 = mat.m3;
1491 float m4 = mat.m4, m5 = mat.m5, m6 = mat.m6, m7 = mat.m7;
1492 float m8 = mat.m8, m9 = mat.m9, m10 = mat.m10, m11 = mat.m11;
1493 float m12 = mat.m12, m13 = mat.m13, m14 = mat.m14, m15 = mat.m15;
1495 result = (m0*((m5*(m10*m15 - m11*m14) - m9*(m6*m15 - m7*m14) + m13*(m6*m11 - m7*m10))) -
1496 m4*((m1*(m10*m15 - m11*m14) - m9*(m2*m15 - m3*m14) + m13*(m2*m11 - m3*m10))) +
1497 m8*((m1*(m6*m15 - m7*m14) - m5*(m2*m15 - m3*m14) + m13*(m2*m7 - m3*m6))) -
1498 m12*((m1*(m6*m11 - m7*m10) - m5*(m2*m11 - m3*m10) + m9*(m2*m7 - m3*m6))));
1500 return result;
1501}
1503// Get the trace of the matrix (sum of the values along the diagonal)
1504RMAPI float MatrixTrace(Matrix mat)
1505{
1506 float result = (mat.m0 + mat.m5 + mat.m10 + mat.m15);
1508 return result;
1509}
1511// Transposes provided matrix
1512RMAPI Matrix MatrixTranspose(Matrix mat)
1513{
1514 Matrix result = { 0 };
1516 result.m0 = mat.m0;
1517 result.m1 = mat.m4;
1518 result.m2 = mat.m8;
1519 result.m3 = mat.m12;
1520 result.m4 = mat.m1;
1521 result.m5 = mat.m5;
1522 result.m6 = mat.m9;
1523 result.m7 = mat.m13;
1524 result.m8 = mat.m2;
1525 result.m9 = mat.m6;
1526 result.m10 = mat.m10;
1527 result.m11 = mat.m14;
1528 result.m12 = mat.m3;
1529 result.m13 = mat.m7;
1530 result.m14 = mat.m11;
1531 result.m15 = mat.m15;
1533 return result;
1534}
1536// Invert provided matrix
1537RMAPI Matrix MatrixInvert(Matrix mat)
1538{
1539 Matrix result = { 0 };
1541 // Cache the matrix values (speed optimization)
1542 float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
1543 float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
1544 float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
1545 float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;
1547 float b00 = a00*a11 - a01*a10;
1548 float b01 = a00*a12 - a02*a10;
1549 float b02 = a00*a13 - a03*a10;
1550 float b03 = a01*a12 - a02*a11;
1551 float b04 = a01*a13 - a03*a11;
1552 float b05 = a02*a13 - a03*a12;
1553 float b06 = a20*a31 - a21*a30;
1554 float b07 = a20*a32 - a22*a30;
1555 float b08 = a20*a33 - a23*a30;
1556 float b09 = a21*a32 - a22*a31;
1557 float b10 = a21*a33 - a23*a31;
1558 float b11 = a22*a33 - a23*a32;
1560 // Calculate the invert determinant (inlined to avoid double-caching)
1561 float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
1563 result.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet;
1564 result.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet;
1565 result.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet;
1566 result.m3 = (-a21*b05 + a22*b04 - a23*b03)*invDet;
1567 result.m4 = (-a10*b11 + a12*b08 - a13*b07)*invDet;
1568 result.m5 = (a00*b11 - a02*b08 + a03*b07)*invDet;
1569 result.m6 = (-a30*b05 + a32*b02 - a33*b01)*invDet;
1570 result.m7 = (a20*b05 - a22*b02 + a23*b01)*invDet;
1571 result.m8 = (a10*b10 - a11*b08 + a13*b06)*invDet;
1572 result.m9 = (-a00*b10 + a01*b08 - a03*b06)*invDet;
1573 result.m10 = (a30*b04 - a31*b02 + a33*b00)*invDet;
1574 result.m11 = (-a20*b04 + a21*b02 - a23*b00)*invDet;
1575 result.m12 = (-a10*b09 + a11*b07 - a12*b06)*invDet;
1576 result.m13 = (a00*b09 - a01*b07 + a02*b06)*invDet;
1577 result.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet;
1578 result.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet;
1580 return result;
1581}
1583// Get identity matrix
1584RMAPI Matrix MatrixIdentity(void)
1585{
1586 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
1587 0.0f, 1.0f, 0.0f, 0.0f,
1588 0.0f, 0.0f, 1.0f, 0.0f,
1589 0.0f, 0.0f, 0.0f, 1.0f };
1591 return result;
1592}
1594// Add two matrices
1595RMAPI Matrix MatrixAdd(Matrix left, Matrix right)
1596{
1597 Matrix result = { 0 };
1599 result.m0 = left.m0 + right.m0;
1600 result.m1 = left.m1 + right.m1;
1601 result.m2 = left.m2 + right.m2;
1602 result.m3 = left.m3 + right.m3;
1603 result.m4 = left.m4 + right.m4;
1604 result.m5 = left.m5 + right.m5;
1605 result.m6 = left.m6 + right.m6;
1606 result.m7 = left.m7 + right.m7;
1607 result.m8 = left.m8 + right.m8;
1608 result.m9 = left.m9 + right.m9;
1609 result.m10 = left.m10 + right.m10;
1610 result.m11 = left.m11 + right.m11;
1611 result.m12 = left.m12 + right.m12;
1612 result.m13 = left.m13 + right.m13;
1613 result.m14 = left.m14 + right.m14;
1614 result.m15 = left.m15 + right.m15;
1616 return result;
1617}
1619// Subtract two matrices (left - right)
1620RMAPI Matrix MatrixSubtract(Matrix left, Matrix right)
1621{
1622 Matrix result = { 0 };
1624 result.m0 = left.m0 - right.m0;
1625 result.m1 = left.m1 - right.m1;
1626 result.m2 = left.m2 - right.m2;
1627 result.m3 = left.m3 - right.m3;
1628 result.m4 = left.m4 - right.m4;
1629 result.m5 = left.m5 - right.m5;
1630 result.m6 = left.m6 - right.m6;
1631 result.m7 = left.m7 - right.m7;
1632 result.m8 = left.m8 - right.m8;
1633 result.m9 = left.m9 - right.m9;
1634 result.m10 = left.m10 - right.m10;
1635 result.m11 = left.m11 - right.m11;
1636 result.m12 = left.m12 - right.m12;
1637 result.m13 = left.m13 - right.m13;
1638 result.m14 = left.m14 - right.m14;
1639 result.m15 = left.m15 - right.m15;
1641 return result;
1642}
1644// Get two matrix multiplication
1645// NOTE: When multiplying matrices... the order matters!
1646RMAPI Matrix MatrixMultiply(Matrix left, Matrix right)
1647{
1648 Matrix result = { 0 };
1650 result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12;
1651 result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13;
1652 result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14;
1653 result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15;
1654 result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12;
1655 result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13;
1656 result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14;
1657 result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15;
1658 result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12;
1659 result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13;
1660 result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14;
1661 result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15;
1662 result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12;
1663 result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13;
1664 result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14;
1665 result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15;
1667 return result;
1668}
1670// Get translation matrix
1671RMAPI Matrix MatrixTranslate(float x, float y, float z)
1672{
1673 Matrix result = { 1.0f, 0.0f, 0.0f, x,
1674 0.0f, 1.0f, 0.0f, y,
1675 0.0f, 0.0f, 1.0f, z,
1676 0.0f, 0.0f, 0.0f, 1.0f };
1678 return result;
1679}
1681// Create rotation matrix from axis and angle
1682// NOTE: Angle should be provided in radians
1683RMAPI Matrix MatrixRotate(Vector3 axis, float angle)
1684{
1685 Matrix result = { 0 };
1687 float x = axis.x, y = axis.y, z = axis.z;
1689 float lengthSquared = x*x + y*y + z*z;
1691 if ((lengthSquared != 1.0f) && (lengthSquared != 0.0f))
1692 {
1693 float ilength = 1.0f/sqrtf(lengthSquared);
1694 x *= ilength;
1695 y *= ilength;
1696 z *= ilength;
1697 }
1699 float sinres = sinf(angle);
1700 float cosres = cosf(angle);
1701 float t = 1.0f - cosres;
1703 result.m0 = x*x*t + cosres;
1704 result.m1 = y*x*t + z*sinres;
1705 result.m2 = z*x*t - y*sinres;
1706 result.m3 = 0.0f;
1708 result.m4 = x*y*t - z*sinres;
1709 result.m5 = y*y*t + cosres;
1710 result.m6 = z*y*t + x*sinres;
1711 result.m7 = 0.0f;
1713 result.m8 = x*z*t + y*sinres;
1714 result.m9 = y*z*t - x*sinres;
1715 result.m10 = z*z*t + cosres;
1716 result.m11 = 0.0f;
1718 result.m12 = 0.0f;
1719 result.m13 = 0.0f;
1720 result.m14 = 0.0f;
1721 result.m15 = 1.0f;
1723 return result;
1724}
1726// Get x-rotation matrix
1727// NOTE: Angle must be provided in radians
1728RMAPI Matrix MatrixRotateX(float angle)
1729{
1730 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
1731 0.0f, 1.0f, 0.0f, 0.0f,
1732 0.0f, 0.0f, 1.0f, 0.0f,
1733 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
1735 float cosres = cosf(angle);
1736 float sinres = sinf(angle);
1738 result.m5 = cosres;
1739 result.m6 = sinres;
1740 result.m9 = -sinres;
1741 result.m10 = cosres;
1743 return result;
1744}
1746// Get y-rotation matrix
1747// NOTE: Angle must be provided in radians
1748RMAPI Matrix MatrixRotateY(float angle)
1749{
1750 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
1751 0.0f, 1.0f, 0.0f, 0.0f,
1752 0.0f, 0.0f, 1.0f, 0.0f,
1753 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
1755 float cosres = cosf(angle);
1756 float sinres = sinf(angle);
1758 result.m0 = cosres;
1759 result.m2 = -sinres;
1760 result.m8 = sinres;
1761 result.m10 = cosres;
1763 return result;
1764}
1766// Get z-rotation matrix
1767// NOTE: Angle must be provided in radians
1768RMAPI Matrix MatrixRotateZ(float angle)
1769{
1770 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
1771 0.0f, 1.0f, 0.0f, 0.0f,
1772 0.0f, 0.0f, 1.0f, 0.0f,
1773 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
1775 float cosres = cosf(angle);
1776 float sinres = sinf(angle);
1778 result.m0 = cosres;
1779 result.m1 = sinres;
1780 result.m4 = -sinres;
1781 result.m5 = cosres;
1783 return result;
1784}
1787// Get xyz-rotation matrix
1788// NOTE: Angle must be provided in radians
1789RMAPI Matrix MatrixRotateXYZ(Vector3 angle)
1790{
1791 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
1792 0.0f, 1.0f, 0.0f, 0.0f,
1793 0.0f, 0.0f, 1.0f, 0.0f,
1794 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
1796 float cosz = cosf(-angle.z);
1797 float sinz = sinf(-angle.z);
1798 float cosy = cosf(-angle.y);
1799 float siny = sinf(-angle.y);
1800 float cosx = cosf(-angle.x);
1801 float sinx = sinf(-angle.x);
1803 result.m0 = cosz*cosy;
1804 result.m1 = (cosz*siny*sinx) - (sinz*cosx);
1805 result.m2 = (cosz*siny*cosx) + (sinz*sinx);
1807 result.m4 = sinz*cosy;
1808 result.m5 = (sinz*siny*sinx) + (cosz*cosx);
1809 result.m6 = (sinz*siny*cosx) - (cosz*sinx);
1811 result.m8 = -siny;
1812 result.m9 = cosy*sinx;
1813 result.m10= cosy*cosx;
1815 return result;
1816}
1818// Get zyx-rotation matrix
1819// NOTE: Angle must be provided in radians
1820RMAPI Matrix MatrixRotateZYX(Vector3 angle)
1821{
1822 Matrix result = { 0 };
1824 float cz = cosf(angle.z);
1825 float sz = sinf(angle.z);
1826 float cy = cosf(angle.y);
1827 float sy = sinf(angle.y);
1828 float cx = cosf(angle.x);
1829 float sx = sinf(angle.x);
1831 result.m0 = cz*cy;
1832 result.m4 = cz*sy*sx - cx*sz;
1833 result.m8 = sz*sx + cz*cx*sy;
1834 result.m12 = 0;
1836 result.m1 = cy*sz;
1837 result.m5 = cz*cx + sz*sy*sx;
1838 result.m9 = cx*sz*sy - cz*sx;
1839 result.m13 = 0;
1841 result.m2 = -sy;
1842 result.m6 = cy*sx;
1843 result.m10 = cy*cx;
1844 result.m14 = 0;
1846 result.m3 = 0;
1847 result.m7 = 0;
1848 result.m11 = 0;
1849 result.m15 = 1;
1851 return result;
1852}
1854// Get scaling matrix
1855RMAPI Matrix MatrixScale(float x, float y, float z)
1856{
1857 Matrix result = { x, 0.0f, 0.0f, 0.0f,
1858 0.0f, y, 0.0f, 0.0f,
1859 0.0f, 0.0f, z, 0.0f,
1860 0.0f, 0.0f, 0.0f, 1.0f };
1862 return result;
1863}
1865// Get perspective projection matrix
1866RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top, double nearPlane, double farPlane)
1867{
1868 Matrix result = { 0 };
1870 float rl = (float)(right - left);
1871 float tb = (float)(top - bottom);
1872 float fn = (float)(farPlane - nearPlane);
1874 result.m0 = ((float)nearPlane*2.0f)/rl;
1875 result.m1 = 0.0f;
1876 result.m2 = 0.0f;
1877 result.m3 = 0.0f;
1879 result.m4 = 0.0f;
1880 result.m5 = ((float)nearPlane*2.0f)/tb;
1881 result.m6 = 0.0f;
1882 result.m7 = 0.0f;
1884 result.m8 = ((float)right + (float)left)/rl;
1885 result.m9 = ((float)top + (float)bottom)/tb;
1886 result.m10 = -((float)farPlane + (float)nearPlane)/fn;
1887 result.m11 = -1.0f;
1889 result.m12 = 0.0f;
1890 result.m13 = 0.0f;
1891 result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn;
1892 result.m15 = 0.0f;
1894 return result;
1895}
1897// Get perspective projection matrix
1898// NOTE: Fovy angle must be provided in radians
1899RMAPI Matrix MatrixPerspective(double fovY, double aspect, double nearPlane, double farPlane)
1900{
1901 Matrix result = { 0 };
1903 double top = nearPlane*tan(fovY*0.5);
1904 double bottom = -top;
1905 double right = top*aspect;
1906 double left = -right;
1908 // MatrixFrustum(-right, right, -top, top, near, far);
1909 float rl = (float)(right - left);
1910 float tb = (float)(top - bottom);
1911 float fn = (float)(farPlane - nearPlane);
1913 result.m0 = ((float)nearPlane*2.0f)/rl;
1914 result.m5 = ((float)nearPlane*2.0f)/tb;
1915 result.m8 = ((float)right + (float)left)/rl;
1916 result.m9 = ((float)top + (float)bottom)/tb;
1917 result.m10 = -((float)farPlane + (float)nearPlane)/fn;
1918 result.m11 = -1.0f;
1919 result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn;
1921 return result;
1922}
1924// Get orthographic projection matrix
1925RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double nearPlane, double farPlane)
1926{
1927 Matrix result = { 0 };
1929 float rl = (float)(right - left);
1930 float tb = (float)(top - bottom);
1931 float fn = (float)(farPlane - nearPlane);
1933 result.m0 = 2.0f/rl;
1934 result.m1 = 0.0f;
1935 result.m2 = 0.0f;
1936 result.m3 = 0.0f;
1937 result.m4 = 0.0f;
1938 result.m5 = 2.0f/tb;
1939 result.m6 = 0.0f;
1940 result.m7 = 0.0f;
1941 result.m8 = 0.0f;
1942 result.m9 = 0.0f;
1943 result.m10 = -2.0f/fn;
1944 result.m11 = 0.0f;
1945 result.m12 = -((float)left + (float)right)/rl;
1946 result.m13 = -((float)top + (float)bottom)/tb;
1947 result.m14 = -((float)farPlane + (float)nearPlane)/fn;
1948 result.m15 = 1.0f;
1950 return result;
1951}
1953// Get camera look-at matrix (view matrix)
1954RMAPI Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
1955{
1956 Matrix result = { 0 };
1958 float length = 0.0f;
1959 float ilength = 0.0f;
1961 // Vector3Subtract(eye, target)
1962 Vector3 vz = { eye.x - target.x, eye.y - target.y, eye.z - target.z };
1964 // Vector3Normalize(vz)
1965 Vector3 v = vz;
1966 length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
1967 if (length == 0.0f) length = 1.0f;
1968 ilength = 1.0f/length;
1969 vz.x *= ilength;
1970 vz.y *= ilength;
1971 vz.z *= ilength;
1973 // Vector3CrossProduct(up, vz)
1974 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 };
1976 // Vector3Normalize(x)
1977 v = vx;
1978 length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
1979 if (length == 0.0f) length = 1.0f;
1980 ilength = 1.0f/length;
1981 vx.x *= ilength;
1982 vx.y *= ilength;
1983 vx.z *= ilength;
1985 // Vector3CrossProduct(vz, vx)
1986 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 };
1988 result.m0 = vx.x;
1989 result.m1 = vy.x;
1990 result.m2 = vz.x;
1991 result.m3 = 0.0f;
1992 result.m4 = vx.y;
1993 result.m5 = vy.y;
1994 result.m6 = vz.y;
1995 result.m7 = 0.0f;
1996 result.m8 = vx.z;
1997 result.m9 = vy.z;
1998 result.m10 = vz.z;
1999 result.m11 = 0.0f;
2000 result.m12 = -(vx.x*eye.x + vx.y*eye.y + vx.z*eye.z); // Vector3DotProduct(vx, eye)
2001 result.m13 = -(vy.x*eye.x + vy.y*eye.y + vy.z*eye.z); // Vector3DotProduct(vy, eye)
2002 result.m14 = -(vz.x*eye.x + vz.y*eye.y + vz.z*eye.z); // Vector3DotProduct(vz, eye)
2003 result.m15 = 1.0f;
2005 return result;
2006}
2008// Get float array of matrix data
2009RMAPI float16 MatrixToFloatV(Matrix mat)
2010{
2011 float16 result = { 0 };
2013 result.v[0] = mat.m0;
2014 result.v[1] = mat.m1;
2015 result.v[2] = mat.m2;
2016 result.v[3] = mat.m3;
2017 result.v[4] = mat.m4;
2018 result.v[5] = mat.m5;
2019 result.v[6] = mat.m6;
2020 result.v[7] = mat.m7;
2021 result.v[8] = mat.m8;
2022 result.v[9] = mat.m9;
2023 result.v[10] = mat.m10;
2024 result.v[11] = mat.m11;
2025 result.v[12] = mat.m12;
2026 result.v[13] = mat.m13;
2027 result.v[14] = mat.m14;
2028 result.v[15] = mat.m15;
2030 return result;
2031}
2033//----------------------------------------------------------------------------------
2034// Module Functions Definition - Quaternion math
2035//----------------------------------------------------------------------------------
2037// Add two quaternions
2038RMAPI Quaternion QuaternionAdd(Quaternion q1, Quaternion q2)
2039{
2040 Quaternion result = {q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w};
2042 return result;
2043}
2045// Add quaternion and float value
2046RMAPI Quaternion QuaternionAddValue(Quaternion q, float add)
2047{
2048 Quaternion result = {q.x + add, q.y + add, q.z + add, q.w + add};
2050 return result;
2051}
2053// Subtract two quaternions
2054RMAPI Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2)
2055{
2056 Quaternion result = {q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w};
2058 return result;
2059}
2061// Subtract quaternion and float value
2062RMAPI Quaternion QuaternionSubtractValue(Quaternion q, float sub)
2063{
2064 Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub};
2066 return result;
2067}
2069// Get identity quaternion
2070RMAPI Quaternion QuaternionIdentity(void)
2071{
2072 Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
2074 return result;
2075}
2077// Computes the length of a quaternion
2078RMAPI float QuaternionLength(Quaternion q)
2079{
2080 float result = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
2082 return result;
2083}
2085// Normalize provided quaternion
2086RMAPI Quaternion QuaternionNormalize(Quaternion q)
2087{
2088 Quaternion result = { 0 };
2090 float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
2091 if (length == 0.0f) length = 1.0f;
2092 float ilength = 1.0f/length;
2094 result.x = q.x*ilength;
2095 result.y = q.y*ilength;
2096 result.z = q.z*ilength;
2097 result.w = q.w*ilength;
2099 return result;
2100}
2102// Invert provided quaternion
2103RMAPI Quaternion QuaternionInvert(Quaternion q)
2104{
2105 Quaternion result = q;
2107 float lengthSq = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
2109 if (lengthSq != 0.0f)
2110 {
2111 float invLength = 1.0f/lengthSq;
2113 result.x *= -invLength;
2114 result.y *= -invLength;
2115 result.z *= -invLength;
2116 result.w *= invLength;
2117 }
2119 return result;
2120}
2122// Calculate two quaternion multiplication
2123RMAPI Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
2124{
2125 Quaternion result = { 0 };
2127 float qax = q1.x, qay = q1.y, qaz = q1.z, qaw = q1.w;
2128 float qbx = q2.x, qby = q2.y, qbz = q2.z, qbw = q2.w;
2130 result.x = qax*qbw + qaw*qbx + qay*qbz - qaz*qby;
2131 result.y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz;
2132 result.z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx;
2133 result.w = qaw*qbw - qax*qbx - qay*qby - qaz*qbz;
2135 return result;
2136}
2138// Scale quaternion by float value
2139RMAPI Quaternion QuaternionScale(Quaternion q, float mul)
2140{
2141 Quaternion result = { 0 };
2143 result.x = q.x*mul;
2144 result.y = q.y*mul;
2145 result.z = q.z*mul;
2146 result.w = q.w*mul;
2148 return result;
2149}
2151// Divide two quaternions
2152RMAPI Quaternion QuaternionDivide(Quaternion q1, Quaternion q2)
2153{
2154 Quaternion result = { q1.x/q2.x, q1.y/q2.y, q1.z/q2.z, q1.w/q2.w };
2156 return result;
2157}
2159// Calculate linear interpolation between two quaternions
2160RMAPI Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount)
2161{
2162 Quaternion result = { 0 };
2164 result.x = q1.x + amount*(q2.x - q1.x);
2165 result.y = q1.y + amount*(q2.y - q1.y);
2166 result.z = q1.z + amount*(q2.z - q1.z);
2167 result.w = q1.w + amount*(q2.w - q1.w);
2169 return result;
2170}
2172// Calculate slerp-optimized interpolation between two quaternions
2173RMAPI Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount)
2174{
2175 Quaternion result = { 0 };
2177 // QuaternionLerp(q1, q2, amount)
2178 result.x = q1.x + amount*(q2.x - q1.x);
2179 result.y = q1.y + amount*(q2.y - q1.y);
2180 result.z = q1.z + amount*(q2.z - q1.z);
2181 result.w = q1.w + amount*(q2.w - q1.w);
2183 // QuaternionNormalize(q);
2184 Quaternion q = result;
2185 float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
2186 if (length == 0.0f) length = 1.0f;
2187 float ilength = 1.0f/length;
2189 result.x = q.x*ilength;
2190 result.y = q.y*ilength;
2191 result.z = q.z*ilength;
2192 result.w = q.w*ilength;
2194 return result;
2195}
2197// Calculates spherical linear interpolation between two quaternions
2198RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
2199{
2200 Quaternion result = { 0 };
2202#if !defined(EPSILON)
2203 #define EPSILON 0.000001f
2204#endif
2206 float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
2208 if (cosHalfTheta < 0)
2209 {
2210 q2.x = -q2.x; q2.y = -q2.y; q2.z = -q2.z; q2.w = -q2.w;
2211 cosHalfTheta = -cosHalfTheta;
2212 }
2214 if (fabsf(cosHalfTheta) >= 1.0f) result = q1;
2215 else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount);
2216 else
2217 {
2218 float halfTheta = acosf(cosHalfTheta);
2219 float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta);
2221 if (fabsf(sinHalfTheta) < EPSILON)
2222 {
2223 result.x = (q1.x*0.5f + q2.x*0.5f);
2224 result.y = (q1.y*0.5f + q2.y*0.5f);
2225 result.z = (q1.z*0.5f + q2.z*0.5f);
2226 result.w = (q1.w*0.5f + q2.w*0.5f);
2227 }
2228 else
2229 {
2230 float ratioA = sinf((1 - amount)*halfTheta)/sinHalfTheta;
2231 float ratioB = sinf(amount*halfTheta)/sinHalfTheta;
2233 result.x = (q1.x*ratioA + q2.x*ratioB);
2234 result.y = (q1.y*ratioA + q2.y*ratioB);
2235 result.z = (q1.z*ratioA + q2.z*ratioB);
2236 result.w = (q1.w*ratioA + q2.w*ratioB);
2237 }
2238 }
2240 return result;
2241}
2243// Calculate quaternion cubic spline interpolation using Cubic Hermite Spline algorithm
2244// as described in the GLTF 2.0 specification: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#interpolation-cubic
2245RMAPI Quaternion QuaternionCubicHermiteSpline(Quaternion q1, Quaternion outTangent1, Quaternion q2, Quaternion inTangent2, float t)
2246{
2247 float t2 = t*t;
2248 float t3 = t2*t;
2249 float h00 = 2*t3 - 3*t2 + 1;
2250 float h10 = t3 - 2*t2 + t;
2251 float h01 = -2*t3 + 3*t2;
2252 float h11 = t3 - t2;
2254 Quaternion p0 = QuaternionScale(q1, h00);
2255 Quaternion m0 = QuaternionScale(outTangent1, h10);
2256 Quaternion p1 = QuaternionScale(q2, h01);
2257 Quaternion m1 = QuaternionScale(inTangent2, h11);
2259 Quaternion result = { 0 };
2261 result = QuaternionAdd(p0, m0);
2262 result = QuaternionAdd(result, p1);
2263 result = QuaternionAdd(result, m1);
2264 result = QuaternionNormalize(result);
2266 return result;
2267}
2269// Calculate quaternion based on the rotation from one vector to another
2270RMAPI Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
2271{
2272 Quaternion result = { 0 };
2274 float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to)
2275 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)
2277 result.x = cross.x;
2278 result.y = cross.y;
2279 result.z = cross.z;
2280 result.w = 1.0f + cos2Theta;
2282 // QuaternionNormalize(q);
2283 // NOTE: Normalize to essentially nlerp the original and identity to 0.5
2284 Quaternion q = result;
2285 float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
2286 if (length == 0.0f) length = 1.0f;
2287 float ilength = 1.0f/length;
2289 result.x = q.x*ilength;
2290 result.y = q.y*ilength;
2291 result.z = q.z*ilength;
2292 result.w = q.w*ilength;
2294 return result;
2295}
2297// Get a quaternion for a given rotation matrix
2298RMAPI Quaternion QuaternionFromMatrix(Matrix mat)
2299{
2300 Quaternion result = { 0 };
2302 float fourWSquaredMinus1 = mat.m0 + mat.m5 + mat.m10;
2303 float fourXSquaredMinus1 = mat.m0 - mat.m5 - mat.m10;
2304 float fourYSquaredMinus1 = mat.m5 - mat.m0 - mat.m10;
2305 float fourZSquaredMinus1 = mat.m10 - mat.m0 - mat.m5;
2307 int biggestIndex = 0;
2308 float fourBiggestSquaredMinus1 = fourWSquaredMinus1;
2309 if (fourXSquaredMinus1 > fourBiggestSquaredMinus1)
2310 {
2311 fourBiggestSquaredMinus1 = fourXSquaredMinus1;
2312 biggestIndex = 1;
2313 }
2315 if (fourYSquaredMinus1 > fourBiggestSquaredMinus1)
2316 {
2317 fourBiggestSquaredMinus1 = fourYSquaredMinus1;
2318 biggestIndex = 2;
2319 }
2321 if (fourZSquaredMinus1 > fourBiggestSquaredMinus1)
2322 {
2323 fourBiggestSquaredMinus1 = fourZSquaredMinus1;
2324 biggestIndex = 3;
2325 }
2327 float biggestVal = sqrtf(fourBiggestSquaredMinus1 + 1.0f)*0.5f;
2328 float mult = 0.25f/biggestVal;
2330 switch (biggestIndex)
2331 {
2332 case 0:
2333 result.w = biggestVal;
2334 result.x = (mat.m6 - mat.m9)*mult;
2335 result.y = (mat.m8 - mat.m2)*mult;
2336 result.z = (mat.m1 - mat.m4)*mult;
2337 break;
2338 case 1:
2339 result.x = biggestVal;
2340 result.w = (mat.m6 - mat.m9)*mult;
2341 result.y = (mat.m1 + mat.m4)*mult;
2342 result.z = (mat.m8 + mat.m2)*mult;
2343 break;
2344 case 2:
2345 result.y = biggestVal;
2346 result.w = (mat.m8 - mat.m2)*mult;
2347 result.x = (mat.m1 + mat.m4)*mult;
2348 result.z = (mat.m6 + mat.m9)*mult;
2349 break;
2350 case 3:
2351 result.z = biggestVal;
2352 result.w = (mat.m1 - mat.m4)*mult;
2353 result.x = (mat.m8 + mat.m2)*mult;
2354 result.y = (mat.m6 + mat.m9)*mult;
2355 break;
2356 }
2358 return result;
2359}
2361// Get a matrix for a given quaternion
2362RMAPI Matrix QuaternionToMatrix(Quaternion q)
2363{
2364 Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
2365 0.0f, 1.0f, 0.0f, 0.0f,
2366 0.0f, 0.0f, 1.0f, 0.0f,
2367 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
2369 float a2 = q.x*q.x;
2370 float b2 = q.y*q.y;
2371 float c2 = q.z*q.z;
2372 float ac = q.x*q.z;
2373 float ab = q.x*q.y;
2374 float bc = q.y*q.z;
2375 float ad = q.w*q.x;
2376 float bd = q.w*q.y;
2377 float cd = q.w*q.z;
2379 result.m0 = 1 - 2*(b2 + c2);
2380 result.m1 = 2*(ab + cd);
2381 result.m2 = 2*(ac - bd);
2383 result.m4 = 2*(ab - cd);
2384 result.m5 = 1 - 2*(a2 + c2);
2385 result.m6 = 2*(bc + ad);
2387 result.m8 = 2*(ac + bd);
2388 result.m9 = 2*(bc - ad);
2389 result.m10 = 1 - 2*(a2 + b2);
2391 return result;
2392}
2394// Get rotation quaternion for an angle and axis
2395// NOTE: Angle must be provided in radians
2396RMAPI Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
2397{
2398 Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
2400 float axisLength = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);
2402 if (axisLength != 0.0f)
2403 {
2404 angle *= 0.5f;
2406 float length = 0.0f;
2407 float ilength = 0.0f;
2409 // Vector3Normalize(axis)
2410 length = axisLength;
2411 if (length == 0.0f) length = 1.0f;
2412 ilength = 1.0f/length;
2413 axis.x *= ilength;
2414 axis.y *= ilength;
2415 axis.z *= ilength;
2417 float sinres = sinf(angle);
2418 float cosres = cosf(angle);
2420 result.x = axis.x*sinres;
2421 result.y = axis.y*sinres;
2422 result.z = axis.z*sinres;
2423 result.w = cosres;
2425 // QuaternionNormalize(q);
2426 Quaternion q = result;
2427 length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
2428 if (length == 0.0f) length = 1.0f;
2429 ilength = 1.0f/length;
2430 result.x = q.x*ilength;
2431 result.y = q.y*ilength;
2432 result.z = q.z*ilength;
2433 result.w = q.w*ilength;
2434 }
2436 return result;
2437}
2439// Get the rotation angle and axis for a given quaternion
2440RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
2441{
2442 if (fabsf(q.w) > 1.0f)
2443 {
2444 // QuaternionNormalize(q);
2445 float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
2446 if (length == 0.0f) length = 1.0f;
2447 float ilength = 1.0f/length;
2449 q.x = q.x*ilength;
2450 q.y = q.y*ilength;
2451 q.z = q.z*ilength;
2452 q.w = q.w*ilength;
2453 }
2455 Vector3 resAxis = { 0.0f, 0.0f, 0.0f };
2456 float resAngle = 2.0f*acosf(q.w);
2457 float den = sqrtf(1.0f - q.w*q.w);
2459 if (den > EPSILON)
2460 {
2461 resAxis.x = q.x/den;
2462 resAxis.y = q.y/den;
2463 resAxis.z = q.z/den;
2464 }
2465 else
2466 {
2467 // This occurs when the angle is zero.
2468 // Not a problem: just set an arbitrary normalized axis.
2469 resAxis.x = 1.0f;
2470 }
2472 *outAxis = resAxis;
2473 *outAngle = resAngle;
2474}
2476// Get the quaternion equivalent to Euler angles
2477// NOTE: Rotation order is ZYX
2478RMAPI Quaternion QuaternionFromEuler(float pitch, float yaw, float roll)
2479{
2480 Quaternion result = { 0 };
2482 float x0 = cosf(pitch*0.5f);
2483 float x1 = sinf(pitch*0.5f);
2484 float y0 = cosf(yaw*0.5f);
2485 float y1 = sinf(yaw*0.5f);
2486 float z0 = cosf(roll*0.5f);
2487 float z1 = sinf(roll*0.5f);
2489 result.x = x1*y0*z0 - x0*y1*z1;
2490 result.y = x0*y1*z0 + x1*y0*z1;
2491 result.z = x0*y0*z1 - x1*y1*z0;
2492 result.w = x0*y0*z0 + x1*y1*z1;
2494 return result;
2495}
2497// Get the Euler angles equivalent to quaternion (roll, pitch, yaw)
2498// NOTE: Angles are returned in a Vector3 struct in radians
2499RMAPI Vector3 QuaternionToEuler(Quaternion q)
2500{
2501 Vector3 result = { 0 };
2503 // Roll (x-axis rotation)
2504 float x0 = 2.0f*(q.w*q.x + q.y*q.z);
2505 float x1 = 1.0f - 2.0f*(q.x*q.x + q.y*q.y);
2506 result.x = atan2f(x0, x1);
2508 // Pitch (y-axis rotation)
2509 float y0 = 2.0f*(q.w*q.y - q.z*q.x);
2510 y0 = y0 > 1.0f ? 1.0f : y0;
2511 y0 = y0 < -1.0f ? -1.0f : y0;
2512 result.y = asinf(y0);
2514 // Yaw (z-axis rotation)
2515 float z0 = 2.0f*(q.w*q.z + q.x*q.y);
2516 float z1 = 1.0f - 2.0f*(q.y*q.y + q.z*q.z);
2517 result.z = atan2f(z0, z1);
2519 return result;
2520}
2522// Transform a quaternion given a transformation matrix
2523RMAPI Quaternion QuaternionTransform(Quaternion q, Matrix mat)
2524{
2525 Quaternion result = { 0 };
2527 result.x = mat.m0*q.x + mat.m4*q.y + mat.m8*q.z + mat.m12*q.w;
2528 result.y = mat.m1*q.x + mat.m5*q.y + mat.m9*q.z + mat.m13*q.w;
2529 result.z = mat.m2*q.x + mat.m6*q.y + mat.m10*q.z + mat.m14*q.w;
2530 result.w = mat.m3*q.x + mat.m7*q.y + mat.m11*q.z + mat.m15*q.w;
2532 return result;
2533}
2535// Check whether two given quaternions are almost equal
2536RMAPI int QuaternionEquals(Quaternion p, Quaternion q)
2537{
2538#if !defined(EPSILON)
2539 #define EPSILON 0.000001f
2540#endif
2542 int result = (((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) &&
2543 ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) &&
2544 ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) &&
2545 ((fabsf(p.w - q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w)))))) ||
2546 (((fabsf(p.x + q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) &&
2547 ((fabsf(p.y + q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) &&
2548 ((fabsf(p.z + q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) &&
2549 ((fabsf(p.w + q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w))))));
2551 return result;
2552}
2554// Compose a transformation matrix from rotational, translational and scaling components
2555// TODO: This function is not following raymath conventions defined in header: NOT self-contained
2556RMAPI Matrix MatrixCompose(Vector3 translation, Quaternion rotation, Vector3 scale)
2557{
2558 // Initialize vectors
2559 Vector3 right = { 1.0f, 0.0f, 0.0f };
2560 Vector3 up = { 0.0f, 1.0f, 0.0f };
2561 Vector3 forward = { 0.0f, 0.0f, 1.0f };
2563 // Scale vectors
2564 right = Vector3Scale(right, scale.x);
2565 up = Vector3Scale(up, scale.y);
2566 forward = Vector3Scale(forward , scale.z);
2568 // Rotate vectors
2569 right = Vector3RotateByQuaternion(right, rotation);
2570 up = Vector3RotateByQuaternion(up, rotation);
2571 forward = Vector3RotateByQuaternion(forward, rotation);
2573 // Set result matrix output
2574 Matrix result = {
2575 right.x, up.x, forward.x, translation.x,
2576 right.y, up.y, forward.y, translation.y,
2577 right.z, up.z, forward.z, translation.z,
2578 0.0f, 0.0f, 0.0f, 1.0f
2579 };
2581 return result;
2582}
2584// Decompose a transformation matrix into its rotational, translational and scaling components and remove shear
2585// TODO: This function is not following raymath conventions defined in header: NOT self-contained
2586RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale)
2587{
2588 float eps = (float)1e-9;
2590 // Extract Translation
2591 translation->x = mat.m12;
2592 translation->y = mat.m13;
2593 translation->z = mat.m14;
2595 // Matrix Columns - Rotation will be extracted into here.
2596 Vector3 matColumns[3] = { { mat.m0, mat.m4, mat.m8 },
2597 { mat.m1, mat.m5, mat.m9 },
2598 { mat.m2, mat.m6, mat.m10 } };
2600 // Shear Parameters XY, XZ, and YZ (extract and ignored)
2601 float shear[3] = { 0 };
2603 // Normalized Scale Parameters
2604 Vector3 scl = { 0 };
2606 // Max-Normalizing helps numerical stability
2607 float stabilizer = eps;
2608 for (int i = 0; i < 3; i++)
2609 {
2610 stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].x));
2611 stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].y));
2612 stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].z));
2613 };
2614 matColumns[0] = Vector3Scale(matColumns[0], 1.0f / stabilizer);
2615 matColumns[1] = Vector3Scale(matColumns[1], 1.0f / stabilizer);
2616 matColumns[2] = Vector3Scale(matColumns[2], 1.0f / stabilizer);
2618 // X Scale
2619 scl.x = Vector3Length(matColumns[0]);
2620 if (scl.x > eps) matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x);
2622 // Compute XY shear and make col2 orthogonal
2623 shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]);
2624 matColumns[1] = Vector3Subtract(matColumns[1], Vector3Scale(matColumns[0], shear[0]));
2626 // Y Scale
2627 scl.y = Vector3Length(matColumns[1]);
2628 if (scl.y > eps)
2629 {
2630 matColumns[1] = Vector3Scale(matColumns[1], 1.0f / scl.y);
2631 shear[0] /= scl.y; // Correct XY shear
2632 }
2634 // Compute XZ and YZ shears and make col3 orthogonal
2635 shear[1] = Vector3DotProduct(matColumns[0], matColumns[2]);
2636 matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[0], shear[1]));
2637 shear[2] = Vector3DotProduct(matColumns[1], matColumns[2]);
2638 matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[1], shear[2]));
2640 // Z Scale
2641 scl.z = Vector3Length(matColumns[2]);
2642 if (scl.z > eps)
2643 {
2644 matColumns[2] = Vector3Scale(matColumns[2], 1.0f / scl.z);
2645 shear[1] /= scl.z; // Correct XZ shear
2646 shear[2] /= scl.z; // Correct YZ shear
2647 }
2649 // matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1.
2650 if (Vector3DotProduct(matColumns[0], Vector3CrossProduct(matColumns[1], matColumns[2])) < 0)
2651 {
2652 scl = Vector3Negate(scl);
2653 matColumns[0] = Vector3Negate(matColumns[0]);
2654 matColumns[1] = Vector3Negate(matColumns[1]);
2655 matColumns[2] = Vector3Negate(matColumns[2]);
2656 }
2658 // Set Scale
2659 *scale = Vector3Scale(scl, stabilizer);
2661 // Extract Rotation
2662 Matrix rotationMatrix = { matColumns[0].x, matColumns[0].y, matColumns[0].z, 0,
2663 matColumns[1].x, matColumns[1].y, matColumns[1].z, 0,
2664 matColumns[2].x, matColumns[2].y, matColumns[2].z, 0,
2665 0, 0, 0, 1 };
2666 *rotation = QuaternionFromMatrix(rotationMatrix);
2667}
2669#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS)
2671// Optional C++ math operators
2672//-------------------------------------------------------------------------------
2674// Vector2 operators
2675static constexpr Vector2 Vector2Zeros = { 0, 0 };
2676static constexpr Vector2 Vector2Ones = { 1, 1 };
2677static constexpr Vector2 Vector2UnitX = { 1, 0 };
2678static constexpr Vector2 Vector2UnitY = { 0, 1 };
2680inline Vector2 operator + (const Vector2& lhs, const Vector2& rhs)
2681{
2682 return Vector2Add(lhs, rhs);
2683}
2685inline const Vector2& operator += (Vector2& lhs, const Vector2& rhs)
2686{
2687 lhs = Vector2Add(lhs, rhs);
2688 return lhs;
2689}
2691inline Vector2 operator - (const Vector2& lhs, const Vector2& rhs)
2692{
2693 return Vector2Subtract(lhs, rhs);
2694}
2696inline const Vector2& operator -= (Vector2& lhs, const Vector2& rhs)
2697{
2698 lhs = Vector2Subtract(lhs, rhs);
2699 return lhs;
2700}
2702inline Vector2 operator * (const Vector2& lhs, const float& rhs)
2703{
2704 return Vector2Scale(lhs, rhs);
2705}
2707inline const Vector2& operator *= (Vector2& lhs, const float& rhs)
2708{
2709 lhs = Vector2Scale(lhs, rhs);
2710 return lhs;
2711}
2713inline Vector2 operator * (const Vector2& lhs, const Vector2& rhs)
2714{
2715 return Vector2Multiply(lhs, rhs);
2716}
2718inline const Vector2& operator *= (Vector2& lhs, const Vector2& rhs)
2719{
2720 lhs = Vector2Multiply(lhs, rhs);
2721 return lhs;
2722}
2724inline Vector2 operator * (const Vector2& lhs, const Matrix& rhs)
2725{
2726 return Vector2Transform(lhs, rhs);
2727}
2729inline const Vector2& operator *= (Vector2& lhs, const Matrix& rhs)
2730{
2731 lhs = Vector2Transform(lhs, rhs);
2732 return lhs;
2733}
2735inline Vector2 operator / (const Vector2& lhs, const float& rhs)
2736{
2737 return Vector2Scale(lhs, 1.0f/rhs);
2738}
2740inline const Vector2& operator /= (Vector2& lhs, const float& rhs)
2741{
2742 lhs = Vector2Scale(lhs, 1.0f/rhs);
2743 return lhs;
2744}
2746inline Vector2 operator / (const Vector2& lhs, const Vector2& rhs)
2747{
2748 return Vector2Divide(lhs, rhs);
2749}
2751inline const Vector2& operator /= (Vector2& lhs, const Vector2& rhs)
2752{
2753 lhs = Vector2Divide(lhs, rhs);
2754 return lhs;
2755}
2757inline bool operator == (const Vector2& lhs, const Vector2& rhs)
2758{
2759 return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y);
2760}
2762inline bool operator != (const Vector2& lhs, const Vector2& rhs)
2763{
2764 return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y);
2765}
2767// Vector3 operators
2768static constexpr Vector3 Vector3Zeros = { 0, 0, 0 };
2769static constexpr Vector3 Vector3Ones = { 1, 1, 1 };
2770static constexpr Vector3 Vector3UnitX = { 1, 0, 0 };
2771static constexpr Vector3 Vector3UnitY = { 0, 1, 0 };
2772static constexpr Vector3 Vector3UnitZ = { 0, 0, 1 };
2774inline Vector3 operator + (const Vector3& lhs, const Vector3& rhs)
2775{
2776 return Vector3Add(lhs, rhs);
2777}
2779inline const Vector3& operator += (Vector3& lhs, const Vector3& rhs)
2780{
2781 lhs = Vector3Add(lhs, rhs);
2782 return lhs;
2783}
2785inline Vector3 operator - (const Vector3& lhs, const Vector3& rhs)
2786{
2787 return Vector3Subtract(lhs, rhs);
2788}
2790inline const Vector3& operator -= (Vector3& lhs, const Vector3& rhs)
2791{
2792 lhs = Vector3Subtract(lhs, rhs);
2793 return lhs;
2794}
2796inline Vector3 operator * (const Vector3& lhs, const float& rhs)
2797{
2798 return Vector3Scale(lhs, rhs);
2799}
2801inline const Vector3& operator *= (Vector3& lhs, const float& rhs)
2802{
2803 lhs = Vector3Scale(lhs, rhs);
2804 return lhs;
2805}
2807inline Vector3 operator * (const Vector3& lhs, const Vector3& rhs)
2808{
2809 return Vector3Multiply(lhs, rhs);
2810}
2812inline const Vector3& operator *= (Vector3& lhs, const Vector3& rhs)
2813{
2814 lhs = Vector3Multiply(lhs, rhs);
2815 return lhs;
2816}
2818inline Vector3 operator * (const Vector3& lhs, const Matrix& rhs)
2819{
2820 return Vector3Transform(lhs, rhs);
2821}
2823inline const Vector3& operator *= (Vector3& lhs, const Matrix& rhs)
2824{
2825 lhs = Vector3Transform(lhs, rhs);
2826 return lhs;
2827}
2829inline Vector3 operator / (const Vector3& lhs, const float& rhs)
2830{
2831 return Vector3Scale(lhs, 1.0f/rhs);
2832}
2834inline const Vector3& operator /= (Vector3& lhs, const float& rhs)
2835{
2836 lhs = Vector3Scale(lhs, 1.0f/rhs);
2837 return lhs;
2838}
2840inline Vector3 operator / (const Vector3& lhs, const Vector3& rhs)
2841{
2842 return Vector3Divide(lhs, rhs);
2843}
2845inline const Vector3& operator /= (Vector3& lhs, const Vector3& rhs)
2846{
2847 lhs = Vector3Divide(lhs, rhs);
2848 return lhs;
2849}
2851inline bool operator == (const Vector3& lhs, const Vector3& rhs)
2852{
2853 return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z);
2854}
2856inline bool operator != (const Vector3& lhs, const Vector3& rhs)
2857{
2858 return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z);
2859}
2861// Vector4 operators
2862static constexpr Vector4 Vector4Zeros = { 0, 0, 0, 0 };
2863static constexpr Vector4 Vector4Ones = { 1, 1, 1, 1 };
2864static constexpr Vector4 Vector4UnitX = { 1, 0, 0, 0 };
2865static constexpr Vector4 Vector4UnitY = { 0, 1, 0, 0 };
2866static constexpr Vector4 Vector4UnitZ = { 0, 0, 1, 0 };
2867static constexpr Vector4 Vector4UnitW = { 0, 0, 0, 1 };
2869inline Vector4 operator + (const Vector4& lhs, const Vector4& rhs)
2870{
2871 return Vector4Add(lhs, rhs);
2872}
2874inline const Vector4& operator += (Vector4& lhs, const Vector4& rhs)
2875{
2876 lhs = Vector4Add(lhs, rhs);
2877 return lhs;
2878}
2880inline Vector4 operator - (const Vector4& lhs, const Vector4& rhs)
2881{
2882 return Vector4Subtract(lhs, rhs);
2883}
2885inline const Vector4& operator -= (Vector4& lhs, const Vector4& rhs)
2886{
2887 lhs = Vector4Subtract(lhs, rhs);
2888 return lhs;
2889}
2891inline Vector4 operator * (const Vector4& lhs, const float& rhs)
2892{
2893 return Vector4Scale(lhs, rhs);
2894}
2896inline const Vector4& operator *= (Vector4& lhs, const float& rhs)
2897{
2898 lhs = Vector4Scale(lhs, rhs);
2899 return lhs;
2900}
2902inline Vector4 operator * (const Vector4& lhs, const Vector4& rhs)
2903{
2904 return Vector4Multiply(lhs, rhs);
2905}
2907inline const Vector4& operator *= (Vector4& lhs, const Vector4& rhs)
2908{
2909 lhs = Vector4Multiply(lhs, rhs);
2910 return lhs;
2911}
2913inline Vector4 operator / (const Vector4& lhs, const float& rhs)
2914{
2915 return Vector4Scale(lhs, 1.0f/rhs);
2916}
2918inline const Vector4& operator /= (Vector4& lhs, const float& rhs)
2919{
2920 lhs = Vector4Scale(lhs, 1.0f/rhs);
2921 return lhs;
2922}
2924inline Vector4 operator / (const Vector4& lhs, const Vector4& rhs)
2925{
2926 return Vector4Divide(lhs, rhs);
2927}
2929inline const Vector4& operator /= (Vector4& lhs, const Vector4& rhs)
2930{
2931 lhs = Vector4Divide(lhs, rhs);
2932 return lhs;
2933}
2935inline bool operator == (const Vector4& lhs, const Vector4& rhs)
2936{
2937 return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z) && FloatEquals(lhs.w, rhs.w);
2938}
2940inline bool operator != (const Vector4& lhs, const Vector4& rhs)
2941{
2942 return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z) || !FloatEquals(lhs.w, rhs.w);
2943}
2945// Quaternion operators
2946static constexpr Quaternion QuaternionZeros = { 0, 0, 0, 0 };
2947static constexpr Quaternion QuaternionOnes = { 1, 1, 1, 1 };
2948static constexpr Quaternion QuaternionUnitX = { 0, 0, 0, 1 };
2950inline Quaternion operator + (const Quaternion& lhs, const float& rhs)
2951{
2952 return QuaternionAddValue(lhs, rhs);
2953}
2955inline const Quaternion& operator += (Quaternion& lhs, const float& rhs)
2956{
2957 lhs = QuaternionAddValue(lhs, rhs);
2958 return lhs;
2959}
2961inline Quaternion operator - (const Quaternion& lhs, const float& rhs)
2962{
2963 return QuaternionSubtractValue(lhs, rhs);
2964}
2966inline const Quaternion& operator -= (Quaternion& lhs, const float& rhs)
2967{
2968 lhs = QuaternionSubtractValue(lhs, rhs);
2969 return lhs;
2970}
2972inline Quaternion operator * (const Quaternion& lhs, const Matrix& rhs)
2973{
2974 return QuaternionTransform(lhs, rhs);
2975}
2977inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs)
2978{
2979 lhs = QuaternionTransform(lhs, rhs);
2980 return lhs;
2981}
2983// Matrix operators
2984inline Matrix operator + (const Matrix& lhs, const Matrix& rhs)
2985{
2986 return MatrixAdd(lhs, rhs);
2987}
2989inline const Matrix& operator += (Matrix& lhs, const Matrix& rhs)
2990{
2991 lhs = MatrixAdd(lhs, rhs);
2992 return lhs;
2993}
2995inline Matrix operator - (const Matrix& lhs, const Matrix& rhs)
2996{
2997 return MatrixSubtract(lhs, rhs);
2998}
3000inline const Matrix& operator -= (Matrix& lhs, const Matrix& rhs)
3001{
3002 lhs = MatrixSubtract(lhs, rhs);
3003 return lhs;
3004}
3006inline Matrix operator * (const Matrix& lhs, const Matrix& rhs)
3007{
3008 return MatrixMultiply(lhs, rhs);
3009}
3011inline const Matrix& operator *= (Matrix& lhs, const Matrix& rhs)
3012{
3013 lhs = MatrixMultiply(lhs, rhs);
3014 return lhs;
3015}
3016//-------------------------------------------------------------------------------
3017#endif // C++ operators
3019#endif // RAYMATH_H
index : raylib-jai
---