1/*
2 HandmadeMath.h v2.0.0
3
4 This is a single header file with a bunch of useful types and functions for
5 games and graphics. Consider it a lightweight alternative to GLM that works
6 both C and C++.
7
8 =============================================================================
9 CONFIG
10 =============================================================================
11
12 By default, all angles in Handmade Math are specified in radians. However, it
13 can be configured to use degrees or turns instead. Use one of the following
14 defines to specify the default unit for angles:
15
16 #define HANDMADE_MATH_USE_RADIANS
17 #define HANDMADE_MATH_USE_DEGREES
18 #define HANDMADE_MATH_USE_TURNS
19
20 Regardless of the default angle, you can use the following functions to
21 specify an angle in a particular unit:
22
23 HMM_AngleRad(radians)
24 HMM_AngleDeg(degrees)
25 HMM_AngleTurn(turns)
26
27 The definitions of these functions change depending on the default unit.
28
29 -----------------------------------------------------------------------------
30
31 Handmade Math ships with SSE (SIMD) implementations of several common
32 operations. To disable the use of SSE intrinsics, you must define
33 HANDMADE_MATH_NO_SSE before including this file:
34
35 #define HANDMADE_MATH_NO_SSE
36 #include "HandmadeMath.h"
37
38 -----------------------------------------------------------------------------
39
40 To use Handmade Math without the C runtime library, you must provide your own
41 implementations of basic math functions. Otherwise, HandmadeMath.h will use
42 the runtime library implementation of these functions.
43
44 Define HANDMADE_MATH_PROVIDE_MATH_FUNCTIONS and provide your own
45 implementations of HMM_SINF, HMM_COSF, HMM_TANF, HMM_ACOSF, and HMM_SQRTF
46 before including HandmadeMath.h, like so:
47
48 #define HANDMADE_MATH_PROVIDE_MATH_FUNCTIONS
49 #define HMM_SINF MySinF
50 #define HMM_COSF MyCosF
51 #define HMM_TANF MyTanF
52 #define HMM_ACOSF MyACosF
53 #define HMM_SQRTF MySqrtF
54 #include "HandmadeMath.h"
55
56 By default, it is assumed that your math functions take radians. To use
57 different units, you must define HMM_ANGLE_USER_TO_INTERNAL and
58 HMM_ANGLE_INTERNAL_TO_USER. For example, if you want to use degrees in your
59 code but your math functions use turns:
60
61 #define HMM_ANGLE_USER_TO_INTERNAL(a) ((a)*HMM_DegToTurn)
62 #define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_TurnToDeg)
63
64 =============================================================================
65
66 LICENSE
67
68 This software is in the public domain. Where that dedication is not
69 recognized, you are granted a perpetual, irrevocable license to copy,
70 distribute, and modify this file as you see fit.
71
72 =============================================================================
73
74 CREDITS
75
76 Originally written by Zakary Strange.
77
78 Functionality:
79 Zakary Strange (strangezak@protonmail.com && @strangezak)
80 Matt Mascarenhas (@miblo_)
81 Aleph
82 FieryDrake (@fierydrake)
83 Gingerbill (@TheGingerBill)
84 Ben Visness (@bvisness)
85 Trinton Bullard (@Peliex_Dev)
86 @AntonDan
87 Logan Forman (@dev_dwarf)
88
89 Fixes:
90 Jeroen van Rijn (@J_vanRijn)
91 Kiljacken (@Kiljacken)
92 Insofaras (@insofaras)
93 Daniel Gibson (@DanielGibson)
94*/
95
96#ifndef HANDMADE_MATH_H
97#define HANDMADE_MATH_H
98
99// Dummy macros for when test framework is not present.
100#ifndef COVERAGE
101# define COVERAGE(a, b)
102#endif
103
104#ifndef ASSERT_COVERED
105# define ASSERT_COVERED(a)
106#endif
107
108#ifdef HANDMADE_MATH_NO_SSE
109# warning "HANDMADE_MATH_NO_SSE is deprecated, use HANDMADE_MATH_NO_SIMD instead"
110# define HANDMADE_MATH_NO_SIMD
111#endif
112
113/* let's figure out if SSE is really available (unless disabled anyway)
114 (it isn't on non-x86/x86_64 platforms or even x86 without explicit SSE support)
115 => only use "#ifdef HANDMADE_MATH__USE_SSE" to check for SSE support below this block! */
116#ifndef HANDMADE_MATH_NO_SIMD
117# ifdef _MSC_VER /* MSVC supports SSE in amd64 mode or _M_IX86_FP >= 1 (2 means SSE2) */
118# if defined(_M_AMD64) || ( defined(_M_IX86_FP) && _M_IX86_FP >= 1 )
119# define HANDMADE_MATH__USE_SSE 1
120# endif
121# else /* not MSVC, probably GCC, clang, icc or something that doesn't support SSE anyway */
122# ifdef __SSE__ /* they #define __SSE__ if it's supported */
123# define HANDMADE_MATH__USE_SSE 1
124# endif /* __SSE__ */
125# endif /* not _MSC_VER */
126# ifdef __ARM_NEON
127# define HANDMADE_MATH__USE_NEON 1
128# endif /* NEON Supported */
129#endif /* #ifndef HANDMADE_MATH_NO_SIMD */
130
131#if (!defined(__cplusplus) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
132# define HANDMADE_MATH__USE_C11_GENERICS 1
133#endif
134
135#ifdef HANDMADE_MATH__USE_SSE
136# include <xmmintrin.h>
137#endif
138
139#ifdef HANDMADE_MATH__USE_NEON
140# include <arm_neon.h>
141#endif
142
143#ifdef _MSC_VER
144#pragma warning(disable:4201)
145#endif
146
147#if defined(__GNUC__) || defined(__clang__)
148# pragma GCC diagnostic push
149# pragma GCC diagnostic ignored "-Wfloat-equal"
150# pragma GCC diagnostic ignored "-Wmissing-braces"
151# ifdef __clang__
152# pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
153# pragma GCC diagnostic ignored "-Wnested-anon-types"
154# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
155# endif
156#endif
157
158#if defined(__GNUC__) || defined(__clang__)
159# define HMM_DEPRECATED(msg) __attribute__((deprecated(msg)))
160#elif defined(_MSC_VER)
161# define HMM_DEPRECATED(msg) __declspec(deprecated(msg))
162#else
163# define HMM_DEPRECATED(msg)
164#endif
165
166#ifdef __cplusplus
167extern "C"
168{
169#endif
170
171#if !defined(HANDMADE_MATH_USE_DEGREES) \
172 && !defined(HANDMADE_MATH_USE_TURNS) \
173 && !defined(HANDMADE_MATH_USE_RADIANS)
174# define HANDMADE_MATH_USE_RADIANS
175#endif
176
177#define HMM_PI 3.14159265358979323846
178#define HMM_PI32 3.14159265359f
179#define HMM_DEG180 180.0
180#define HMM_DEG18032 180.0f
181#define HMM_TURNHALF 0.5
182#define HMM_TURNHALF32 0.5f
183#define HMM_RadToDeg ((float)(HMM_DEG180/HMM_PI))
184#define HMM_RadToTurn ((float)(HMM_TURNHALF/HMM_PI))
185#define HMM_DegToRad ((float)(HMM_PI/HMM_DEG180))
186#define HMM_DegToTurn ((float)(HMM_TURNHALF/HMM_DEG180))
187#define HMM_TurnToRad ((float)(HMM_PI/HMM_TURNHALF))
188#define HMM_TurnToDeg ((float)(HMM_DEG180/HMM_TURNHALF))
189
190#if defined(HANDMADE_MATH_USE_RADIANS)
191# define HMM_AngleRad(a) (a)
192# define HMM_AngleDeg(a) ((a)*HMM_DegToRad)
193# define HMM_AngleTurn(a) ((a)*HMM_TurnToRad)
194#elif defined(HANDMADE_MATH_USE_DEGREES)
195# define HMM_AngleRad(a) ((a)*HMM_RadToDeg)
196# define HMM_AngleDeg(a) (a)
197# define HMM_AngleTurn(a) ((a)*HMM_TurnToDeg)
198#elif defined(HANDMADE_MATH_USE_TURNS)
199# define HMM_AngleRad(a) ((a)*HMM_RadToTurn)
200# define HMM_AngleDeg(a) ((a)*HMM_DegToTurn)
201# define HMM_AngleTurn(a) (a)
202#endif
203
204#if !defined(HANDMADE_MATH_PROVIDE_MATH_FUNCTIONS)
205# include <math.h>
206# define HMM_SINF sinf
207# define HMM_COSF cosf
208# define HMM_TANF tanf
209# define HMM_SQRTF sqrtf
210# define HMM_ACOSF acosf
211#endif
212
213#if !defined(HMM_ANGLE_USER_TO_INTERNAL)
214# define HMM_ANGLE_USER_TO_INTERNAL(a) (HMM_ToRad(a))
215#endif
216
217#if !defined(HMM_ANGLE_INTERNAL_TO_USER)
218# if defined(HANDMADE_MATH_USE_RADIANS)
219# define HMM_ANGLE_INTERNAL_TO_USER(a) (a)
220# elif defined(HANDMADE_MATH_USE_DEGREES)
221# define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_RadToDeg)
222# elif defined(HANDMADE_MATH_USE_TURNS)
223# define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_RadToTurn)
224# endif
225#endif
226
227#define HMM_MIN(a, b) ((a) > (b) ? (b) : (a))
228#define HMM_MAX(a, b) ((a) < (b) ? (b) : (a))
229#define HMM_ABS(a) ((a) > 0 ? (a) : -(a))
230#define HMM_MOD(a, m) (((a) % (m)) >= 0 ? ((a) % (m)) : (((a) % (m)) + (m)))
231#define HMM_SQUARE(x) ((x) * (x))
232
233typedef union HMM_Vec2
234{
235 struct
236 {
237 float X, Y;
238 };
239
240 struct
241 {
242 float U, V;
243 };
244
245 struct
246 {
247 float Left, Right;
248 };
249
250 struct
251 {
252 float Width, Height;
253 };
254
255 float Elements[2];
256
257#ifdef __cplusplus
258 inline float &operator[](int Index) { return Elements[Index]; }
259 inline const float &operator[](int Index) const { return Elements[Index]; }
260#endif
261} HMM_Vec2;
262
263typedef union HMM_Vec3
264{
265 struct
266 {
267 float X, Y, Z;
268 };
269
270 struct
271 {
272 float U, V, W;
273 };
274
275 struct
276 {
277 float R, G, B;
278 };
279
280 struct
281 {
282 HMM_Vec2 XY;
283 float _Ignored0;
284 };
285
286 struct
287 {
288 float _Ignored1;
289 HMM_Vec2 YZ;
290 };
291
292 struct
293 {
294 HMM_Vec2 UV;
295 float _Ignored2;
296 };
297
298 struct
299 {
300 float _Ignored3;
301 HMM_Vec2 VW;
302 };
303
304 float Elements[3];
305
306#ifdef __cplusplus
307 inline float &operator[](int Index) { return Elements[Index]; }
308 inline const float &operator[](int Index) const { return Elements[Index]; }
309#endif
310} HMM_Vec3;
311
312typedef union HMM_Vec4
313{
314 struct
315 {
316 union
317 {
318 HMM_Vec3 XYZ;
319 struct
320 {
321 float X, Y, Z;
322 };
323 };
324
325 float W;
326 };
327 struct
328 {
329 union
330 {
331 HMM_Vec3 RGB;
332 struct
333 {
334 float R, G, B;
335 };
336 };
337
338 float A;
339 };
340
341 struct
342 {
343 HMM_Vec2 XY;
344 float _Ignored0;
345 float _Ignored1;
346 };
347
348 struct
349 {
350 float _Ignored2;
351 HMM_Vec2 YZ;
352 float _Ignored3;
353 };
354
355 struct
356 {
357 float _Ignored4;
358 float _Ignored5;
359 HMM_Vec2 ZW;
360 };
361
362 float Elements[4];
363
364#ifdef HANDMADE_MATH__USE_SSE
365 __m128 SSE;
366#endif
367
368#ifdef HANDMADE_MATH__USE_NEON
369 float32x4_t NEON;
370#endif
371
372#ifdef __cplusplus
373 inline float &operator[](int Index) { return Elements[Index]; }
374 inline const float &operator[](int Index) const { return Elements[Index]; }
375#endif
376} HMM_Vec4;
377
378typedef union HMM_Mat2
379{
380 float Elements[2][2];
381 HMM_Vec2 Columns[2];
382
383#ifdef __cplusplus
384 inline HMM_Vec2 &operator[](int Index) { return Columns[Index]; }
385 inline const HMM_Vec2 &operator[](int Index) const { return Columns[Index]; }
386#endif
387} HMM_Mat2;
388
389typedef union HMM_Mat3
390{
391 float Elements[3][3];
392 HMM_Vec3 Columns[3];
393
394#ifdef __cplusplus
395 inline HMM_Vec3 &operator[](int Index) { return Columns[Index]; }
396 inline const HMM_Vec3 &operator[](int Index) const { return Columns[Index]; }
397#endif
398} HMM_Mat3;
399
400typedef union HMM_Mat4
401{
402 float Elements[4][4];
403 HMM_Vec4 Columns[4];
404
405#ifdef __cplusplus
406 inline HMM_Vec4 &operator[](int Index) { return Columns[Index]; }
407 inline const HMM_Vec4 &operator[](int Index) const { return Columns[Index]; }
408#endif
409} HMM_Mat4;
410
411typedef union HMM_Quat
412{
413 struct
414 {
415 union
416 {
417 HMM_Vec3 XYZ;
418 struct
419 {
420 float X, Y, Z;
421 };
422 };
423
424 float W;
425 };
426
427 float Elements[4];
428
429#ifdef HANDMADE_MATH__USE_SSE
430 __m128 SSE;
431#endif
432#ifdef HANDMADE_MATH__USE_NEON
433 float32x4_t NEON;
434#endif
435} HMM_Quat;
436
437typedef signed int HMM_Bool;
438
439/*
440 * Angle unit conversion functions
441 */
442static inline float HMM_ToRad(float Angle)
443{
444#if defined(HANDMADE_MATH_USE_RADIANS)
445 float Result = Angle;
446#elif defined(HANDMADE_MATH_USE_DEGREES)
447 float Result = Angle * HMM_DegToRad;
448#elif defined(HANDMADE_MATH_USE_TURNS)
449 float Result = Angle * HMM_TurnToRad;
450#endif
451
452 return Result;
453}
454
455static inline float HMM_ToDeg(float Angle)
456{
457#if defined(HANDMADE_MATH_USE_RADIANS)
458 float Result = Angle * HMM_RadToDeg;
459#elif defined(HANDMADE_MATH_USE_DEGREES)
460 float Result = Angle;
461#elif defined(HANDMADE_MATH_USE_TURNS)
462 float Result = Angle * HMM_TurnToDeg;
463#endif
464
465 return Result;
466}
467
468static inline float HMM_ToTurn(float Angle)
469{
470#if defined(HANDMADE_MATH_USE_RADIANS)
471 float Result = Angle * HMM_RadToTurn;
472#elif defined(HANDMADE_MATH_USE_DEGREES)
473 float Result = Angle * HMM_DegToTurn;
474#elif defined(HANDMADE_MATH_USE_TURNS)
475 float Result = Angle;
476#endif
477
478 return Result;
479}
480
481/*
482 * Floating-point math functions
483 */
484
485COVERAGE(HMM_SinF, 1)
486static inline float HMM_SinF(float Angle)
487{
488 ASSERT_COVERED(HMM_SinF);
489 return HMM_SINF(HMM_ANGLE_USER_TO_INTERNAL(Angle));
490}
491
492COVERAGE(HMM_CosF, 1)
493static inline float HMM_CosF(float Angle)
494{
495 ASSERT_COVERED(HMM_CosF);
496 return HMM_COSF(HMM_ANGLE_USER_TO_INTERNAL(Angle));
497}
498
499COVERAGE(HMM_TanF, 1)
500static inline float HMM_TanF(float Angle)
501{
502 ASSERT_COVERED(HMM_TanF);
503 return HMM_TANF(HMM_ANGLE_USER_TO_INTERNAL(Angle));
504}
505
506COVERAGE(HMM_ACosF, 1)
507static inline float HMM_ACosF(float Arg)
508{
509 ASSERT_COVERED(HMM_ACosF);
510 return HMM_ANGLE_INTERNAL_TO_USER(HMM_ACOSF(Arg));
511}
512
513COVERAGE(HMM_SqrtF, 1)
514static inline float HMM_SqrtF(float Float)
515{
516 ASSERT_COVERED(HMM_SqrtF);
517
518 float Result;
519
520#ifdef HANDMADE_MATH__USE_SSE
521 __m128 In = _mm_set_ss(Float);
522 __m128 Out = _mm_sqrt_ss(In);
523 Result = _mm_cvtss_f32(Out);
524#elif defined(HANDMADE_MATH__USE_NEON)
525 float32x4_t In = vdupq_n_f32(Float);
526 float32x4_t Out = vsqrtq_f32(In);
527 Result = vgetq_lane_f32(Out, 0);
528#else
529 Result = HMM_SQRTF(Float);
530#endif
531
532 return Result;
533}
534
535COVERAGE(HMM_InvSqrtF, 1)
536static inline float HMM_InvSqrtF(float Float)
537{
538 ASSERT_COVERED(HMM_InvSqrtF);
539
540 float Result;
541
542 Result = 1.0f/HMM_SqrtF(Float);
543
544 return Result;
545}
546
547
548/*
549 * Utility functions
550 */
551
552COVERAGE(HMM_Lerp, 1)
553static inline float HMM_Lerp(float A, float Time, float B)
554{
555 ASSERT_COVERED(HMM_Lerp);
556 return (1.0f - Time) * A + Time * B;
557}
558
559COVERAGE(HMM_Clamp, 1)
560static inline float HMM_Clamp(float Min, float Value, float Max)
561{
562 ASSERT_COVERED(HMM_Clamp);
563
564 float Result = Value;
565
566 if (Result < Min)
567 {
568 Result = Min;
569 }
570
571 if (Result > Max)
572 {
573 Result = Max;
574 }
575
576 return Result;
577}
578
579
580/*
581 * Vector initialization
582 */
583
584COVERAGE(HMM_V2, 1)
585static inline HMM_Vec2 HMM_V2(float X, float Y)
586{
587 ASSERT_COVERED(HMM_V2);
588
589 HMM_Vec2 Result;
590 Result.X = X;
591 Result.Y = Y;
592
593 return Result;
594}
595
596COVERAGE(HMM_V3, 1)
597static inline HMM_Vec3 HMM_V3(float X, float Y, float Z)
598{
599 ASSERT_COVERED(HMM_V3);
600
601 HMM_Vec3 Result;
602 Result.X = X;
603 Result.Y = Y;
604 Result.Z = Z;
605
606 return Result;
607}
608
609COVERAGE(HMM_V4, 1)
610static inline HMM_Vec4 HMM_V4(float X, float Y, float Z, float W)
611{
612 ASSERT_COVERED(HMM_V4);
613
614 HMM_Vec4 Result;
615
616#ifdef HANDMADE_MATH__USE_SSE
617 Result.SSE = _mm_setr_ps(X, Y, Z, W);
618#elif defined(HANDMADE_MATH__USE_NEON)
619 float32x4_t v = {X, Y, Z, W};
620 Result.NEON = v;
621#else
622 Result.X = X;
623 Result.Y = Y;
624 Result.Z = Z;
625 Result.W = W;
626#endif
627
628 return Result;
629}
630
631COVERAGE(HMM_V4V, 1)
632static inline HMM_Vec4 HMM_V4V(HMM_Vec3 Vector, float W)
633{
634 ASSERT_COVERED(HMM_V4V);
635
636 HMM_Vec4 Result;
637
638#ifdef HANDMADE_MATH__USE_SSE
639 Result.SSE = _mm_setr_ps(Vector.X, Vector.Y, Vector.Z, W);
640#elif defined(HANDMADE_MATH__USE_NEON)
641 float32x4_t v = {Vector.X, Vector.Y, Vector.Z, W};
642 Result.NEON = v;
643#else
644 Result.XYZ = Vector;
645 Result.W = W;
646#endif
647
648 return Result;
649}
650
651
652/*
653 * Binary vector operations
654 */
655
656COVERAGE(HMM_AddV2, 1)
657static inline HMM_Vec2 HMM_AddV2(HMM_Vec2 Left, HMM_Vec2 Right)
658{
659 ASSERT_COVERED(HMM_AddV2);
660
661 HMM_Vec2 Result;
662 Result.X = Left.X + Right.X;
663 Result.Y = Left.Y + Right.Y;
664
665 return Result;
666}
667
668COVERAGE(HMM_AddV3, 1)
669static inline HMM_Vec3 HMM_AddV3(HMM_Vec3 Left, HMM_Vec3 Right)
670{
671 ASSERT_COVERED(HMM_AddV3);
672
673 HMM_Vec3 Result;
674 Result.X = Left.X + Right.X;
675 Result.Y = Left.Y + Right.Y;
676 Result.Z = Left.Z + Right.Z;
677
678 return Result;
679}
680
681COVERAGE(HMM_AddV4, 1)
682static inline HMM_Vec4 HMM_AddV4(HMM_Vec4 Left, HMM_Vec4 Right)
683{
684 ASSERT_COVERED(HMM_AddV4);
685
686 HMM_Vec4 Result;
687
688#ifdef HANDMADE_MATH__USE_SSE
689 Result.SSE = _mm_add_ps(Left.SSE, Right.SSE);
690#elif defined(HANDMADE_MATH__USE_NEON)
691 Result.NEON = vaddq_f32(Left.NEON, Right.NEON);
692#else
693 Result.X = Left.X + Right.X;
694 Result.Y = Left.Y + Right.Y;
695 Result.Z = Left.Z + Right.Z;
696 Result.W = Left.W + Right.W;
697#endif
698
699 return Result;
700}
701
702COVERAGE(HMM_SubV2, 1)
703static inline HMM_Vec2 HMM_SubV2(HMM_Vec2 Left, HMM_Vec2 Right)
704{
705 ASSERT_COVERED(HMM_SubV2);
706
707 HMM_Vec2 Result;
708 Result.X = Left.X - Right.X;
709 Result.Y = Left.Y - Right.Y;
710
711 return Result;
712}
713
714COVERAGE(HMM_SubV3, 1)
715static inline HMM_Vec3 HMM_SubV3(HMM_Vec3 Left, HMM_Vec3 Right)
716{
717 ASSERT_COVERED(HMM_SubV3);
718
719 HMM_Vec3 Result;
720 Result.X = Left.X - Right.X;
721 Result.Y = Left.Y - Right.Y;
722 Result.Z = Left.Z - Right.Z;
723
724 return Result;
725}
726
727COVERAGE(HMM_SubV4, 1)
728static inline HMM_Vec4 HMM_SubV4(HMM_Vec4 Left, HMM_Vec4 Right)
729{
730 ASSERT_COVERED(HMM_SubV4);
731
732 HMM_Vec4 Result;
733
734#ifdef HANDMADE_MATH__USE_SSE
735 Result.SSE = _mm_sub_ps(Left.SSE, Right.SSE);
736#elif defined(HANDMADE_MATH__USE_NEON)
737 Result.NEON = vsubq_f32(Left.NEON, Right.NEON);
738#else
739 Result.X = Left.X - Right.X;
740 Result.Y = Left.Y - Right.Y;
741 Result.Z = Left.Z - Right.Z;
742 Result.W = Left.W - Right.W;
743#endif
744
745 return Result;
746}
747
748COVERAGE(HMM_MulV2, 1)
749static inline HMM_Vec2 HMM_MulV2(HMM_Vec2 Left, HMM_Vec2 Right)
750{
751 ASSERT_COVERED(HMM_MulV2);
752
753 HMM_Vec2 Result;
754 Result.X = Left.X * Right.X;
755 Result.Y = Left.Y * Right.Y;
756
757 return Result;
758}
759
760COVERAGE(HMM_MulV2F, 1)
761static inline HMM_Vec2 HMM_MulV2F(HMM_Vec2 Left, float Right)
762{
763 ASSERT_COVERED(HMM_MulV2F);
764
765 HMM_Vec2 Result;
766 Result.X = Left.X * Right;
767 Result.Y = Left.Y * Right;
768
769 return Result;
770}
771
772COVERAGE(HMM_MulV3, 1)
773static inline HMM_Vec3 HMM_MulV3(HMM_Vec3 Left, HMM_Vec3 Right)
774{
775 ASSERT_COVERED(HMM_MulV3);
776
777 HMM_Vec3 Result;
778 Result.X = Left.X * Right.X;
779 Result.Y = Left.Y * Right.Y;
780 Result.Z = Left.Z * Right.Z;
781
782 return Result;
783}
784
785COVERAGE(HMM_MulV3F, 1)
786static inline HMM_Vec3 HMM_MulV3F(HMM_Vec3 Left, float Right)
787{
788 ASSERT_COVERED(HMM_MulV3F);
789
790 HMM_Vec3 Result;
791 Result.X = Left.X * Right;
792 Result.Y = Left.Y * Right;
793 Result.Z = Left.Z * Right;
794
795 return Result;
796}
797
798COVERAGE(HMM_MulV4, 1)
799static inline HMM_Vec4 HMM_MulV4(HMM_Vec4 Left, HMM_Vec4 Right)
800{
801 ASSERT_COVERED(HMM_MulV4);
802
803 HMM_Vec4 Result;
804
805#ifdef HANDMADE_MATH__USE_SSE
806 Result.SSE = _mm_mul_ps(Left.SSE, Right.SSE);
807#elif defined(HANDMADE_MATH__USE_NEON)
808 Result.NEON = vmulq_f32(Left.NEON, Right.NEON);
809#else
810 Result.X = Left.X * Right.X;
811 Result.Y = Left.Y * Right.Y;
812 Result.Z = Left.Z * Right.Z;
813 Result.W = Left.W * Right.W;
814#endif
815
816 return Result;
817}
818
819COVERAGE(HMM_MulV4F, 1)
820static inline HMM_Vec4 HMM_MulV4F(HMM_Vec4 Left, float Right)
821{
822 ASSERT_COVERED(HMM_MulV4F);
823
824 HMM_Vec4 Result;
825
826#ifdef HANDMADE_MATH__USE_SSE
827 __m128 Scalar = _mm_set1_ps(Right);
828 Result.SSE = _mm_mul_ps(Left.SSE, Scalar);
829#elif defined(HANDMADE_MATH__USE_NEON)
830 Result.NEON = vmulq_n_f32(Left.NEON, Right);
831#else
832 Result.X = Left.X * Right;
833 Result.Y = Left.Y * Right;
834 Result.Z = Left.Z * Right;
835 Result.W = Left.W * Right;
836#endif
837
838 return Result;
839}
840
841COVERAGE(HMM_DivV2, 1)
842static inline HMM_Vec2 HMM_DivV2(HMM_Vec2 Left, HMM_Vec2 Right)
843{
844 ASSERT_COVERED(HMM_DivV2);
845
846 HMM_Vec2 Result;
847 Result.X = Left.X / Right.X;
848 Result.Y = Left.Y / Right.Y;
849
850 return Result;
851}
852
853COVERAGE(HMM_DivV2F, 1)
854static inline HMM_Vec2 HMM_DivV2F(HMM_Vec2 Left, float Right)
855{
856 ASSERT_COVERED(HMM_DivV2F);
857
858 HMM_Vec2 Result;
859 Result.X = Left.X / Right;
860 Result.Y = Left.Y / Right;
861
862 return Result;
863}
864
865COVERAGE(HMM_DivV3, 1)
866static inline HMM_Vec3 HMM_DivV3(HMM_Vec3 Left, HMM_Vec3 Right)
867{
868 ASSERT_COVERED(HMM_DivV3);
869
870 HMM_Vec3 Result;
871 Result.X = Left.X / Right.X;
872 Result.Y = Left.Y / Right.Y;
873 Result.Z = Left.Z / Right.Z;
874
875 return Result;
876}
877
878COVERAGE(HMM_DivV3F, 1)
879static inline HMM_Vec3 HMM_DivV3F(HMM_Vec3 Left, float Right)
880{
881 ASSERT_COVERED(HMM_DivV3F);
882
883 HMM_Vec3 Result;
884 Result.X = Left.X / Right;
885 Result.Y = Left.Y / Right;
886 Result.Z = Left.Z / Right;
887
888 return Result;
889}
890
891COVERAGE(HMM_DivV4, 1)
892static inline HMM_Vec4 HMM_DivV4(HMM_Vec4 Left, HMM_Vec4 Right)
893{
894 ASSERT_COVERED(HMM_DivV4);
895
896 HMM_Vec4 Result;
897
898#ifdef HANDMADE_MATH__USE_SSE
899 Result.SSE = _mm_div_ps(Left.SSE, Right.SSE);
900#elif defined(HANDMADE_MATH__USE_NEON)
901 Result.NEON = vdivq_f32(Left.NEON, Right.NEON);
902#else
903 Result.X = Left.X / Right.X;
904 Result.Y = Left.Y / Right.Y;
905 Result.Z = Left.Z / Right.Z;
906 Result.W = Left.W / Right.W;
907#endif
908
909 return Result;
910}
911
912COVERAGE(HMM_DivV4F, 1)
913static inline HMM_Vec4 HMM_DivV4F(HMM_Vec4 Left, float Right)
914{
915 ASSERT_COVERED(HMM_DivV4F);
916
917 HMM_Vec4 Result;
918
919#ifdef HANDMADE_MATH__USE_SSE
920 __m128 Scalar = _mm_set1_ps(Right);
921 Result.SSE = _mm_div_ps(Left.SSE, Scalar);
922#elif defined(HANDMADE_MATH__USE_NEON)
923 float32x4_t Scalar = vdupq_n_f32(Right);
924 Result.NEON = vdivq_f32(Left.NEON, Scalar);
925#else
926 Result.X = Left.X / Right;
927 Result.Y = Left.Y / Right;
928 Result.Z = Left.Z / Right;
929 Result.W = Left.W / Right;
930#endif
931
932 return Result;
933}
934
935COVERAGE(HMM_EqV2, 1)
936static inline HMM_Bool HMM_EqV2(HMM_Vec2 Left, HMM_Vec2 Right)
937{
938 ASSERT_COVERED(HMM_EqV2);
939 return Left.X == Right.X && Left.Y == Right.Y;
940}
941
942COVERAGE(HMM_EqV3, 1)
943static inline HMM_Bool HMM_EqV3(HMM_Vec3 Left, HMM_Vec3 Right)
944{
945 ASSERT_COVERED(HMM_EqV3);
946 return Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z;
947}
948
949COVERAGE(HMM_EqV4, 1)
950static inline HMM_Bool HMM_EqV4(HMM_Vec4 Left, HMM_Vec4 Right)
951{
952 ASSERT_COVERED(HMM_EqV4);
953 return Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W;
954}
955
956COVERAGE(HMM_DotV2, 1)
957static inline float HMM_DotV2(HMM_Vec2 Left, HMM_Vec2 Right)
958{
959 ASSERT_COVERED(HMM_DotV2);
960 return (Left.X * Right.X) + (Left.Y * Right.Y);
961}
962
963COVERAGE(HMM_DotV3, 1)
964static inline float HMM_DotV3(HMM_Vec3 Left, HMM_Vec3 Right)
965{
966 ASSERT_COVERED(HMM_DotV3);
967 return (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z);
968}
969
970COVERAGE(HMM_DotV4, 1)
971static inline float HMM_DotV4(HMM_Vec4 Left, HMM_Vec4 Right)
972{
973 ASSERT_COVERED(HMM_DotV4);
974
975 float Result;
976
977 // NOTE(zak): IN the future if we wanna check what version SSE is support
978 // we can use _mm_dp_ps (4.3) but for now we will use the old way.
979 // Or a r = _mm_mul_ps(v1, v2), r = _mm_hadd_ps(r, r), r = _mm_hadd_ps(r, r) for SSE3
980#ifdef HANDMADE_MATH__USE_SSE
981 __m128 SSEResultOne = _mm_mul_ps(Left.SSE, Right.SSE);
982 __m128 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(2, 3, 0, 1));
983 SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);
984 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3));
985 SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);
986 _mm_store_ss(&Result, SSEResultOne);
987#elif defined(HANDMADE_MATH__USE_NEON)
988 float32x4_t NEONMultiplyResult = vmulq_f32(Left.NEON, Right.NEON);
989 float32x4_t NEONHalfAdd = vpaddq_f32(NEONMultiplyResult, NEONMultiplyResult);
990 float32x4_t NEONFullAdd = vpaddq_f32(NEONHalfAdd, NEONHalfAdd);
991 Result = vgetq_lane_f32(NEONFullAdd, 0);
992#else
993 Result = ((Left.X * Right.X) + (Left.Z * Right.Z)) + ((Left.Y * Right.Y) + (Left.W * Right.W));
994#endif
995
996 return Result;
997}
998
999COVERAGE(HMM_Cross, 1)
1000static inline HMM_Vec3 HMM_Cross(HMM_Vec3 Left, HMM_Vec3 Right)
1001{
1002 ASSERT_COVERED(HMM_Cross);
1003
1004 HMM_Vec3 Result;
1005 Result.X = (Left.Y * Right.Z) - (Left.Z * Right.Y);
1006 Result.Y = (Left.Z * Right.X) - (Left.X * Right.Z);
1007 Result.Z = (Left.X * Right.Y) - (Left.Y * Right.X);
1008
1009 return Result;
1010}
1011
1012
1013/*
1014 * Unary vector operations
1015 */
1016
1017COVERAGE(HMM_LenSqrV2, 1)
1018static inline float HMM_LenSqrV2(HMM_Vec2 A)
1019{
1020 ASSERT_COVERED(HMM_LenSqrV2);
1021 return HMM_DotV2(A, A);
1022}
1023
1024COVERAGE(HMM_LenSqrV3, 1)
1025static inline float HMM_LenSqrV3(HMM_Vec3 A)
1026{
1027 ASSERT_COVERED(HMM_LenSqrV3);
1028 return HMM_DotV3(A, A);
1029}
1030
1031COVERAGE(HMM_LenSqrV4, 1)
1032static inline float HMM_LenSqrV4(HMM_Vec4 A)
1033{
1034 ASSERT_COVERED(HMM_LenSqrV4);
1035 return HMM_DotV4(A, A);
1036}
1037
1038COVERAGE(HMM_LenV2, 1)
1039static inline float HMM_LenV2(HMM_Vec2 A)
1040{
1041 ASSERT_COVERED(HMM_LenV2);
1042 return HMM_SqrtF(HMM_LenSqrV2(A));
1043}
1044
1045COVERAGE(HMM_LenV3, 1)
1046static inline float HMM_LenV3(HMM_Vec3 A)
1047{
1048 ASSERT_COVERED(HMM_LenV3);
1049 return HMM_SqrtF(HMM_LenSqrV3(A));
1050}
1051
1052COVERAGE(HMM_LenV4, 1)
1053static inline float HMM_LenV4(HMM_Vec4 A)
1054{
1055 ASSERT_COVERED(HMM_LenV4);
1056 return HMM_SqrtF(HMM_LenSqrV4(A));
1057}
1058
1059COVERAGE(HMM_NormV2, 1)
1060static inline HMM_Vec2 HMM_NormV2(HMM_Vec2 A)
1061{
1062 ASSERT_COVERED(HMM_NormV2);
1063 return HMM_MulV2F(A, HMM_InvSqrtF(HMM_DotV2(A, A)));
1064}
1065
1066COVERAGE(HMM_NormV3, 1)
1067static inline HMM_Vec3 HMM_NormV3(HMM_Vec3 A)
1068{
1069 ASSERT_COVERED(HMM_NormV3);
1070 return HMM_MulV3F(A, HMM_InvSqrtF(HMM_DotV3(A, A)));
1071}
1072
1073COVERAGE(HMM_NormV4, 1)
1074static inline HMM_Vec4 HMM_NormV4(HMM_Vec4 A)
1075{
1076 ASSERT_COVERED(HMM_NormV4);
1077 return HMM_MulV4F(A, HMM_InvSqrtF(HMM_DotV4(A, A)));
1078}
1079
1080/*
1081 * Utility vector functions
1082 */
1083
1084COVERAGE(HMM_LerpV2, 1)
1085static inline HMM_Vec2 HMM_LerpV2(HMM_Vec2 A, float Time, HMM_Vec2 B)
1086{
1087 ASSERT_COVERED(HMM_LerpV2);
1088 return HMM_AddV2(HMM_MulV2F(A, 1.0f - Time), HMM_MulV2F(B, Time));
1089}
1090
1091COVERAGE(HMM_LerpV3, 1)
1092static inline HMM_Vec3 HMM_LerpV3(HMM_Vec3 A, float Time, HMM_Vec3 B)
1093{
1094 ASSERT_COVERED(HMM_LerpV3);
1095 return HMM_AddV3(HMM_MulV3F(A, 1.0f - Time), HMM_MulV3F(B, Time));
1096}
1097
1098COVERAGE(HMM_LerpV4, 1)
1099static inline HMM_Vec4 HMM_LerpV4(HMM_Vec4 A, float Time, HMM_Vec4 B)
1100{
1101 ASSERT_COVERED(HMM_LerpV4);
1102 return HMM_AddV4(HMM_MulV4F(A, 1.0f - Time), HMM_MulV4F(B, Time));
1103}
1104
1105/*
1106 * SSE stuff
1107 */
1108
1109COVERAGE(HMM_LinearCombineV4M4, 1)
1110static inline HMM_Vec4 HMM_LinearCombineV4M4(HMM_Vec4 Left, HMM_Mat4 Right)
1111{
1112 ASSERT_COVERED(HMM_LinearCombineV4M4);
1113
1114 HMM_Vec4 Result;
1115#ifdef HANDMADE_MATH__USE_SSE
1116 Result.SSE = _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0x00), Right.Columns[0].SSE);
1117 Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0x55), Right.Columns[1].SSE));
1118 Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xaa), Right.Columns[2].SSE));
1119 Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xff), Right.Columns[3].SSE));
1120#elif defined(HANDMADE_MATH__USE_NEON)
1121 Result.NEON = vmulq_laneq_f32(Right.Columns[0].NEON, Left.NEON, 0);
1122 Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.Columns[1].NEON, Left.NEON, 1);
1123 Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.Columns[2].NEON, Left.NEON, 2);
1124 Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.Columns[3].NEON, Left.NEON, 3);
1125#else
1126 Result.X = Left.Elements[0] * Right.Columns[0].X;
1127 Result.Y = Left.Elements[0] * Right.Columns[0].Y;
1128 Result.Z = Left.Elements[0] * Right.Columns[0].Z;
1129 Result.W = Left.Elements[0] * Right.Columns[0].W;
1130
1131 Result.X += Left.Elements[1] * Right.Columns[1].X;
1132 Result.Y += Left.Elements[1] * Right.Columns[1].Y;
1133 Result.Z += Left.Elements[1] * Right.Columns[1].Z;
1134 Result.W += Left.Elements[1] * Right.Columns[1].W;
1135
1136 Result.X += Left.Elements[2] * Right.Columns[2].X;
1137 Result.Y += Left.Elements[2] * Right.Columns[2].Y;
1138 Result.Z += Left.Elements[2] * Right.Columns[2].Z;
1139 Result.W += Left.Elements[2] * Right.Columns[2].W;
1140
1141 Result.X += Left.Elements[3] * Right.Columns[3].X;
1142 Result.Y += Left.Elements[3] * Right.Columns[3].Y;
1143 Result.Z += Left.Elements[3] * Right.Columns[3].Z;
1144 Result.W += Left.Elements[3] * Right.Columns[3].W;
1145#endif
1146
1147 return Result;
1148}
1149
1150/*
1151 * 2x2 Matrices
1152 */
1153
1154COVERAGE(HMM_M2, 1)
1155static inline HMM_Mat2 HMM_M2(void)
1156{
1157 ASSERT_COVERED(HMM_M2);
1158 HMM_Mat2 Result = {0};
1159 return Result;
1160}
1161
1162COVERAGE(HMM_M2D, 1)
1163static inline HMM_Mat2 HMM_M2D(float Diagonal)
1164{
1165 ASSERT_COVERED(HMM_M2D);
1166
1167 HMM_Mat2 Result = {0};
1168 Result.Elements[0][0] = Diagonal;
1169 Result.Elements[1][1] = Diagonal;
1170
1171 return Result;
1172}
1173
1174COVERAGE(HMM_TransposeM2, 1)
1175static inline HMM_Mat2 HMM_TransposeM2(HMM_Mat2 Matrix)
1176{
1177 ASSERT_COVERED(HMM_TransposeM2);
1178
1179 HMM_Mat2 Result = Matrix;
1180
1181 Result.Elements[0][1] = Matrix.Elements[1][0];
1182 Result.Elements[1][0] = Matrix.Elements[0][1];
1183
1184 return Result;
1185}
1186
1187COVERAGE(HMM_AddM2, 1)
1188static inline HMM_Mat2 HMM_AddM2(HMM_Mat2 Left, HMM_Mat2 Right)
1189{
1190 ASSERT_COVERED(HMM_AddM2);
1191
1192 HMM_Mat2 Result;
1193
1194 Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0];
1195 Result.Elements[0][1] = Left.Elements[0][1] + Right.Elements[0][1];
1196 Result.Elements[1][0] = Left.Elements[1][0] + Right.Elements[1][0];
1197 Result.Elements[1][1] = Left.Elements[1][1] + Right.Elements[1][1];
1198
1199 return Result;
1200}
1201
1202COVERAGE(HMM_SubM2, 1)
1203static inline HMM_Mat2 HMM_SubM2(HMM_Mat2 Left, HMM_Mat2 Right)
1204{
1205 ASSERT_COVERED(HMM_SubM2);
1206
1207 HMM_Mat2 Result;
1208
1209 Result.Elements[0][0] = Left.Elements[0][0] - Right.Elements[0][0];
1210 Result.Elements[0][1] = Left.Elements[0][1] - Right.Elements[0][1];
1211 Result.Elements[1][0] = Left.Elements[1][0] - Right.Elements[1][0];
1212 Result.Elements[1][1] = Left.Elements[1][1] - Right.Elements[1][1];
1213
1214 return Result;
1215}
1216
1217COVERAGE(HMM_MulM2V2, 1)
1218static inline HMM_Vec2 HMM_MulM2V2(HMM_Mat2 Matrix, HMM_Vec2 Vector)
1219{
1220 ASSERT_COVERED(HMM_MulM2V2);
1221
1222 HMM_Vec2 Result;
1223
1224 Result.X = Vector.Elements[0] * Matrix.Columns[0].X;
1225 Result.Y = Vector.Elements[0] * Matrix.Columns[0].Y;
1226
1227 Result.X += Vector.Elements[1] * Matrix.Columns[1].X;
1228 Result.Y += Vector.Elements[1] * Matrix.Columns[1].Y;
1229
1230 return Result;
1231}
1232
1233COVERAGE(HMM_MulM2, 1)
1234static inline HMM_Mat2 HMM_MulM2(HMM_Mat2 Left, HMM_Mat2 Right)
1235{
1236 ASSERT_COVERED(HMM_MulM2);
1237
1238 HMM_Mat2 Result;
1239 Result.Columns[0] = HMM_MulM2V2(Left, Right.Columns[0]);
1240 Result.Columns[1] = HMM_MulM2V2(Left, Right.Columns[1]);
1241
1242 return Result;
1243}
1244
1245COVERAGE(HMM_MulM2F, 1)
1246static inline HMM_Mat2 HMM_MulM2F(HMM_Mat2 Matrix, float Scalar)
1247{
1248 ASSERT_COVERED(HMM_MulM2F);
1249
1250 HMM_Mat2 Result;
1251
1252 Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar;
1253 Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar;
1254 Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar;
1255 Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar;
1256
1257 return Result;
1258}
1259
1260COVERAGE(HMM_DivM2F, 1)
1261static inline HMM_Mat2 HMM_DivM2F(HMM_Mat2 Matrix, float Scalar)
1262{
1263 ASSERT_COVERED(HMM_DivM2F);
1264
1265 HMM_Mat2 Result;
1266
1267 Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar;
1268 Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar;
1269 Result.Elements[1][0] = Matrix.Elements[1][0] / Scalar;
1270 Result.Elements[1][1] = Matrix.Elements[1][1] / Scalar;
1271
1272 return Result;
1273}
1274
1275COVERAGE(HMM_DeterminantM2, 1)
1276static inline float HMM_DeterminantM2(HMM_Mat2 Matrix)
1277{
1278 ASSERT_COVERED(HMM_DeterminantM2);
1279 return Matrix.Elements[0][0]*Matrix.Elements[1][1] - Matrix.Elements[0][1]*Matrix.Elements[1][0];
1280}
1281
1282
1283COVERAGE(HMM_InvGeneralM2, 1)
1284static inline HMM_Mat2 HMM_InvGeneralM2(HMM_Mat2 Matrix)
1285{
1286 ASSERT_COVERED(HMM_InvGeneralM2);
1287
1288 HMM_Mat2 Result;
1289 float InvDeterminant = 1.0f / HMM_DeterminantM2(Matrix);
1290 Result.Elements[0][0] = InvDeterminant * +Matrix.Elements[1][1];
1291 Result.Elements[1][1] = InvDeterminant * +Matrix.Elements[0][0];
1292 Result.Elements[0][1] = InvDeterminant * -Matrix.Elements[0][1];
1293 Result.Elements[1][0] = InvDeterminant * -Matrix.Elements[1][0];
1294
1295 return Result;
1296}
1297
1298/*
1299 * 3x3 Matrices
1300 */
1301
1302COVERAGE(HMM_M3, 1)
1303static inline HMM_Mat3 HMM_M3(void)
1304{
1305 ASSERT_COVERED(HMM_M3);
1306 HMM_Mat3 Result = {0};
1307 return Result;
1308}
1309
1310COVERAGE(HMM_M3D, 1)
1311static inline HMM_Mat3 HMM_M3D(float Diagonal)
1312{
1313 ASSERT_COVERED(HMM_M3D);
1314
1315 HMM_Mat3 Result = {0};
1316 Result.Elements[0][0] = Diagonal;
1317 Result.Elements[1][1] = Diagonal;
1318 Result.Elements[2][2] = Diagonal;
1319
1320 return Result;
1321}
1322
1323COVERAGE(HMM_TransposeM3, 1)
1324static inline HMM_Mat3 HMM_TransposeM3(HMM_Mat3 Matrix)
1325{
1326 ASSERT_COVERED(HMM_TransposeM3);
1327
1328 HMM_Mat3 Result = Matrix;
1329
1330 Result.Elements[0][1] = Matrix.Elements[1][0];
1331 Result.Elements[0][2] = Matrix.Elements[2][0];
1332 Result.Elements[1][0] = Matrix.Elements[0][1];
1333 Result.Elements[1][2] = Matrix.Elements[2][1];
1334 Result.Elements[2][1] = Matrix.Elements[1][2];
1335 Result.Elements[2][0] = Matrix.Elements[0][2];
1336
1337 return Result;
1338}
1339
1340COVERAGE(HMM_AddM3, 1)
1341static inline HMM_Mat3 HMM_AddM3(HMM_Mat3 Left, HMM_Mat3 Right)
1342{
1343 ASSERT_COVERED(HMM_AddM3);
1344
1345 HMM_Mat3 Result;
1346
1347 Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0];
1348 Result.Elements[0][1] = Left.Elements[0][1] + Right.Elements[0][1];
1349 Result.Elements[0][2] = Left.Elements[0][2] + Right.Elements[0][2];
1350 Result.Elements[1][0] = Left.Elements[1][0] + Right.Elements[1][0];
1351 Result.Elements[1][1] = Left.Elements[1][1] + Right.Elements[1][1];
1352 Result.Elements[1][2] = Left.Elements[1][2] + Right.Elements[1][2];
1353 Result.Elements[2][0] = Left.Elements[2][0] + Right.Elements[2][0];
1354 Result.Elements[2][1] = Left.Elements[2][1] + Right.Elements[2][1];
1355 Result.Elements[2][2] = Left.Elements[2][2] + Right.Elements[2][2];
1356
1357 return Result;
1358}
1359
1360COVERAGE(HMM_SubM3, 1)
1361static inline HMM_Mat3 HMM_SubM3(HMM_Mat3 Left, HMM_Mat3 Right)
1362{
1363 ASSERT_COVERED(HMM_SubM3);
1364
1365 HMM_Mat3 Result;
1366
1367 Result.Elements[0][0] = Left.Elements[0][0] - Right.Elements[0][0];
1368 Result.Elements[0][1] = Left.Elements[0][1] - Right.Elements[0][1];
1369 Result.Elements[0][2] = Left.Elements[0][2] - Right.Elements[0][2];
1370 Result.Elements[1][0] = Left.Elements[1][0] - Right.Elements[1][0];
1371 Result.Elements[1][1] = Left.Elements[1][1] - Right.Elements[1][1];
1372 Result.Elements[1][2] = Left.Elements[1][2] - Right.Elements[1][2];
1373 Result.Elements[2][0] = Left.Elements[2][0] - Right.Elements[2][0];
1374 Result.Elements[2][1] = Left.Elements[2][1] - Right.Elements[2][1];
1375 Result.Elements[2][2] = Left.Elements[2][2] - Right.Elements[2][2];
1376
1377 return Result;
1378}
1379
1380COVERAGE(HMM_MulM3V3, 1)
1381static inline HMM_Vec3 HMM_MulM3V3(HMM_Mat3 Matrix, HMM_Vec3 Vector)
1382{
1383 ASSERT_COVERED(HMM_MulM3V3);
1384
1385 HMM_Vec3 Result;
1386
1387 Result.X = Vector.Elements[0] * Matrix.Columns[0].X;
1388 Result.Y = Vector.Elements[0] * Matrix.Columns[0].Y;
1389 Result.Z = Vector.Elements[0] * Matrix.Columns[0].Z;
1390
1391 Result.X += Vector.Elements[1] * Matrix.Columns[1].X;
1392 Result.Y += Vector.Elements[1] * Matrix.Columns[1].Y;
1393 Result.Z += Vector.Elements[1] * Matrix.Columns[1].Z;
1394
1395 Result.X += Vector.Elements[2] * Matrix.Columns[2].X;
1396 Result.Y += Vector.Elements[2] * Matrix.Columns[2].Y;
1397 Result.Z += Vector.Elements[2] * Matrix.Columns[2].Z;
1398
1399 return Result;
1400}
1401
1402COVERAGE(HMM_MulM3, 1)
1403static inline HMM_Mat3 HMM_MulM3(HMM_Mat3 Left, HMM_Mat3 Right)
1404{
1405 ASSERT_COVERED(HMM_MulM3);
1406
1407 HMM_Mat3 Result;
1408 Result.Columns[0] = HMM_MulM3V3(Left, Right.Columns[0]);
1409 Result.Columns[1] = HMM_MulM3V3(Left, Right.Columns[1]);
1410 Result.Columns[2] = HMM_MulM3V3(Left, Right.Columns[2]);
1411
1412 return Result;
1413}
1414
1415COVERAGE(HMM_MulM3F, 1)
1416static inline HMM_Mat3 HMM_MulM3F(HMM_Mat3 Matrix, float Scalar)
1417{
1418 ASSERT_COVERED(HMM_MulM3F);
1419
1420 HMM_Mat3 Result;
1421
1422 Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar;
1423 Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar;
1424 Result.Elements[0][2] = Matrix.Elements[0][2] * Scalar;
1425 Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar;
1426 Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar;
1427 Result.Elements[1][2] = Matrix.Elements[1][2] * Scalar;
1428 Result.Elements[2][0] = Matrix.Elements[2][0] * Scalar;
1429 Result.Elements[2][1] = Matrix.Elements[2][1] * Scalar;
1430 Result.Elements[2][2] = Matrix.Elements[2][2] * Scalar;
1431
1432 return Result;
1433}
1434
1435COVERAGE(HMM_DivM3F, 1)
1436static inline HMM_Mat3 HMM_DivM3F(HMM_Mat3 Matrix, float Scalar)
1437{
1438 ASSERT_COVERED(HMM_DivM3F);
1439
1440 HMM_Mat3 Result;
1441
1442 Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar;
1443 Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar;
1444 Result.Elements[0][2] = Matrix.Elements[0][2] / Scalar;
1445 Result.Elements[1][0] = Matrix.Elements[1][0] / Scalar;
1446 Result.Elements[1][1] = Matrix.Elements[1][1] / Scalar;
1447 Result.Elements[1][2] = Matrix.Elements[1][2] / Scalar;
1448 Result.Elements[2][0] = Matrix.Elements[2][0] / Scalar;
1449 Result.Elements[2][1] = Matrix.Elements[2][1] / Scalar;
1450 Result.Elements[2][2] = Matrix.Elements[2][2] / Scalar;
1451
1452 return Result;
1453}
1454
1455COVERAGE(HMM_DeterminantM3, 1)
1456static inline float HMM_DeterminantM3(HMM_Mat3 Matrix)
1457{
1458 ASSERT_COVERED(HMM_DeterminantM3);
1459
1460 HMM_Mat3 Cross;
1461 Cross.Columns[0] = HMM_Cross(Matrix.Columns[1], Matrix.Columns[2]);
1462 Cross.Columns[1] = HMM_Cross(Matrix.Columns[2], Matrix.Columns[0]);
1463 Cross.Columns[2] = HMM_Cross(Matrix.Columns[0], Matrix.Columns[1]);
1464
1465 return HMM_DotV3(Cross.Columns[2], Matrix.Columns[2]);
1466}
1467
1468COVERAGE(HMM_InvGeneralM3, 1)
1469static inline HMM_Mat3 HMM_InvGeneralM3(HMM_Mat3 Matrix)
1470{
1471 ASSERT_COVERED(HMM_InvGeneralM3);
1472
1473 HMM_Mat3 Cross;
1474 Cross.Columns[0] = HMM_Cross(Matrix.Columns[1], Matrix.Columns[2]);
1475 Cross.Columns[1] = HMM_Cross(Matrix.Columns[2], Matrix.Columns[0]);
1476 Cross.Columns[2] = HMM_Cross(Matrix.Columns[0], Matrix.Columns[1]);
1477
1478 float InvDeterminant = 1.0f / HMM_DotV3(Cross.Columns[2], Matrix.Columns[2]);
1479
1480 HMM_Mat3 Result;
1481 Result.Columns[0] = HMM_MulV3F(Cross.Columns[0], InvDeterminant);
1482 Result.Columns[1] = HMM_MulV3F(Cross.Columns[1], InvDeterminant);
1483 Result.Columns[2] = HMM_MulV3F(Cross.Columns[2], InvDeterminant);
1484
1485 return HMM_TransposeM3(Result);
1486}
1487
1488/*
1489 * 4x4 Matrices
1490 */
1491
1492COVERAGE(HMM_M4, 1)
1493static inline HMM_Mat4 HMM_M4(void)
1494{
1495 ASSERT_COVERED(HMM_M4);
1496 HMM_Mat4 Result = {0};
1497 return Result;
1498}
1499
1500COVERAGE(HMM_M4D, 1)
1501static inline HMM_Mat4 HMM_M4D(float Diagonal)
1502{
1503 ASSERT_COVERED(HMM_M4D);
1504
1505 HMM_Mat4 Result = {0};
1506 Result.Elements[0][0] = Diagonal;
1507 Result.Elements[1][1] = Diagonal;
1508 Result.Elements[2][2] = Diagonal;
1509 Result.Elements[3][3] = Diagonal;
1510
1511 return Result;
1512}
1513
1514COVERAGE(HMM_TransposeM4, 1)
1515static inline HMM_Mat4 HMM_TransposeM4(HMM_Mat4 Matrix)
1516{
1517 ASSERT_COVERED(HMM_TransposeM4);
1518
1519 HMM_Mat4 Result;
1520#ifdef HANDMADE_MATH__USE_SSE
1521 Result = Matrix;
1522 _MM_TRANSPOSE4_PS(Result.Columns[0].SSE, Result.Columns[1].SSE, Result.Columns[2].SSE, Result.Columns[3].SSE);
1523#elif defined(HANDMADE_MATH__USE_NEON)
1524 float32x4x4_t Transposed = vld4q_f32((float*)Matrix.Columns);
1525 Result.Columns[0].NEON = Transposed.val[0];
1526 Result.Columns[1].NEON = Transposed.val[1];
1527 Result.Columns[2].NEON = Transposed.val[2];
1528 Result.Columns[3].NEON = Transposed.val[3];
1529#else
1530 Result.Elements[0][0] = Matrix.Elements[0][0];
1531 Result.Elements[0][1] = Matrix.Elements[1][0];
1532 Result.Elements[0][2] = Matrix.Elements[2][0];
1533 Result.Elements[0][3] = Matrix.Elements[3][0];
1534 Result.Elements[1][0] = Matrix.Elements[0][1];
1535 Result.Elements[1][1] = Matrix.Elements[1][1];
1536 Result.Elements[1][2] = Matrix.Elements[2][1];
1537 Result.Elements[1][3] = Matrix.Elements[3][1];
1538 Result.Elements[2][0] = Matrix.Elements[0][2];
1539 Result.Elements[2][1] = Matrix.Elements[1][2];
1540 Result.Elements[2][2] = Matrix.Elements[2][2];
1541 Result.Elements[2][3] = Matrix.Elements[3][2];
1542 Result.Elements[3][0] = Matrix.Elements[0][3];
1543 Result.Elements[3][1] = Matrix.Elements[1][3];
1544 Result.Elements[3][2] = Matrix.Elements[2][3];
1545 Result.Elements[3][3] = Matrix.Elements[3][3];
1546#endif
1547
1548 return Result;
1549}
1550
1551COVERAGE(HMM_AddM4, 1)
1552static inline HMM_Mat4 HMM_AddM4(HMM_Mat4 Left, HMM_Mat4 Right)
1553{
1554 ASSERT_COVERED(HMM_AddM4);
1555
1556 HMM_Mat4 Result;
1557
1558 Result.Columns[0] = HMM_AddV4(Left.Columns[0], Right.Columns[0]);
1559 Result.Columns[1] = HMM_AddV4(Left.Columns[1], Right.Columns[1]);
1560 Result.Columns[2] = HMM_AddV4(Left.Columns[2], Right.Columns[2]);
1561 Result.Columns[3] = HMM_AddV4(Left.Columns[3], Right.Columns[3]);
1562
1563 return Result;
1564}
1565
1566COVERAGE(HMM_SubM4, 1)
1567static inline HMM_Mat4 HMM_SubM4(HMM_Mat4 Left, HMM_Mat4 Right)
1568{
1569 ASSERT_COVERED(HMM_SubM4);
1570
1571 HMM_Mat4 Result;
1572
1573 Result.Columns[0] = HMM_SubV4(Left.Columns[0], Right.Columns[0]);
1574 Result.Columns[1] = HMM_SubV4(Left.Columns[1], Right.Columns[1]);
1575 Result.Columns[2] = HMM_SubV4(Left.Columns[2], Right.Columns[2]);
1576 Result.Columns[3] = HMM_SubV4(Left.Columns[3], Right.Columns[3]);
1577
1578 return Result;
1579}
1580
1581COVERAGE(HMM_MulM4, 1)
1582static inline HMM_Mat4 HMM_MulM4(HMM_Mat4 Left, HMM_Mat4 Right)
1583{
1584 ASSERT_COVERED(HMM_MulM4);
1585
1586 HMM_Mat4 Result;
1587 Result.Columns[0] = HMM_LinearCombineV4M4(Right.Columns[0], Left);
1588 Result.Columns[1] = HMM_LinearCombineV4M4(Right.Columns[1], Left);
1589 Result.Columns[2] = HMM_LinearCombineV4M4(Right.Columns[2], Left);
1590 Result.Columns[3] = HMM_LinearCombineV4M4(Right.Columns[3], Left);
1591
1592 return Result;
1593}
1594
1595COVERAGE(HMM_MulM4F, 1)
1596static inline HMM_Mat4 HMM_MulM4F(HMM_Mat4 Matrix, float Scalar)
1597{
1598 ASSERT_COVERED(HMM_MulM4F);
1599
1600 HMM_Mat4 Result;
1601
1602
1603#ifdef HANDMADE_MATH__USE_SSE
1604 __m128 SSEScalar = _mm_set1_ps(Scalar);
1605 Result.Columns[0].SSE = _mm_mul_ps(Matrix.Columns[0].SSE, SSEScalar);
1606 Result.Columns[1].SSE = _mm_mul_ps(Matrix.Columns[1].SSE, SSEScalar);
1607 Result.Columns[2].SSE = _mm_mul_ps(Matrix.Columns[2].SSE, SSEScalar);
1608 Result.Columns[3].SSE = _mm_mul_ps(Matrix.Columns[3].SSE, SSEScalar);
1609#elif defined(HANDMADE_MATH__USE_NEON)
1610 Result.Columns[0].NEON = vmulq_n_f32(Matrix.Columns[0].NEON, Scalar);
1611 Result.Columns[1].NEON = vmulq_n_f32(Matrix.Columns[1].NEON, Scalar);
1612 Result.Columns[2].NEON = vmulq_n_f32(Matrix.Columns[2].NEON, Scalar);
1613 Result.Columns[3].NEON = vmulq_n_f32(Matrix.Columns[3].NEON, Scalar);
1614#else
1615 Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar;
1616 Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar;
1617 Result.Elements[0][2] = Matrix.Elements[0][2] * Scalar;
1618 Result.Elements[0][3] = Matrix.Elements[0][3] * Scalar;
1619 Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar;
1620 Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar;
1621 Result.Elements[1][2] = Matrix.Elements[1][2] * Scalar;
1622 Result.Elements[1][3] = Matrix.Elements[1][3] * Scalar;
1623 Result.Elements[2][0] = Matrix.Elements[2][0] * Scalar;
1624 Result.Elements[2][1] = Matrix.Elements[2][1] * Scalar;
1625 Result.Elements[2][2] = Matrix.Elements[2][2] * Scalar;
1626 Result.Elements[2][3] = Matrix.Elements[2][3] * Scalar;
1627 Result.Elements[3][0] = Matrix.Elements[3][0] * Scalar;
1628 Result.Elements[3][1] = Matrix.Elements[3][1] * Scalar;
1629 Result.Elements[3][2] = Matrix.Elements[3][2] * Scalar;
1630 Result.Elements[3][3] = Matrix.Elements[3][3] * Scalar;
1631#endif
1632
1633 return Result;
1634}
1635
1636COVERAGE(HMM_MulM4V4, 1)
1637static inline HMM_Vec4 HMM_MulM4V4(HMM_Mat4 Matrix, HMM_Vec4 Vector)
1638{
1639 ASSERT_COVERED(HMM_MulM4V4);
1640 return HMM_LinearCombineV4M4(Vector, Matrix);
1641}
1642
1643COVERAGE(HMM_DivM4F, 1)
1644static inline HMM_Mat4 HMM_DivM4F(HMM_Mat4 Matrix, float Scalar)
1645{
1646 ASSERT_COVERED(HMM_DivM4F);
1647
1648 HMM_Mat4 Result;
1649
1650#ifdef HANDMADE_MATH__USE_SSE
1651 __m128 SSEScalar = _mm_set1_ps(Scalar);
1652 Result.Columns[0].SSE = _mm_div_ps(Matrix.Columns[0].SSE, SSEScalar);
1653 Result.Columns[1].SSE = _mm_div_ps(Matrix.Columns[1].SSE, SSEScalar);
1654 Result.Columns[2].SSE = _mm_div_ps(Matrix.Columns[2].SSE, SSEScalar);
1655 Result.Columns[3].SSE = _mm_div_ps(Matrix.Columns[3].SSE, SSEScalar);
1656#elif defined(HANDMADE_MATH__USE_NEON)
1657 float32x4_t NEONScalar = vdupq_n_f32(Scalar);
1658 Result.Columns[0].NEON = vdivq_f32(Matrix.Columns[0].NEON, NEONScalar);
1659 Result.Columns[1].NEON = vdivq_f32(Matrix.Columns[1].NEON, NEONScalar);
1660 Result.Columns[2].NEON = vdivq_f32(Matrix.Columns[2].NEON, NEONScalar);
1661 Result.Columns[3].NEON = vdivq_f32(Matrix.Columns[3].NEON, NEONScalar);
1662#else
1663 Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar;
1664 Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar;
1665 Result.Elements[0][2] = Matrix.Elements[0][2] / Scalar;
1666 Result.Elements[0][3] = Matrix.Elements[0][3] / Scalar;
1667 Result.Elements[1][0] = Matrix.Elements[1][0] / Scalar;
1668 Result.Elements[1][1] = Matrix.Elements[1][1] / Scalar;
1669 Result.Elements[1][2] = Matrix.Elements[1][2] / Scalar;
1670 Result.Elements[1][3] = Matrix.Elements[1][3] / Scalar;
1671 Result.Elements[2][0] = Matrix.Elements[2][0] / Scalar;
1672 Result.Elements[2][1] = Matrix.Elements[2][1] / Scalar;
1673 Result.Elements[2][2] = Matrix.Elements[2][2] / Scalar;
1674 Result.Elements[2][3] = Matrix.Elements[2][3] / Scalar;
1675 Result.Elements[3][0] = Matrix.Elements[3][0] / Scalar;
1676 Result.Elements[3][1] = Matrix.Elements[3][1] / Scalar;
1677 Result.Elements[3][2] = Matrix.Elements[3][2] / Scalar;
1678 Result.Elements[3][3] = Matrix.Elements[3][3] / Scalar;
1679#endif
1680
1681 return Result;
1682}
1683
1684COVERAGE(HMM_DeterminantM4, 1)
1685static inline float HMM_DeterminantM4(HMM_Mat4 Matrix)
1686{
1687 ASSERT_COVERED(HMM_DeterminantM4);
1688
1689 HMM_Vec3 C01 = HMM_Cross(Matrix.Columns[0].XYZ, Matrix.Columns[1].XYZ);
1690 HMM_Vec3 C23 = HMM_Cross(Matrix.Columns[2].XYZ, Matrix.Columns[3].XYZ);
1691 HMM_Vec3 B10 = HMM_SubV3(HMM_MulV3F(Matrix.Columns[0].XYZ, Matrix.Columns[1].W), HMM_MulV3F(Matrix.Columns[1].XYZ, Matrix.Columns[0].W));
1692 HMM_Vec3 B32 = HMM_SubV3(HMM_MulV3F(Matrix.Columns[2].XYZ, Matrix.Columns[3].W), HMM_MulV3F(Matrix.Columns[3].XYZ, Matrix.Columns[2].W));
1693
1694 return HMM_DotV3(C01, B32) + HMM_DotV3(C23, B10);
1695}
1696
1697COVERAGE(HMM_InvGeneralM4, 1)
1698// Returns a general-purpose inverse of an HMM_Mat4. Note that special-purpose inverses of many transformations
1699// are available and will be more efficient.
1700static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix)
1701{
1702 ASSERT_COVERED(HMM_InvGeneralM4);
1703
1704 HMM_Vec3 C01 = HMM_Cross(Matrix.Columns[0].XYZ, Matrix.Columns[1].XYZ);
1705 HMM_Vec3 C23 = HMM_Cross(Matrix.Columns[2].XYZ, Matrix.Columns[3].XYZ);
1706 HMM_Vec3 B10 = HMM_SubV3(HMM_MulV3F(Matrix.Columns[0].XYZ, Matrix.Columns[1].W), HMM_MulV3F(Matrix.Columns[1].XYZ, Matrix.Columns[0].W));
1707 HMM_Vec3 B32 = HMM_SubV3(HMM_MulV3F(Matrix.Columns[2].XYZ, Matrix.Columns[3].W), HMM_MulV3F(Matrix.Columns[3].XYZ, Matrix.Columns[2].W));
1708
1709 float InvDeterminant = 1.0f / (HMM_DotV3(C01, B32) + HMM_DotV3(C23, B10));
1710 C01 = HMM_MulV3F(C01, InvDeterminant);
1711 C23 = HMM_MulV3F(C23, InvDeterminant);
1712 B10 = HMM_MulV3F(B10, InvDeterminant);
1713 B32 = HMM_MulV3F(B32, InvDeterminant);
1714
1715 HMM_Mat4 Result;
1716 Result.Columns[0] = HMM_V4V(HMM_AddV3(HMM_Cross(Matrix.Columns[1].XYZ, B32), HMM_MulV3F(C23, Matrix.Columns[1].W)), -HMM_DotV3(Matrix.Columns[1].XYZ, C23));
1717 Result.Columns[1] = HMM_V4V(HMM_SubV3(HMM_Cross(B32, Matrix.Columns[0].XYZ), HMM_MulV3F(C23, Matrix.Columns[0].W)), +HMM_DotV3(Matrix.Columns[0].XYZ, C23));
1718 Result.Columns[2] = HMM_V4V(HMM_AddV3(HMM_Cross(Matrix.Columns[3].XYZ, B10), HMM_MulV3F(C01, Matrix.Columns[3].W)), -HMM_DotV3(Matrix.Columns[3].XYZ, C01));
1719 Result.Columns[3] = HMM_V4V(HMM_SubV3(HMM_Cross(B10, Matrix.Columns[2].XYZ), HMM_MulV3F(C01, Matrix.Columns[2].W)), +HMM_DotV3(Matrix.Columns[2].XYZ, C01));
1720
1721 return HMM_TransposeM4(Result);
1722}
1723
1724/*
1725 * Common graphics transformations
1726 */
1727
1728COVERAGE(HMM_Orthographic_RH_NO, 1)
1729// Produces a right-handed orthographic projection matrix with Z ranging from -1 to 1 (the GL convention).
1730// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes.
1731// Near and Far specify the distances to the near and far clipping planes.
1732static inline HMM_Mat4 HMM_Orthographic_RH_NO(float Left, float Right, float Bottom, float Top, float Near, float Far)
1733{
1734 ASSERT_COVERED(HMM_Orthographic_RH_NO);
1735
1736 HMM_Mat4 Result = {0};
1737
1738 Result.Elements[0][0] = 2.0f / (Right - Left);
1739 Result.Elements[1][1] = 2.0f / (Top - Bottom);
1740 Result.Elements[2][2] = 2.0f / (Near - Far);
1741 Result.Elements[3][3] = 1.0f;
1742
1743 Result.Elements[3][0] = (Left + Right) / (Left - Right);
1744 Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
1745 Result.Elements[3][2] = (Near + Far) / (Near - Far);
1746
1747 return Result;
1748}
1749
1750COVERAGE(HMM_Orthographic_RH_ZO, 1)
1751// Produces a right-handed orthographic projection matrix with Z ranging from 0 to 1 (the DirectX convention).
1752// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes.
1753// Near and Far specify the distances to the near and far clipping planes.
1754static inline HMM_Mat4 HMM_Orthographic_RH_ZO(float Left, float Right, float Bottom, float Top, float Near, float Far)
1755{
1756 ASSERT_COVERED(HMM_Orthographic_RH_ZO);
1757
1758 HMM_Mat4 Result = {0};
1759
1760 Result.Elements[0][0] = 2.0f / (Right - Left);
1761 Result.Elements[1][1] = 2.0f / (Top - Bottom);
1762 Result.Elements[2][2] = 1.0f / (Near - Far);
1763 Result.Elements[3][3] = 1.0f;
1764
1765 Result.Elements[3][0] = (Left + Right) / (Left - Right);
1766 Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
1767 Result.Elements[3][2] = (Near) / (Near - Far);
1768
1769 return Result;
1770}
1771
1772COVERAGE(HMM_Orthographic_LH_NO, 1)
1773// Produces a left-handed orthographic projection matrix with Z ranging from -1 to 1 (the GL convention).
1774// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes.
1775// Near and Far specify the distances to the near and far clipping planes.
1776static inline HMM_Mat4 HMM_Orthographic_LH_NO(float Left, float Right, float Bottom, float Top, float Near, float Far)
1777{
1778 ASSERT_COVERED(HMM_Orthographic_LH_NO);
1779
1780 HMM_Mat4 Result = HMM_Orthographic_RH_NO(Left, Right, Bottom, Top, Near, Far);
1781 Result.Elements[2][2] = -Result.Elements[2][2];
1782
1783 return Result;
1784}
1785
1786COVERAGE(HMM_Orthographic_LH_ZO, 1)
1787// Produces a left-handed orthographic projection matrix with Z ranging from 0 to 1 (the DirectX convention).
1788// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes.
1789// Near and Far specify the distances to the near and far clipping planes.
1790static inline HMM_Mat4 HMM_Orthographic_LH_ZO(float Left, float Right, float Bottom, float Top, float Near, float Far)
1791{
1792 ASSERT_COVERED(HMM_Orthographic_LH_ZO);
1793
1794 HMM_Mat4 Result = HMM_Orthographic_RH_ZO(Left, Right, Bottom, Top, Near, Far);
1795 Result.Elements[2][2] = -Result.Elements[2][2];
1796
1797 return Result;
1798}
1799
1800COVERAGE(HMM_InvOrthographic, 1)
1801// Returns an inverse for the given orthographic projection matrix. Works for all orthographic
1802// projection matrices, regardless of handedness or NDC convention.
1803static inline HMM_Mat4 HMM_InvOrthographic(HMM_Mat4 OrthoMatrix)
1804{
1805 ASSERT_COVERED(HMM_InvOrthographic);
1806
1807 HMM_Mat4 Result = {0};
1808 Result.Elements[0][0] = 1.0f / OrthoMatrix.Elements[0][0];
1809 Result.Elements[1][1] = 1.0f / OrthoMatrix.Elements[1][1];
1810 Result.Elements[2][2] = 1.0f / OrthoMatrix.Elements[2][2];
1811 Result.Elements[3][3] = 1.0f;
1812
1813 Result.Elements[3][0] = -OrthoMatrix.Elements[3][0] * Result.Elements[0][0];
1814 Result.Elements[3][1] = -OrthoMatrix.Elements[3][1] * Result.Elements[1][1];
1815 Result.Elements[3][2] = -OrthoMatrix.Elements[3][2] * Result.Elements[2][2];
1816
1817 return Result;
1818}
1819
1820COVERAGE(HMM_Perspective_RH_NO, 1)
1821static inline HMM_Mat4 HMM_Perspective_RH_NO(float FOV, float AspectRatio, float Near, float Far)
1822{
1823 ASSERT_COVERED(HMM_Perspective_RH_NO);
1824
1825 HMM_Mat4 Result = {0};
1826
1827 // See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
1828
1829 float Cotangent = 1.0f / HMM_TanF(FOV / 2.0f);
1830 Result.Elements[0][0] = Cotangent / AspectRatio;
1831 Result.Elements[1][1] = Cotangent;
1832 Result.Elements[2][3] = -1.0f;
1833
1834 Result.Elements[2][2] = (Near + Far) / (Near - Far);
1835 Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far);
1836
1837 return Result;
1838}
1839
1840COVERAGE(HMM_Perspective_RH_ZO, 1)
1841static inline HMM_Mat4 HMM_Perspective_RH_ZO(float FOV, float AspectRatio, float Near, float Far)
1842{
1843 ASSERT_COVERED(HMM_Perspective_RH_ZO);
1844
1845 HMM_Mat4 Result = {0};
1846
1847 // See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
1848
1849 float Cotangent = 1.0f / HMM_TanF(FOV / 2.0f);
1850 Result.Elements[0][0] = Cotangent / AspectRatio;
1851 Result.Elements[1][1] = Cotangent;
1852 Result.Elements[2][3] = -1.0f;
1853
1854 Result.Elements[2][2] = (Far) / (Near - Far);
1855 Result.Elements[3][2] = (Near * Far) / (Near - Far);
1856
1857 return Result;
1858}
1859
1860COVERAGE(HMM_Perspective_LH_NO, 1)
1861static inline HMM_Mat4 HMM_Perspective_LH_NO(float FOV, float AspectRatio, float Near, float Far)
1862{
1863 ASSERT_COVERED(HMM_Perspective_LH_NO);
1864
1865 HMM_Mat4 Result = HMM_Perspective_RH_NO(FOV, AspectRatio, Near, Far);
1866 Result.Elements[2][2] = -Result.Elements[2][2];
1867 Result.Elements[2][3] = -Result.Elements[2][3];
1868
1869 return Result;
1870}
1871
1872COVERAGE(HMM_Perspective_LH_ZO, 1)
1873static inline HMM_Mat4 HMM_Perspective_LH_ZO(float FOV, float AspectRatio, float Near, float Far)
1874{
1875 ASSERT_COVERED(HMM_Perspective_LH_ZO);
1876
1877 HMM_Mat4 Result = HMM_Perspective_RH_ZO(FOV, AspectRatio, Near, Far);
1878 Result.Elements[2][2] = -Result.Elements[2][2];
1879 Result.Elements[2][3] = -Result.Elements[2][3];
1880
1881 return Result;
1882}
1883
1884COVERAGE(HMM_InvPerspective_RH, 1)
1885static inline HMM_Mat4 HMM_InvPerspective_RH(HMM_Mat4 PerspectiveMatrix)
1886{
1887 ASSERT_COVERED(HMM_InvPerspective_RH);
1888
1889 HMM_Mat4 Result = {0};
1890 Result.Elements[0][0] = 1.0f / PerspectiveMatrix.Elements[0][0];
1891 Result.Elements[1][1] = 1.0f / PerspectiveMatrix.Elements[1][1];
1892 Result.Elements[2][2] = 0.0f;
1893
1894 Result.Elements[2][3] = 1.0f / PerspectiveMatrix.Elements[3][2];
1895 Result.Elements[3][3] = PerspectiveMatrix.Elements[2][2] * Result.Elements[2][3];
1896 Result.Elements[3][2] = PerspectiveMatrix.Elements[2][3];
1897
1898 return Result;
1899}
1900
1901COVERAGE(HMM_InvPerspective_LH, 1)
1902static inline HMM_Mat4 HMM_InvPerspective_LH(HMM_Mat4 PerspectiveMatrix)
1903{
1904 ASSERT_COVERED(HMM_InvPerspective_LH);
1905
1906 HMM_Mat4 Result = {0};
1907 Result.Elements[0][0] = 1.0f / PerspectiveMatrix.Elements[0][0];
1908 Result.Elements[1][1] = 1.0f / PerspectiveMatrix.Elements[1][1];
1909 Result.Elements[2][2] = 0.0f;
1910
1911 Result.Elements[2][3] = 1.0f / PerspectiveMatrix.Elements[3][2];
1912 Result.Elements[3][3] = PerspectiveMatrix.Elements[2][2] * -Result.Elements[2][3];
1913 Result.Elements[3][2] = PerspectiveMatrix.Elements[2][3];
1914
1915 return Result;
1916}
1917
1918COVERAGE(HMM_Translate, 1)
1919static inline HMM_Mat4 HMM_Translate(HMM_Vec3 Translation)
1920{
1921 ASSERT_COVERED(HMM_Translate);
1922
1923 HMM_Mat4 Result = HMM_M4D(1.0f);
1924 Result.Elements[3][0] = Translation.X;
1925 Result.Elements[3][1] = Translation.Y;
1926 Result.Elements[3][2] = Translation.Z;
1927
1928 return Result;
1929}
1930
1931COVERAGE(HMM_InvTranslate, 1)
1932static inline HMM_Mat4 HMM_InvTranslate(HMM_Mat4 TranslationMatrix)
1933{
1934 ASSERT_COVERED(HMM_InvTranslate);
1935
1936 HMM_Mat4 Result = TranslationMatrix;
1937 Result.Elements[3][0] = -Result.Elements[3][0];
1938 Result.Elements[3][1] = -Result.Elements[3][1];
1939 Result.Elements[3][2] = -Result.Elements[3][2];
1940
1941 return Result;
1942}
1943
1944COVERAGE(HMM_Rotate_RH, 1)
1945static inline HMM_Mat4 HMM_Rotate_RH(float Angle, HMM_Vec3 Axis)
1946{
1947 ASSERT_COVERED(HMM_Rotate_RH);
1948
1949 HMM_Mat4 Result = HMM_M4D(1.0f);
1950
1951 Axis = HMM_NormV3(Axis);
1952
1953 float SinTheta = HMM_SinF(Angle);
1954 float CosTheta = HMM_CosF(Angle);
1955 float CosValue = 1.0f - CosTheta;
1956
1957 Result.Elements[0][0] = (Axis.X * Axis.X * CosValue) + CosTheta;
1958 Result.Elements[0][1] = (Axis.X * Axis.Y * CosValue) + (Axis.Z * SinTheta);
1959 Result.Elements[0][2] = (Axis.X * Axis.Z * CosValue) - (Axis.Y * SinTheta);
1960
1961 Result.Elements[1][0] = (Axis.Y * Axis.X * CosValue) - (Axis.Z * SinTheta);
1962 Result.Elements[1][1] = (Axis.Y * Axis.Y * CosValue) + CosTheta;
1963 Result.Elements[1][2] = (Axis.Y * Axis.Z * CosValue) + (Axis.X * SinTheta);
1964
1965 Result.Elements[2][0] = (Axis.Z * Axis.X * CosValue) + (Axis.Y * SinTheta);
1966 Result.Elements[2][1] = (Axis.Z * Axis.Y * CosValue) - (Axis.X * SinTheta);
1967 Result.Elements[2][2] = (Axis.Z * Axis.Z * CosValue) + CosTheta;
1968
1969 return Result;
1970}
1971
1972COVERAGE(HMM_Rotate_LH, 1)
1973static inline HMM_Mat4 HMM_Rotate_LH(float Angle, HMM_Vec3 Axis)
1974{
1975 ASSERT_COVERED(HMM_Rotate_LH);
1976 /* NOTE(lcf): Matrix will be inverse/transpose of RH. */
1977 return HMM_Rotate_RH(-Angle, Axis);
1978}
1979
1980COVERAGE(HMM_InvRotate, 1)
1981static inline HMM_Mat4 HMM_InvRotate(HMM_Mat4 RotationMatrix)
1982{
1983 ASSERT_COVERED(HMM_InvRotate);
1984 return HMM_TransposeM4(RotationMatrix);
1985}
1986
1987COVERAGE(HMM_Scale, 1)
1988static inline HMM_Mat4 HMM_Scale(HMM_Vec3 Scale)
1989{
1990 ASSERT_COVERED(HMM_Scale);
1991
1992 HMM_Mat4 Result = HMM_M4D(1.0f);
1993 Result.Elements[0][0] = Scale.X;
1994 Result.Elements[1][1] = Scale.Y;
1995 Result.Elements[2][2] = Scale.Z;
1996
1997 return Result;
1998}
1999
2000COVERAGE(HMM_InvScale, 1)
2001static inline HMM_Mat4 HMM_InvScale(HMM_Mat4 ScaleMatrix)
2002{
2003 ASSERT_COVERED(HMM_InvScale);
2004
2005 HMM_Mat4 Result = ScaleMatrix;
2006 Result.Elements[0][0] = 1.0f / Result.Elements[0][0];
2007 Result.Elements[1][1] = 1.0f / Result.Elements[1][1];
2008 Result.Elements[2][2] = 1.0f / Result.Elements[2][2];
2009
2010 return Result;
2011}
2012
2013static inline HMM_Mat4 _HMM_LookAt(HMM_Vec3 F, HMM_Vec3 S, HMM_Vec3 U, HMM_Vec3 Eye)
2014{
2015 HMM_Mat4 Result;
2016
2017 Result.Elements[0][0] = S.X;
2018 Result.Elements[0][1] = U.X;
2019 Result.Elements[0][2] = -F.X;
2020 Result.Elements[0][3] = 0.0f;
2021
2022 Result.Elements[1][0] = S.Y;
2023 Result.Elements[1][1] = U.Y;
2024 Result.Elements[1][2] = -F.Y;
2025 Result.Elements[1][3] = 0.0f;
2026
2027 Result.Elements[2][0] = S.Z;
2028 Result.Elements[2][1] = U.Z;
2029 Result.Elements[2][2] = -F.Z;
2030 Result.Elements[2][3] = 0.0f;
2031
2032 Result.Elements[3][0] = -HMM_DotV3(S, Eye);
2033 Result.Elements[3][1] = -HMM_DotV3(U, Eye);
2034 Result.Elements[3][2] = HMM_DotV3(F, Eye);
2035 Result.Elements[3][3] = 1.0f;
2036
2037 return Result;
2038}
2039
2040COVERAGE(HMM_LookAt_RH, 1)
2041static inline HMM_Mat4 HMM_LookAt_RH(HMM_Vec3 Eye, HMM_Vec3 Center, HMM_Vec3 Up)
2042{
2043 ASSERT_COVERED(HMM_LookAt_RH);
2044
2045 HMM_Vec3 F = HMM_NormV3(HMM_SubV3(Center, Eye));
2046 HMM_Vec3 S = HMM_NormV3(HMM_Cross(F, Up));
2047 HMM_Vec3 U = HMM_Cross(S, F);
2048
2049 return _HMM_LookAt(F, S, U, Eye);
2050}
2051
2052COVERAGE(HMM_LookAt_LH, 1)
2053static inline HMM_Mat4 HMM_LookAt_LH(HMM_Vec3 Eye, HMM_Vec3 Center, HMM_Vec3 Up)
2054{
2055 ASSERT_COVERED(HMM_LookAt_LH);
2056
2057 HMM_Vec3 F = HMM_NormV3(HMM_SubV3(Eye, Center));
2058 HMM_Vec3 S = HMM_NormV3(HMM_Cross(F, Up));
2059 HMM_Vec3 U = HMM_Cross(S, F);
2060
2061 return _HMM_LookAt(F, S, U, Eye);
2062}
2063
2064COVERAGE(HMM_InvLookAt, 1)
2065static inline HMM_Mat4 HMM_InvLookAt(HMM_Mat4 Matrix)
2066{
2067 ASSERT_COVERED(HMM_InvLookAt);
2068 HMM_Mat4 Result;
2069
2070 HMM_Mat3 Rotation = {0};
2071 Rotation.Columns[0] = Matrix.Columns[0].XYZ;
2072 Rotation.Columns[1] = Matrix.Columns[1].XYZ;
2073 Rotation.Columns[2] = Matrix.Columns[2].XYZ;
2074 Rotation = HMM_TransposeM3(Rotation);
2075
2076 Result.Columns[0] = HMM_V4V(Rotation.Columns[0], 0.0f);
2077 Result.Columns[1] = HMM_V4V(Rotation.Columns[1], 0.0f);
2078 Result.Columns[2] = HMM_V4V(Rotation.Columns[2], 0.0f);
2079 Result.Columns[3] = HMM_MulV4F(Matrix.Columns[3], -1.0f);
2080 Result.Elements[3][0] = -1.0f * Matrix.Elements[3][0] /
2081 (Rotation.Elements[0][0] + Rotation.Elements[0][1] + Rotation.Elements[0][2]);
2082 Result.Elements[3][1] = -1.0f * Matrix.Elements[3][1] /
2083 (Rotation.Elements[1][0] + Rotation.Elements[1][1] + Rotation.Elements[1][2]);
2084 Result.Elements[3][2] = -1.0f * Matrix.Elements[3][2] /
2085 (Rotation.Elements[2][0] + Rotation.Elements[2][1] + Rotation.Elements[2][2]);
2086 Result.Elements[3][3] = 1.0f;
2087
2088 return Result;
2089}
2090
2091/*
2092 * Quaternion operations
2093 */
2094
2095COVERAGE(HMM_Q, 1)
2096static inline HMM_Quat HMM_Q(float X, float Y, float Z, float W)
2097{
2098 ASSERT_COVERED(HMM_Q);
2099
2100 HMM_Quat Result;
2101
2102#ifdef HANDMADE_MATH__USE_SSE
2103 Result.SSE = _mm_setr_ps(X, Y, Z, W);
2104#elif defined(HANDMADE_MATH__USE_NEON)
2105 float32x4_t v = { X, Y, Z, W };
2106 Result.NEON = v;
2107#else
2108 Result.X = X;
2109 Result.Y = Y;
2110 Result.Z = Z;
2111 Result.W = W;
2112#endif
2113
2114 return Result;
2115}
2116
2117COVERAGE(HMM_QV4, 1)
2118static inline HMM_Quat HMM_QV4(HMM_Vec4 Vector)
2119{
2120 ASSERT_COVERED(HMM_QV4);
2121
2122 HMM_Quat Result;
2123
2124#ifdef HANDMADE_MATH__USE_SSE
2125 Result.SSE = Vector.SSE;
2126#elif defined(HANDMADE_MATH__USE_NEON)
2127 Result.NEON = Vector.NEON;
2128#else
2129 Result.X = Vector.X;
2130 Result.Y = Vector.Y;
2131 Result.Z = Vector.Z;
2132 Result.W = Vector.W;
2133#endif
2134
2135 return Result;
2136}
2137
2138COVERAGE(HMM_AddQ, 1)
2139static inline HMM_Quat HMM_AddQ(HMM_Quat Left, HMM_Quat Right)
2140{
2141 ASSERT_COVERED(HMM_AddQ);
2142
2143 HMM_Quat Result;
2144
2145#ifdef HANDMADE_MATH__USE_SSE
2146 Result.SSE = _mm_add_ps(Left.SSE, Right.SSE);
2147#elif defined(HANDMADE_MATH__USE_NEON)
2148 Result.NEON = vaddq_f32(Left.NEON, Right.NEON);
2149#else
2150
2151 Result.X = Left.X + Right.X;
2152 Result.Y = Left.Y + Right.Y;
2153 Result.Z = Left.Z + Right.Z;
2154 Result.W = Left.W + Right.W;
2155#endif
2156
2157 return Result;
2158}
2159
2160COVERAGE(HMM_SubQ, 1)
2161static inline HMM_Quat HMM_SubQ(HMM_Quat Left, HMM_Quat Right)
2162{
2163 ASSERT_COVERED(HMM_SubQ);
2164
2165 HMM_Quat Result;
2166
2167#ifdef HANDMADE_MATH__USE_SSE
2168 Result.SSE = _mm_sub_ps(Left.SSE, Right.SSE);
2169#elif defined(HANDMADE_MATH__USE_NEON)
2170 Result.NEON = vsubq_f32(Left.NEON, Right.NEON);
2171#else
2172 Result.X = Left.X - Right.X;
2173 Result.Y = Left.Y - Right.Y;
2174 Result.Z = Left.Z - Right.Z;
2175 Result.W = Left.W - Right.W;
2176#endif
2177
2178 return Result;
2179}
2180
2181COVERAGE(HMM_MulQ, 1)
2182static inline HMM_Quat HMM_MulQ(HMM_Quat Left, HMM_Quat Right)
2183{
2184 ASSERT_COVERED(HMM_MulQ);
2185
2186 HMM_Quat Result;
2187
2188#ifdef HANDMADE_MATH__USE_SSE
2189 __m128 SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, _MM_SHUFFLE(0, 0, 0, 0)), _mm_setr_ps(0.f, -0.f, 0.f, -0.f));
2190 __m128 SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(0, 1, 2, 3));
2191 __m128 SSEResultThree = _mm_mul_ps(SSEResultTwo, SSEResultOne);
2192
2193 SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, _MM_SHUFFLE(1, 1, 1, 1)) , _mm_setr_ps(0.f, 0.f, -0.f, -0.f));
2194 SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(1, 0, 3, 2));
2195 SSEResultThree = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));
2196
2197 SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, _MM_SHUFFLE(2, 2, 2, 2)), _mm_setr_ps(-0.f, 0.f, 0.f, -0.f));
2198 SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(2, 3, 0, 1));
2199 SSEResultThree = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));
2200
2201 SSEResultOne = _mm_shuffle_ps(Left.SSE, Left.SSE, _MM_SHUFFLE(3, 3, 3, 3));
2202 SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(3, 2, 1, 0));
2203 Result.SSE = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));
2204#elif defined(HANDMADE_MATH__USE_NEON)
2205 float32x4_t Right1032 = vrev64q_f32(Right.NEON);
2206 float32x4_t Right3210 = vcombine_f32(vget_high_f32(Right1032), vget_low_f32(Right1032));
2207 float32x4_t Right2301 = vrev64q_f32(Right3210);
2208
2209 float32x4_t FirstSign = {1.0f, -1.0f, 1.0f, -1.0f};
2210 Result.NEON = vmulq_f32(Right3210, vmulq_f32(vdupq_laneq_f32(Left.NEON, 0), FirstSign));
2211 float32x4_t SecondSign = {1.0f, 1.0f, -1.0f, -1.0f};
2212 Result.NEON = vfmaq_f32(Result.NEON, Right2301, vmulq_f32(vdupq_laneq_f32(Left.NEON, 1), SecondSign));
2213 float32x4_t ThirdSign = {-1.0f, 1.0f, 1.0f, -1.0f};
2214 Result.NEON = vfmaq_f32(Result.NEON, Right1032, vmulq_f32(vdupq_laneq_f32(Left.NEON, 2), ThirdSign));
2215 Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.NEON, Left.NEON, 3);
2216
2217#else
2218 Result.X = Right.Elements[3] * +Left.Elements[0];
2219 Result.Y = Right.Elements[2] * -Left.Elements[0];
2220 Result.Z = Right.Elements[1] * +Left.Elements[0];
2221 Result.W = Right.Elements[0] * -Left.Elements[0];
2222
2223 Result.X += Right.Elements[2] * +Left.Elements[1];
2224 Result.Y += Right.Elements[3] * +Left.Elements[1];
2225 Result.Z += Right.Elements[0] * -Left.Elements[1];
2226 Result.W += Right.Elements[1] * -Left.Elements[1];
2227
2228 Result.X += Right.Elements[1] * -Left.Elements[2];
2229 Result.Y += Right.Elements[0] * +Left.Elements[2];
2230 Result.Z += Right.Elements[3] * +Left.Elements[2];
2231 Result.W += Right.Elements[2] * -Left.Elements[2];
2232
2233 Result.X += Right.Elements[0] * +Left.Elements[3];
2234 Result.Y += Right.Elements[1] * +Left.Elements[3];
2235 Result.Z += Right.Elements[2] * +Left.Elements[3];
2236 Result.W += Right.Elements[3] * +Left.Elements[3];
2237#endif
2238
2239 return Result;
2240}
2241
2242COVERAGE(HMM_MulQF, 1)
2243static inline HMM_Quat HMM_MulQF(HMM_Quat Left, float Multiplicative)
2244{
2245 ASSERT_COVERED(HMM_MulQF);
2246
2247 HMM_Quat Result;
2248
2249#ifdef HANDMADE_MATH__USE_SSE
2250 __m128 Scalar = _mm_set1_ps(Multiplicative);
2251 Result.SSE = _mm_mul_ps(Left.SSE, Scalar);
2252#elif defined(HANDMADE_MATH__USE_NEON)
2253 Result.NEON = vmulq_n_f32(Left.NEON, Multiplicative);
2254#else
2255 Result.X = Left.X * Multiplicative;
2256 Result.Y = Left.Y * Multiplicative;
2257 Result.Z = Left.Z * Multiplicative;
2258 Result.W = Left.W * Multiplicative;
2259#endif
2260
2261 return Result;
2262}
2263
2264COVERAGE(HMM_DivQF, 1)
2265static inline HMM_Quat HMM_DivQF(HMM_Quat Left, float Divnd)
2266{
2267 ASSERT_COVERED(HMM_DivQF);
2268
2269 HMM_Quat Result;
2270
2271#ifdef HANDMADE_MATH__USE_SSE
2272 __m128 Scalar = _mm_set1_ps(Divnd);
2273 Result.SSE = _mm_div_ps(Left.SSE, Scalar);
2274#elif defined(HANDMADE_MATH__USE_NEON)
2275 float32x4_t Scalar = vdupq_n_f32(Divnd);
2276 Result.NEON = vdivq_f32(Left.NEON, Scalar);
2277#else
2278 Result.X = Left.X / Divnd;
2279 Result.Y = Left.Y / Divnd;
2280 Result.Z = Left.Z / Divnd;
2281 Result.W = Left.W / Divnd;
2282#endif
2283
2284 return Result;
2285}
2286
2287COVERAGE(HMM_DotQ, 1)
2288static inline float HMM_DotQ(HMM_Quat Left, HMM_Quat Right)
2289{
2290 ASSERT_COVERED(HMM_DotQ);
2291
2292 float Result;
2293
2294#ifdef HANDMADE_MATH__USE_SSE
2295 __m128 SSEResultOne = _mm_mul_ps(Left.SSE, Right.SSE);
2296 __m128 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(2, 3, 0, 1));
2297 SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);
2298 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3));
2299 SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);
2300 _mm_store_ss(&Result, SSEResultOne);
2301#elif defined(HANDMADE_MATH__USE_NEON)
2302 float32x4_t NEONMultiplyResult = vmulq_f32(Left.NEON, Right.NEON);
2303 float32x4_t NEONHalfAdd = vpaddq_f32(NEONMultiplyResult, NEONMultiplyResult);
2304 float32x4_t NEONFullAdd = vpaddq_f32(NEONHalfAdd, NEONHalfAdd);
2305 Result = vgetq_lane_f32(NEONFullAdd, 0);
2306#else
2307 Result = ((Left.X * Right.X) + (Left.Z * Right.Z)) + ((Left.Y * Right.Y) + (Left.W * Right.W));
2308#endif
2309
2310 return Result;
2311}
2312
2313COVERAGE(HMM_InvQ, 1)
2314static inline HMM_Quat HMM_InvQ(HMM_Quat Left)
2315{
2316 ASSERT_COVERED(HMM_InvQ);
2317
2318 HMM_Quat Result;
2319 Result.X = -Left.X;
2320 Result.Y = -Left.Y;
2321 Result.Z = -Left.Z;
2322 Result.W = Left.W;
2323
2324 return HMM_DivQF(Result, (HMM_DotQ(Left, Left)));
2325}
2326
2327COVERAGE(HMM_NormQ, 1)
2328static inline HMM_Quat HMM_NormQ(HMM_Quat Quat)
2329{
2330 ASSERT_COVERED(HMM_NormQ);
2331
2332 /* NOTE(lcf): Take advantage of SSE implementation in HMM_NormV4 */
2333 HMM_Vec4 Vec = HMM_V4(Quat.X, Quat.Y, Quat.Z, Quat.W);
2334 Vec = HMM_NormV4(Vec);
2335 HMM_Quat Result = HMM_QV4(Vec);
2336
2337 return Result;
2338}
2339
2340static inline HMM_Quat _HMM_MixQ(HMM_Quat Left, float MixLeft, HMM_Quat Right, float MixRight) {
2341 HMM_Quat Result;
2342
2343#ifdef HANDMADE_MATH__USE_SSE
2344 __m128 ScalarLeft = _mm_set1_ps(MixLeft);
2345 __m128 ScalarRight = _mm_set1_ps(MixRight);
2346 __m128 SSEResultOne = _mm_mul_ps(Left.SSE, ScalarLeft);
2347 __m128 SSEResultTwo = _mm_mul_ps(Right.SSE, ScalarRight);
2348 Result.SSE = _mm_add_ps(SSEResultOne, SSEResultTwo);
2349#elif defined(HANDMADE_MATH__USE_NEON)
2350 float32x4_t ScaledLeft = vmulq_n_f32(Left.NEON, MixLeft);
2351 float32x4_t ScaledRight = vmulq_n_f32(Right.NEON, MixRight);
2352 Result.NEON = vaddq_f32(ScaledLeft, ScaledRight);
2353#else
2354 Result.X = Left.X*MixLeft + Right.X*MixRight;
2355 Result.Y = Left.Y*MixLeft + Right.Y*MixRight;
2356 Result.Z = Left.Z*MixLeft + Right.Z*MixRight;
2357 Result.W = Left.W*MixLeft + Right.W*MixRight;
2358#endif
2359
2360 return Result;
2361}
2362
2363COVERAGE(HMM_NLerp, 1)
2364static inline HMM_Quat HMM_NLerp(HMM_Quat Left, float Time, HMM_Quat Right)
2365{
2366 ASSERT_COVERED(HMM_NLerp);
2367
2368 HMM_Quat Result = _HMM_MixQ(Left, 1.0f-Time, Right, Time);
2369 Result = HMM_NormQ(Result);
2370
2371 return Result;
2372}
2373
2374COVERAGE(HMM_SLerp, 1)
2375static inline HMM_Quat HMM_SLerp(HMM_Quat Left, float Time, HMM_Quat Right)
2376{
2377 ASSERT_COVERED(HMM_SLerp);
2378
2379 HMM_Quat Result;
2380
2381 float Cos_Theta = HMM_DotQ(Left, Right);
2382
2383 if (Cos_Theta < 0.0f) { /* NOTE(lcf): Take shortest path on Hyper-sphere */
2384 Cos_Theta = -Cos_Theta;
2385 Right = HMM_Q(-Right.X, -Right.Y, -Right.Z, -Right.W);
2386 }
2387
2388 /* NOTE(lcf): Use Normalized Linear interpolation when vectors are roughly not L.I. */
2389 if (Cos_Theta > 0.9995f) {
2390 Result = HMM_NLerp(Left, Time, Right);
2391 } else {
2392 float Angle = HMM_ACosF(Cos_Theta);
2393 float MixLeft = HMM_SinF((1.0f - Time) * Angle);
2394 float MixRight = HMM_SinF(Time * Angle);
2395
2396 Result = _HMM_MixQ(Left, MixLeft, Right, MixRight);
2397 Result = HMM_NormQ(Result);
2398 }
2399
2400 return Result;
2401}
2402
2403COVERAGE(HMM_QToM4, 1)
2404static inline HMM_Mat4 HMM_QToM4(HMM_Quat Left)
2405{
2406 ASSERT_COVERED(HMM_QToM4);
2407
2408 HMM_Mat4 Result;
2409
2410 HMM_Quat NormalizedQ = HMM_NormQ(Left);
2411
2412 float XX, YY, ZZ,
2413 XY, XZ, YZ,
2414 WX, WY, WZ;
2415
2416 XX = NormalizedQ.X * NormalizedQ.X;
2417 YY = NormalizedQ.Y * NormalizedQ.Y;
2418 ZZ = NormalizedQ.Z * NormalizedQ.Z;
2419 XY = NormalizedQ.X * NormalizedQ.Y;
2420 XZ = NormalizedQ.X * NormalizedQ.Z;
2421 YZ = NormalizedQ.Y * NormalizedQ.Z;
2422 WX = NormalizedQ.W * NormalizedQ.X;
2423 WY = NormalizedQ.W * NormalizedQ.Y;
2424 WZ = NormalizedQ.W * NormalizedQ.Z;
2425
2426 Result.Elements[0][0] = 1.0f - 2.0f * (YY + ZZ);
2427 Result.Elements[0][1] = 2.0f * (XY + WZ);
2428 Result.Elements[0][2] = 2.0f * (XZ - WY);
2429 Result.Elements[0][3] = 0.0f;
2430
2431 Result.Elements[1][0] = 2.0f * (XY - WZ);
2432 Result.Elements[1][1] = 1.0f - 2.0f * (XX + ZZ);
2433 Result.Elements[1][2] = 2.0f * (YZ + WX);
2434 Result.Elements[1][3] = 0.0f;
2435
2436 Result.Elements[2][0] = 2.0f * (XZ + WY);
2437 Result.Elements[2][1] = 2.0f * (YZ - WX);
2438 Result.Elements[2][2] = 1.0f - 2.0f * (XX + YY);
2439 Result.Elements[2][3] = 0.0f;
2440
2441 Result.Elements[3][0] = 0.0f;
2442 Result.Elements[3][1] = 0.0f;
2443 Result.Elements[3][2] = 0.0f;
2444 Result.Elements[3][3] = 1.0f;
2445
2446 return Result;
2447}
2448
2449// This method taken from Mike Day at Insomniac Games.
2450// https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf
2451//
2452// Note that as mentioned at the top of the paper, the paper assumes the matrix
2453// would be *post*-multiplied to a vector to rotate it, meaning the matrix is
2454// the transpose of what we're dealing with. But, because our matrices are
2455// stored in column-major order, the indices *appear* to match the paper.
2456//
2457// For example, m12 in the paper is row 1, column 2. We need to transpose it to
2458// row 2, column 1. But, because the column comes first when referencing
2459// elements, it looks like M.Elements[1][2].
2460//
2461// Don't be confused! Or if you must be confused, at least trust this
2462// comment. :)
2463COVERAGE(HMM_M4ToQ_RH, 4)
2464static inline HMM_Quat HMM_M4ToQ_RH(HMM_Mat4 M)
2465{
2466 float T;
2467 HMM_Quat Q;
2468
2469 if (M.Elements[2][2] < 0.0f) {
2470 if (M.Elements[0][0] > M.Elements[1][1]) {
2471 ASSERT_COVERED(HMM_M4ToQ_RH);
2472
2473 T = 1 + M.Elements[0][0] - M.Elements[1][1] - M.Elements[2][2];
2474 Q = HMM_Q(
2475 T,
2476 M.Elements[0][1] + M.Elements[1][0],
2477 M.Elements[2][0] + M.Elements[0][2],
2478 M.Elements[1][2] - M.Elements[2][1]
2479 );
2480 } else {
2481 ASSERT_COVERED(HMM_M4ToQ_RH);
2482
2483 T = 1 - M.Elements[0][0] + M.Elements[1][1] - M.Elements[2][2];
2484 Q = HMM_Q(
2485 M.Elements[0][1] + M.Elements[1][0],
2486 T,
2487 M.Elements[1][2] + M.Elements[2][1],
2488 M.Elements[2][0] - M.Elements[0][2]
2489 );
2490 }
2491 } else {
2492 if (M.Elements[0][0] < -M.Elements[1][1]) {
2493 ASSERT_COVERED(HMM_M4ToQ_RH);
2494
2495 T = 1 - M.Elements[0][0] - M.Elements[1][1] + M.Elements[2][2];
2496 Q = HMM_Q(
2497 M.Elements[2][0] + M.Elements[0][2],
2498 M.Elements[1][2] + M.Elements[2][1],
2499 T,
2500 M.Elements[0][1] - M.Elements[1][0]
2501 );
2502 } else {
2503 ASSERT_COVERED(HMM_M4ToQ_RH);
2504
2505 T = 1 + M.Elements[0][0] + M.Elements[1][1] + M.Elements[2][2];
2506 Q = HMM_Q(
2507 M.Elements[1][2] - M.Elements[2][1],
2508 M.Elements[2][0] - M.Elements[0][2],
2509 M.Elements[0][1] - M.Elements[1][0],
2510 T
2511 );
2512 }
2513 }
2514
2515 Q = HMM_MulQF(Q, 0.5f / HMM_SqrtF(T));
2516
2517 return Q;
2518}
2519
2520COVERAGE(HMM_M4ToQ_LH, 4)
2521static inline HMM_Quat HMM_M4ToQ_LH(HMM_Mat4 M)
2522{
2523 float T;
2524 HMM_Quat Q;
2525
2526 if (M.Elements[2][2] < 0.0f) {
2527 if (M.Elements[0][0] > M.Elements[1][1]) {
2528 ASSERT_COVERED(HMM_M4ToQ_LH);
2529
2530 T = 1 + M.Elements[0][0] - M.Elements[1][1] - M.Elements[2][2];
2531 Q = HMM_Q(
2532 T,
2533 M.Elements[0][1] + M.Elements[1][0],
2534 M.Elements[2][0] + M.Elements[0][2],
2535 M.Elements[2][1] - M.Elements[1][2]
2536 );
2537 } else {
2538 ASSERT_COVERED(HMM_M4ToQ_LH);
2539
2540 T = 1 - M.Elements[0][0] + M.Elements[1][1] - M.Elements[2][2];
2541 Q = HMM_Q(
2542 M.Elements[0][1] + M.Elements[1][0],
2543 T,
2544 M.Elements[1][2] + M.Elements[2][1],
2545 M.Elements[0][2] - M.Elements[2][0]
2546 );
2547 }
2548 } else {
2549 if (M.Elements[0][0] < -M.Elements[1][1]) {
2550 ASSERT_COVERED(HMM_M4ToQ_LH);
2551
2552 T = 1 - M.Elements[0][0] - M.Elements[1][1] + M.Elements[2][2];
2553 Q = HMM_Q(
2554 M.Elements[2][0] + M.Elements[0][2],
2555 M.Elements[1][2] + M.Elements[2][1],
2556 T,
2557 M.Elements[1][0] - M.Elements[0][1]
2558 );
2559 } else {
2560 ASSERT_COVERED(HMM_M4ToQ_LH);
2561
2562 T = 1 + M.Elements[0][0] + M.Elements[1][1] + M.Elements[2][2];
2563 Q = HMM_Q(
2564 M.Elements[2][1] - M.Elements[1][2],
2565 M.Elements[0][2] - M.Elements[2][0],
2566 M.Elements[1][0] - M.Elements[0][2],
2567 T
2568 );
2569 }
2570 }
2571
2572 Q = HMM_MulQF(Q, 0.5f / HMM_SqrtF(T));
2573
2574 return Q;
2575}
2576
2577
2578COVERAGE(HMM_QFromAxisAngle_RH, 1)
2579static inline HMM_Quat HMM_QFromAxisAngle_RH(HMM_Vec3 Axis, float Angle)
2580{
2581 ASSERT_COVERED(HMM_QFromAxisAngle_RH);
2582
2583 HMM_Quat Result;
2584
2585 HMM_Vec3 AxisNormalized = HMM_NormV3(Axis);
2586 float SineOfRotation = HMM_SinF(Angle / 2.0f);
2587
2588 Result.XYZ = HMM_MulV3F(AxisNormalized, SineOfRotation);
2589 Result.W = HMM_CosF(Angle / 2.0f);
2590
2591 return Result;
2592}
2593
2594COVERAGE(HMM_QFromAxisAngle_LH, 1)
2595static inline HMM_Quat HMM_QFromAxisAngle_LH(HMM_Vec3 Axis, float Angle)
2596{
2597 ASSERT_COVERED(HMM_QFromAxisAngle_LH);
2598
2599 return HMM_QFromAxisAngle_RH(Axis, -Angle);
2600}
2601
2602COVERAGE(HMM_QFromNormPair, 1)
2603static inline HMM_Quat HMM_QFromNormPair(HMM_Vec3 Left, HMM_Vec3 Right)
2604{
2605 ASSERT_COVERED(HMM_QFromNormPair);
2606
2607 HMM_Quat Result;
2608
2609 Result.XYZ = HMM_Cross(Left, Right);
2610 Result.W = 1.0f + HMM_DotV3(Left, Right);
2611
2612 return HMM_NormQ(Result);
2613}
2614
2615COVERAGE(HMM_QFromVecPair, 1)
2616static inline HMM_Quat HMM_QFromVecPair(HMM_Vec3 Left, HMM_Vec3 Right)
2617{
2618 ASSERT_COVERED(HMM_QFromVecPair);
2619
2620 return HMM_QFromNormPair(HMM_NormV3(Left), HMM_NormV3(Right));
2621}
2622
2623COVERAGE(HMM_RotateV2, 1)
2624static inline HMM_Vec2 HMM_RotateV2(HMM_Vec2 V, float Angle)
2625{
2626 ASSERT_COVERED(HMM_RotateV2)
2627
2628 float sinA = HMM_SinF(Angle);
2629 float cosA = HMM_CosF(Angle);
2630
2631 return HMM_V2(V.X * cosA - V.Y * sinA, V.X * sinA + V.Y * cosA);
2632}
2633
2634// implementation from
2635// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
2636COVERAGE(HMM_RotateV3Q, 1)
2637static inline HMM_Vec3 HMM_RotateV3Q(HMM_Vec3 V, HMM_Quat Q)
2638{
2639 ASSERT_COVERED(HMM_RotateV3Q);
2640
2641 HMM_Vec3 t = HMM_MulV3F(HMM_Cross(Q.XYZ, V), 2);
2642 return HMM_AddV3(V, HMM_AddV3(HMM_MulV3F(t, Q.W), HMM_Cross(Q.XYZ, t)));
2643}
2644
2645COVERAGE(HMM_RotateV3AxisAngle_LH, 1)
2646static inline HMM_Vec3 HMM_RotateV3AxisAngle_LH(HMM_Vec3 V, HMM_Vec3 Axis, float Angle) {
2647 ASSERT_COVERED(HMM_RotateV3AxisAngle_LH);
2648
2649 return HMM_RotateV3Q(V, HMM_QFromAxisAngle_LH(Axis, Angle));
2650}
2651
2652COVERAGE(HMM_RotateV3AxisAngle_RH, 1)
2653static inline HMM_Vec3 HMM_RotateV3AxisAngle_RH(HMM_Vec3 V, HMM_Vec3 Axis, float Angle) {
2654 ASSERT_COVERED(HMM_RotateV3AxisAngle_RH);
2655
2656 return HMM_RotateV3Q(V, HMM_QFromAxisAngle_RH(Axis, Angle));
2657}
2658
2659
2660#ifdef __cplusplus
2661}
2662#endif
2663
2664#ifdef __cplusplus
2665
2666COVERAGE(HMM_LenV2CPP, 1)
2667static inline float HMM_Len(HMM_Vec2 A)
2668{
2669 ASSERT_COVERED(HMM_LenV2CPP);
2670 return HMM_LenV2(A);
2671}
2672
2673COVERAGE(HMM_LenV3CPP, 1)
2674static inline float HMM_Len(HMM_Vec3 A)
2675{
2676 ASSERT_COVERED(HMM_LenV3CPP);
2677 return HMM_LenV3(A);
2678}
2679
2680COVERAGE(HMM_LenV4CPP, 1)
2681static inline float HMM_Len(HMM_Vec4 A)
2682{
2683 ASSERT_COVERED(HMM_LenV4CPP);
2684 return HMM_LenV4(A);
2685}
2686
2687COVERAGE(HMM_LenSqrV2CPP, 1)
2688static inline float HMM_LenSqr(HMM_Vec2 A)
2689{
2690 ASSERT_COVERED(HMM_LenSqrV2CPP);
2691 return HMM_LenSqrV2(A);
2692}
2693
2694COVERAGE(HMM_LenSqrV3CPP, 1)
2695static inline float HMM_LenSqr(HMM_Vec3 A)
2696{
2697 ASSERT_COVERED(HMM_LenSqrV3CPP);
2698 return HMM_LenSqrV3(A);
2699}
2700
2701COVERAGE(HMM_LenSqrV4CPP, 1)
2702static inline float HMM_LenSqr(HMM_Vec4 A)
2703{
2704 ASSERT_COVERED(HMM_LenSqrV4CPP);
2705 return HMM_LenSqrV4(A);
2706}
2707
2708COVERAGE(HMM_NormV2CPP, 1)
2709static inline HMM_Vec2 HMM_Norm(HMM_Vec2 A)
2710{
2711 ASSERT_COVERED(HMM_NormV2CPP);
2712 return HMM_NormV2(A);
2713}
2714
2715COVERAGE(HMM_NormV3CPP, 1)
2716static inline HMM_Vec3 HMM_Norm(HMM_Vec3 A)
2717{
2718 ASSERT_COVERED(HMM_NormV3CPP);
2719 return HMM_NormV3(A);
2720}
2721
2722COVERAGE(HMM_NormV4CPP, 1)
2723static inline HMM_Vec4 HMM_Norm(HMM_Vec4 A)
2724{
2725 ASSERT_COVERED(HMM_NormV4CPP);
2726 return HMM_NormV4(A);
2727}
2728
2729COVERAGE(HMM_NormQCPP, 1)
2730static inline HMM_Quat HMM_Norm(HMM_Quat A)
2731{
2732 ASSERT_COVERED(HMM_NormQCPP);
2733 return HMM_NormQ(A);
2734}
2735
2736COVERAGE(HMM_DotV2CPP, 1)
2737static inline float HMM_Dot(HMM_Vec2 Left, HMM_Vec2 VecTwo)
2738{
2739 ASSERT_COVERED(HMM_DotV2CPP);
2740 return HMM_DotV2(Left, VecTwo);
2741}
2742
2743COVERAGE(HMM_DotV3CPP, 1)
2744static inline float HMM_Dot(HMM_Vec3 Left, HMM_Vec3 VecTwo)
2745{
2746 ASSERT_COVERED(HMM_DotV3CPP);
2747 return HMM_DotV3(Left, VecTwo);
2748}
2749
2750COVERAGE(HMM_DotV4CPP, 1)
2751static inline float HMM_Dot(HMM_Vec4 Left, HMM_Vec4 VecTwo)
2752{
2753 ASSERT_COVERED(HMM_DotV4CPP);
2754 return HMM_DotV4(Left, VecTwo);
2755}
2756
2757COVERAGE(HMM_LerpV2CPP, 1)
2758static inline HMM_Vec2 HMM_Lerp(HMM_Vec2 Left, float Time, HMM_Vec2 Right)
2759{
2760 ASSERT_COVERED(HMM_LerpV2CPP);
2761 return HMM_LerpV2(Left, Time, Right);
2762}
2763
2764COVERAGE(HMM_LerpV3CPP, 1)
2765static inline HMM_Vec3 HMM_Lerp(HMM_Vec3 Left, float Time, HMM_Vec3 Right)
2766{
2767 ASSERT_COVERED(HMM_LerpV3CPP);
2768 return HMM_LerpV3(Left, Time, Right);
2769}
2770
2771COVERAGE(HMM_LerpV4CPP, 1)
2772static inline HMM_Vec4 HMM_Lerp(HMM_Vec4 Left, float Time, HMM_Vec4 Right)
2773{
2774 ASSERT_COVERED(HMM_LerpV4CPP);
2775 return HMM_LerpV4(Left, Time, Right);
2776}
2777
2778COVERAGE(HMM_TransposeM2CPP, 1)
2779static inline HMM_Mat2 HMM_Transpose(HMM_Mat2 Matrix)
2780{
2781 ASSERT_COVERED(HMM_TransposeM2CPP);
2782 return HMM_TransposeM2(Matrix);
2783}
2784
2785COVERAGE(HMM_TransposeM3CPP, 1)
2786static inline HMM_Mat3 HMM_Transpose(HMM_Mat3 Matrix)
2787{
2788 ASSERT_COVERED(HMM_TransposeM3CPP);
2789 return HMM_TransposeM3(Matrix);
2790}
2791
2792COVERAGE(HMM_TransposeM4CPP, 1)
2793static inline HMM_Mat4 HMM_Transpose(HMM_Mat4 Matrix)
2794{
2795 ASSERT_COVERED(HMM_TransposeM4CPP);
2796 return HMM_TransposeM4(Matrix);
2797}
2798
2799COVERAGE(HMM_DeterminantM2CPP, 1)
2800static inline float HMM_Determinant(HMM_Mat2 Matrix)
2801{
2802 ASSERT_COVERED(HMM_DeterminantM2CPP);
2803 return HMM_DeterminantM2(Matrix);
2804}
2805
2806COVERAGE(HMM_DeterminantM3CPP, 1)
2807static inline float HMM_Determinant(HMM_Mat3 Matrix)
2808{
2809 ASSERT_COVERED(HMM_DeterminantM3CPP);
2810 return HMM_DeterminantM3(Matrix);
2811}
2812
2813COVERAGE(HMM_DeterminantM4CPP, 1)
2814static inline float HMM_Determinant(HMM_Mat4 Matrix)
2815{
2816 ASSERT_COVERED(HMM_DeterminantM4CPP);
2817 return HMM_DeterminantM4(Matrix);
2818}
2819
2820COVERAGE(HMM_InvGeneralM2CPP, 1)
2821static inline HMM_Mat2 HMM_InvGeneral(HMM_Mat2 Matrix)
2822{
2823 ASSERT_COVERED(HMM_InvGeneralM2CPP);
2824 return HMM_InvGeneralM2(Matrix);
2825}
2826
2827COVERAGE(HMM_InvGeneralM3CPP, 1)
2828static inline HMM_Mat3 HMM_InvGeneral(HMM_Mat3 Matrix)
2829{
2830 ASSERT_COVERED(HMM_InvGeneralM3CPP);
2831 return HMM_InvGeneralM3(Matrix);
2832}
2833
2834COVERAGE(HMM_InvGeneralM4CPP, 1)
2835static inline HMM_Mat4 HMM_InvGeneral(HMM_Mat4 Matrix)
2836{
2837 ASSERT_COVERED(HMM_InvGeneralM4CPP);
2838 return HMM_InvGeneralM4(Matrix);
2839}
2840
2841COVERAGE(HMM_DotQCPP, 1)
2842static inline float HMM_Dot(HMM_Quat QuatOne, HMM_Quat QuatTwo)
2843{
2844 ASSERT_COVERED(HMM_DotQCPP);
2845 return HMM_DotQ(QuatOne, QuatTwo);
2846}
2847
2848COVERAGE(HMM_AddV2CPP, 1)
2849static inline HMM_Vec2 HMM_Add(HMM_Vec2 Left, HMM_Vec2 Right)
2850{
2851 ASSERT_COVERED(HMM_AddV2CPP);
2852 return HMM_AddV2(Left, Right);
2853}
2854
2855COVERAGE(HMM_AddV3CPP, 1)
2856static inline HMM_Vec3 HMM_Add(HMM_Vec3 Left, HMM_Vec3 Right)
2857{
2858 ASSERT_COVERED(HMM_AddV3CPP);
2859 return HMM_AddV3(Left, Right);
2860}
2861
2862COVERAGE(HMM_AddV4CPP, 1)
2863static inline HMM_Vec4 HMM_Add(HMM_Vec4 Left, HMM_Vec4 Right)
2864{
2865 ASSERT_COVERED(HMM_AddV4CPP);
2866 return HMM_AddV4(Left, Right);
2867}
2868
2869COVERAGE(HMM_AddM2CPP, 1)
2870static inline HMM_Mat2 HMM_Add(HMM_Mat2 Left, HMM_Mat2 Right)
2871{
2872 ASSERT_COVERED(HMM_AddM2CPP);
2873 return HMM_AddM2(Left, Right);
2874}
2875
2876COVERAGE(HMM_AddM3CPP, 1)
2877static inline HMM_Mat3 HMM_Add(HMM_Mat3 Left, HMM_Mat3 Right)
2878{
2879 ASSERT_COVERED(HMM_AddM3CPP);
2880 return HMM_AddM3(Left, Right);
2881}
2882
2883COVERAGE(HMM_AddM4CPP, 1)
2884static inline HMM_Mat4 HMM_Add(HMM_Mat4 Left, HMM_Mat4 Right)
2885{
2886 ASSERT_COVERED(HMM_AddM4CPP);
2887 return HMM_AddM4(Left, Right);
2888}
2889
2890COVERAGE(HMM_AddQCPP, 1)
2891static inline HMM_Quat HMM_Add(HMM_Quat Left, HMM_Quat Right)
2892{
2893 ASSERT_COVERED(HMM_AddQCPP);
2894 return HMM_AddQ(Left, Right);
2895}
2896
2897COVERAGE(HMM_SubV2CPP, 1)
2898static inline HMM_Vec2 HMM_Sub(HMM_Vec2 Left, HMM_Vec2 Right)
2899{
2900 ASSERT_COVERED(HMM_SubV2CPP);
2901 return HMM_SubV2(Left, Right);
2902}
2903
2904COVERAGE(HMM_SubV3CPP, 1)
2905static inline HMM_Vec3 HMM_Sub(HMM_Vec3 Left, HMM_Vec3 Right)
2906{
2907 ASSERT_COVERED(HMM_SubV3CPP);
2908 return HMM_SubV3(Left, Right);
2909}
2910
2911COVERAGE(HMM_SubV4CPP, 1)
2912static inline HMM_Vec4 HMM_Sub(HMM_Vec4 Left, HMM_Vec4 Right)
2913{
2914 ASSERT_COVERED(HMM_SubV4CPP);
2915 return HMM_SubV4(Left, Right);
2916}
2917
2918COVERAGE(HMM_SubM2CPP, 1)
2919static inline HMM_Mat2 HMM_Sub(HMM_Mat2 Left, HMM_Mat2 Right)
2920{
2921 ASSERT_COVERED(HMM_SubM2CPP);
2922 return HMM_SubM2(Left, Right);
2923}
2924
2925COVERAGE(HMM_SubM3CPP, 1)
2926static inline HMM_Mat3 HMM_Sub(HMM_Mat3 Left, HMM_Mat3 Right)
2927{
2928 ASSERT_COVERED(HMM_SubM3CPP);
2929 return HMM_SubM3(Left, Right);
2930}
2931
2932COVERAGE(HMM_SubM4CPP, 1)
2933static inline HMM_Mat4 HMM_Sub(HMM_Mat4 Left, HMM_Mat4 Right)
2934{
2935 ASSERT_COVERED(HMM_SubM4CPP);
2936 return HMM_SubM4(Left, Right);
2937}
2938
2939COVERAGE(HMM_SubQCPP, 1)
2940static inline HMM_Quat HMM_Sub(HMM_Quat Left, HMM_Quat Right)
2941{
2942 ASSERT_COVERED(HMM_SubQCPP);
2943 return HMM_SubQ(Left, Right);
2944}
2945
2946COVERAGE(HMM_MulV2CPP, 1)
2947static inline HMM_Vec2 HMM_Mul(HMM_Vec2 Left, HMM_Vec2 Right)
2948{
2949 ASSERT_COVERED(HMM_MulV2CPP);
2950 return HMM_MulV2(Left, Right);
2951}
2952
2953COVERAGE(HMM_MulV2FCPP, 1)
2954static inline HMM_Vec2 HMM_Mul(HMM_Vec2 Left, float Right)
2955{
2956 ASSERT_COVERED(HMM_MulV2FCPP);
2957 return HMM_MulV2F(Left, Right);
2958}
2959
2960COVERAGE(HMM_MulV3CPP, 1)
2961static inline HMM_Vec3 HMM_Mul(HMM_Vec3 Left, HMM_Vec3 Right)
2962{
2963 ASSERT_COVERED(HMM_MulV3CPP);
2964 return HMM_MulV3(Left, Right);
2965}
2966
2967COVERAGE(HMM_MulV3FCPP, 1)
2968static inline HMM_Vec3 HMM_Mul(HMM_Vec3 Left, float Right)
2969{
2970 ASSERT_COVERED(HMM_MulV3FCPP);
2971 return HMM_MulV3F(Left, Right);
2972}
2973
2974COVERAGE(HMM_MulV4CPP, 1)
2975static inline HMM_Vec4 HMM_Mul(HMM_Vec4 Left, HMM_Vec4 Right)
2976{
2977 ASSERT_COVERED(HMM_MulV4CPP);
2978 return HMM_MulV4(Left, Right);
2979}
2980
2981COVERAGE(HMM_MulV4FCPP, 1)
2982static inline HMM_Vec4 HMM_Mul(HMM_Vec4 Left, float Right)
2983{
2984 ASSERT_COVERED(HMM_MulV4FCPP);
2985 return HMM_MulV4F(Left, Right);
2986}
2987
2988COVERAGE(HMM_MulM2CPP, 1)
2989static inline HMM_Mat2 HMM_Mul(HMM_Mat2 Left, HMM_Mat2 Right)
2990{
2991 ASSERT_COVERED(HMM_MulM2CPP);
2992 return HMM_MulM2(Left, Right);
2993}
2994
2995COVERAGE(HMM_MulM3CPP, 1)
2996static inline HMM_Mat3 HMM_Mul(HMM_Mat3 Left, HMM_Mat3 Right)
2997{
2998 ASSERT_COVERED(HMM_MulM3CPP);
2999 return HMM_MulM3(Left, Right);
3000}
3001
3002COVERAGE(HMM_MulM4CPP, 1)
3003static inline HMM_Mat4 HMM_Mul(HMM_Mat4 Left, HMM_Mat4 Right)
3004{
3005 ASSERT_COVERED(HMM_MulM4CPP);
3006 return HMM_MulM4(Left, Right);
3007}
3008
3009COVERAGE(HMM_MulM2FCPP, 1)
3010static inline HMM_Mat2 HMM_Mul(HMM_Mat2 Left, float Right)
3011{
3012 ASSERT_COVERED(HMM_MulM2FCPP);
3013 return HMM_MulM2F(Left, Right);
3014}
3015
3016COVERAGE(HMM_MulM3FCPP, 1)
3017static inline HMM_Mat3 HMM_Mul(HMM_Mat3 Left, float Right)
3018{
3019 ASSERT_COVERED(HMM_MulM3FCPP);
3020 return HMM_MulM3F(Left, Right);
3021}
3022
3023COVERAGE(HMM_MulM4FCPP, 1)
3024static inline HMM_Mat4 HMM_Mul(HMM_Mat4 Left, float Right)
3025{
3026 ASSERT_COVERED(HMM_MulM4FCPP);
3027 return HMM_MulM4F(Left, Right);
3028}
3029
3030COVERAGE(HMM_MulM2V2CPP, 1)
3031static inline HMM_Vec2 HMM_Mul(HMM_Mat2 Matrix, HMM_Vec2 Vector)
3032{
3033 ASSERT_COVERED(HMM_MulM2V2CPP);
3034 return HMM_MulM2V2(Matrix, Vector);
3035}
3036
3037COVERAGE(HMM_MulM3V3CPP, 1)
3038static inline HMM_Vec3 HMM_Mul(HMM_Mat3 Matrix, HMM_Vec3 Vector)
3039{
3040 ASSERT_COVERED(HMM_MulM3V3CPP);
3041 return HMM_MulM3V3(Matrix, Vector);
3042}
3043
3044COVERAGE(HMM_MulM4V4CPP, 1)
3045static inline HMM_Vec4 HMM_Mul(HMM_Mat4 Matrix, HMM_Vec4 Vector)
3046{
3047 ASSERT_COVERED(HMM_MulM4V4CPP);
3048 return HMM_MulM4V4(Matrix, Vector);
3049}
3050
3051COVERAGE(HMM_MulQCPP, 1)
3052static inline HMM_Quat HMM_Mul(HMM_Quat Left, HMM_Quat Right)
3053{
3054 ASSERT_COVERED(HMM_MulQCPP);
3055 return HMM_MulQ(Left, Right);
3056}
3057
3058COVERAGE(HMM_MulQFCPP, 1)
3059static inline HMM_Quat HMM_Mul(HMM_Quat Left, float Right)
3060{
3061 ASSERT_COVERED(HMM_MulQFCPP);
3062 return HMM_MulQF(Left, Right);
3063}
3064
3065COVERAGE(HMM_DivV2CPP, 1)
3066static inline HMM_Vec2 HMM_Div(HMM_Vec2 Left, HMM_Vec2 Right)
3067{
3068 ASSERT_COVERED(HMM_DivV2CPP);
3069 return HMM_DivV2(Left, Right);
3070}
3071
3072COVERAGE(HMM_DivV2FCPP, 1)
3073static inline HMM_Vec2 HMM_Div(HMM_Vec2 Left, float Right)
3074{
3075 ASSERT_COVERED(HMM_DivV2FCPP);
3076 return HMM_DivV2F(Left, Right);
3077}
3078
3079COVERAGE(HMM_DivV3CPP, 1)
3080static inline HMM_Vec3 HMM_Div(HMM_Vec3 Left, HMM_Vec3 Right)
3081{
3082 ASSERT_COVERED(HMM_DivV3CPP);
3083 return HMM_DivV3(Left, Right);
3084}
3085
3086COVERAGE(HMM_DivV3FCPP, 1)
3087static inline HMM_Vec3 HMM_Div(HMM_Vec3 Left, float Right)
3088{
3089 ASSERT_COVERED(HMM_DivV3FCPP);
3090 return HMM_DivV3F(Left, Right);
3091}
3092
3093COVERAGE(HMM_DivV4CPP, 1)
3094static inline HMM_Vec4 HMM_Div(HMM_Vec4 Left, HMM_Vec4 Right)
3095{
3096 ASSERT_COVERED(HMM_DivV4CPP);
3097 return HMM_DivV4(Left, Right);
3098}
3099
3100COVERAGE(HMM_DivV4FCPP, 1)
3101static inline HMM_Vec4 HMM_Div(HMM_Vec4 Left, float Right)
3102{
3103 ASSERT_COVERED(HMM_DivV4FCPP);
3104 return HMM_DivV4F(Left, Right);
3105}
3106
3107COVERAGE(HMM_DivM2FCPP, 1)
3108static inline HMM_Mat2 HMM_Div(HMM_Mat2 Left, float Right)
3109{
3110 ASSERT_COVERED(HMM_DivM2FCPP);
3111 return HMM_DivM2F(Left, Right);
3112}
3113
3114COVERAGE(HMM_DivM3FCPP, 1)
3115static inline HMM_Mat3 HMM_Div(HMM_Mat3 Left, float Right)
3116{
3117 ASSERT_COVERED(HMM_DivM3FCPP);
3118 return HMM_DivM3F(Left, Right);
3119}
3120
3121COVERAGE(HMM_DivM4FCPP, 1)
3122static inline HMM_Mat4 HMM_Div(HMM_Mat4 Left, float Right)
3123{
3124 ASSERT_COVERED(HMM_DivM4FCPP);
3125 return HMM_DivM4F(Left, Right);
3126}
3127
3128COVERAGE(HMM_DivQFCPP, 1)
3129static inline HMM_Quat HMM_Div(HMM_Quat Left, float Right)
3130{
3131 ASSERT_COVERED(HMM_DivQFCPP);
3132 return HMM_DivQF(Left, Right);
3133}
3134
3135COVERAGE(HMM_EqV2CPP, 1)
3136static inline HMM_Bool HMM_Eq(HMM_Vec2 Left, HMM_Vec2 Right)
3137{
3138 ASSERT_COVERED(HMM_EqV2CPP);
3139 return HMM_EqV2(Left, Right);
3140}
3141
3142COVERAGE(HMM_EqV3CPP, 1)
3143static inline HMM_Bool HMM_Eq(HMM_Vec3 Left, HMM_Vec3 Right)
3144{
3145 ASSERT_COVERED(HMM_EqV3CPP);
3146 return HMM_EqV3(Left, Right);
3147}
3148
3149COVERAGE(HMM_EqV4CPP, 1)
3150static inline HMM_Bool HMM_Eq(HMM_Vec4 Left, HMM_Vec4 Right)
3151{
3152 ASSERT_COVERED(HMM_EqV4CPP);
3153 return HMM_EqV4(Left, Right);
3154}
3155
3156COVERAGE(HMM_AddV2Op, 1)
3157static inline HMM_Vec2 operator+(HMM_Vec2 Left, HMM_Vec2 Right)
3158{
3159 ASSERT_COVERED(HMM_AddV2Op);
3160 return HMM_AddV2(Left, Right);
3161}
3162
3163COVERAGE(HMM_AddV3Op, 1)
3164static inline HMM_Vec3 operator+(HMM_Vec3 Left, HMM_Vec3 Right)
3165{
3166 ASSERT_COVERED(HMM_AddV3Op);
3167 return HMM_AddV3(Left, Right);
3168}
3169
3170COVERAGE(HMM_AddV4Op, 1)
3171static inline HMM_Vec4 operator+(HMM_Vec4 Left, HMM_Vec4 Right)
3172{
3173 ASSERT_COVERED(HMM_AddV4Op);
3174 return HMM_AddV4(Left, Right);
3175}
3176
3177COVERAGE(HMM_AddM2Op, 1)
3178static inline HMM_Mat2 operator+(HMM_Mat2 Left, HMM_Mat2 Right)
3179{
3180 ASSERT_COVERED(HMM_AddM2Op);
3181 return HMM_AddM2(Left, Right);
3182}
3183
3184COVERAGE(HMM_AddM3Op, 1)
3185static inline HMM_Mat3 operator+(HMM_Mat3 Left, HMM_Mat3 Right)
3186{
3187 ASSERT_COVERED(HMM_AddM3Op);
3188 return HMM_AddM3(Left, Right);
3189}
3190
3191COVERAGE(HMM_AddM4Op, 1)
3192static inline HMM_Mat4 operator+(HMM_Mat4 Left, HMM_Mat4 Right)
3193{
3194 ASSERT_COVERED(HMM_AddM4Op);
3195 return HMM_AddM4(Left, Right);
3196}
3197
3198COVERAGE(HMM_AddQOp, 1)
3199static inline HMM_Quat operator+(HMM_Quat Left, HMM_Quat Right)
3200{
3201 ASSERT_COVERED(HMM_AddQOp);
3202 return HMM_AddQ(Left, Right);
3203}
3204
3205COVERAGE(HMM_SubV2Op, 1)
3206static inline HMM_Vec2 operator-(HMM_Vec2 Left, HMM_Vec2 Right)
3207{
3208 ASSERT_COVERED(HMM_SubV2Op);
3209 return HMM_SubV2(Left, Right);
3210}
3211
3212COVERAGE(HMM_SubV3Op, 1)
3213static inline HMM_Vec3 operator-(HMM_Vec3 Left, HMM_Vec3 Right)
3214{
3215 ASSERT_COVERED(HMM_SubV3Op);
3216 return HMM_SubV3(Left, Right);
3217}
3218
3219COVERAGE(HMM_SubV4Op, 1)
3220static inline HMM_Vec4 operator-(HMM_Vec4 Left, HMM_Vec4 Right)
3221{
3222 ASSERT_COVERED(HMM_SubV4Op);
3223 return HMM_SubV4(Left, Right);
3224}
3225
3226COVERAGE(HMM_SubM2Op, 1)
3227static inline HMM_Mat2 operator-(HMM_Mat2 Left, HMM_Mat2 Right)
3228{
3229 ASSERT_COVERED(HMM_SubM2Op);
3230 return HMM_SubM2(Left, Right);
3231}
3232
3233COVERAGE(HMM_SubM3Op, 1)
3234static inline HMM_Mat3 operator-(HMM_Mat3 Left, HMM_Mat3 Right)
3235{
3236 ASSERT_COVERED(HMM_SubM3Op);
3237 return HMM_SubM3(Left, Right);
3238}
3239
3240COVERAGE(HMM_SubM4Op, 1)
3241static inline HMM_Mat4 operator-(HMM_Mat4 Left, HMM_Mat4 Right)
3242{
3243 ASSERT_COVERED(HMM_SubM4Op);
3244 return HMM_SubM4(Left, Right);
3245}
3246
3247COVERAGE(HMM_SubQOp, 1)
3248static inline HMM_Quat operator-(HMM_Quat Left, HMM_Quat Right)
3249{
3250 ASSERT_COVERED(HMM_SubQOp);
3251 return HMM_SubQ(Left, Right);
3252}
3253
3254COVERAGE(HMM_MulV2Op, 1)
3255static inline HMM_Vec2 operator*(HMM_Vec2 Left, HMM_Vec2 Right)
3256{
3257 ASSERT_COVERED(HMM_MulV2Op);
3258 return HMM_MulV2(Left, Right);
3259}
3260
3261COVERAGE(HMM_MulV3Op, 1)
3262static inline HMM_Vec3 operator*(HMM_Vec3 Left, HMM_Vec3 Right)
3263{
3264 ASSERT_COVERED(HMM_MulV3Op);
3265 return HMM_MulV3(Left, Right);
3266}
3267
3268COVERAGE(HMM_MulV4Op, 1)
3269static inline HMM_Vec4 operator*(HMM_Vec4 Left, HMM_Vec4 Right)
3270{
3271 ASSERT_COVERED(HMM_MulV4Op);
3272 return HMM_MulV4(Left, Right);
3273}
3274
3275COVERAGE(HMM_MulM2Op, 1)
3276static inline HMM_Mat2 operator*(HMM_Mat2 Left, HMM_Mat2 Right)
3277{
3278 ASSERT_COVERED(HMM_MulM2Op);
3279 return HMM_MulM2(Left, Right);
3280}
3281
3282COVERAGE(HMM_MulM3Op, 1)
3283static inline HMM_Mat3 operator*(HMM_Mat3 Left, HMM_Mat3 Right)
3284{
3285 ASSERT_COVERED(HMM_MulM3Op);
3286 return HMM_MulM3(Left, Right);
3287}
3288
3289COVERAGE(HMM_MulM4Op, 1)
3290static inline HMM_Mat4 operator*(HMM_Mat4 Left, HMM_Mat4 Right)
3291{
3292 ASSERT_COVERED(HMM_MulM4Op);
3293 return HMM_MulM4(Left, Right);
3294}
3295
3296COVERAGE(HMM_MulQOp, 1)
3297static inline HMM_Quat operator*(HMM_Quat Left, HMM_Quat Right)
3298{
3299 ASSERT_COVERED(HMM_MulQOp);
3300 return HMM_MulQ(Left, Right);
3301}
3302
3303COVERAGE(HMM_MulV2FOp, 1)
3304static inline HMM_Vec2 operator*(HMM_Vec2 Left, float Right)
3305{
3306 ASSERT_COVERED(HMM_MulV2FOp);
3307 return HMM_MulV2F(Left, Right);
3308}
3309
3310COVERAGE(HMM_MulV3FOp, 1)
3311static inline HMM_Vec3 operator*(HMM_Vec3 Left, float Right)
3312{
3313 ASSERT_COVERED(HMM_MulV3FOp);
3314 return HMM_MulV3F(Left, Right);
3315}
3316
3317COVERAGE(HMM_MulV4FOp, 1)
3318static inline HMM_Vec4 operator*(HMM_Vec4 Left, float Right)
3319{
3320 ASSERT_COVERED(HMM_MulV4FOp);
3321 return HMM_MulV4F(Left, Right);
3322}
3323
3324COVERAGE(HMM_MulM2FOp, 1)
3325static inline HMM_Mat2 operator*(HMM_Mat2 Left, float Right)
3326{
3327 ASSERT_COVERED(HMM_MulM2FOp);
3328 return HMM_MulM2F(Left, Right);
3329}
3330
3331COVERAGE(HMM_MulM3FOp, 1)
3332static inline HMM_Mat3 operator*(HMM_Mat3 Left, float Right)
3333{
3334 ASSERT_COVERED(HMM_MulM3FOp);
3335 return HMM_MulM3F(Left, Right);
3336}
3337
3338COVERAGE(HMM_MulM4FOp, 1)
3339static inline HMM_Mat4 operator*(HMM_Mat4 Left, float Right)
3340{
3341 ASSERT_COVERED(HMM_MulM4FOp);
3342 return HMM_MulM4F(Left, Right);
3343}
3344
3345COVERAGE(HMM_MulQFOp, 1)
3346static inline HMM_Quat operator*(HMM_Quat Left, float Right)
3347{
3348 ASSERT_COVERED(HMM_MulQFOp);
3349 return HMM_MulQF(Left, Right);
3350}
3351
3352COVERAGE(HMM_MulV2FOpLeft, 1)
3353static inline HMM_Vec2 operator*(float Left, HMM_Vec2 Right)
3354{
3355 ASSERT_COVERED(HMM_MulV2FOpLeft);
3356 return HMM_MulV2F(Right, Left);
3357}
3358
3359COVERAGE(HMM_MulV3FOpLeft, 1)
3360static inline HMM_Vec3 operator*(float Left, HMM_Vec3 Right)
3361{
3362 ASSERT_COVERED(HMM_MulV3FOpLeft);
3363 return HMM_MulV3F(Right, Left);
3364}
3365
3366COVERAGE(HMM_MulV4FOpLeft, 1)
3367static inline HMM_Vec4 operator*(float Left, HMM_Vec4 Right)
3368{
3369 ASSERT_COVERED(HMM_MulV4FOpLeft);
3370 return HMM_MulV4F(Right, Left);
3371}
3372
3373COVERAGE(HMM_MulM2FOpLeft, 1)
3374static inline HMM_Mat2 operator*(float Left, HMM_Mat2 Right)
3375{
3376 ASSERT_COVERED(HMM_MulM2FOpLeft);
3377 return HMM_MulM2F(Right, Left);
3378}
3379
3380COVERAGE(HMM_MulM3FOpLeft, 1)
3381static inline HMM_Mat3 operator*(float Left, HMM_Mat3 Right)
3382{
3383 ASSERT_COVERED(HMM_MulM3FOpLeft);
3384 return HMM_MulM3F(Right, Left);
3385}
3386
3387COVERAGE(HMM_MulM4FOpLeft, 1)
3388static inline HMM_Mat4 operator*(float Left, HMM_Mat4 Right)
3389{
3390 ASSERT_COVERED(HMM_MulM4FOpLeft);
3391 return HMM_MulM4F(Right, Left);
3392}
3393
3394COVERAGE(HMM_MulQFOpLeft, 1)
3395static inline HMM_Quat operator*(float Left, HMM_Quat Right)
3396{
3397 ASSERT_COVERED(HMM_MulQFOpLeft);
3398 return HMM_MulQF(Right, Left);
3399}
3400
3401COVERAGE(HMM_MulM2V2Op, 1)
3402static inline HMM_Vec2 operator*(HMM_Mat2 Matrix, HMM_Vec2 Vector)
3403{
3404 ASSERT_COVERED(HMM_MulM2V2Op);
3405 return HMM_MulM2V2(Matrix, Vector);
3406}
3407
3408COVERAGE(HMM_MulM3V3Op, 1)
3409static inline HMM_Vec3 operator*(HMM_Mat3 Matrix, HMM_Vec3 Vector)
3410{
3411 ASSERT_COVERED(HMM_MulM3V3Op);
3412 return HMM_MulM3V3(Matrix, Vector);
3413}
3414
3415COVERAGE(HMM_MulM4V4Op, 1)
3416static inline HMM_Vec4 operator*(HMM_Mat4 Matrix, HMM_Vec4 Vector)
3417{
3418 ASSERT_COVERED(HMM_MulM4V4Op);
3419 return HMM_MulM4V4(Matrix, Vector);
3420}
3421
3422COVERAGE(HMM_DivV2Op, 1)
3423static inline HMM_Vec2 operator/(HMM_Vec2 Left, HMM_Vec2 Right)
3424{
3425 ASSERT_COVERED(HMM_DivV2Op);
3426 return HMM_DivV2(Left, Right);
3427}
3428
3429COVERAGE(HMM_DivV3Op, 1)
3430static inline HMM_Vec3 operator/(HMM_Vec3 Left, HMM_Vec3 Right)
3431{
3432 ASSERT_COVERED(HMM_DivV3Op);
3433 return HMM_DivV3(Left, Right);
3434}
3435
3436COVERAGE(HMM_DivV4Op, 1)
3437static inline HMM_Vec4 operator/(HMM_Vec4 Left, HMM_Vec4 Right)
3438{
3439 ASSERT_COVERED(HMM_DivV4Op);
3440 return HMM_DivV4(Left, Right);
3441}
3442
3443COVERAGE(HMM_DivV2FOp, 1)
3444static inline HMM_Vec2 operator/(HMM_Vec2 Left, float Right)
3445{
3446 ASSERT_COVERED(HMM_DivV2FOp);
3447 return HMM_DivV2F(Left, Right);
3448}
3449
3450COVERAGE(HMM_DivV3FOp, 1)
3451static inline HMM_Vec3 operator/(HMM_Vec3 Left, float Right)
3452{
3453 ASSERT_COVERED(HMM_DivV3FOp);
3454 return HMM_DivV3F(Left, Right);
3455}
3456
3457COVERAGE(HMM_DivV4FOp, 1)
3458static inline HMM_Vec4 operator/(HMM_Vec4 Left, float Right)
3459{
3460 ASSERT_COVERED(HMM_DivV4FOp);
3461 return HMM_DivV4F(Left, Right);
3462}
3463
3464COVERAGE(HMM_DivM4FOp, 1)
3465static inline HMM_Mat4 operator/(HMM_Mat4 Left, float Right)
3466{
3467 ASSERT_COVERED(HMM_DivM4FOp);
3468 return HMM_DivM4F(Left, Right);
3469}
3470
3471COVERAGE(HMM_DivM3FOp, 1)
3472static inline HMM_Mat3 operator/(HMM_Mat3 Left, float Right)
3473{
3474 ASSERT_COVERED(HMM_DivM3FOp);
3475 return HMM_DivM3F(Left, Right);
3476}
3477
3478COVERAGE(HMM_DivM2FOp, 1)
3479static inline HMM_Mat2 operator/(HMM_Mat2 Left, float Right)
3480{
3481 ASSERT_COVERED(HMM_DivM2FOp);
3482 return HMM_DivM2F(Left, Right);
3483}
3484
3485COVERAGE(HMM_DivQFOp, 1)
3486static inline HMM_Quat operator/(HMM_Quat Left, float Right)
3487{
3488 ASSERT_COVERED(HMM_DivQFOp);
3489 return HMM_DivQF(Left, Right);
3490}
3491
3492COVERAGE(HMM_AddV2Assign, 1)
3493static inline HMM_Vec2 &operator+=(HMM_Vec2 &Left, HMM_Vec2 Right)
3494{
3495 ASSERT_COVERED(HMM_AddV2Assign);
3496 return Left = Left + Right;
3497}
3498
3499COVERAGE(HMM_AddV3Assign, 1)
3500static inline HMM_Vec3 &operator+=(HMM_Vec3 &Left, HMM_Vec3 Right)
3501{
3502 ASSERT_COVERED(HMM_AddV3Assign);
3503 return Left = Left + Right;
3504}
3505
3506COVERAGE(HMM_AddV4Assign, 1)
3507static inline HMM_Vec4 &operator+=(HMM_Vec4 &Left, HMM_Vec4 Right)
3508{
3509 ASSERT_COVERED(HMM_AddV4Assign);
3510 return Left = Left + Right;
3511}
3512
3513COVERAGE(HMM_AddM2Assign, 1)
3514static inline HMM_Mat2 &operator+=(HMM_Mat2 &Left, HMM_Mat2 Right)
3515{
3516 ASSERT_COVERED(HMM_AddM2Assign);
3517 return Left = Left + Right;
3518}
3519
3520COVERAGE(HMM_AddM3Assign, 1)
3521static inline HMM_Mat3 &operator+=(HMM_Mat3 &Left, HMM_Mat3 Right)
3522{
3523 ASSERT_COVERED(HMM_AddM3Assign);
3524 return Left = Left + Right;
3525}
3526
3527COVERAGE(HMM_AddM4Assign, 1)
3528static inline HMM_Mat4 &operator+=(HMM_Mat4 &Left, HMM_Mat4 Right)
3529{
3530 ASSERT_COVERED(HMM_AddM4Assign);
3531 return Left = Left + Right;
3532}
3533
3534COVERAGE(HMM_AddQAssign, 1)
3535static inline HMM_Quat &operator+=(HMM_Quat &Left, HMM_Quat Right)
3536{
3537 ASSERT_COVERED(HMM_AddQAssign);
3538 return Left = Left + Right;
3539}
3540
3541COVERAGE(HMM_SubV2Assign, 1)
3542static inline HMM_Vec2 &operator-=(HMM_Vec2 &Left, HMM_Vec2 Right)
3543{
3544 ASSERT_COVERED(HMM_SubV2Assign);
3545 return Left = Left - Right;
3546}
3547
3548COVERAGE(HMM_SubV3Assign, 1)
3549static inline HMM_Vec3 &operator-=(HMM_Vec3 &Left, HMM_Vec3 Right)
3550{
3551 ASSERT_COVERED(HMM_SubV3Assign);
3552 return Left = Left - Right;
3553}
3554
3555COVERAGE(HMM_SubV4Assign, 1)
3556static inline HMM_Vec4 &operator-=(HMM_Vec4 &Left, HMM_Vec4 Right)
3557{
3558 ASSERT_COVERED(HMM_SubV4Assign);
3559 return Left = Left - Right;
3560}
3561
3562COVERAGE(HMM_SubM2Assign, 1)
3563static inline HMM_Mat2 &operator-=(HMM_Mat2 &Left, HMM_Mat2 Right)
3564{
3565 ASSERT_COVERED(HMM_SubM2Assign);
3566 return Left = Left - Right;
3567}
3568
3569COVERAGE(HMM_SubM3Assign, 1)
3570static inline HMM_Mat3 &operator-=(HMM_Mat3 &Left, HMM_Mat3 Right)
3571{
3572 ASSERT_COVERED(HMM_SubM3Assign);
3573 return Left = Left - Right;
3574}
3575
3576COVERAGE(HMM_SubM4Assign, 1)
3577static inline HMM_Mat4 &operator-=(HMM_Mat4 &Left, HMM_Mat4 Right)
3578{
3579 ASSERT_COVERED(HMM_SubM4Assign);
3580 return Left = Left - Right;
3581}
3582
3583COVERAGE(HMM_SubQAssign, 1)
3584static inline HMM_Quat &operator-=(HMM_Quat &Left, HMM_Quat Right)
3585{
3586 ASSERT_COVERED(HMM_SubQAssign);
3587 return Left = Left - Right;
3588}
3589
3590COVERAGE(HMM_MulV2Assign, 1)
3591static inline HMM_Vec2 &operator*=(HMM_Vec2 &Left, HMM_Vec2 Right)
3592{
3593 ASSERT_COVERED(HMM_MulV2Assign);
3594 return Left = Left * Right;
3595}
3596
3597COVERAGE(HMM_MulV3Assign, 1)
3598static inline HMM_Vec3 &operator*=(HMM_Vec3 &Left, HMM_Vec3 Right)
3599{
3600 ASSERT_COVERED(HMM_MulV3Assign);
3601 return Left = Left * Right;
3602}
3603
3604COVERAGE(HMM_MulV4Assign, 1)
3605static inline HMM_Vec4 &operator*=(HMM_Vec4 &Left, HMM_Vec4 Right)
3606{
3607 ASSERT_COVERED(HMM_MulV4Assign);
3608 return Left = Left * Right;
3609}
3610
3611COVERAGE(HMM_MulV2FAssign, 1)
3612static inline HMM_Vec2 &operator*=(HMM_Vec2 &Left, float Right)
3613{
3614 ASSERT_COVERED(HMM_MulV2FAssign);
3615 return Left = Left * Right;
3616}
3617
3618COVERAGE(HMM_MulV3FAssign, 1)
3619static inline HMM_Vec3 &operator*=(HMM_Vec3 &Left, float Right)
3620{
3621 ASSERT_COVERED(HMM_MulV3FAssign);
3622 return Left = Left * Right;
3623}
3624
3625COVERAGE(HMM_MulV4FAssign, 1)
3626static inline HMM_Vec4 &operator*=(HMM_Vec4 &Left, float Right)
3627{
3628 ASSERT_COVERED(HMM_MulV4FAssign);
3629 return Left = Left * Right;
3630}
3631
3632COVERAGE(HMM_MulM2FAssign, 1)
3633static inline HMM_Mat2 &operator*=(HMM_Mat2 &Left, float Right)
3634{
3635 ASSERT_COVERED(HMM_MulM2FAssign);
3636 return Left = Left * Right;
3637}
3638
3639COVERAGE(HMM_MulM3FAssign, 1)
3640static inline HMM_Mat3 &operator*=(HMM_Mat3 &Left, float Right)
3641{
3642 ASSERT_COVERED(HMM_MulM3FAssign);
3643 return Left = Left * Right;
3644}
3645
3646COVERAGE(HMM_MulM4FAssign, 1)
3647static inline HMM_Mat4 &operator*=(HMM_Mat4 &Left, float Right)
3648{
3649 ASSERT_COVERED(HMM_MulM4FAssign);
3650 return Left = Left * Right;
3651}
3652
3653COVERAGE(HMM_MulQFAssign, 1)
3654static inline HMM_Quat &operator*=(HMM_Quat &Left, float Right)
3655{
3656 ASSERT_COVERED(HMM_MulQFAssign);
3657 return Left = Left * Right;
3658}
3659
3660COVERAGE(HMM_DivV2Assign, 1)
3661static inline HMM_Vec2 &operator/=(HMM_Vec2 &Left, HMM_Vec2 Right)
3662{
3663 ASSERT_COVERED(HMM_DivV2Assign);
3664 return Left = Left / Right;
3665}
3666
3667COVERAGE(HMM_DivV3Assign, 1)
3668static inline HMM_Vec3 &operator/=(HMM_Vec3 &Left, HMM_Vec3 Right)
3669{
3670 ASSERT_COVERED(HMM_DivV3Assign);
3671 return Left = Left / Right;
3672}
3673
3674COVERAGE(HMM_DivV4Assign, 1)
3675static inline HMM_Vec4 &operator/=(HMM_Vec4 &Left, HMM_Vec4 Right)
3676{
3677 ASSERT_COVERED(HMM_DivV4Assign);
3678 return Left = Left / Right;
3679}
3680
3681COVERAGE(HMM_DivV2FAssign, 1)
3682static inline HMM_Vec2 &operator/=(HMM_Vec2 &Left, float Right)
3683{
3684 ASSERT_COVERED(HMM_DivV2FAssign);
3685 return Left = Left / Right;
3686}
3687
3688COVERAGE(HMM_DivV3FAssign, 1)
3689static inline HMM_Vec3 &operator/=(HMM_Vec3 &Left, float Right)
3690{
3691 ASSERT_COVERED(HMM_DivV3FAssign);
3692 return Left = Left / Right;
3693}
3694
3695COVERAGE(HMM_DivV4FAssign, 1)
3696static inline HMM_Vec4 &operator/=(HMM_Vec4 &Left, float Right)
3697{
3698 ASSERT_COVERED(HMM_DivV4FAssign);
3699 return Left = Left / Right;
3700}
3701
3702COVERAGE(HMM_DivM4FAssign, 1)
3703static inline HMM_Mat4 &operator/=(HMM_Mat4 &Left, float Right)
3704{
3705 ASSERT_COVERED(HMM_DivM4FAssign);
3706 return Left = Left / Right;
3707}
3708
3709COVERAGE(HMM_DivQFAssign, 1)
3710static inline HMM_Quat &operator/=(HMM_Quat &Left, float Right)
3711{
3712 ASSERT_COVERED(HMM_DivQFAssign);
3713 return Left = Left / Right;
3714}
3715
3716COVERAGE(HMM_EqV2Op, 1)
3717static inline HMM_Bool operator==(HMM_Vec2 Left, HMM_Vec2 Right)
3718{
3719 ASSERT_COVERED(HMM_EqV2Op);
3720 return HMM_EqV2(Left, Right);
3721}
3722
3723COVERAGE(HMM_EqV3Op, 1)
3724static inline HMM_Bool operator==(HMM_Vec3 Left, HMM_Vec3 Right)
3725{
3726 ASSERT_COVERED(HMM_EqV3Op);
3727 return HMM_EqV3(Left, Right);
3728}
3729
3730COVERAGE(HMM_EqV4Op, 1)
3731static inline HMM_Bool operator==(HMM_Vec4 Left, HMM_Vec4 Right)
3732{
3733 ASSERT_COVERED(HMM_EqV4Op);
3734 return HMM_EqV4(Left, Right);
3735}
3736
3737COVERAGE(HMM_EqV2OpNot, 1)
3738static inline HMM_Bool operator!=(HMM_Vec2 Left, HMM_Vec2 Right)
3739{
3740 ASSERT_COVERED(HMM_EqV2OpNot);
3741 return !HMM_EqV2(Left, Right);
3742}
3743
3744COVERAGE(HMM_EqV3OpNot, 1)
3745static inline HMM_Bool operator!=(HMM_Vec3 Left, HMM_Vec3 Right)
3746{
3747 ASSERT_COVERED(HMM_EqV3OpNot);
3748 return !HMM_EqV3(Left, Right);
3749}
3750
3751COVERAGE(HMM_EqV4OpNot, 1)
3752static inline HMM_Bool operator!=(HMM_Vec4 Left, HMM_Vec4 Right)
3753{
3754 ASSERT_COVERED(HMM_EqV4OpNot);
3755 return !HMM_EqV4(Left, Right);
3756}
3757
3758COVERAGE(HMM_UnaryMinusV2, 1)
3759static inline HMM_Vec2 operator-(HMM_Vec2 In)
3760{
3761 ASSERT_COVERED(HMM_UnaryMinusV2);
3762
3763 HMM_Vec2 Result;
3764 Result.X = -In.X;
3765 Result.Y = -In.Y;
3766
3767 return Result;
3768}
3769
3770COVERAGE(HMM_UnaryMinusV3, 1)
3771static inline HMM_Vec3 operator-(HMM_Vec3 In)
3772{
3773 ASSERT_COVERED(HMM_UnaryMinusV3);
3774
3775 HMM_Vec3 Result;
3776 Result.X = -In.X;
3777 Result.Y = -In.Y;
3778 Result.Z = -In.Z;
3779
3780 return Result;
3781}
3782
3783COVERAGE(HMM_UnaryMinusV4, 1)
3784static inline HMM_Vec4 operator-(HMM_Vec4 In)
3785{
3786 ASSERT_COVERED(HMM_UnaryMinusV4);
3787
3788 HMM_Vec4 Result;
3789#if HANDMADE_MATH__USE_SSE
3790 Result.SSE = _mm_xor_ps(In.SSE, _mm_set1_ps(-0.0f));
3791#elif defined(HANDMADE_MATH__USE_NEON)
3792 float32x4_t Zero = vdupq_n_f32(0.0f);
3793 Result.NEON = vsubq_f32(Zero, In.NEON);
3794#else
3795 Result.X = -In.X;
3796 Result.Y = -In.Y;
3797 Result.Z = -In.Z;
3798 Result.W = -In.W;
3799#endif
3800
3801 return Result;
3802}
3803
3804#endif /* __cplusplus*/
3805
3806#ifdef HANDMADE_MATH__USE_C11_GENERICS
3807
3808void __hmm_invalid_generic(void);
3809
3810#define HMM_Add(A, B) _Generic((A), \
3811 HMM_Vec2: HMM_AddV2, \
3812 HMM_Vec3: HMM_AddV3, \
3813 HMM_Vec4: HMM_AddV4, \
3814 HMM_Mat2: HMM_AddM2, \
3815 HMM_Mat3: HMM_AddM3, \
3816 HMM_Mat4: HMM_AddM4, \
3817 HMM_Quat: HMM_AddQ \
3818)(A, B)
3819
3820#define HMM_Sub(A, B) _Generic((A), \
3821 HMM_Vec2: HMM_SubV2, \
3822 HMM_Vec3: HMM_SubV3, \
3823 HMM_Vec4: HMM_SubV4, \
3824 HMM_Mat2: HMM_SubM2, \
3825 HMM_Mat3: HMM_SubM3, \
3826 HMM_Mat4: HMM_SubM4, \
3827 HMM_Quat: HMM_SubQ \
3828)(A, B)
3829
3830#define HMM_Mul(A, B) _Generic((B), \
3831 float: _Generic((A), \
3832 HMM_Vec2: HMM_MulV2F, \
3833 HMM_Vec3: HMM_MulV3F, \
3834 HMM_Vec4: HMM_MulV4F, \
3835 HMM_Mat2: HMM_MulM2F, \
3836 HMM_Mat3: HMM_MulM3F, \
3837 HMM_Mat4: HMM_MulM4F, \
3838 HMM_Quat: HMM_MulQF, \
3839 default: __hmm_invalid_generic \
3840 ), \
3841 HMM_Vec2: _Generic((A), \
3842 HMM_Vec2: HMM_MulV2, \
3843 HMM_Mat2: HMM_MulM2V2, \
3844 default: __hmm_invalid_generic \
3845 ), \
3846 HMM_Vec3: _Generic((A), \
3847 HMM_Vec3: HMM_MulV3, \
3848 HMM_Mat3: HMM_MulM3V3, \
3849 default: __hmm_invalid_generic \
3850 ), \
3851 HMM_Vec4: _Generic((A), \
3852 HMM_Vec4: HMM_MulV4, \
3853 HMM_Mat4: HMM_MulM4V4, \
3854 default: __hmm_invalid_generic \
3855 ), \
3856 HMM_Mat2: HMM_MulM2, \
3857 HMM_Mat3: HMM_MulM3, \
3858 HMM_Mat4: HMM_MulM4, \
3859 HMM_Quat: HMM_MulQ \
3860)(A, B)
3861
3862#define HMM_Div(A, B) _Generic((B), \
3863 float: _Generic((A), \
3864 HMM_Vec2: HMM_DivV2F, \
3865 HMM_Vec3: HMM_DivV3F, \
3866 HMM_Vec4: HMM_DivV4F, \
3867 HMM_Mat2: HMM_DivM2F, \
3868 HMM_Mat3: HMM_DivM3F, \
3869 HMM_Mat4: HMM_DivM4F, \
3870 HMM_Quat: HMM_DivQF \
3871 ), \
3872 HMM_Vec2: HMM_DivV2, \
3873 HMM_Vec3: HMM_DivV3, \
3874 HMM_Vec4: HMM_DivV4 \
3875)(A, B)
3876
3877#define HMM_Len(A) _Generic((A), \
3878 HMM_Vec2: HMM_LenV2, \
3879 HMM_Vec3: HMM_LenV3, \
3880 HMM_Vec4: HMM_LenV4 \
3881)(A)
3882
3883#define HMM_LenSqr(A) _Generic((A), \
3884 HMM_Vec2: HMM_LenSqrV2, \
3885 HMM_Vec3: HMM_LenSqrV3, \
3886 HMM_Vec4: HMM_LenSqrV4 \
3887)(A)
3888
3889#define HMM_Norm(A) _Generic((A), \
3890 HMM_Vec2: HMM_NormV2, \
3891 HMM_Vec3: HMM_NormV3, \
3892 HMM_Vec4: HMM_NormV4, \
3893 HMM_Quat: HMM_NormQ \
3894)(A)
3895
3896#define HMM_Dot(A, B) _Generic((A), \
3897 HMM_Vec2: HMM_DotV2, \
3898 HMM_Vec3: HMM_DotV3, \
3899 HMM_Vec4: HMM_DotV4, \
3900 HMM_Quat: HMM_DotQ \
3901)(A, B)
3902
3903#define HMM_Lerp(A, T, B) _Generic((A), \
3904 float: HMM_Lerp, \
3905 HMM_Vec2: HMM_LerpV2, \
3906 HMM_Vec3: HMM_LerpV3, \
3907 HMM_Vec4: HMM_LerpV4 \
3908)(A, T, B)
3909
3910#define HMM_Eq(A, B) _Generic((A), \
3911 HMM_Vec2: HMM_EqV2, \
3912 HMM_Vec3: HMM_EqV3, \
3913 HMM_Vec4: HMM_EqV4 \
3914)(A, B)
3915
3916#define HMM_Transpose(M) _Generic((M), \
3917 HMM_Mat2: HMM_TransposeM2, \
3918 HMM_Mat3: HMM_TransposeM3, \
3919 HMM_Mat4: HMM_TransposeM4 \
3920)(M)
3921
3922#define HMM_Determinant(M) _Generic((M), \
3923 HMM_Mat2: HMM_DeterminantM2, \
3924 HMM_Mat3: HMM_DeterminantM3, \
3925 HMM_Mat4: HMM_DeterminantM4 \
3926)(M)
3927
3928#define HMM_InvGeneral(M) _Generic((M), \
3929 HMM_Mat2: HMM_InvGeneralM2, \
3930 HMM_Mat3: HMM_InvGeneralM3, \
3931 HMM_Mat4: HMM_InvGeneralM4 \
3932)(M)
3933
3934#endif
3935
3936#if defined(__GNUC__) || defined(__clang__)
3937#pragma GCC diagnostic pop
3938#endif
3939
3940#endif /* HANDMADE_MATH_H */