-
Notifications
You must be signed in to change notification settings - Fork 2
/
fmath.h
1833 lines (1559 loc) · 40.7 KB
/
fmath.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef VIOLET_FMATH_H
#define VIOLET_FMATH_H
#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
/* General utilities */
#define fmaxf(x, y) (((x) < (y)) ? (y) : (x))
#define fminf(x, y) (((x) > (y)) ? (y) : (x))
#define fPI 3.14159265359f
#define f2PI (2.f * fPI)
#define fDEG2RAD (fPI / 180.f)
#define fmath_clamp(lo, val, hi) fmaxf(lo, fminf(hi, val))
#define fmath_deg2rad(deg) ((deg) * fDEG2RAD)
#define fmath_rad2deg(rad) ((rad) / fDEG2RAD)
#define fmath_eq(a, b, err) (fabs((a)-(b)) <= (err))
#define froundto(x, step) (roundf((x) / (step)) * (step))
/* 2D Vector */
typedef union v2f
{
struct { r32 x, y; };
struct { r32 u, v; };
struct { r32 d[2]; };
} v2f;
extern const v2f g_v2f_x_axis;
extern const v2f g_v2f_y_axis;
extern const v2f g_v2f_zero;
extern const v2f g_v2f_one;
extern const v2f g_v2f_up;
extern const v2f g_v2f_down;
extern const v2f g_v2f_left;
extern const v2f g_v2f_right;
void v2f_set(v2f *v, r32 x, r32 y);
r32 v2f_mag(v2f v);
r32 v2f_mag_sq(v2f v);
r32 v2f_dist(v2f lhs, v2f rhs);
r32 v2f_dist_sq(v2f lhs, v2f rhs);
v2f v2f_normalize(v2f v);
void v2f_normalize_eq(v2f *v);
v2f v2f_scale(v2f v, r32 s);
void v2f_scale_eq(v2f *v, r32 s);
v2f v2f_add(v2f lhs, v2f rhs);
void v2f_add_eq(v2f *lhs, v2f rhs);
v2f v2f_sub(v2f lhs, v2f rhs);
void v2f_sub_eq(v2f *lhs, v2f rhs);
v2f v2f_mul(v2f lhs, v2f rhs);
void v2f_mul_eq(v2f *lhs, v2f rhs);
v2f v2f_div(v2f lhs, v2f rhs);
void v2f_div_eq(v2f *lhs, v2f rhs);
v2f v2f_dir(v2f src, v2f dst);
v2f v2f_fmadd(v2f v, v2f dir, r32 s);
v2f v2f_fmsub(v2f v, v2f dir, r32 s);
v2f v2f_rot(v2f v, r32 radians);
r32 v2f_dot(v2f lhs, v2f rhs);
r32 v2f_cross(v2f lhs, v2f rhs);
v2f v2f_proj(v2f v, v2f axis);
v2f v2f_reflect(v2f v, v2f axis);
v2f v2f_lperp(v2f v);
v2f v2f_rperp(v2f v);
v2f v2f_perp_cw(v2f v);
v2f v2f_perp_ccw(v2f v);
v2f v2f_inverse(v2f v);
void v2f_inverse_eq(v2f *v);
v2f v2f_round(v2f v, r32 unit);
void v2f_round_eq(v2f *v, r32 unit);
b32 v2f_is_zero(v2f v);
b32 v2f_equal(v2f lhs, v2f rhs);
b32 v2f_share_quadrant(v2f lhs, v2f rhs);
v2f v2f_midpoint(v2f v0, v2f v1);
v2f v2f_bisect(v2f v0, v2f v1);
v2f v2f_abs(v2f v);
/* 3D Vector */
typedef union v3f
{
struct { r32 x, y, z; };
struct { v2f xy; };
struct { r32 d[3]; };
} v3f;
extern const v3f g_v3f_x_axis;
extern const v3f g_v3f_y_axis;
extern const v3f g_v3f_z_axis;
extern const v3f g_v3f_zero;
extern const v3f g_v3f_one;
v3f v3f_create_xy_z(v2f xy, r32 z);
r32 v3f_mag(v3f v);
r32 v3f_mag_sq(v3f v);
r32 v3f_dist(v3f lhs, v3f rhs);
r32 v3f_dist_sq(v3f lhs, v3f rhs);
v3f v3f_normalize(v3f v);
v3f v3f_scale(v3f v, r32 s);
v3f v3f_add(v3f lhs, v3f rhs);
v3f v3f_sub(v3f lhs, v3f rhs);
v3f v3f_dir(v3f src, v3f dst);
v3f v3f_fmadd(v3f v, v3f dir, r32 s);
v3f v3f_fmsub(v3f v, v3f dir, r32 s);
r32 v3f_dot(v3f lhs, v3f rhs);
v3f v3f_cross(v3f lhs, v3f rhs);
v3f v3f_proj(v3f v, v3f axis);
v3f v3f_inverse(v3f v);
b32 v3f_is_zero(v3f v);
b32 v3f_equal(v3f lhs, v3f rhs);
/* 3x3 Matrix */
typedef struct m3f
{
r32 v[9];
} m3f;
extern const m3f g_m3f_identity;
extern const m3f g_m3f_zero;
m3f m3f_init_scale(v2f scale);
m3f m3f_init_translation(v2f disp);
m3f m3f_init_rotation(r32 radians);
m3f m3f_inverse(m3f m);
m3f m3f_mul_m3(m3f lhs, m3f rhs);
v2f m3f_mul_v2(m3f m, v2f v);
b32 m3f_equal(m3f lhs, m3f rhs);
/* 4D Vector */
typedef union v4f
{
struct { r32 x, y, z, w; };
struct { v2f xy; };
struct { v3f xyz; };
struct { r32 d[4]; };
} v4f;
v4f v4f_create_xyz_w(v3f xyz, r32 w);
/* 4x4 Matrix */
typedef struct m4f
{
r32 v[16];
} m4f;
extern const m4f g_m4f_identity;
extern const m4f g_m4f_zero;
m4f m4f_init_scale(v3f scale);
m4f m4f_init_translation(v3f disp);
m4f m4f_init_rotation(v3f axis, r32 radians);
m4f m4f_init_rotation_y(r32 radians);
m4f m4f_perspective(r32 fovy, r32 aspect, r32 near_z, r32 far_z);
m4f m4f_orthographic(r32 left, r32 right, r32 bottom, r32 top,
r32 near_z, r32 far_z);
m4f m4f_look_at(v3f eye, v3f center, v3f up);
m4f m4f_mul_m4(m4f lhs, m4f rhs);
v3f m4f_mul_v3(m4f lhs, v3f rhs);
v3f m4f_mul_v3w(m4f lhs, v3f rhs, r32 w);
v4f m4f_mul_v4(m4f lhs, v4f rhs);
m4f m4f_scale(m4f m, v3f scale);
m4f m4f_inverse(m4f m);
m4f m4f_translate(m4f m, v3f diff);
m4f m4f_rotate(m4f m, v3f axis, r32 radians);
m4f m4f_transpose(m4f m);
b32 m4f_equal(m4f lhs, m4f rhs);
/* Interval */
typedef struct ivalf
{
r32 l, r;
} ivalf;
extern const ivalf g_ivalf_0_to_1;
extern const ivalf g_ivalf_zero;
ivalf ivalf_range(r32 center, r32 radius);
r32 ivalf_center(ivalf i);
ivalf ivalf_slide(ivalf i, r32 d);
r32 ivalf_length(ivalf i);
b32 ivalf_contains_val(ivalf i, r32 x);
b32 ivalf_contains_val_within(ivalf i, r32 x, r32 error);
b32 ivalf_contains_ival(ivalf lhs, ivalf rhs);
b32 ivalf_contains_ival_within(ivalf lhs, ivalf rhs, r32 error);
b32 ivalf_overlaps(ivalf lhs, ivalf rhs);
b32 ivalf_overlaps_within(ivalf lhs, ivalf rhs, r32 error);
r32 ivalf_overlap(ivalf lhs, ivalf rhs);
ivalf ivalf_overlap_ival(ivalf lhs, ivalf rhs);
ivalf ivalf_invert(ivalf i);
ivalf ivalf_join(ivalf lhs, ivalf rhs);
/* 2D Anti-aliased bounding box */
typedef struct box2f
{
v2f min;
v2f max;
} box2f;
void box2f_from_point(box2f *b, v2f p);
void box2f_from_line(box2f *b, v2f start, v2f end);
void box2f_from_center(box2f *b, v2f center, v2f half_dim);
void box2f_from_dims(box2f *b, r32 left, r32 top, r32 right, r32 bottom);
void box2f_from_xywh(box2f *b, r32 x, r32 y, r32 w, r32 h);
b32 box2f_empty(box2f b);
b32 box2f_contains_point(box2f b, v2f p);
b32 box2f_contains_box(box2f lhs, box2f rhs);
void box2f_clamp_point(box2f b, v2f *p);
b32 box2f_overlaps(box2f lhs, box2f rhs);
b32 box2f_overlaps_within(box2f lhs, box2f rhs, r32 error);
b32 box2f_eq(box2f lhs, box2f rhs);
void box2f_extend_point(box2f *b, v2f p);
void box2f_extend_points(box2f *b, const v2f *p, u32 n);
void box2f_extend_box(box2f *b, box2f other);
void box2f_extend_scalar(box2f *b, r32 dim);
void box2f_translate(box2f *b, v2f v);
void box2f_transform(box2f *b, const m3f mat);
v2f box2f_get_center(box2f b);
v2f box2f_get_extent(box2f b);
v2f box2f_get_half_dim(box2f b);
r32 box2f_get_width(box2f b);
r32 box2f_get_height(box2f b);
/* 3D Anti-aliased bounding box */
typedef struct box3f
{
v3f min;
v3f max;
} box3f;
void box3f_from_point(box3f *b, v3f p);
void box3f_extend_point(box3f *b, v3f p);
void box3f_extend_box(box3f *b, box3f other);
v3f box3f_get_center(box3f b);
v3f box3f_get_extent(box3f b);
v3f box3f_get_half_dim(box3f b);
void box3f_clip_v3f(box3f b, v3f *p);
/* Line/Segment utilities */
v2f fmath_line_extrapolate(v2f a, v2f b, r32 t);
r32 fmath_line_interpolate(v2f a, v2f b, v2f p);
b32 fmath_ray_intersect_coords(v2f a, v2f adir, v2f b, v2f bdir, r32 *t, r32 *u);
b32 fmath_ray_intersect(v2f a, v2f adir, v2f b, v2f bdir, v2f *isec);
b32 fmath_line_intersect_coords(v2f a0, v2f a1, v2f b0, v2f b1, r32 *t, r32 *u);
b32 fmath_line_intersect(v2f a0, v2f a1, v2f b0, v2f b1, v2f *isec);
b32 fmath_segment_intersect_coords(v2f a0, v2f a1, v2f b0, v2f b1, r32 *t, r32 *u);
b32 fmath_segment_intersect(v2f a0, v2f a1, v2f b0, v2f b1, v2f *isec);
v2f fmath_nearest_point_on_segment(v2f a, v2f b, v2f p);
v2f fmath_nearest_point_on_line(v2f a, v2f b, v2f p);
r32 fmath_point_to_segment_dist(v2f a, v2f b, v2f p);
r32 fmath_point_to_segment_dist_sq(v2f a, v2f b, v2f p);
r32 fmath_point_to_line_dist(v2f a, v2f b, v2f p);
r32 fmath_point_to_line_dist_sq(v2f a, v2f b, v2f p);
r32 fmath_point_to_ray_dist(v2f a0, v2f dir, v2f p);
ivalf linef_project(v2f a, v2f b, v2f axis);
ivalf linef_project_onto_ray(v2f a, v2f b, v2f start, v2f dir);
/* NOTE(rgriege): returns a unix-style error code - see implementation for details */
s32 fmath_ray_intersect_coords_3d(v3f a, v3f adir, v3f b, v3f bdir, r32 *t, r32 *u);
v3f fmath_nearest_point_on_line_3d(v3f a, v3f b, v3f p);
r32 fmath_point_to_line_dist_3d(v3f a, v3f b, v3f p);
r32 fmath_point_to_line_dist_sq_3d(v3f a, v3f b, v3f p);
/* Polygon */
void polyf_from_box(v2f v[4], box2f box);
b32 polyf_is_simple(const v2f *v, u32 n);
b32 polyf_is_convex(const v2f *v, u32 n);
b32 polyf_is_concave(const v2f *v, u32 n);
b32 polyf_contains(const v2f *v, u32 n, v2f point);
b32 polyf_contains_fast(const v2f *v, u32 n, box2f *bbox, v2f pt);
void polyf_bounding_box(const v2f *v, u32 n, box2f *box);
box2f polyf_bbox(const v2f *v, u32 n);
v2f polyf_extent(const v2f *v, u32 n);
void polyf_translate(v2f *v, u32 n, v2f delta);
void polyf_transform(v2f *v, u32 n, const m3f mat);
ivalf polyf_project(const v2f *v, u32 n, v2f axis);
ivalf polyf_project_onto_ray(const v2f *v, u32 n, v2f start, v2f dir);
v2f polyf_center(const v2f *v, u32 n);
r32 polyf_area(const v2f *v, u32 n);
r32 polyf_area_signed(const v2f *v, u32 n);
r32 polyf_perimeter(const v2f *v, u32 n);
v2f polyf_centroid(const v2f *v, u32 n);
b32 polyf_is_cw(const v2f *v, u32 n);
b32 polyf_is_ccw(const v2f *v, u32 n);
b32 polyf_line_intersect(const v2f *v, u32 n, v2f v0, v2f v1);
u32 polyf_line_intersections(const v2f *v, u32 n, v2f v0, v2f v1, v2f *first, v2f *last);
b32 polyf_intersect(const v2f *p1, u32 n1, const v2f *p2, u32 n2, v2f *isec);
r32 polyf_pt_dist(const v2f *v, u32 n, v2f p);
r32 polyf_pt_dist_sq(const v2f *v, u32 n, v2f p);
#endif // VIOLET_FMATH_H
/* Implementation */
#ifdef FMATH_IMPLEMENTATION
/* 2D Vector */
const v2f g_v2f_x_axis = { 1, 0 };
const v2f g_v2f_y_axis = { 0, 1 };
const v2f g_v2f_zero = { 0, 0 };
const v2f g_v2f_one = { 1, 1 };
const v2f g_v2f_up = { 0, 1 };
const v2f g_v2f_down = { 0, -1 };
const v2f g_v2f_left = { -1, 0 };
const v2f g_v2f_right = { 1, 0 };
void v2f_set(v2f *v, r32 x, r32 y)
{
v->x = x;
v->y = y;
}
r32 v2f_mag(v2f v)
{
return sqrtf(v2f_mag_sq(v));
}
r32 v2f_mag_sq(v2f v)
{
return v2f_dot(v, v);
}
r32 v2f_dist(v2f lhs, v2f rhs)
{
return sqrtf(v2f_dist_sq(lhs, rhs));
}
r32 v2f_dist_sq(v2f lhs, v2f rhs)
{
v2f_sub_eq(&lhs, rhs);
return v2f_mag_sq(lhs);
}
v2f v2f_normalize(v2f v)
{
return v2f_scale(v, 1.f/v2f_mag(v));
}
void v2f_normalize_eq(v2f *v)
{
*v = v2f_normalize(*v);
}
v2f v2f_scale(v2f v, r32 s)
{
v2f result = { v.x * s, v.y * s };
return result;
}
void v2f_scale_eq(v2f *v, r32 s)
{
v->x *= s;
v->y *= s;
}
v2f v2f_add(v2f lhs, v2f rhs)
{
v2f result = { lhs.x + rhs.x, lhs.y + rhs.y };
return result;
}
void v2f_add_eq(v2f *lhs, v2f rhs)
{
lhs->x += rhs.x;
lhs->y += rhs.y;
}
v2f v2f_sub(v2f lhs, v2f rhs)
{
return (v2f){ .x = lhs.x - rhs.x, .y = lhs.y - rhs.y };
}
void v2f_sub_eq(v2f *lhs, v2f rhs)
{
lhs->x -= rhs.x;
lhs->y -= rhs.y;
}
v2f v2f_mul(v2f lhs, v2f rhs)
{
return (v2f){ .x = lhs.x * rhs.x, .y = lhs.y * rhs.y };
}
void v2f_mul_eq(v2f *lhs, v2f rhs)
{
lhs->x *= rhs.x;
lhs->y *= rhs.y;
}
v2f v2f_div(v2f lhs, v2f rhs)
{
return (v2f){ .x = lhs.x / rhs.x, .y = lhs.y / rhs.y };
}
void v2f_div_eq(v2f *lhs, v2f rhs)
{
lhs->x /= rhs.x;
lhs->y /= rhs.y;
}
v2f v2f_dir(v2f src, v2f dst)
{
return v2f_normalize(v2f_sub(dst, src));
}
v2f v2f_fmadd(v2f v, v2f dir, r32 s)
{
return v2f_add(v, v2f_scale(dir, s));
}
v2f v2f_fmsub(v2f v, v2f dir, r32 s)
{
return v2f_sub(v, v2f_scale(dir, s));
}
v2f v2f_rot(v2f v, r32 radians)
{
const r32 c = cosf(radians);
const r32 s = sinf(radians);
return (v2f){ .x = v.x * c - v.y * s, .y = v.x * s + v.y * c };
}
r32 v2f_dot(v2f lhs, v2f rhs)
{
return lhs.x * rhs.x + lhs.y * rhs.y;
}
r32 v2f_cross(v2f lhs, v2f rhs)
{
return lhs.x * rhs.y - lhs.y * rhs.x;
}
v2f v2f_proj(v2f v, v2f axis)
{
return v2f_scale(axis, v2f_dot(v, axis) / v2f_mag_sq(axis));
}
v2f v2f_reflect(v2f v, v2f axis)
{
v2f proj = v2f_proj(v, axis);
v2f perp = v2f_sub(v, proj);
return v2f_sub(proj, perp);
}
v2f v2f_lperp(v2f v)
{
return (v2f){ .x = -v.y, .y = v.x };
}
v2f v2f_rperp(v2f v)
{
return (v2f){ .x = v.y, .y = -v.x };
}
v2f v2f_perp_cw(v2f v)
{
return (v2f){ .x = v.y, .y = -v.x };
}
v2f v2f_perp_ccw(v2f v)
{
return (v2f){ .x = -v.y, .y = v.x };
}
v2f v2f_inverse(v2f v)
{
return (v2f){ .x = -v.x, .y = -v.y };
}
void v2f_inverse_eq(v2f *v)
{
v->x = -v->x;
v->y = -v->y;
}
v2f v2f_round(v2f v, r32 unit)
{
v2f_round_eq(&v, unit);
return v;
}
void v2f_round_eq(v2f *v, r32 unit)
{
const r32 inv_unit = 1.f / unit;
v->x = roundf(v->x * inv_unit) / inv_unit;
v->y = roundf(v->y * inv_unit) / inv_unit;
}
b32 v2f_is_zero(v2f v)
{
return v.x == 0 && v.y == 0;
}
b32 v2f_equal(v2f lhs, v2f rhs)
{
return lhs.x == rhs.x && lhs.y == rhs.y;
}
b32 v2f_share_quadrant(v2f lhs, v2f rhs)
{
return v2f_dot(lhs, rhs) >= 0;
}
v2f v2f_midpoint(v2f v0, v2f v1)
{
return v2f_scale(v2f_add(v0, v1), 0.5f);
}
v2f v2f_bisect(v2f v0, v2f v1)
{
return v2f_normalize(v2f_add(v0, v1));
}
v2f v2f_abs(v2f v)
{
return (v2f){ .x = fabsf(v.x), .y = fabsf(v.y) };
}
/* 3D Vector */
const v3f g_v3f_x_axis = { 1, 0, 0 };
const v3f g_v3f_y_axis = { 0, 1, 0 };
const v3f g_v3f_z_axis = { 0, 0, 1 };
const v3f g_v3f_zero = { 0, 0, 0 };
const v3f g_v3f_one = { 1, 1, 1 };
v3f v3f_create_xy_z(v2f xy, r32 z)
{
return (v3f){ .x = xy.x, .y = xy.y, .z = z };
}
r32 v3f_mag(v3f v)
{
return sqrtf(v3f_mag_sq(v));
}
r32 v3f_mag_sq(v3f v)
{
return v.x * v.x + v.y * v.y + v.z * v.z;
}
r32 v3f_dist(v3f lhs, v3f rhs)
{
return sqrtf(v3f_dist_sq(lhs, rhs));
}
r32 v3f_dist_sq(v3f lhs, v3f rhs)
{
return v3f_mag_sq(v3f_sub(lhs, rhs));
}
v3f v3f_normalize(v3f v)
{
return v3f_scale(v, 1.f / v3f_mag(v));
}
v3f v3f_scale(v3f v, r32 s)
{
return (v3f){ .x = v.x * s, .y = v.y * s, .z = v.z * s };
}
v3f v3f_add(v3f lhs, v3f rhs)
{
return (v3f){ .x = lhs.x + rhs.x, .y = lhs.y + rhs.y, .z = lhs.z + rhs.z };
}
v3f v3f_sub(v3f lhs, v3f rhs)
{
return (v3f){ .x = lhs.x - rhs.x, .y = lhs.y - rhs.y, .z = lhs.z - rhs.z };
}
v3f v3f_dir(v3f src, v3f dst)
{
return v3f_normalize(v3f_sub(dst, src));
}
v3f v3f_fmadd(v3f v, v3f dir, r32 s)
{
return v3f_add(v, v3f_scale(dir, s));
}
v3f v3f_fmsub(v3f v, v3f dir, r32 s)
{
return v3f_sub(v, v3f_scale(dir, s));
}
r32 v3f_dot(v3f lhs, v3f rhs)
{
return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
}
v3f v3f_cross(v3f lhs, v3f rhs)
{
return (v3f){
.x = lhs.y * rhs.z - lhs.z * rhs.y,
.y = lhs.z * rhs.x - lhs.x * rhs.z,
.z = lhs.x * rhs.y - lhs.y * rhs.x
};
}
v3f v3f_proj(v3f v, v3f axis)
{
return v3f_scale(axis, v3f_dot(v, axis) / v3f_mag_sq(axis));
}
v3f v3f_inverse(v3f v)
{
return (v3f){ .x = -v.x, .y = -v.y, .z = -v.z };
}
b32 v3f_is_zero(v3f v)
{
return v3f_equal(v, g_v3f_zero);
}
b32 v3f_equal(v3f lhs, v3f rhs)
{
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z;
}
/* 3x3 Matrix */
const m3f g_m3f_identity = {
1, 0, 0,
0, 1, 0,
0, 0, 1
};
const m3f g_m3f_zero = {
0, 0, 0,
0, 0, 0,
0, 0, 0
};
m3f m3f_init_scale(v2f scale)
{
return (m3f) {
scale.x, 0, 0,
0, scale.y, 0,
0, 0, 1,
};
}
m3f m3f_init_translation(v2f disp)
{
return (m3f) {
1, 0, disp.x,
0, 1, disp.y,
0, 0, 1,
};
}
m3f m3f_init_rotation(r32 radians)
{
m3f m;
m.v[0] = cosf(radians);
m.v[1] = -sinf(radians);
m.v[2] = 0;
m.v[3] = -m.v[1];
m.v[4] = m.v[0];
m.v[5] = 0;
m.v[6] = 0;
m.v[7] = 0;
m.v[8] = 1;
return m;
}
m3f m3f_inverse(m3f m)
{
const v3f c0 = { m.v[0], m.v[3], m.v[6] };
const v3f c1 = { m.v[1], m.v[4], m.v[7] };
const v3f c2 = { m.v[2], m.v[5], m.v[8] };
const r32 det = v3f_dot(c0, v3f_cross(c1, c2));
if (det == 0.f) {
ASSERT_FALSE_AND_LOG("uninvertible");
return m;
}
const r32 s = 1.f / det;
const v3f r0 = v3f_scale(v3f_cross(c1, c2), s);
const v3f r1 = v3f_scale(v3f_cross(c2, c0), s);
const v3f r2 = v3f_scale(v3f_cross(c0, c1), s);
return (m3f) {
r0.x, r0.y, r0.z,
r1.x, r1.y, r1.z,
r2.x, r2.y, r2.z,
};
}
m3f m3f_mul_m3(m3f lhs, m3f rhs)
{
m3f res = g_m3f_zero;
const r32 *lhs_i, *rhs_k;
r32 *res_i, lhs_ik;
for (int i = 0; i < 3; i++) {
lhs_i = lhs.v + 3 * i;
res_i = res.v + 3 * i;
for (int k = 0; k < 3; k++) {
rhs_k = rhs.v + 3 * k;
lhs_ik = lhs_i[k];
for (int j = 0; j < 3; j++)
res_i[j] += lhs_ik * rhs_k[j];
}
}
return res;
}
v2f m3f_mul_v2(m3f m, v2f v)
{
v2f result;
result.x = m.v[0] * v.x + m.v[1] * v.y + m.v[2];
result.y = m.v[3] * v.x + m.v[4] * v.y + m.v[5];
return result;
}
b32 m3f_equal(m3f lhs, m3f rhs)
{
return memcmp(lhs.v, rhs.v, 9 * sizeof(r32)) == 0;
}
/* 4D Vector */
v4f v4f_create_xyz_w(v3f xyz, r32 w)
{
return (v4f){ .x = xyz.x, .y = xyz.y, .z = xyz.z, .w = w };
}
/* 4x4 Matrix */
const m4f g_m4f_identity = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
const m4f g_m4f_zero = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
};
m4f m4f_init_scale(v3f scale)
{
return (m4f) {
scale.x, 0, 0, 0,
0, scale.y, 0, 0,
0, 0, scale.z, 0,
0, 0, 0, 1,
};
}
m4f m4f_init_translation(v3f disp)
{
return (m4f) {
1, 0, 0, disp.x,
0, 1, 0, disp.y,
0, 0, 1, disp.z,
0, 0, 0, 1,
};
}
m4f m4f_init_rotation(v3f axis, r32 radians)
{
const v3f a = axis;
const r32 c = cos(radians);
const r32 nc = 1.f - c;
const r32 s = sin(radians);
return (m4f) {
c + a.x * a.x * nc, a.x * a.y * nc - a.z * s, a.x * a.z * nc + a.y * s, 0,
a.y * a.x * nc + a.z * s, c + a.y * a.y * nc, a.y * a.z * nc - a.x * s, 0,
a.z * a.x * nc - a.y * s, a.z * a.y * nc + a.x * s, c + a.z * a.z * nc, 0,
0, 0, 0, 1,
};
}
m4f m4f_init_rotation_y(r32 radians)
{
const r32 c = cosf(radians);
const r32 s = sinf(radians);
return (m4f) {
c, 0, s, 0,
0, 1, 0, 0,
-s, 0, c, 0,
0, 0, 0, 1,
};
}
m4f m4f_perspective(r32 fovy, r32 aspect, r32 near_z, r32 far_z)
{
const r32 f = 1.f / tanf(fmath_deg2rad(fovy / 2.f));
const r32 denom = near_z == far_z ? 1.f : near_z - far_z;
return (m4f) {
f / aspect, 0, 0, 0,
0, f, 0, 0,
0, 0, (far_z + near_z) / denom, 2.f * far_z * near_z / denom,
0, 0, -1, 0
};
}
m4f m4f_orthographic(r32 left, r32 right, r32 bottom, r32 top,
r32 near_z, r32 far_z)
{
const r32 w = (right - left);
const r32 h = (top - bottom);
const r32 depth = (far_z - near_z);
return (m4f) {
2.f / w, 0.f, 0.f, (right + left) / w,
0.f, 2.f / h, 0.f, (top + bottom) / h,
0.f, 0.f, -2.f / depth, -(far_z + near_z) / depth,
0.f, 0.f, 0.f, 1.f
};
}
m4f m4f_look_at(v3f eye, v3f center, v3f up_)
{
const v3f f = v3f_normalize(v3f_sub(center, eye));
const v3f up = v3f_normalize(up_);
const v3f s = v3f_cross(f, up);
const v3f u = v3f_cross(s, f);
return (m4f) {
s.x, s.y, s.z, -v3f_dot(s, eye),
u.x, u.y, u.z, -v3f_dot(u, eye),
-f.x, -f.y, -f.z, v3f_dot(f, eye),
0, 0, 0, 1,
};
}
m4f m4f_mul_m4(m4f lhs, m4f rhs)
{
const r32 *lhs_i, *rhs_k;
r32 *res_i;
m4f res = g_m4f_zero;
for (int i = 0; i < 4; ++i) {
lhs_i = lhs.v + 4 * i;
res_i = res.v + 4 * i;
for (int k = 0; k < 4; ++k) {
rhs_k = rhs.v + 4 * k;
for (int j = 0; j < 4; j++)
res_i[j] += lhs_i[k] * rhs_k[j];
}
}
return res;
}
v3f m4f_mul_v3(m4f lhs, v3f rhs)
{
v4f result = m4f_mul_v4(lhs, v4f_create_xyz_w(rhs, 1.f));
return v3f_scale(result.xyz, 1.f / result.w);
}
v3f m4f_mul_v3w(m4f lhs, v3f rhs, r32 w)
{
return m4f_mul_v4(lhs, v4f_create_xyz_w(rhs, w)).xyz;
}
v4f m4f_mul_v4(m4f lhs, v4f rhs)
{
return (v4f) {
.x = lhs.v[ 0] * rhs.x + lhs.v[ 1] * rhs.y + lhs.v[ 2] * rhs.z + lhs.v[ 3] * rhs.w,
.y = lhs.v[ 4] * rhs.x + lhs.v[ 5] * rhs.y + lhs.v[ 6] * rhs.z + lhs.v[ 7] * rhs.w,
.z = lhs.v[ 8] * rhs.x + lhs.v[ 9] * rhs.y + lhs.v[10] * rhs.z + lhs.v[11] * rhs.w,
.w = lhs.v[12] * rhs.x + lhs.v[13] * rhs.y + lhs.v[14] * rhs.z + lhs.v[15] * rhs.w,
};
}
m4f m4f_scale(m4f m, v3f scale)
{
return m4f_mul_m4(m4f_init_scale(scale), m);
}
m4f m4f_inverse(m4f m)
{
m4f dst;
const r32 m00 = m.v[0 * 4 + 0];
const r32 m01 = m.v[0 * 4 + 1];
const r32 m02 = m.v[0 * 4 + 2];
const r32 m03 = m.v[0 * 4 + 3];
const r32 m10 = m.v[1 * 4 + 0];
const r32 m11 = m.v[1 * 4 + 1];
const r32 m12 = m.v[1 * 4 + 2];
const r32 m13 = m.v[1 * 4 + 3];
const r32 m20 = m.v[2 * 4 + 0];
const r32 m21 = m.v[2 * 4 + 1];
const r32 m22 = m.v[2 * 4 + 2];
const r32 m23 = m.v[2 * 4 + 3];
const r32 m30 = m.v[3 * 4 + 0];
const r32 m31 = m.v[3 * 4 + 1];
const r32 m32 = m.v[3 * 4 + 2];
const r32 m33 = m.v[3 * 4 + 3];
const r32 tmp_0 = m22 * m33;
const r32 tmp_1 = m32 * m23;
const r32 tmp_2 = m12 * m33;
const r32 tmp_3 = m32 * m13;
const r32 tmp_4 = m12 * m23;
const r32 tmp_5 = m22 * m13;
const r32 tmp_6 = m02 * m33;
const r32 tmp_7 = m32 * m03;
const r32 tmp_8 = m02 * m23;
const r32 tmp_9 = m22 * m03;
const r32 tmp_10 = m02 * m13;
const r32 tmp_11 = m12 * m03;
const r32 tmp_12 = m20 * m31;
const r32 tmp_13 = m30 * m21;
const r32 tmp_14 = m10 * m31;
const r32 tmp_15 = m30 * m11;
const r32 tmp_16 = m10 * m21;
const r32 tmp_17 = m20 * m11;
const r32 tmp_18 = m00 * m31;
const r32 tmp_19 = m30 * m01;
const r32 tmp_20 = m00 * m21;
const r32 tmp_21 = m20 * m01;
const r32 tmp_22 = m00 * m11;
const r32 tmp_23 = m10 * m01;
const r32 t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) -
(tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31);
const r32 t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) -
(tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31);
const r32 t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) -
(tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31);
const r32 t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) -
(tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21);
const r32 d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3);
dst.v[ 0] = d * t0;
dst.v[ 1] = d * t1;
dst.v[ 2] = d * t2;
dst.v[ 3] = d * t3;
dst.v[ 4] = d * ((tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30) -
(tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30));
dst.v[ 5] = d * ((tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30) -
(tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30));
dst.v[ 6] = d * ((tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30) -
(tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30));
dst.v[ 7] = d * ((tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20) -
(tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20));
dst.v[ 8] = d * ((tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33) -
(tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33));
dst.v[ 9] = d * ((tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33) -
(tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33));
dst.v[10] = d * ((tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33) -
(tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33));
dst.v[11] = d * ((tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23) -
(tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23));
dst.v[12] = d * ((tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12) -
(tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22));
dst.v[13] = d * ((tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22) -
(tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02));
dst.v[14] = d * ((tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02) -
(tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12));
dst.v[15] = d * ((tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12) -
(tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02));
return dst;
}
m4f m4f_translate(m4f m, v3f diff)
{
return m4f_mul_m4(m4f_init_translation(diff), m);
}
m4f m4f_rotate(m4f m, v3f axis, r32 radians)
{
return m4f_mul_m4(m4f_init_rotation(axis, radians), m);
}
m4f m4f_transpose(m4f m)
{
return (m4f) {
m.v[0], m.v[4], m.v[8], m.v[12],
m.v[1], m.v[5], m.v[9], m.v[13],
m.v[2], m.v[6], m.v[10], m.v[14],
m.v[3], m.v[7], m.v[11], m.v[15],
};
}