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