A retro platform game
git clone git://soophie.de/freezo
blob: 15e403cbba2f9860d37f74479e5e67e9b116304a (63013 bytes)[raw]
1
/**********************************************************************************************2
*3
* raymath v1.5 - Math functions to work with Vector2, Vector3, Matrix and Quaternions4
*5
* CONVENTIONS:6
* - Matrix structure is defined as row-major (memory layout) but parameters naming AND all7
* math operations performed by the library consider the structure as it was column-major8
* It is like transposed versions of the matrices are used for all the maths9
* It benefits some functions making them cache-friendly and also avoids matrix10
* transpositions sometimes required by OpenGL11
* Example: In memory order, row0 is [m0 m4 m8 m12] but in semantic math row0 is [m0 m1 m2 m3]12
* - Functions are always self-contained, no function use another raymath function inside,13
* required code is directly re-implemented inside14
* - Functions input parameters are always received by value (2 unavoidable exceptions)15
* - Functions use always a "result" variable for return16
* - Functions are always defined inline17
* - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience)18
* - No compound literals used to make sure libray is compatible with C++19
*20
* CONFIGURATION:21
* #define RAYMATH_IMPLEMENTATION22
* Generates the implementation of the library into the included file.23
* If not defined, the library is in header only mode and can be included in other headers24
* or source files without problems. But only ONE file should hold the implementation.25
*26
* #define RAYMATH_STATIC_INLINE27
* Define static inline functions code, so #include header suffices for use.28
* This may use up lots of memory.29
*30
*31
* LICENSE: zlib/libpng32
*33
* Copyright (c) 2015-2024 Ramon Santamaria (@raysan5)34
*35
* This software is provided "as-is", without any express or implied warranty. In no event36
* will the authors be held liable for any damages arising from the use of this software.37
*38
* Permission is granted to anyone to use this software for any purpose, including commercial39
* applications, and to alter it and redistribute it freely, subject to the following restrictions:40
*41
* 1. The origin of this software must not be misrepresented; you must not claim that you42
* wrote the original software. If you use this software in a product, an acknowledgment43
* in the product documentation would be appreciated but is not required.44
*45
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented46
* as being the original software.47
*48
* 3. This notice may not be removed or altered from any source distribution.49
*50
**********************************************************************************************/52
#ifndef RAYMATH_H53
#define RAYMATH_H55
#if defined(RAYMATH_IMPLEMENTATION) && defined(RAYMATH_STATIC_INLINE)56
#error "Specifying both RAYMATH_IMPLEMENTATION and RAYMATH_STATIC_INLINE is contradictory"57
#endif59
// Function specifiers definition60
#if defined(RAYMATH_IMPLEMENTATION)61
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)62
#define RMAPI __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll)63
#elif defined(BUILD_LIBTYPE_SHARED)64
#define RMAPI __attribute__((visibility("default"))) // We are building raylib as a Unix shared library (.so/.dylib)65
#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)66
#define RMAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)67
#else68
#define RMAPI extern inline // Provide external definition69
#endif70
#elif defined(RAYMATH_STATIC_INLINE)71
#define RMAPI static inline // Functions may be inlined, no external out-of-line definition72
#else73
#if defined(__TINYC__)74
#define RMAPI static inline // plain inline not supported by tinycc (See issue #435)75
#else76
#define RMAPI inline // Functions may be inlined or external definition used77
#endif78
#endif80
//----------------------------------------------------------------------------------81
// Defines and Macros82
//----------------------------------------------------------------------------------83
#ifndef PI84
#define PI 3.14159265358979323846f85
#endif87
#ifndef EPSILON88
#define EPSILON 0.000001f89
#endif91
#ifndef DEG2RAD92
#define DEG2RAD (PI/180.0f)93
#endif95
#ifndef RAD2DEG96
#define RAD2DEG (180.0f/PI)97
#endif99
// Get float vector for Matrix100
#ifndef MatrixToFloat101
#define MatrixToFloat(mat) (MatrixToFloatV(mat).v)102
#endif104
// Get float vector for Vector3105
#ifndef Vector3ToFloat106
#define Vector3ToFloat(vec) (Vector3ToFloatV(vec).v)107
#endif109
//----------------------------------------------------------------------------------110
// Types and Structures Definition111
//----------------------------------------------------------------------------------112
#if !defined(RL_VECTOR2_TYPE)113
// Vector2 type114
typedef struct Vector2 {115
float x;116
float y;117
} Vector2;118
#define RL_VECTOR2_TYPE119
#endif121
#if !defined(RL_VECTOR3_TYPE)122
// Vector3 type123
typedef struct Vector3 {124
float x;125
float y;126
float z;127
} Vector3;128
#define RL_VECTOR3_TYPE129
#endif131
#if !defined(RL_VECTOR4_TYPE)132
// Vector4 type133
typedef struct Vector4 {134
float x;135
float y;136
float z;137
float w;138
} Vector4;139
#define RL_VECTOR4_TYPE140
#endif142
#if !defined(RL_QUATERNION_TYPE)143
// Quaternion type144
typedef Vector4 Quaternion;145
#define RL_QUATERNION_TYPE146
#endif148
#if !defined(RL_MATRIX_TYPE)149
// Matrix type (OpenGL style 4x4 - right handed, column major)150
typedef struct Matrix {151
float m0, m4, m8, m12; // Matrix first row (4 components)152
float m1, m5, m9, m13; // Matrix second row (4 components)153
float m2, m6, m10, m14; // Matrix third row (4 components)154
float m3, m7, m11, m15; // Matrix fourth row (4 components)155
} Matrix;156
#define RL_MATRIX_TYPE157
#endif159
// NOTE: Helper types to be used instead of array return types for *ToFloat functions160
typedef struct float3 {161
float v[3];162
} float3;164
typedef struct float16 {165
float v[16];166
} float16;168
#include <math.h> // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabsf()170
//----------------------------------------------------------------------------------171
// Module Functions Definition - Utils math172
//----------------------------------------------------------------------------------174
// Clamp float value175
RMAPI float Clamp(float value, float min, float max)176
{177
float result = (value < min) ? min : value;179
if (result > max) result = max;181
return result;182
}184
// Calculate linear interpolation between two floats185
RMAPI float Lerp(float start, float end, float amount)186
{187
float result = start + amount*(end - start);189
return result;190
}192
// Normalize input value within input range193
RMAPI float Normalize(float value, float start, float end)194
{195
float result = (value - start)/(end - start);197
return result;198
}200
// Remap input value within input range to output range201
RMAPI float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd)202
{203
float result = (value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart;205
return result;206
}208
// Wrap input value from min to max209
RMAPI float Wrap(float value, float min, float max)210
{211
float result = value - (max - min)*floorf((value - min)/(max - min));213
return result;214
}216
// Check whether two given floats are almost equal217
RMAPI int FloatEquals(float x, float y)218
{219
#if !defined(EPSILON)220
#define EPSILON 0.000001f221
#endif223
int result = (fabsf(x - y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(x), fabsf(y))));225
return result;226
}228
//----------------------------------------------------------------------------------229
// Module Functions Definition - Vector2 math230
//----------------------------------------------------------------------------------232
// Vector with components value 0.0f233
RMAPI Vector2 Vector2Zero(void)234
{235
Vector2 result = { 0.0f, 0.0f };237
return result;238
}240
// Vector with components value 1.0f241
RMAPI Vector2 Vector2One(void)242
{243
Vector2 result = { 1.0f, 1.0f };245
return result;246
}248
// Add two vectors (v1 + v2)249
RMAPI Vector2 Vector2Add(Vector2 v1, Vector2 v2)250
{251
Vector2 result = { v1.x + v2.x, v1.y + v2.y };253
return result;254
}256
// Add vector and float value257
RMAPI Vector2 Vector2AddValue(Vector2 v, float add)258
{259
Vector2 result = { v.x + add, v.y + add };261
return result;262
}264
// Subtract two vectors (v1 - v2)265
RMAPI Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)266
{267
Vector2 result = { v1.x - v2.x, v1.y - v2.y };269
return result;270
}272
// Subtract vector by float value273
RMAPI Vector2 Vector2SubtractValue(Vector2 v, float sub)274
{275
Vector2 result = { v.x - sub, v.y - sub };277
return result;278
}280
// Calculate vector length281
RMAPI float Vector2Length(Vector2 v)282
{283
float result = sqrtf((v.x*v.x) + (v.y*v.y));285
return result;286
}288
// Calculate vector square length289
RMAPI float Vector2LengthSqr(Vector2 v)290
{291
float result = (v.x*v.x) + (v.y*v.y);293
return result;294
}296
// Calculate two vectors dot product297
RMAPI float Vector2DotProduct(Vector2 v1, Vector2 v2)298
{299
float result = (v1.x*v2.x + v1.y*v2.y);301
return result;302
}304
// Calculate distance between two vectors305
RMAPI float Vector2Distance(Vector2 v1, Vector2 v2)306
{307
float result = sqrtf((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y));309
return result;310
}312
// Calculate square distance between two vectors313
RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2)314
{315
float result = ((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y));317
return result;318
}320
// Calculate angle between two vectors321
// NOTE: Angle is calculated from origin point (0, 0)322
RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)323
{324
float result = 0.0f;326
float dot = v1.x*v2.x + v1.y*v2.y;327
float det = v1.x*v2.y - v1.y*v2.x;329
result = atan2f(det, dot);331
return result;332
}334
// Calculate angle defined by a two vectors line335
// NOTE: Parameters need to be normalized336
// Current implementation should be aligned with glm::angle337
RMAPI float Vector2LineAngle(Vector2 start, Vector2 end)338
{339
float result = 0.0f;341
// TODO(10/9/2023): Currently angles move clockwise, determine if this is wanted behavior342
result = -atan2f(end.y - start.y, end.x - start.x);344
return result;345
}347
// Scale vector (multiply by value)348
RMAPI Vector2 Vector2Scale(Vector2 v, float scale)349
{350
Vector2 result = { v.x*scale, v.y*scale };352
return result;353
}355
// Multiply vector by vector356
RMAPI Vector2 Vector2Multiply(Vector2 v1, Vector2 v2)357
{358
Vector2 result = { v1.x*v2.x, v1.y*v2.y };360
return result;361
}363
// Negate vector364
RMAPI Vector2 Vector2Negate(Vector2 v)365
{366
Vector2 result = { -v.x, -v.y };368
return result;369
}371
// Divide vector by vector372
RMAPI Vector2 Vector2Divide(Vector2 v1, Vector2 v2)373
{374
Vector2 result = { v1.x/v2.x, v1.y/v2.y };376
return result;377
}379
// Normalize provided vector380
RMAPI Vector2 Vector2Normalize(Vector2 v)381
{382
Vector2 result = { 0 };383
float length = sqrtf((v.x*v.x) + (v.y*v.y));385
if (length > 0)386
{387
float ilength = 1.0f/length;388
result.x = v.x*ilength;389
result.y = v.y*ilength;390
}392
return result;393
}395
// Transforms a Vector2 by a given Matrix396
RMAPI Vector2 Vector2Transform(Vector2 v, Matrix mat)397
{398
Vector2 result = { 0 };400
float x = v.x;401
float y = v.y;402
float z = 0;404
result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12;405
result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13;407
return result;408
}410
// Calculate linear interpolation between two vectors411
RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount)412
{413
Vector2 result = { 0 };415
result.x = v1.x + amount*(v2.x - v1.x);416
result.y = v1.y + amount*(v2.y - v1.y);418
return result;419
}421
// Calculate reflected vector to normal422
RMAPI Vector2 Vector2Reflect(Vector2 v, Vector2 normal)423
{424
Vector2 result = { 0 };426
float dotProduct = (v.x*normal.x + v.y*normal.y); // Dot product428
result.x = v.x - (2.0f*normal.x)*dotProduct;429
result.y = v.y - (2.0f*normal.y)*dotProduct;431
return result;432
}434
// Rotate vector by angle435
RMAPI Vector2 Vector2Rotate(Vector2 v, float angle)436
{437
Vector2 result = { 0 };439
float cosres = cosf(angle);440
float sinres = sinf(angle);442
result.x = v.x*cosres - v.y*sinres;443
result.y = v.x*sinres + v.y*cosres;445
return result;446
}448
// Move Vector towards target449
RMAPI Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance)450
{451
Vector2 result = { 0 };453
float dx = target.x - v.x;454
float dy = target.y - v.y;455
float value = (dx*dx) + (dy*dy);457
if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target;459
float dist = sqrtf(value);461
result.x = v.x + dx/dist*maxDistance;462
result.y = v.y + dy/dist*maxDistance;464
return result;465
}467
// Invert the given vector468
RMAPI Vector2 Vector2Invert(Vector2 v)469
{470
Vector2 result = { 1.0f/v.x, 1.0f/v.y };472
return result;473
}475
// Clamp the components of the vector between476
// min and max values specified by the given vectors477
RMAPI Vector2 Vector2Clamp(Vector2 v, Vector2 min, Vector2 max)478
{479
Vector2 result = { 0 };481
result.x = fminf(max.x, fmaxf(min.x, v.x));482
result.y = fminf(max.y, fmaxf(min.y, v.y));484
return result;485
}487
// Clamp the magnitude of the vector between two min and max values488
RMAPI Vector2 Vector2ClampValue(Vector2 v, float min, float max)489
{490
Vector2 result = v;492
float length = (v.x*v.x) + (v.y*v.y);493
if (length > 0.0f)494
{495
length = sqrtf(length);497
float scale = 1; // By default, 1 as the neutral element.498
if (length < min)499
{500
scale = min/length;501
}502
else if (length > max)503
{504
scale = max/length;505
}507
result.x = v.x*scale;508
result.y = v.y*scale;509
}511
return result;512
}514
// Check whether two given vectors are almost equal515
RMAPI int Vector2Equals(Vector2 p, Vector2 q)516
{517
#if !defined(EPSILON)518
#define EPSILON 0.000001f519
#endif521
int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) &&522
((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y)))));524
return result;525
}527
//----------------------------------------------------------------------------------528
// Module Functions Definition - Vector3 math529
//----------------------------------------------------------------------------------531
// Vector with components value 0.0f532
RMAPI Vector3 Vector3Zero(void)533
{534
Vector3 result = { 0.0f, 0.0f, 0.0f };536
return result;537
}539
// Vector with components value 1.0f540
RMAPI Vector3 Vector3One(void)541
{542
Vector3 result = { 1.0f, 1.0f, 1.0f };544
return result;545
}547
// Add two vectors548
RMAPI Vector3 Vector3Add(Vector3 v1, Vector3 v2)549
{550
Vector3 result = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };552
return result;553
}555
// Add vector and float value556
RMAPI Vector3 Vector3AddValue(Vector3 v, float add)557
{558
Vector3 result = { v.x + add, v.y + add, v.z + add };560
return result;561
}563
// Subtract two vectors564
RMAPI Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)565
{566
Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };568
return result;569
}571
// Subtract vector by float value572
RMAPI Vector3 Vector3SubtractValue(Vector3 v, float sub)573
{574
Vector3 result = { v.x - sub, v.y - sub, v.z - sub };576
return result;577
}579
// Multiply vector by scalar580
RMAPI Vector3 Vector3Scale(Vector3 v, float scalar)581
{582
Vector3 result = { v.x*scalar, v.y*scalar, v.z*scalar };584
return result;585
}587
// Multiply vector by vector588
RMAPI Vector3 Vector3Multiply(Vector3 v1, Vector3 v2)589
{590
Vector3 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z };592
return result;593
}595
// Calculate two vectors cross product596
RMAPI Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2)597
{598
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 };600
return result;601
}603
// Calculate one vector perpendicular vector604
RMAPI Vector3 Vector3Perpendicular(Vector3 v)605
{606
Vector3 result = { 0 };608
float min = fabsf(v.x);609
Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f};611
if (fabsf(v.y) < min)612
{613
min = fabsf(v.y);614
Vector3 tmp = {0.0f, 1.0f, 0.0f};615
cardinalAxis = tmp;616
}618
if (fabsf(v.z) < min)619
{620
Vector3 tmp = {0.0f, 0.0f, 1.0f};621
cardinalAxis = tmp;622
}624
// Cross product between vectors625
result.x = v.y*cardinalAxis.z - v.z*cardinalAxis.y;626
result.y = v.z*cardinalAxis.x - v.x*cardinalAxis.z;627
result.z = v.x*cardinalAxis.y - v.y*cardinalAxis.x;629
return result;630
}632
// Calculate vector length633
RMAPI float Vector3Length(const Vector3 v)634
{635
float result = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);637
return result;638
}640
// Calculate vector square length641
RMAPI float Vector3LengthSqr(const Vector3 v)642
{643
float result = v.x*v.x + v.y*v.y + v.z*v.z;645
return result;646
}648
// Calculate two vectors dot product649
RMAPI float Vector3DotProduct(Vector3 v1, Vector3 v2)650
{651
float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);653
return result;654
}656
// Calculate distance between two vectors657
RMAPI float Vector3Distance(Vector3 v1, Vector3 v2)658
{659
float result = 0.0f;661
float dx = v2.x - v1.x;662
float dy = v2.y - v1.y;663
float dz = v2.z - v1.z;664
result = sqrtf(dx*dx + dy*dy + dz*dz);666
return result;667
}669
// Calculate square distance between two vectors670
RMAPI float Vector3DistanceSqr(Vector3 v1, Vector3 v2)671
{672
float result = 0.0f;674
float dx = v2.x - v1.x;675
float dy = v2.y - v1.y;676
float dz = v2.z - v1.z;677
result = dx*dx + dy*dy + dz*dz;679
return result;680
}682
// Calculate angle between two vectors683
RMAPI float Vector3Angle(Vector3 v1, Vector3 v2)684
{685
float result = 0.0f;687
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 };688
float len = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z);689
float dot = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);690
result = atan2f(len, dot);692
return result;693
}695
// Negate provided vector (invert direction)696
RMAPI Vector3 Vector3Negate(Vector3 v)697
{698
Vector3 result = { -v.x, -v.y, -v.z };700
return result;701
}703
// Divide vector by vector704
RMAPI Vector3 Vector3Divide(Vector3 v1, Vector3 v2)705
{706
Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z };708
return result;709
}711
// Normalize provided vector712
RMAPI Vector3 Vector3Normalize(Vector3 v)713
{714
Vector3 result = v;716
float length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);717
if (length != 0.0f)718
{719
float ilength = 1.0f/length;721
result.x *= ilength;722
result.y *= ilength;723
result.z *= ilength;724
}726
return result;727
}729
//Calculate the projection of the vector v1 on to v2730
RMAPI Vector3 Vector3Project(Vector3 v1, Vector3 v2)731
{732
Vector3 result = { 0 };734
float v1dv2 = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);735
float v2dv2 = (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z);737
float mag = v1dv2/v2dv2;739
result.x = v2.x*mag;740
result.y = v2.y*mag;741
result.z = v2.z*mag;743
return result;744
}746
//Calculate the rejection of the vector v1 on to v2747
RMAPI Vector3 Vector3Reject(Vector3 v1, Vector3 v2)748
{749
Vector3 result = { 0 };751
float v1dv2 = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);752
float v2dv2 = (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z);754
float mag = v1dv2/v2dv2;756
result.x = v1.x - (v2.x*mag);757
result.y = v1.y - (v2.y*mag);758
result.z = v1.z - (v2.z*mag);760
return result;761
}763
// Orthonormalize provided vectors764
// Makes vectors normalized and orthogonal to each other765
// Gram-Schmidt function implementation766
RMAPI void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2)767
{768
float length = 0.0f;769
float ilength = 0.0f;771
// Vector3Normalize(*v1);772
Vector3 v = *v1;773
length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);774
if (length == 0.0f) length = 1.0f;775
ilength = 1.0f/length;776
v1->x *= ilength;777
v1->y *= ilength;778
v1->z *= ilength;780
// Vector3CrossProduct(*v1, *v2)781
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 };783
// Vector3Normalize(vn1);784
v = vn1;785
length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);786
if (length == 0.0f) length = 1.0f;787
ilength = 1.0f/length;788
vn1.x *= ilength;789
vn1.y *= ilength;790
vn1.z *= ilength;792
// Vector3CrossProduct(vn1, *v1)793
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 };795
*v2 = vn2;796
}798
// Transforms a Vector3 by a given Matrix799
RMAPI Vector3 Vector3Transform(Vector3 v, Matrix mat)800
{801
Vector3 result = { 0 };803
float x = v.x;804
float y = v.y;805
float z = v.z;807
result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12;808
result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13;809
result.z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14;811
return result;812
}814
// Transform a vector by quaternion rotation815
RMAPI Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q)816
{817
Vector3 result = { 0 };819
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);820
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);821
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);823
return result;824
}826
// Rotates a vector around an axis827
RMAPI Vector3 Vector3RotateByAxisAngle(Vector3 v, Vector3 axis, float angle)828
{829
// Using Euler-Rodrigues Formula830
// Ref.: https://en.wikipedia.org/w/index.php?title=Euler%E2%80%93Rodrigues_formula832
Vector3 result = v;834
// Vector3Normalize(axis);835
float length = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);836
if (length == 0.0f) length = 1.0f;837
float ilength = 1.0f/length;838
axis.x *= ilength;839
axis.y *= ilength;840
axis.z *= ilength;842
angle /= 2.0f;843
float a = sinf(angle);844
float b = axis.x*a;845
float c = axis.y*a;846
float d = axis.z*a;847
a = cosf(angle);848
Vector3 w = { b, c, d };850
// Vector3CrossProduct(w, v)851
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 };853
// Vector3CrossProduct(w, wv)854
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 };856
// Vector3Scale(wv, 2*a)857
a *= 2;858
wv.x *= a;859
wv.y *= a;860
wv.z *= a;862
// Vector3Scale(wwv, 2)863
wwv.x *= 2;864
wwv.y *= 2;865
wwv.z *= 2;867
result.x += wv.x;868
result.y += wv.y;869
result.z += wv.z;871
result.x += wwv.x;872
result.y += wwv.y;873
result.z += wwv.z;875
return result;876
}878
// Calculate linear interpolation between two vectors879
RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount)880
{881
Vector3 result = { 0 };883
result.x = v1.x + amount*(v2.x - v1.x);884
result.y = v1.y + amount*(v2.y - v1.y);885
result.z = v1.z + amount*(v2.z - v1.z);887
return result;888
}890
// Calculate reflected vector to normal891
RMAPI Vector3 Vector3Reflect(Vector3 v, Vector3 normal)892
{893
Vector3 result = { 0 };895
// I is the original vector896
// N is the normal of the incident plane897
// R = I - (2*N*(DotProduct[I, N]))899
float dotProduct = (v.x*normal.x + v.y*normal.y + v.z*normal.z);901
result.x = v.x - (2.0f*normal.x)*dotProduct;902
result.y = v.y - (2.0f*normal.y)*dotProduct;903
result.z = v.z - (2.0f*normal.z)*dotProduct;905
return result;906
}908
// Get min value for each pair of components909
RMAPI Vector3 Vector3Min(Vector3 v1, Vector3 v2)910
{911
Vector3 result = { 0 };913
result.x = fminf(v1.x, v2.x);914
result.y = fminf(v1.y, v2.y);915
result.z = fminf(v1.z, v2.z);917
return result;918
}920
// Get max value for each pair of components921
RMAPI Vector3 Vector3Max(Vector3 v1, Vector3 v2)922
{923
Vector3 result = { 0 };925
result.x = fmaxf(v1.x, v2.x);926
result.y = fmaxf(v1.y, v2.y);927
result.z = fmaxf(v1.z, v2.z);929
return result;930
}932
// Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c)933
// NOTE: Assumes P is on the plane of the triangle934
RMAPI Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)935
{936
Vector3 result = { 0 };938
Vector3 v0 = { b.x - a.x, b.y - a.y, b.z - a.z }; // Vector3Subtract(b, a)939
Vector3 v1 = { c.x - a.x, c.y - a.y, c.z - a.z }; // Vector3Subtract(c, a)940
Vector3 v2 = { p.x - a.x, p.y - a.y, p.z - a.z }; // Vector3Subtract(p, a)941
float d00 = (v0.x*v0.x + v0.y*v0.y + v0.z*v0.z); // Vector3DotProduct(v0, v0)942
float d01 = (v0.x*v1.x + v0.y*v1.y + v0.z*v1.z); // Vector3DotProduct(v0, v1)943
float d11 = (v1.x*v1.x + v1.y*v1.y + v1.z*v1.z); // Vector3DotProduct(v1, v1)944
float d20 = (v2.x*v0.x + v2.y*v0.y + v2.z*v0.z); // Vector3DotProduct(v2, v0)945
float d21 = (v2.x*v1.x + v2.y*v1.y + v2.z*v1.z); // Vector3DotProduct(v2, v1)947
float denom = d00*d11 - d01*d01;949
result.y = (d11*d20 - d01*d21)/denom;950
result.z = (d00*d21 - d01*d20)/denom;951
result.x = 1.0f - (result.z + result.y);953
return result;954
}956
// Projects a Vector3 from screen space into object space957
// NOTE: We are avoiding calling other raymath functions despite available958
RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)959
{960
Vector3 result = { 0 };962
// Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it963
Matrix matViewProj = { // MatrixMultiply(view, projection);964
view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12,965
view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13,966
view.m0*projection.m2 + view.m1*projection.m6 + view.m2*projection.m10 + view.m3*projection.m14,967
view.m0*projection.m3 + view.m1*projection.m7 + view.m2*projection.m11 + view.m3*projection.m15,968
view.m4*projection.m0 + view.m5*projection.m4 + view.m6*projection.m8 + view.m7*projection.m12,969
view.m4*projection.m1 + view.m5*projection.m5 + view.m6*projection.m9 + view.m7*projection.m13,970
view.m4*projection.m2 + view.m5*projection.m6 + view.m6*projection.m10 + view.m7*projection.m14,971
view.m4*projection.m3 + view.m5*projection.m7 + view.m6*projection.m11 + view.m7*projection.m15,972
view.m8*projection.m0 + view.m9*projection.m4 + view.m10*projection.m8 + view.m11*projection.m12,973
view.m8*projection.m1 + view.m9*projection.m5 + view.m10*projection.m9 + view.m11*projection.m13,974
view.m8*projection.m2 + view.m9*projection.m6 + view.m10*projection.m10 + view.m11*projection.m14,975
view.m8*projection.m3 + view.m9*projection.m7 + view.m10*projection.m11 + view.m11*projection.m15,976
view.m12*projection.m0 + view.m13*projection.m4 + view.m14*projection.m8 + view.m15*projection.m12,977
view.m12*projection.m1 + view.m13*projection.m5 + view.m14*projection.m9 + view.m15*projection.m13,978
view.m12*projection.m2 + view.m13*projection.m6 + view.m14*projection.m10 + view.m15*projection.m14,979
view.m12*projection.m3 + view.m13*projection.m7 + view.m14*projection.m11 + view.m15*projection.m15 };981
// Calculate inverted matrix -> MatrixInvert(matViewProj);982
// Cache the matrix values (speed optimization)983
float a00 = matViewProj.m0, a01 = matViewProj.m1, a02 = matViewProj.m2, a03 = matViewProj.m3;984
float a10 = matViewProj.m4, a11 = matViewProj.m5, a12 = matViewProj.m6, a13 = matViewProj.m7;985
float a20 = matViewProj.m8, a21 = matViewProj.m9, a22 = matViewProj.m10, a23 = matViewProj.m11;986
float a30 = matViewProj.m12, a31 = matViewProj.m13, a32 = matViewProj.m14, a33 = matViewProj.m15;988
float b00 = a00*a11 - a01*a10;989
float b01 = a00*a12 - a02*a10;990
float b02 = a00*a13 - a03*a10;991
float b03 = a01*a12 - a02*a11;992
float b04 = a01*a13 - a03*a11;993
float b05 = a02*a13 - a03*a12;994
float b06 = a20*a31 - a21*a30;995
float b07 = a20*a32 - a22*a30;996
float b08 = a20*a33 - a23*a30;997
float b09 = a21*a32 - a22*a31;998
float b10 = a21*a33 - a23*a31;999
float b11 = a22*a33 - a23*a32;1001
// Calculate the invert determinant (inlined to avoid double-caching)1002
float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);1004
Matrix matViewProjInv = {1005
(a11*b11 - a12*b10 + a13*b09)*invDet,1006
(-a01*b11 + a02*b10 - a03*b09)*invDet,1007
(a31*b05 - a32*b04 + a33*b03)*invDet,1008
(-a21*b05 + a22*b04 - a23*b03)*invDet,1009
(-a10*b11 + a12*b08 - a13*b07)*invDet,1010
(a00*b11 - a02*b08 + a03*b07)*invDet,1011
(-a30*b05 + a32*b02 - a33*b01)*invDet,1012
(a20*b05 - a22*b02 + a23*b01)*invDet,1013
(a10*b10 - a11*b08 + a13*b06)*invDet,1014
(-a00*b10 + a01*b08 - a03*b06)*invDet,1015
(a30*b04 - a31*b02 + a33*b00)*invDet,1016
(-a20*b04 + a21*b02 - a23*b00)*invDet,1017
(-a10*b09 + a11*b07 - a12*b06)*invDet,1018
(a00*b09 - a01*b07 + a02*b06)*invDet,1019
(-a30*b03 + a31*b01 - a32*b00)*invDet,1020
(a20*b03 - a21*b01 + a22*b00)*invDet };1022
// Create quaternion from source point1023
Quaternion quat = { source.x, source.y, source.z, 1.0f };1025
// Multiply quat point by unprojecte matrix1026
Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv)1027
matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w,1028
matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w,1029
matViewProjInv.m2*quat.x + matViewProjInv.m6*quat.y + matViewProjInv.m10*quat.z + matViewProjInv.m14*quat.w,1030
matViewProjInv.m3*quat.x + matViewProjInv.m7*quat.y + matViewProjInv.m11*quat.z + matViewProjInv.m15*quat.w };1032
// Normalized world points in vectors1033
result.x = qtransformed.x/qtransformed.w;1034
result.y = qtransformed.y/qtransformed.w;1035
result.z = qtransformed.z/qtransformed.w;1037
return result;1038
}1040
// Get Vector3 as float array1041
RMAPI float3 Vector3ToFloatV(Vector3 v)1042
{1043
float3 buffer = { 0 };1045
buffer.v[0] = v.x;1046
buffer.v[1] = v.y;1047
buffer.v[2] = v.z;1049
return buffer;1050
}1052
// Invert the given vector1053
RMAPI Vector3 Vector3Invert(Vector3 v)1054
{1055
Vector3 result = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z };1057
return result;1058
}1060
// Clamp the components of the vector between1061
// min and max values specified by the given vectors1062
RMAPI Vector3 Vector3Clamp(Vector3 v, Vector3 min, Vector3 max)1063
{1064
Vector3 result = { 0 };1066
result.x = fminf(max.x, fmaxf(min.x, v.x));1067
result.y = fminf(max.y, fmaxf(min.y, v.y));1068
result.z = fminf(max.z, fmaxf(min.z, v.z));1070
return result;1071
}1073
// Clamp the magnitude of the vector between two values1074
RMAPI Vector3 Vector3ClampValue(Vector3 v, float min, float max)1075
{1076
Vector3 result = v;1078
float length = (v.x*v.x) + (v.y*v.y) + (v.z*v.z);1079
if (length > 0.0f)1080
{1081
length = sqrtf(length);1083
float scale = 1; // By default, 1 as the neutral element.1084
if (length < min)1085
{1086
scale = min/length;1087
}1088
else if (length > max)1089
{1090
scale = max/length;1091
}1093
result.x = v.x*scale;1094
result.y = v.y*scale;1095
result.z = v.z*scale;1096
}1098
return result;1099
}1101
// Check whether two given vectors are almost equal1102
RMAPI int Vector3Equals(Vector3 p, Vector3 q)1103
{1104
#if !defined(EPSILON)1105
#define EPSILON 0.000001f1106
#endif1108
int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) &&1109
((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) &&1110
((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z)))));1112
return result;1113
}1115
// Compute the direction of a refracted ray1116
// v: normalized direction of the incoming ray1117
// n: normalized normal vector of the interface of two optical media1118
// r: ratio of the refractive index of the medium from where the ray comes1119
// to the refractive index of the medium on the other side of the surface1120
RMAPI Vector3 Vector3Refract(Vector3 v, Vector3 n, float r)1121
{1122
Vector3 result = { 0 };1124
float dot = v.x*n.x + v.y*n.y + v.z*n.z;1125
float d = 1.0f - r*r*(1.0f - dot*dot);1127
if (d >= 0.0f)1128
{1129
d = sqrtf(d);1130
v.x = r*v.x - (r*dot + d)*n.x;1131
v.y = r*v.y - (r*dot + d)*n.y;1132
v.z = r*v.z - (r*dot + d)*n.z;1134
result = v;1135
}1137
return result;1138
}1140
//----------------------------------------------------------------------------------1141
// Module Functions Definition - Matrix math1142
//----------------------------------------------------------------------------------1144
// Compute matrix determinant1145
RMAPI float MatrixDeterminant(Matrix mat)1146
{1147
float result = 0.0f;1149
// Cache the matrix values (speed optimization)1150
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;1151
float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;1152
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;1153
float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;1155
result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +1156
a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +1157
a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +1158
a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +1159
a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +1160
a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;1162
return result;1163
}1165
// Get the trace of the matrix (sum of the values along the diagonal)1166
RMAPI float MatrixTrace(Matrix mat)1167
{1168
float result = (mat.m0 + mat.m5 + mat.m10 + mat.m15);1170
return result;1171
}1173
// Transposes provided matrix1174
RMAPI Matrix MatrixTranspose(Matrix mat)1175
{1176
Matrix result = { 0 };1178
result.m0 = mat.m0;1179
result.m1 = mat.m4;1180
result.m2 = mat.m8;1181
result.m3 = mat.m12;1182
result.m4 = mat.m1;1183
result.m5 = mat.m5;1184
result.m6 = mat.m9;1185
result.m7 = mat.m13;1186
result.m8 = mat.m2;1187
result.m9 = mat.m6;1188
result.m10 = mat.m10;1189
result.m11 = mat.m14;1190
result.m12 = mat.m3;1191
result.m13 = mat.m7;1192
result.m14 = mat.m11;1193
result.m15 = mat.m15;1195
return result;1196
}1198
// Invert provided matrix1199
RMAPI Matrix MatrixInvert(Matrix mat)1200
{1201
Matrix result = { 0 };1203
// Cache the matrix values (speed optimization)1204
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;1205
float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;1206
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;1207
float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;1209
float b00 = a00*a11 - a01*a10;1210
float b01 = a00*a12 - a02*a10;1211
float b02 = a00*a13 - a03*a10;1212
float b03 = a01*a12 - a02*a11;1213
float b04 = a01*a13 - a03*a11;1214
float b05 = a02*a13 - a03*a12;1215
float b06 = a20*a31 - a21*a30;1216
float b07 = a20*a32 - a22*a30;1217
float b08 = a20*a33 - a23*a30;1218
float b09 = a21*a32 - a22*a31;1219
float b10 = a21*a33 - a23*a31;1220
float b11 = a22*a33 - a23*a32;1222
// Calculate the invert determinant (inlined to avoid double-caching)1223
float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);1225
result.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet;1226
result.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet;1227
result.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet;1228
result.m3 = (-a21*b05 + a22*b04 - a23*b03)*invDet;1229
result.m4 = (-a10*b11 + a12*b08 - a13*b07)*invDet;1230
result.m5 = (a00*b11 - a02*b08 + a03*b07)*invDet;1231
result.m6 = (-a30*b05 + a32*b02 - a33*b01)*invDet;1232
result.m7 = (a20*b05 - a22*b02 + a23*b01)*invDet;1233
result.m8 = (a10*b10 - a11*b08 + a13*b06)*invDet;1234
result.m9 = (-a00*b10 + a01*b08 - a03*b06)*invDet;1235
result.m10 = (a30*b04 - a31*b02 + a33*b00)*invDet;1236
result.m11 = (-a20*b04 + a21*b02 - a23*b00)*invDet;1237
result.m12 = (-a10*b09 + a11*b07 - a12*b06)*invDet;1238
result.m13 = (a00*b09 - a01*b07 + a02*b06)*invDet;1239
result.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet;1240
result.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet;1242
return result;1243
}1245
// Get identity matrix1246
RMAPI Matrix MatrixIdentity(void)1247
{1248
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,1249
0.0f, 1.0f, 0.0f, 0.0f,1250
0.0f, 0.0f, 1.0f, 0.0f,1251
0.0f, 0.0f, 0.0f, 1.0f };1253
return result;1254
}1256
// Add two matrices1257
RMAPI Matrix MatrixAdd(Matrix left, Matrix right)1258
{1259
Matrix result = { 0 };1261
result.m0 = left.m0 + right.m0;1262
result.m1 = left.m1 + right.m1;1263
result.m2 = left.m2 + right.m2;1264
result.m3 = left.m3 + right.m3;1265
result.m4 = left.m4 + right.m4;1266
result.m5 = left.m5 + right.m5;1267
result.m6 = left.m6 + right.m6;1268
result.m7 = left.m7 + right.m7;1269
result.m8 = left.m8 + right.m8;1270
result.m9 = left.m9 + right.m9;1271
result.m10 = left.m10 + right.m10;1272
result.m11 = left.m11 + right.m11;1273
result.m12 = left.m12 + right.m12;1274
result.m13 = left.m13 + right.m13;1275
result.m14 = left.m14 + right.m14;1276
result.m15 = left.m15 + right.m15;1278
return result;1279
}1281
// Subtract two matrices (left - right)1282
RMAPI Matrix MatrixSubtract(Matrix left, Matrix right)1283
{1284
Matrix result = { 0 };1286
result.m0 = left.m0 - right.m0;1287
result.m1 = left.m1 - right.m1;1288
result.m2 = left.m2 - right.m2;1289
result.m3 = left.m3 - right.m3;1290
result.m4 = left.m4 - right.m4;1291
result.m5 = left.m5 - right.m5;1292
result.m6 = left.m6 - right.m6;1293
result.m7 = left.m7 - right.m7;1294
result.m8 = left.m8 - right.m8;1295
result.m9 = left.m9 - right.m9;1296
result.m10 = left.m10 - right.m10;1297
result.m11 = left.m11 - right.m11;1298
result.m12 = left.m12 - right.m12;1299
result.m13 = left.m13 - right.m13;1300
result.m14 = left.m14 - right.m14;1301
result.m15 = left.m15 - right.m15;1303
return result;1304
}1306
// Get two matrix multiplication1307
// NOTE: When multiplying matrices... the order matters!1308
RMAPI Matrix MatrixMultiply(Matrix left, Matrix right)1309
{1310
Matrix result = { 0 };1312
result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12;1313
result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13;1314
result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14;1315
result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15;1316
result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12;1317
result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13;1318
result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14;1319
result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15;1320
result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12;1321
result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13;1322
result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14;1323
result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15;1324
result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12;1325
result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13;1326
result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14;1327
result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15;1329
return result;1330
}1332
// Get translation matrix1333
RMAPI Matrix MatrixTranslate(float x, float y, float z)1334
{1335
Matrix result = { 1.0f, 0.0f, 0.0f, x,1336
0.0f, 1.0f, 0.0f, y,1337
0.0f, 0.0f, 1.0f, z,1338
0.0f, 0.0f, 0.0f, 1.0f };1340
return result;1341
}1343
// Create rotation matrix from axis and angle1344
// NOTE: Angle should be provided in radians1345
RMAPI Matrix MatrixRotate(Vector3 axis, float angle)1346
{1347
Matrix result = { 0 };1349
float x = axis.x, y = axis.y, z = axis.z;1351
float lengthSquared = x*x + y*y + z*z;1353
if ((lengthSquared != 1.0f) && (lengthSquared != 0.0f))1354
{1355
float ilength = 1.0f/sqrtf(lengthSquared);1356
x *= ilength;1357
y *= ilength;1358
z *= ilength;1359
}1361
float sinres = sinf(angle);1362
float cosres = cosf(angle);1363
float t = 1.0f - cosres;1365
result.m0 = x*x*t + cosres;1366
result.m1 = y*x*t + z*sinres;1367
result.m2 = z*x*t - y*sinres;1368
result.m3 = 0.0f;1370
result.m4 = x*y*t - z*sinres;1371
result.m5 = y*y*t + cosres;1372
result.m6 = z*y*t + x*sinres;1373
result.m7 = 0.0f;1375
result.m8 = x*z*t + y*sinres;1376
result.m9 = y*z*t - x*sinres;1377
result.m10 = z*z*t + cosres;1378
result.m11 = 0.0f;1380
result.m12 = 0.0f;1381
result.m13 = 0.0f;1382
result.m14 = 0.0f;1383
result.m15 = 1.0f;1385
return result;1386
}1388
// Get x-rotation matrix1389
// NOTE: Angle must be provided in radians1390
RMAPI Matrix MatrixRotateX(float angle)1391
{1392
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,1393
0.0f, 1.0f, 0.0f, 0.0f,1394
0.0f, 0.0f, 1.0f, 0.0f,1395
0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()1397
float cosres = cosf(angle);1398
float sinres = sinf(angle);1400
result.m5 = cosres;1401
result.m6 = sinres;1402
result.m9 = -sinres;1403
result.m10 = cosres;1405
return result;1406
}1408
// Get y-rotation matrix1409
// NOTE: Angle must be provided in radians1410
RMAPI Matrix MatrixRotateY(float angle)1411
{1412
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,1413
0.0f, 1.0f, 0.0f, 0.0f,1414
0.0f, 0.0f, 1.0f, 0.0f,1415
0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()1417
float cosres = cosf(angle);1418
float sinres = sinf(angle);1420
result.m0 = cosres;1421
result.m2 = -sinres;1422
result.m8 = sinres;1423
result.m10 = cosres;1425
return result;1426
}1428
// Get z-rotation matrix1429
// NOTE: Angle must be provided in radians1430
RMAPI Matrix MatrixRotateZ(float angle)1431
{1432
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,1433
0.0f, 1.0f, 0.0f, 0.0f,1434
0.0f, 0.0f, 1.0f, 0.0f,1435
0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()1437
float cosres = cosf(angle);1438
float sinres = sinf(angle);1440
result.m0 = cosres;1441
result.m1 = sinres;1442
result.m4 = -sinres;1443
result.m5 = cosres;1445
return result;1446
}1449
// Get xyz-rotation matrix1450
// NOTE: Angle must be provided in radians1451
RMAPI Matrix MatrixRotateXYZ(Vector3 angle)1452
{1453
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,1454
0.0f, 1.0f, 0.0f, 0.0f,1455
0.0f, 0.0f, 1.0f, 0.0f,1456
0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()1458
float cosz = cosf(-angle.z);1459
float sinz = sinf(-angle.z);1460
float cosy = cosf(-angle.y);1461
float siny = sinf(-angle.y);1462
float cosx = cosf(-angle.x);1463
float sinx = sinf(-angle.x);1465
result.m0 = cosz*cosy;1466
result.m1 = (cosz*siny*sinx) - (sinz*cosx);1467
result.m2 = (cosz*siny*cosx) + (sinz*sinx);1469
result.m4 = sinz*cosy;1470
result.m5 = (sinz*siny*sinx) + (cosz*cosx);1471
result.m6 = (sinz*siny*cosx) - (cosz*sinx);1473
result.m8 = -siny;1474
result.m9 = cosy*sinx;1475
result.m10= cosy*cosx;1477
return result;1478
}1480
// Get zyx-rotation matrix1481
// NOTE: Angle must be provided in radians1482
RMAPI Matrix MatrixRotateZYX(Vector3 angle)1483
{1484
Matrix result = { 0 };1486
float cz = cosf(angle.z);1487
float sz = sinf(angle.z);1488
float cy = cosf(angle.y);1489
float sy = sinf(angle.y);1490
float cx = cosf(angle.x);1491
float sx = sinf(angle.x);1493
result.m0 = cz*cy;1494
result.m4 = cz*sy*sx - cx*sz;1495
result.m8 = sz*sx + cz*cx*sy;1496
result.m12 = 0;1498
result.m1 = cy*sz;1499
result.m5 = cz*cx + sz*sy*sx;1500
result.m9 = cx*sz*sy - cz*sx;1501
result.m13 = 0;1503
result.m2 = -sy;1504
result.m6 = cy*sx;1505
result.m10 = cy*cx;1506
result.m14 = 0;1508
result.m3 = 0;1509
result.m7 = 0;1510
result.m11 = 0;1511
result.m15 = 1;1513
return result;1514
}1516
// Get scaling matrix1517
RMAPI Matrix MatrixScale(float x, float y, float z)1518
{1519
Matrix result = { x, 0.0f, 0.0f, 0.0f,1520
0.0f, y, 0.0f, 0.0f,1521
0.0f, 0.0f, z, 0.0f,1522
0.0f, 0.0f, 0.0f, 1.0f };1524
return result;1525
}1527
// Get perspective projection matrix1528
RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far)1529
{1530
Matrix result = { 0 };1532
float rl = (float)(right - left);1533
float tb = (float)(top - bottom);1534
float fn = (float)(far - near);1536
result.m0 = ((float)near*2.0f)/rl;1537
result.m1 = 0.0f;1538
result.m2 = 0.0f;1539
result.m3 = 0.0f;1541
result.m4 = 0.0f;1542
result.m5 = ((float)near*2.0f)/tb;1543
result.m6 = 0.0f;1544
result.m7 = 0.0f;1546
result.m8 = ((float)right + (float)left)/rl;1547
result.m9 = ((float)top + (float)bottom)/tb;1548
result.m10 = -((float)far + (float)near)/fn;1549
result.m11 = -1.0f;1551
result.m12 = 0.0f;1552
result.m13 = 0.0f;1553
result.m14 = -((float)far*(float)near*2.0f)/fn;1554
result.m15 = 0.0f;1556
return result;1557
}1559
// Get perspective projection matrix1560
// NOTE: Fovy angle must be provided in radians1561
RMAPI Matrix MatrixPerspective(double fovY, double aspect, double nearPlane, double farPlane)1562
{1563
Matrix result = { 0 };1565
double top = nearPlane*tan(fovY*0.5);1566
double bottom = -top;1567
double right = top*aspect;1568
double left = -right;1570
// MatrixFrustum(-right, right, -top, top, near, far);1571
float rl = (float)(right - left);1572
float tb = (float)(top - bottom);1573
float fn = (float)(farPlane - nearPlane);1575
result.m0 = ((float)nearPlane*2.0f)/rl;1576
result.m5 = ((float)nearPlane*2.0f)/tb;1577
result.m8 = ((float)right + (float)left)/rl;1578
result.m9 = ((float)top + (float)bottom)/tb;1579
result.m10 = -((float)farPlane + (float)nearPlane)/fn;1580
result.m11 = -1.0f;1581
result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn;1583
return result;1584
}1586
// Get orthographic projection matrix1587
RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double nearPlane, double farPlane)1588
{1589
Matrix result = { 0 };1591
float rl = (float)(right - left);1592
float tb = (float)(top - bottom);1593
float fn = (float)(farPlane - nearPlane);1595
result.m0 = 2.0f/rl;1596
result.m1 = 0.0f;1597
result.m2 = 0.0f;1598
result.m3 = 0.0f;1599
result.m4 = 0.0f;1600
result.m5 = 2.0f/tb;1601
result.m6 = 0.0f;1602
result.m7 = 0.0f;1603
result.m8 = 0.0f;1604
result.m9 = 0.0f;1605
result.m10 = -2.0f/fn;1606
result.m11 = 0.0f;1607
result.m12 = -((float)left + (float)right)/rl;1608
result.m13 = -((float)top + (float)bottom)/tb;1609
result.m14 = -((float)farPlane + (float)nearPlane)/fn;1610
result.m15 = 1.0f;1612
return result;1613
}1615
// Get camera look-at matrix (view matrix)1616
RMAPI Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)1617
{1618
Matrix result = { 0 };1620
float length = 0.0f;1621
float ilength = 0.0f;1623
// Vector3Subtract(eye, target)1624
Vector3 vz = { eye.x - target.x, eye.y - target.y, eye.z - target.z };1626
// Vector3Normalize(vz)1627
Vector3 v = vz;1628
length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);1629
if (length == 0.0f) length = 1.0f;1630
ilength = 1.0f/length;1631
vz.x *= ilength;1632
vz.y *= ilength;1633
vz.z *= ilength;1635
// Vector3CrossProduct(up, vz)1636
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 };1638
// Vector3Normalize(x)1639
v = vx;1640
length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);1641
if (length == 0.0f) length = 1.0f;1642
ilength = 1.0f/length;1643
vx.x *= ilength;1644
vx.y *= ilength;1645
vx.z *= ilength;1647
// Vector3CrossProduct(vz, vx)1648
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 };1650
result.m0 = vx.x;1651
result.m1 = vy.x;1652
result.m2 = vz.x;1653
result.m3 = 0.0f;1654
result.m4 = vx.y;1655
result.m5 = vy.y;1656
result.m6 = vz.y;1657
result.m7 = 0.0f;1658
result.m8 = vx.z;1659
result.m9 = vy.z;1660
result.m10 = vz.z;1661
result.m11 = 0.0f;1662
result.m12 = -(vx.x*eye.x + vx.y*eye.y + vx.z*eye.z); // Vector3DotProduct(vx, eye)1663
result.m13 = -(vy.x*eye.x + vy.y*eye.y + vy.z*eye.z); // Vector3DotProduct(vy, eye)1664
result.m14 = -(vz.x*eye.x + vz.y*eye.y + vz.z*eye.z); // Vector3DotProduct(vz, eye)1665
result.m15 = 1.0f;1667
return result;1668
}1670
// Get float array of matrix data1671
RMAPI float16 MatrixToFloatV(Matrix mat)1672
{1673
float16 result = { 0 };1675
result.v[0] = mat.m0;1676
result.v[1] = mat.m1;1677
result.v[2] = mat.m2;1678
result.v[3] = mat.m3;1679
result.v[4] = mat.m4;1680
result.v[5] = mat.m5;1681
result.v[6] = mat.m6;1682
result.v[7] = mat.m7;1683
result.v[8] = mat.m8;1684
result.v[9] = mat.m9;1685
result.v[10] = mat.m10;1686
result.v[11] = mat.m11;1687
result.v[12] = mat.m12;1688
result.v[13] = mat.m13;1689
result.v[14] = mat.m14;1690
result.v[15] = mat.m15;1692
return result;1693
}1695
//----------------------------------------------------------------------------------1696
// Module Functions Definition - Quaternion math1697
//----------------------------------------------------------------------------------1699
// Add two quaternions1700
RMAPI Quaternion QuaternionAdd(Quaternion q1, Quaternion q2)1701
{1702
Quaternion result = {q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w};1704
return result;1705
}1707
// Add quaternion and float value1708
RMAPI Quaternion QuaternionAddValue(Quaternion q, float add)1709
{1710
Quaternion result = {q.x + add, q.y + add, q.z + add, q.w + add};1712
return result;1713
}1715
// Subtract two quaternions1716
RMAPI Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2)1717
{1718
Quaternion result = {q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w};1720
return result;1721
}1723
// Subtract quaternion and float value1724
RMAPI Quaternion QuaternionSubtractValue(Quaternion q, float sub)1725
{1726
Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub};1728
return result;1729
}1731
// Get identity quaternion1732
RMAPI Quaternion QuaternionIdentity(void)1733
{1734
Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };1736
return result;1737
}1739
// Computes the length of a quaternion1740
RMAPI float QuaternionLength(Quaternion q)1741
{1742
float result = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);1744
return result;1745
}1747
// Normalize provided quaternion1748
RMAPI Quaternion QuaternionNormalize(Quaternion q)1749
{1750
Quaternion result = { 0 };1752
float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);1753
if (length == 0.0f) length = 1.0f;1754
float ilength = 1.0f/length;1756
result.x = q.x*ilength;1757
result.y = q.y*ilength;1758
result.z = q.z*ilength;1759
result.w = q.w*ilength;1761
return result;1762
}1764
// Invert provided quaternion1765
RMAPI Quaternion QuaternionInvert(Quaternion q)1766
{1767
Quaternion result = q;1769
float lengthSq = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;1771
if (lengthSq != 0.0f)1772
{1773
float invLength = 1.0f/lengthSq;1775
result.x *= -invLength;1776
result.y *= -invLength;1777
result.z *= -invLength;1778
result.w *= invLength;1779
}1781
return result;1782
}1784
// Calculate two quaternion multiplication1785
RMAPI Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)1786
{1787
Quaternion result = { 0 };1789
float qax = q1.x, qay = q1.y, qaz = q1.z, qaw = q1.w;1790
float qbx = q2.x, qby = q2.y, qbz = q2.z, qbw = q2.w;1792
result.x = qax*qbw + qaw*qbx + qay*qbz - qaz*qby;1793
result.y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz;1794
result.z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx;1795
result.w = qaw*qbw - qax*qbx - qay*qby - qaz*qbz;1797
return result;1798
}1800
// Scale quaternion by float value1801
RMAPI Quaternion QuaternionScale(Quaternion q, float mul)1802
{1803
Quaternion result = { 0 };1805
result.x = q.x*mul;1806
result.y = q.y*mul;1807
result.z = q.z*mul;1808
result.w = q.w*mul;1810
return result;1811
}1813
// Divide two quaternions1814
RMAPI Quaternion QuaternionDivide(Quaternion q1, Quaternion q2)1815
{1816
Quaternion result = { q1.x/q2.x, q1.y/q2.y, q1.z/q2.z, q1.w/q2.w };1818
return result;1819
}1821
// Calculate linear interpolation between two quaternions1822
RMAPI Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount)1823
{1824
Quaternion result = { 0 };1826
result.x = q1.x + amount*(q2.x - q1.x);1827
result.y = q1.y + amount*(q2.y - q1.y);1828
result.z = q1.z + amount*(q2.z - q1.z);1829
result.w = q1.w + amount*(q2.w - q1.w);1831
return result;1832
}1834
// Calculate slerp-optimized interpolation between two quaternions1835
RMAPI Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount)1836
{1837
Quaternion result = { 0 };1839
// QuaternionLerp(q1, q2, amount)1840
result.x = q1.x + amount*(q2.x - q1.x);1841
result.y = q1.y + amount*(q2.y - q1.y);1842
result.z = q1.z + amount*(q2.z - q1.z);1843
result.w = q1.w + amount*(q2.w - q1.w);1845
// QuaternionNormalize(q);1846
Quaternion q = result;1847
float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);1848
if (length == 0.0f) length = 1.0f;1849
float ilength = 1.0f/length;1851
result.x = q.x*ilength;1852
result.y = q.y*ilength;1853
result.z = q.z*ilength;1854
result.w = q.w*ilength;1856
return result;1857
}1859
// Calculates spherical linear interpolation between two quaternions1860
RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)1861
{1862
Quaternion result = { 0 };1864
#if !defined(EPSILON)1865
#define EPSILON 0.000001f1866
#endif1868
float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;1870
if (cosHalfTheta < 0)1871
{1872
q2.x = -q2.x; q2.y = -q2.y; q2.z = -q2.z; q2.w = -q2.w;1873
cosHalfTheta = -cosHalfTheta;1874
}1876
if (fabsf(cosHalfTheta) >= 1.0f) result = q1;1877
else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount);1878
else1879
{1880
float halfTheta = acosf(cosHalfTheta);1881
float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta);1883
if (fabsf(sinHalfTheta) < EPSILON)1884
{1885
result.x = (q1.x*0.5f + q2.x*0.5f);1886
result.y = (q1.y*0.5f + q2.y*0.5f);1887
result.z = (q1.z*0.5f + q2.z*0.5f);1888
result.w = (q1.w*0.5f + q2.w*0.5f);1889
}1890
else1891
{1892
float ratioA = sinf((1 - amount)*halfTheta)/sinHalfTheta;1893
float ratioB = sinf(amount*halfTheta)/sinHalfTheta;1895
result.x = (q1.x*ratioA + q2.x*ratioB);1896
result.y = (q1.y*ratioA + q2.y*ratioB);1897
result.z = (q1.z*ratioA + q2.z*ratioB);1898
result.w = (q1.w*ratioA + q2.w*ratioB);1899
}1900
}1902
return result;1903
}1905
// Calculate quaternion based on the rotation from one vector to another1906
RMAPI Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)1907
{1908
Quaternion result = { 0 };1910
float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to)1911
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)1913
result.x = cross.x;1914
result.y = cross.y;1915
result.z = cross.z;1916
result.w = 1.0f + cos2Theta;1918
// QuaternionNormalize(q);1919
// NOTE: Normalize to essentially nlerp the original and identity to 0.51920
Quaternion q = result;1921
float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);1922
if (length == 0.0f) length = 1.0f;1923
float ilength = 1.0f/length;1925
result.x = q.x*ilength;1926
result.y = q.y*ilength;1927
result.z = q.z*ilength;1928
result.w = q.w*ilength;1930
return result;1931
}1933
// Get a quaternion for a given rotation matrix1934
RMAPI Quaternion QuaternionFromMatrix(Matrix mat)1935
{1936
Quaternion result = { 0 };1938
float fourWSquaredMinus1 = mat.m0 + mat.m5 + mat.m10;1939
float fourXSquaredMinus1 = mat.m0 - mat.m5 - mat.m10;1940
float fourYSquaredMinus1 = mat.m5 - mat.m0 - mat.m10;1941
float fourZSquaredMinus1 = mat.m10 - mat.m0 - mat.m5;1943
int biggestIndex = 0;1944
float fourBiggestSquaredMinus1 = fourWSquaredMinus1;1945
if (fourXSquaredMinus1 > fourBiggestSquaredMinus1)1946
{1947
fourBiggestSquaredMinus1 = fourXSquaredMinus1;1948
biggestIndex = 1;1949
}1951
if (fourYSquaredMinus1 > fourBiggestSquaredMinus1)1952
{1953
fourBiggestSquaredMinus1 = fourYSquaredMinus1;1954
biggestIndex = 2;1955
}1957
if (fourZSquaredMinus1 > fourBiggestSquaredMinus1)1958
{1959
fourBiggestSquaredMinus1 = fourZSquaredMinus1;1960
biggestIndex = 3;1961
}1963
float biggestVal = sqrtf(fourBiggestSquaredMinus1 + 1.0f)*0.5f;1964
float mult = 0.25f/biggestVal;1966
switch (biggestIndex)1967
{1968
case 0:1969
result.w = biggestVal;1970
result.x = (mat.m6 - mat.m9)*mult;1971
result.y = (mat.m8 - mat.m2)*mult;1972
result.z = (mat.m1 - mat.m4)*mult;1973
break;1974
case 1:1975
result.x = biggestVal;1976
result.w = (mat.m6 - mat.m9)*mult;1977
result.y = (mat.m1 + mat.m4)*mult;1978
result.z = (mat.m8 + mat.m2)*mult;1979
break;1980
case 2:1981
result.y = biggestVal;1982
result.w = (mat.m8 - mat.m2)*mult;1983
result.x = (mat.m1 + mat.m4)*mult;1984
result.z = (mat.m6 + mat.m9)*mult;1985
break;1986
case 3:1987
result.z = biggestVal;1988
result.w = (mat.m1 - mat.m4)*mult;1989
result.x = (mat.m8 + mat.m2)*mult;1990
result.y = (mat.m6 + mat.m9)*mult;1991
break;1992
}1994
return result;1995
}1997
// Get a matrix for a given quaternion1998
RMAPI Matrix QuaternionToMatrix(Quaternion q)1999
{2000
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,2001
0.0f, 1.0f, 0.0f, 0.0f,2002
0.0f, 0.0f, 1.0f, 0.0f,2003
0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()2005
float a2 = q.x*q.x;2006
float b2 = q.y*q.y;2007
float c2 = q.z*q.z;2008
float ac = q.x*q.z;2009
float ab = q.x*q.y;2010
float bc = q.y*q.z;2011
float ad = q.w*q.x;2012
float bd = q.w*q.y;2013
float cd = q.w*q.z;2015
result.m0 = 1 - 2*(b2 + c2);2016
result.m1 = 2*(ab + cd);2017
result.m2 = 2*(ac - bd);2019
result.m4 = 2*(ab - cd);2020
result.m5 = 1 - 2*(a2 + c2);2021
result.m6 = 2*(bc + ad);2023
result.m8 = 2*(ac + bd);2024
result.m9 = 2*(bc - ad);2025
result.m10 = 1 - 2*(a2 + b2);2027
return result;2028
}2030
// Get rotation quaternion for an angle and axis2031
// NOTE: Angle must be provided in radians2032
RMAPI Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)2033
{2034
Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };2036
float axisLength = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);2038
if (axisLength != 0.0f)2039
{2040
angle *= 0.5f;2042
float length = 0.0f;2043
float ilength = 0.0f;2045
// Vector3Normalize(axis)2046
Vector3 v = axis;2047
length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);2048
if (length == 0.0f) length = 1.0f;2049
ilength = 1.0f/length;2050
axis.x *= ilength;2051
axis.y *= ilength;2052
axis.z *= ilength;2054
float sinres = sinf(angle);2055
float cosres = cosf(angle);2057
result.x = axis.x*sinres;2058
result.y = axis.y*sinres;2059
result.z = axis.z*sinres;2060
result.w = cosres;2062
// QuaternionNormalize(q);2063
Quaternion q = result;2064
length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);2065
if (length == 0.0f) length = 1.0f;2066
ilength = 1.0f/length;2067
result.x = q.x*ilength;2068
result.y = q.y*ilength;2069
result.z = q.z*ilength;2070
result.w = q.w*ilength;2071
}2073
return result;2074
}2076
// Get the rotation angle and axis for a given quaternion2077
RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)2078
{2079
if (fabsf(q.w) > 1.0f)2080
{2081
// QuaternionNormalize(q);2082
float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);2083
if (length == 0.0f) length = 1.0f;2084
float ilength = 1.0f/length;2086
q.x = q.x*ilength;2087
q.y = q.y*ilength;2088
q.z = q.z*ilength;2089
q.w = q.w*ilength;2090
}2092
Vector3 resAxis = { 0.0f, 0.0f, 0.0f };2093
float resAngle = 2.0f*acosf(q.w);2094
float den = sqrtf(1.0f - q.w*q.w);2096
if (den > EPSILON)2097
{2098
resAxis.x = q.x/den;2099
resAxis.y = q.y/den;2100
resAxis.z = q.z/den;2101
}2102
else2103
{2104
// This occurs when the angle is zero.2105
// Not a problem: just set an arbitrary normalized axis.2106
resAxis.x = 1.0f;2107
}2109
*outAxis = resAxis;2110
*outAngle = resAngle;2111
}2113
// Get the quaternion equivalent to Euler angles2114
// NOTE: Rotation order is ZYX2115
RMAPI Quaternion QuaternionFromEuler(float pitch, float yaw, float roll)2116
{2117
Quaternion result = { 0 };2119
float x0 = cosf(pitch*0.5f);2120
float x1 = sinf(pitch*0.5f);2121
float y0 = cosf(yaw*0.5f);2122
float y1 = sinf(yaw*0.5f);2123
float z0 = cosf(roll*0.5f);2124
float z1 = sinf(roll*0.5f);2126
result.x = x1*y0*z0 - x0*y1*z1;2127
result.y = x0*y1*z0 + x1*y0*z1;2128
result.z = x0*y0*z1 - x1*y1*z0;2129
result.w = x0*y0*z0 + x1*y1*z1;2131
return result;2132
}2134
// Get the Euler angles equivalent to quaternion (roll, pitch, yaw)2135
// NOTE: Angles are returned in a Vector3 struct in radians2136
RMAPI Vector3 QuaternionToEuler(Quaternion q)2137
{2138
Vector3 result = { 0 };2140
// Roll (x-axis rotation)2141
float x0 = 2.0f*(q.w*q.x + q.y*q.z);2142
float x1 = 1.0f - 2.0f*(q.x*q.x + q.y*q.y);2143
result.x = atan2f(x0, x1);2145
// Pitch (y-axis rotation)2146
float y0 = 2.0f*(q.w*q.y - q.z*q.x);2147
y0 = y0 > 1.0f ? 1.0f : y0;2148
y0 = y0 < -1.0f ? -1.0f : y0;2149
result.y = asinf(y0);2151
// Yaw (z-axis rotation)2152
float z0 = 2.0f*(q.w*q.z + q.x*q.y);2153
float z1 = 1.0f - 2.0f*(q.y*q.y + q.z*q.z);2154
result.z = atan2f(z0, z1);2156
return result;2157
}2159
// Transform a quaternion given a transformation matrix2160
RMAPI Quaternion QuaternionTransform(Quaternion q, Matrix mat)2161
{2162
Quaternion result = { 0 };2164
result.x = mat.m0*q.x + mat.m4*q.y + mat.m8*q.z + mat.m12*q.w;2165
result.y = mat.m1*q.x + mat.m5*q.y + mat.m9*q.z + mat.m13*q.w;2166
result.z = mat.m2*q.x + mat.m6*q.y + mat.m10*q.z + mat.m14*q.w;2167
result.w = mat.m3*q.x + mat.m7*q.y + mat.m11*q.z + mat.m15*q.w;2169
return result;2170
}2172
// Check whether two given quaternions are almost equal2173
RMAPI int QuaternionEquals(Quaternion p, Quaternion q)2174
{2175
#if !defined(EPSILON)2176
#define EPSILON 0.000001f2177
#endif2179
int result = (((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) &&2180
((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) &&2181
((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) &&2182
((fabsf(p.w - q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w)))))) ||2183
(((fabsf(p.x + q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) &&2184
((fabsf(p.y + q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) &&2185
((fabsf(p.z + q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) &&2186
((fabsf(p.w + q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w))))));2188
return result;2189
}2191
#endif // RAYMATH_H