forked from rasmusbarr/nudge
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathnudge.h
More file actions
9547 lines (8082 loc) · 487 KB
/
Copy pathnudge.h
File metadata and controls
9547 lines (8082 loc) · 487 KB
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
//
// Copyright (c) 2017 Rasmus Barringer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Modified, refactored and documented by Flix01 (https://github.com/Flix01/nudge/tree/master) in 2024
// [I'm not a physics engine expert at all, the mods I've made are just to ease my usage scenario]
// [I've also probably decreased performance and broken something, so if you're a
// physics engine expert, I suggest you base your mods on the original version]
// Further info can be read in the doxygen comment below.
/**
* \mainpage Nudge Physics Library Documentation
*
* \section intro_sec Introduction
*
* Nudge is a single-file, header-only, c++ small data-oriented and SIMD-optimized 3D rigid body physics library created by Rasmus Barringer in 2017 (https://github.com/rasmusbarr/nudge).
*
* This 2024 version (https://github.com/Flix01/nudge/tree/master subfolder) is just an attempt
* to ease user experience, by embedding part of the original demo code in the library itself,
* and extending some of its functionalities.
*
* \note Most of the physics-related stuff has been kept intact, so the new version does not improve stuff in this area.
*
*
* \section features_sec Features
* - Single file nudge.h
* - Only box and sphere colliders (i.e. collision shapes) supported (but every body can be a compound of colliders)
* - Max number of colliders: 8192
* - Static, kinematic and dynamic bodies
* - Collision groups and collision masks
* - Kinematic animation support
* - Doxygen documentation
*
* \section building_sec Building
* - Being a header-only library, all that is required is to define NUDGE_IMPLEMENTATION in a .cpp file before including "nudge.h".
* - The library works only with SIMD enabled: the recommended requirements are AVX2 and FMA; the minimum requirement is just SSE2. In many cases adding something like -march=native in the compiler options is enough (in g++/clang++ syntax): -march=haswell is probably better for independent builds.
* - \note Running a SIMD-compiled program on hardware where SIMD is not supported is likely to cause RANDOM CRASHES.
* - \note When compiling using emscripten, something that works for me (at least when I'm writing this) is: -msse2 -msimd128 -s STACK_SIZE=512kb -s ALLOW_MEMORY_GROWTH=1 (the first two flags set up SIMD support, the last two are not mandatory, but necessary in most cases, expecially the latter, to ensure that the program has enough memory to run, and to prevent crashes at startup inside browsers). However not all browsers support SIMD by default (without activating it someway): that's one of the reasons of random crashes inside browsers, after the program starts.
* - \note Note that emscripten does not support FMA as far as I know, so something like: -mavx2 -msimd128 does not compile (nudge.h seems to use AVX2 only with FMA).
* - \note The <a href="https://github.com/simd-everywhere/simde">[SIMDE]</a> library can be used to compile and run nudge replacing or removing SIMD support. One way to remove SIMD (through SIMDE) is to replace the SIMD compilation flags with (g++/clang syntax): -DUSE_SIMDE -DSIMDE_NO_NATIVE (optionally with: -DSIMDE_ENABLE_OPENMP -fopenmp-simd) [tested: it works when I'm writing this (hopefully without SIMD)]. Of course we should expect a performance penalty when running without SIMD support (but in any case consider that there's always an overhead when running something inside a web browser).
* - The library documentation (recommended) can be generated with the doxygen command launched from the same folder as the Doxyfile file.
*
* \section usage_sec Usage
* \subsection example_code Example Code
* Here is a code snippet to get started with the library (users can easily extend it using the TODO sections):
*
* \code
* // file example01.cpp (in the ./example folder)
* // g++ example01.cpp -I../ -I./ -march=native -O3 -Wall -o example01
* // or using emscripten, with output in a subfolder named ./html :
* // em++ -O3 -msse2 -msimd128 -fno-rtti -fno-exceptions -s ALLOW_MEMORY_GROWTH=1 -o html/nudge_example01.html ./example01.cpp -I"./" -I"../"
*
* #define NUDGE_IMPLEMENTATION // [TODO 0] better do this in another cpp file to speed up recompilations
* #include "nudge.h"
*
* int main() {
* using namespace nudge;
*
* // Display helpful info
* show_info();
*
* // Initialize the context
* context_t c = {}; // reset it
* init_context(&c);
*
* // Add bodies
* Transform T = identity_transform;T.position[1]=40.f;
* unsigned body = add_sphere(&c,1.f,0.5f,&T); // returns the 'permanent' index to the physic body
*
* // Program main loop
* while (1) {
* double elapsed_time_from_previous_frame_in_seconds = 1.0f/60.f; // [TODO 1] get the seconds elapsed from the previous (graphic) frame here somehow
*
* // Update simulation
* const unsigned substeps = pre_simulation_step(&c,elapsed_time_from_previous_frame_in_seconds); // mandatory call (substeps are the number of physic frames that are going to be performed in simulation_step(...))
* if (substeps>0) {
* // here you can manually move kinematic bodies, for example, using nudge::TransformAssignToBody(...)
* }
* simulation_step(&c); // mandatory call (main function of the library)
*
* // Read back bodies
* for (unsigned body=0;body<c.bodies.count;body++) {
* const Transform* T = &c.bodies.transforms[body];
* printf("[physic frame: %llu] [body:%u] pos: {%1.3f,%1.3f,%1.3f}\n",c.simulation_params.num_frames,body,T->position[0],T->position[1],T->position[2]);
*
* // or just draw the body using a smoothed 16-float column-major matrix:
* // float mMatrix[16];calculate_graphic_transform_for_body(&c,body,mMatrix);
* // [TODO 2] place the code to draw 'body' at model matrix 'mMatrix' here
* }
*
* if (c.simulation_params.num_frames>120) break; // [TODO 3] break the loop when user presses ESC somehow
* }
*
* // Free the context
* destroy_context(&c);
*
* printf("Exiting...\n");fflush(stdout);
*
* return 0;
* }
* \endcode
*
*
* \section faq_sec FAQ
* - The sample application is crashing. Why?
*
* Most likely, your CPU doesn't support AVX2 and/or FMA. The project files are set to compile with AVX2 and FMA support and you need to disable it in build settings.
* Xcode: Set "Enable Additional Vector Extensions" to your supported level. Remove -mfma and -mno-fma4 from "Other C Flags".
* Visual Studio: Set "Enable Enhanced Instruction Set" under code generation to your supported level. Remove __FMA__ from the preprocessor definitions.
*
* - How can I add other colliders (i.e. collision shapes), so that I can use height maps, convex and concave meshes, cylinders, capsules, etc.? And how can I add constraints between bodies?
*
* ...I suggest you use another physics library!
* In any case, the new (2024) version was made mainly to ease the nudge API, and to expose properties (like friction) that were hard-coded before.
* Extending the physics-related stuff is not a purpose of this work.
*
* If you have some experience in physics-engine programming, maybe you could try extending the original version: it allows some extension possibility even in the example code (without touching nudge.h at all)!
* Also it might be helpful to read this (old) <a href="https://rasmusbarr.github.io/blog/dod-physics.html">[link]</a> from the original author.
*
* - How do collision masks work?
*
* Well, the way collision groups and masks are implemented is very efficient, but a bit difficult to understand, because it allows incoherent conditions.
* Every body belongs to a single collision group, and owns a collision mask of all the groups the body should collide with. An example of incoherent condition if the following:
* \code
* // c nudge context ptr
* unsigned a,b; // set these to 2 body indices
* // we could have used 'body_set_collision_group_and_mask(...)' here:
* c->bodies.filters[a].collision_group = nudge::COLLISION_GROUP_A;c->bodies.filters[a].collision_mask = nudge::COLLISION_GROUP_ALL&(~nudge::COLLISION_GROUP_B);
* c->bodies.filters[b].collision_group = nudge::COLLISION_GROUP_B;c->bodies.filters[b].collision_mask = nudge::COLLISION_GROUP_ALL;
* // => a doesn't want to collide with b, but b wants to collide with a
* \endcode
* How incoherent conditions are handled depends on the optional definition NUDGE_COLLISION_MASKS_CONSISTENT (undefined by default, can be defined before the NUDGE_IMPLEMENTATION definition).
* By default, in the code above, a and b do not collide. Please note that by always using coherent conditions, collision behavior should not depend on the NUDGE_COLLISION_MASKS_CONSISTENT definition at all.
*/
#ifndef NUDGE_H
#define NUDGE_H
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h> // log function declaration
#ifdef NUDGE_USER_CFG_FILE_NAME
# include NUDGE_USER_CFG_FILE_NAME // optional definition for advanced users (to be placed in the project options or in the compiler commandline, not inside code files). Remember to escape quotes (e.g. -DNUDGE_USER_CFG_FILE_NAME="\"nudge_user_cfg.h\"" on the commandline)
#endif
#ifndef NUDGE_NO_STDIO
# include <stdio.h>
#endif
#ifndef __cplusplus
# error nudge.h is a c++ file and should be compiled as c++
#elif __cplusplus < 201103L
# define NUDGE_NO_CPP11_DETECTED
# define NUDGE_CONSTEXPRFNC /*no-op*/ /*never used in nudge.h*/
# define NUDGE_CONSTEXPR const /*never used in nudge.h*/
# define NUDGE_STATIC_ASSERT_WITH_MESSAGE(X,MESSAGE) assert(X) /*this needs <assert.h>, but I don't want to include it here*/
# undef NUDGE_USE_INT32_ENUMS
# define NUDGE_USE_INT32_ENUMS // if set: bigger enums (more space for body flags and collision groups: the BodyFilter struct is 3x bigger), but worse cache performance (note that bit operations are generally not faster with smaller types)
// Also note that there are still a few anonymous structs (that by standard require C++11 compilation),
// but in my tests both g++ and clang++ work just fine with -std=c++98
// In case of problems please define NUDGE_NO_ANONYMOUS_STRUCTS
#else // c++11 detected
# define NUDGE_CONSTEXPRFNC constexpr /*never used in nudge.h*/
# define NUDGE_CONSTEXPR constexpr /*never used in nudge.h*/
# define NUDGE_STATIC_ASSERT_WITH_MESSAGE(X,MESSAGE) static_assert((X), MESSAGE) /*no <assert.h> required; never used in nudge.h*/
#endif // __cplusplus
#define NUDGE_STATIC_ASSERT(X) NUDGE_STATIC_ASSERT_WITH_MESSAGE((X), "") /*never used in nudge.h*/
#ifdef __SIZEOF_POINTER__
# define NUDGE_POINTER_SIZE ((__SIZEOF_POINTER__)*8) /* __SIZEOF_POINTER__ (gcc/clang) is in bytes */
#elif defined(_WIN64) || defined(_M_X64)
# define NUDGE_POINTER_SIZE (64)
#elif defined(_WIN32) || defined(_M_X86)
# define NUDGE_POINTER_SIZE (32)
#else
# define NUDGE_POINTER_SIZE (0)
#endif //__SIZEOF_POINTER__
#ifdef NUDGE_USE_INT32_ENUMS
# undef NUDGE_COLLISION_MASK_TYPE
# define NUDGE_COLLISION_MASK_TYPE uint32_t
# undef NUDGE_FLAG_MASK_TYPE
# define NUDGE_FLAG_MASK_TYPE uint32_t
#else //NUDGE_USE_INT32_ENUMS
# ifndef NUDGE_COLLISION_MASK_TYPE
# define NUDGE_COLLISION_MASK_TYPE uint8_t
# endif
# ifndef NUDGE_FLAG_MASK_TYPE
# define NUDGE_FLAG_MASK_TYPE uint16_t
# endif
#endif // NUDGE_USE_INT32_ENUMS
namespace nudge {
/**
* @brief The Arena struct used internally
* @note Devs: technically we could allow multiple \ref context_t "nudge contexts" running on the same thread to share the same arena to minimize memory usage, but this is not a priority (and in most cases multiple contexts are used in parallel)
*/
struct Arena {
void* data;
uintptr_t size;
};
/**
* @brief Storage struct for user data (by default used inside \ref context_t "context_t"): a per-context 64-bit user space in 11 different variable names that share the same space, so that ONLY one of them must be chosen and used
*/
union UserData64Bit{
# if NUDGE_POINTER_SIZE==64
void* ptrs[1];
# endif
int64_t i64;uint64_t u64;double f64;
# if NUDGE_POINTER_SIZE==32
void* ptrs[2];
# endif
int32_t i32[2];uint32_t u32[2];float f32[2];
int16_t i16[4];uint16_t u16[4];int8_t i8[8];uint8_t u8[8];
};
/**
* @brief Storage struct for user data (by default used inside \ref BodyInfo "BodyInfo"): a per-body 32-bit user space in 7 different variable names that share the same space, so that ONLY one of them must be chosen and used
*/
union UserData32Bit{int32_t i32;uint32_t u32;float f32;int16_t i16[2];uint16_t u16[2];int8_t i8[4];uint8_t u8[4];};
/**
* @brief The Transform struct
* @note This struct has been rearranged to use anomymous unions for improved flexibility, but now initializations must be done with and additional pair of curly parenthesis, otherwise some compiler can issue a warning; for example: Transform T = { {{0,0,0}} , {0} , {{0,0,0,1}} };
* @note The 'vector' and 'quaternion' fields have been added only to allow partial assignments like: T2.quaternion = T1.quaternion;
* @note By default this struct contains nested anonymous structs that allow to use {.px,.px,.pz} and {.rx,.rx,.rz,.rw}/{.qx,.qx,.qz,.qw} fields: this requires the C++11 standard (but in my tests g++ and clang++ with -std=c++98 is enough)
* @note There is a definition named NUDGE_NO_ANONYMOUS_STRUCTS that can be used to remove anonymous structs, that usually require -std=c++11 (even if g++ and clang++ seem to work just fine with -std=c++98 in my tests)
*/
struct Transform {
union {
float position[3]; /**< position applied before rotation */
float p[3];
struct {float x,y,z;} vector;
# ifndef NUDGE_NO_ANONYMOUS_STRUCTS
struct {float px,py,pz;};
# endif
};
union {
uint32_t body; /**< the body index (used mainly inside colliders to retrieve the body) */
float time; /**< only used inside KinematicData key frames */
};
union {
float rotation[4]; /**< the orientation in quaternion form */
float r[4];
float q[4];
struct {float x,y,z,w;} quaternion;
# ifndef NUDGE_NO_ANONYMOUS_STRUCTS
struct {float rx,ry,rz,rw;};
struct {float qx,qy,qz,qw;};
# endif
};
};
/**
* @brief The BodyProperties struct
*/
struct BodyProperties {
float inertia_inverse[3]; /**< the inertia tensor inverse (@see inertia) (each component is always positive or null, even if the body is kinematic) */
float mass_inverse; /**< the inverse of the mass of the body (it's always positive or null, even if the body is kinematic) */
float gravity[3]; /**< the body gravity; default value: {0,-9.82,0} */
float friction; /**< the body friction; default value: 1.0 */
};
/**
* @brief The BodyMomentum struct
*/
struct BodyMomentum {
float velocity[3]; /**< the body linear velocity in world space */
float unused0; /**< padding value used internally (better not touch) */
float angular_velocity[3]; /**< the body angular velocity in world space */
float unused1; /**< padding value (this is not used AFAIK) */
};
/**
* @brief The SphereCollider struct
*/
struct SphereCollider {
float radius; /**< the radius of the sphere collider */
};
/**
* @brief The BoxCollider struct
*/
struct BoxCollider {
float size[3]; /**< the half dimensions of the box collider */
float unused; /**< padding value used internally (better not touch) */
};
/**
* @brief The Contact struct
*/
struct Contact {
float position[3]; /**< position of the contact in world space coordinates */
float penetration; /**< amount of contact penetration */
float normal[3]; /**< contact normal directed from the first body (\ref ContactData "c->contact_data.bodies.a") to the second body (\ref ContactData "c->contact_data.bodies.b"); it seems to be normalized AFAICS */
float friction; /**< contact friction */
};
/**
* @brief The BodyPair struct
*/
struct BodyPair {
uint16_t a; /**< index of body a */
uint16_t b; /**< index of body b */
};
/**
* @brief The ContactData class
*/
struct ContactData {
Contact* data; /**< array of Contact structs of size count */
BodyPair* bodies; /**< array of BodyPair structs of size count */
uint64_t* tags; /**< array of uint64_t tags of size count. Each tag contains the two uint16_t tags of the colliders involved in the contact */
uint32_t capacity; /**< the capacity of the arrays */
uint32_t count; /**< the number of contacts */
uint32_t* sleeping_pairs; /**< [something related to sleeping] */
uint32_t sleeping_count; /**< the number of sleeping pairs */
};
/**
* @brief This struct is used to access all the colliders in the physic world
* @note Colliders are shuffled in their two arrays, so it's not safe to store indices (but colliders relative to a single body are kept contiguos in their two arrays). Every collider has an (automatic) unique tag to reference it.
*/
struct ColliderData {
struct {
uint16_t* tags; /**< array of the collider unique identifiers of size count (do not touch) */
BoxCollider* data; /**< array of BoxCollider structs of size count */
Transform* transforms; /**< array of Transform structs of size count, also used to get the body this collider belongs to */
uint32_t count; /**< the number of box colliders */
} boxes; /**< Anonymous struct instance used to access all the box colliders */
struct {
uint16_t* tags; /**< array of the collider unique identifiers of size count (do not touch) */
SphereCollider* data; /**< array of SphereCollider structs of size count */
Transform* transforms; /**< array of Transform structs of size count, also used to get the body this collider belongs to */ // probably a simple position is enough here... possible optimization?
uint32_t count; /**< the number of sphere colliders */
} spheres; /**< Anonymous struct instance used to access all the shpere colliders */
};
/**
* @brief The unsigned type used for the \ref CollisionMaskEnum "COLLISION_GROUP_ flags"; it defaults to uint8_t (i.e. 8 groups available) if C++11 is supported and NUDGE_USE_INT32_ENUMS is not defined, and to uint32_t otherwise (i.e. 32 groups available)
* @note Always using this typedef for collision group flags is recommended
* @note When C++11 is available the type can be further tuned with the NUDGE_COLLISION_MASK_TYPE definition (having smaller types has benefits on the cache size, not much on the bit operation speed)
*/
typedef NUDGE_COLLISION_MASK_TYPE CollisionMask;
/**
* @brief The CollisionMaskEnum enum
* @note If more groups are required, please see the \ref CollisionMask "CollisionMask doc" for the available space and add the additional entries in your code: namespace nudge {const CollisionMask COLLISION_GROUP_H=1<<8,COLLISION_GROUP_I=1<<9,...;}
*/
enum CollisionMaskEnum
# ifndef NUDGE_USE_INT32_ENUMS
: CollisionMask
# endif
{
COLLISION_GROUP_DEFAULT = 1<<0,
COLLISION_GROUP_A = 1<<1,
COLLISION_GROUP_B = 1<<2,
COLLISION_GROUP_C = 1<<3,
COLLISION_GROUP_D = 1<<4,
COLLISION_GROUP_E = 1<<5,
COLLISION_GROUP_F = 1<<6,
COLLISION_GROUP_G = 1<<7,
COLLISION_GROUP_ALL = (CollisionMask)(-1)
};
/**
* @brief The unsigned type used for the \ref BodyFlagEnum "BF_ flags"; it defaults to uint16_t (i.e. 16 flags available) if C++11 is supported and NUDGE_USE_INT32_ENUMS is not defined, and to uint32_t otherwise (i.e. 32 flags available)
* @note Always using this typedef for body flags is recommended
* @note When C++11 is available the type can be further tuned with the NUDGE_FLAG_MASK_TYPE definition (having smaller types has benefits on the cache size, not much on the bit operation speed)
*/
typedef NUDGE_FLAG_MASK_TYPE FlagMask;
/**
* @brief The BodyFlagEnum enum
* @note User can easily add custom flags this way: namespace nudge {const FlagMask BF_IS_MY_TYPE_1=1<<13,BF_IS_MY_TYPE_2=1<<14,BF_IS_MY_TYPE_3=1<<15;}
* @note Flags marked [unused, not implemented] will never be implemented inside nudge.h
* @note To understand how many entries are available, please see the \ref FlagMask "FlagMask doc" (by default they are at least 16)
*/
enum BodyFlagEnum
# ifndef NUDGE_USE_INT32_ENUMS
: FlagMask
# endif
{
BF_HAS_COM_OFFSET = 1<<0, /**< read-only [internal usage: automatically set when bodies are created] */
BF_IS_DISABLED = 1<<1, /**< [experimental] if used, it's better to set the body to static, reset its velocities and set its collision group and mask both to zero (TODO: test if this is really necessary) */
BF_IS_REMOVED = 1<<2, /**< read-only [internal flag added when bodies are removed] */
BF_IS_DISABLED_OR_REMOVED = BF_IS_DISABLED|BF_IS_REMOVED, /**< read-only flag useful to filter out bodies excluded from simulation */
BF_IS_STATIC = 1<<3, /**< read-only [internal flag added when bodies are added] */
BF_IS_KINEMATIC = 1<<4, /**< read-only [internal flag added when bodies are added] */
BF_IS_DYNAMIC = 1<<5, /**< read-only [internal flag added when bodies are added] */
BF_NEVER_SLEEPING = 1<<6, /**< [experimental] affects only dynamic bodies */
BF_HAS_DIFFERENT_GRAVITY_MODE = 1<<7, /**< [experimental] inverts the \ref GlobalDataMaskEnum "GF_USE_GLOBAL_GRAVITY" mode in \ref GlobalData "c->global_data.flags" on a per-body base */
BF_HAS_DIFFERENT_AUX_BODIES_RESET_MODE = 1<<8, /**< [experimental] inverts the \ref GlobalDataMaskEnum "GF_DONT_RESET_AUX_BODIES" mode in \ref GlobalData "c->global_data.flags" on a per-body base */
# ifndef NUDGE_BODYFLAG_ENUM_NO_UNUSED_FLAGS
BF_IS_CHARACTER = 1<<9, /**< [unused, not implemented, removable] flag added for user convenience */
BF_IS_PLATFORM = 1<<10, /**< [unused, not implemented, removable] flag added for user convenience */
BF_IS_SENSOR = 1<<11, /**< [unused, not implemented, removable] flag added for user convenience */
BF_IS_FRUSTUM_CULLED = 1<<12, /**< [unused, not implemented, removable] flag added for user convenience */
BF_IS_DISABLED_OR_REMOVED_OR_FRUSTUM_CULLED = BF_IS_DISABLED_OR_REMOVED|BF_IS_FRUSTUM_CULLED, /**< [unused, not implemented, removable] flag added for user convenience */
# endif
BF_IS_STATIC_OR_KINEMATIC = BF_IS_STATIC|BF_IS_KINEMATIC, /**< read-only [internal flag] */
BF_IS_STATIC_OR_DYNAMIC = BF_IS_STATIC|BF_IS_DYNAMIC, /**< read-only [internal flag] */
BF_IS_KINEMATIC_OR_DYNAMIC = BF_IS_KINEMATIC|BF_IS_DYNAMIC, /**< read-only [internal flag] */
BF_IS_STATIC_OR_KINEMATIC_OR_DYNAMIC = BF_IS_STATIC|BF_IS_KINEMATIC|BF_IS_DYNAMIC, /**< read-only [internal flag] */
BF_IS_STATIC_OR_KINEMATIC_OR_DISABLED_OR_REMOVED = BF_IS_STATIC_OR_KINEMATIC|BF_IS_DISABLED_OR_REMOVED /**< read-only [internal flag] */
# ifdef NUDGE_BODYFLAG_ENUM_EXTRA_FIELDS
# define NUDGE_BODYFLAG_ENUM_EXTRA_FIELDS
# endif
};
/**
* @brief The BodyFilter struct
*/
struct BodyFilter {
FlagMask flags; /**< a bit masks of \ref BodyFlagEnum "BF_ enums"; most values are read-only, so don't (re)set it, but just add/remove tweakable flags to it */
CollisionMask collision_group; /**< a SINGLE \ref CollisionMaskEnum "COLLISION_GROUP_ value". Default value: COLLISION_GROUP_DEFAULT (means that the body belongs to this group. Better not use more than one group per body) */
CollisionMask collision_mask; /**< a bit mask of \ref CollisionMaskEnum "COLLISION_GROUP_ values". Default value: COLLISION_GROUP_ALL (means that the body can collide with all the groups) */
};
/**
* @brief Per-body struct that contains the indices of the body colliders inside \ref ColliderData "ColliderData::boxes and ColliderData::spheres"
* @note It's also possible to retrieve the body index from \ref ColliderData "c->colliders" using the bodyId field inside each collider's \ref Transform "Transform"
*/
struct BodyLayout {
uint16_t num_boxes; /**< the number of box colliders this body owns */
int16_t first_box_index; /**< the index of the first box collider in \ref ColliderData "ColliderData::boxes" (box colliders are assumed to be contiguous, with no fragmentation), or -1 */
uint16_t num_spheres; /**< the number of sphere colliders this body owns */
int16_t first_sphere_index; /**< the index of the first sphere collider in \ref ColliderData "ColliderData::spheres" (sphere colliders are assumed to be contiguous, with no fragmentation), or -1 */
};
/**
* @brief The BodyInfo struct contains some read-only graphic properties of the body (e.g. axis aligned bounding box and center of mass offset), and plenty of per-body user available space, handy to bind user-side structs to a nudge physic body
* @note User custom field injection is allowed by the two definitions NUDGE_BODYINFO_STRUCT_EXTRA_FIELDS and NUDGE_BODYINFO_STRUCT_EXTRA_PADDING; the best place to do so is in a nudge config header file (setting its name in the project-scope definition: NUDGE_USER_CFG_FILE_NAME)
* @note It's possible to remove the default (per-body) UserData32Bit user field of this struct using the definition NUDGE_BODYINFO_STRUCT_NO_USER_DATA, and the 'aux_bodies[...] array / sk_user struct' by setting the NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES definition to zero
*/
struct BodyInfo {
# ifndef NUDGE_BODYINFO_STRUCT_NO_USER_DATA
UserData32Bit user; /**< user data: a per-body user space in 7 different variable names that share the same space, so that ONLY one of them must be chosen and used */
# endif // NUDGE_BODYINFO_STRUCT_NO_USER_DATA
# ifdef NUDGE_BODYINFO_STRUCT_EXTRA_FIELDS
NUDGE_BODYINFO_STRUCT_EXTRA_FIELDS /**< user stuff injected at the beginning of the BodyInfo struct */
# endif // NUDGE_BODYINFO_STRUCT_EXTRA_FIELDS
float aabb_center[3]; /**< [read-only; unused by nudge.h] the axis aligned bounding box center of the body; note that the com_offset has not been stripped from it (it must be summed to strip it from aabb_center) */
float aabb_half_extents[3]; /**< [read-only; unused by nudge.h] the axis aligned bounding box half extents of the body (it does not depend on com_offset) */
float com_offset[3]; /**< [read-only] the center of mass offset of the body (it's only used in the \ref calculate_graphic_transform_for_body "calculate_graphic_transform_xxx(...)" functions) */
float aabb_enlarged_radius; /**< [read-only] this radius is the sum of |com_offset|+|aabb_half_extents|, so that it can be used only with the body's transform position (no transform orientation required) */
# ifndef NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES
# define NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES (2) // sizeof(BodyInfo): (2) => 48 bytes; (4) => 52 bytes; (6) => 56 bytes; (8) => 60 bytes; (10) => 64 bytes
# endif // NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES
# if NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES>0
union {
int16_t aux_bodies[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES]; /**< user data that by default can be used for dynamic bodies ONLY, and that are reset to -1 every frame (but only for dynamic bodies in the \ref ActiveBodies "c->active_bodies" list); they can be used to store body indices, since they are currently in the [0,8192) range */
union {
# if (NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES%4)==0
# if NUDGE_POINTER_SIZE==64
void* ptrs[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES/4]; /**< user data that can be used for static and kinematic bodies only (and only one of its array variants) */
# endif
int64_t i64[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES/4]; /**< user data that can be used for static and kinematic bodies only (and only one of its array variants) */
uint64_t u64[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES/4]; /**< user data that can be used for static and kinematic bodies only (and only one of its array variants) */
# endif
# if (NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES%2)==0
# if NUDGE_POINTER_SIZE==32
void* ptrs[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES/2]; /**< user data that can be used for static and kinematic bodies only (and only one of its array variants) */
# endif
int32_t i32[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES/2]; /**< user data that can be used for static and kinematic bodies only (and only one of its array variants) */
uint32_t u32[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES/2]; /**< user data that can be used for static and kinematic bodies only (and only one of its array variants) */
# endif
int16_t i16[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES]; /**< user data that can be used for static and kinematic bodies only (and only one of its array variants) */
uint16_t u16[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES]; /**< user data that can be used for static and kinematic bodies only (and only one of its array variants) */
int8_t i8[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES*2]; /**< user data that can be used for static and kinematic bodies only (and only one of its array variants) */
uint8_t u8[NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES*2]; /**< user data that can be used for static and kinematic bodies only (and only one of its array variants) */
} sk_user; /**< user data that by default can be used for static and kinematic bodies ONLY (and only one of the available array variants); using \ref GlobalDataMaskEnum "c->global_data.flags" and/or per-body \ref BodyFlagEnum "c->bodies.filters[body].flags" we can use this field for dynamic bodies too, at the expense of the "aux_bodies" field */
};
# endif // NUDGE_BODYINFO_STRUCT_NUM_AUX_BODIES
# ifdef NUDGE_BODYINFO_STRUCT_EXTRA_PADDING
NUDGE_BODYINFO_STRUCT_EXTRA_PADDING /**< user stuff injected at the end of the BodyInfo struct */
# endif // NUDGE_BODYINFO_STRUCT_EXTRA_PADDING
};
/**
* @brief The main struct contained in \ref context_t "context_t": it exposes every per-body data in the simulation, except collisions
* @note This structure contains arrays of size: count. Every array index is persistent (it's never shuffled or moved)
*/
struct BodyData {
Transform* transforms; /**< array of size count, containing the position and rotation (in quaternion form) of each body */
BodyProperties* properties; /**< array of size count, containing the mass, inertia, gravity and friction of each body */
BodyMomentum* momentum; /**< array of size count, containing the linear and angular velocity of each body */
BodyFilter* filters; /**< array of size count, containing the collision group, the collision mask, and flags for each body */
BodyLayout* layouts; /**< array of size count, containing the colliders (i.e. collision shapes) indices of each body (see also the \ref ColliderData "c->colliders" arrays) */
BodyInfo* infos; /**< array of size count, , and customizable per-body user data */
uint8_t* idle_counters; /**< array of size count, containing a counter per body, where a value of 0xFF indicates that the body is sleeping (it currently affectes only dynamic bodies); each value can be set to 0x00 to wake up a dynamic body */
uint32_t count; /**< the number of bodies in the world. Bodies are never shuffled in the array, so indices are preserved. When bodies are removed count does not change (tip: filter the bodies with their flags to exclude removed and disabled bodies) */
};
/**
* @brief [unused] The BodyConnections struct is actually just sketched in nudge (it was intended to add custom constraints)
* @note The original version of the nudge library is better suited for user-side physic-related extensions (see the original nudge example code)
*/
struct BodyConnections {
BodyPair* data;
uint32_t count;
};
/**
* @brief The CachedContactImpulse struct
* @note Cached impulses persist across frames to implement warmstarting
*/
struct CachedContactImpulse {
float impulse[3];
float unused;
};
/**
* @brief The ContactCache struct contains the CachedContactImpulse and persists across frames
*/
struct ContactCache {
uint64_t* tags;
CachedContactImpulse* data;
uint32_t capacity;
uint32_t count;
};
/**
* @brief The ActiveBodies struct
* @note AFAICU it has something to do with bodies that have contacts between them. However for some strange reason even sleeping bodies can be in the list.
*/
struct ActiveBodies {
uint16_t* indices; /**< array of size count of body indices */
uint32_t capacity;
uint32_t count;
};
struct ContactImpulseData;
struct ContactConstraintData;
/**
* \def NUDGE_INVALID_BODY_ID
* Value of a body index in an invalid state
*/
# define NUDGE_INVALID_BODY_ID (32767)
// TODO: currently int32_t or uint32_t is used as body index: but at most MAX_NUM_BODIES is 8192.
// So we can use int16_t and uint16_t (where padding/alignment is not required).
// [Well, there are some parts in nudge internal where the upper
// 16-bit of a body index is used, so I'm not sure if this can be done everywhere]
/**
* @brief The KinematicData is composed by two arrays: an array of global key frames and an array of animations.
* Each animation owns a (kinematic) body index and a range of key frames.
* @note Kinematic animations are just used to automatically move kinematic bodies. Each range of key frames can be used by more than one Animation (i.e. body), because each Animation can have an offset transform (baseT) and/or an offset time (offset_time).
* @note All the times are intended in seconds, and they represent the (relative) time to get to the current key frame.
*/
struct KinematicData {
// key_frame_transforms and key_frame_modes are a single memory block used by all animations
Transform* key_frame_transforms; /**< array of size key_frame_count of Transform structs, where each element has the Transform::time field set (it represents the seconds to get from the previous frame to that frame when the animation speed is 1.0f) */
/**
* @brief TimeMode enum is an optional experimental flag
*/
enum TimeMode {
TM_NORMAL=0, /**< uniform speed across the transforms */
TM_ACCELERATE, /**< accelerated speed across the transforms */
TM_DECELERATE /**< decelerated speed across the transforms */
}* key_frame_modes; /**< array of size key_frame_count of TimeMode enums (experimental, it can probably be completely ignored in most cases) [TODO: remove?] */
uint32_t key_frame_capacity; /**< the number of key frames the arrays can contain (use \ref kinematic_data_reserve_key_frames "kinematic_data_reserve_key_frames(...)" to increase it) */
uint32_t key_frame_count; /**< the number of inserted key frames */
/**
* @brief The Animation class. Each animation owns a (kinematic) body index and a range of key frames.
* @note Each animation use (or reuse) a chunk of the key_frame array. The same chunk (i.e. range of key frames) can be used by more than one Animation (i.e. body), because each Animation can have an offset transform (baseT) and/or an offset time (offset_time).
* @note Animations referencing removed bodies (by default) are assigned to \ref NUDGE_INVALID_BODY_ID "NUDGE_INVALID_BODY_ID" (and skipped) next time \ref simulation_step "simulation_step(...)" is called (this behavior can be changed using the definition NUDGE_DELETE_KINEMATIC_ANIMATIONS_REFERENCING_REMOVED_BODIES).
* @note So by default it's safe to store animation indices (unless we manually delete animations, or define NUDGE_DELETE_KINEMATIC_ANIMATIONS_REFERENCING_REMOVED_BODIES).
* @note Using static/dynamic bodies in kinematic animations is something never tested (undefined behavior).
*/
struct Animation {
float play_time; /**< [read] animation current time of play */
float offset_time; /**< if set, animation starts after offset_time */
float speed; /**< tweakable animation speed (can be negative) */
float total_time; /**< total duration of the animation (if negative, value is refreshed before playing it) */
Transform baseT; /**< offset transform used if use_baseT is set */
uint32_t key_frame_start; /**< start animation key_frame index */
uint32_t key_frame_count; /**< num key_frame indices (from key_frame_start) */
uint32_t body; /**< index of the kinematic body to be animated */
bool playing; /**< true if animation is playing */
bool use_baseT; /**< activates the offset transform baseT */
enum LoopMode {
LM_NO_LOOP, /**< normal mode */
LM_LOOP_NORMAL, /**< at the end, animation restarts */
LM_LOOP_PING_PONG /**< at the end, animation goes back and forth */
} loop_mode; /**< animation loop mode */
}* animations; /**< array of size animations_count of Animation structs; by default entries in this array are persistent, i.e. not deleted or reordered by nudge (but this behavior can be changed using the definition NUDGE_DELETE_KINEMATIC_ANIMATIONS_REFERENCING_REMOVED_BODIES) */
uint32_t animations_capacity; /**< the number of animations the array can contain (use \ref kinematic_data_reserve_animations "kinematic_data_reserve_animations(...)" to increase it) */
uint32_t animations_count; /**< the number of inserted animations */
};
/**
* @brief The SimulationParams struct
* @note It's used to tweak the simulation
*/
struct SimulationParams {
// read/write
double time_step; /**< [tweakable] [default value 1.0/60.0] */
unsigned max_num_substeps; /**< [tweakable] [default value 2] when too much time passes, only max_num_substeps are performed, and the simulation 'burns' the remaining substeps */
unsigned num_iterations_per_substep; /**< [tweakable] [default value 5] it improves some stability at the expense of performance */
float sleeping_threshold_linear_velocity_squared; /**< [tweakable] [default value 1e-2f]; by increasing it the bodies goes to sleep faster */
float sleeping_threshold_angular_velocity_squared; /**< [tweakable] [default value 1e-1f]; by increasing it the bodies goes to sleep faster */
float linear_damping; /**< [tweakable] [default value 0.25]; by increasing it, the bodies slow down their movement faster */
float angular_damping; /**< [tweakable] [default value 0.25]; by increasing it, the bodies slow down their rotation faster */
float penetration_allowed_amount; /**< [tweakable(?)] [default value 1e-3f]; */
float penetration_bias_factor; /**< [tweakable(?)] [default value 2.0f]; */
unsigned numsubsteps_overflow_warning_mode; /**< [tweakable] nudge::log warns on every frame with a numsubstep overflown. Modes: 0:warn on second successive frame;1:warn always;2:never warn. Default is 0 */
// read only
unsigned long long num_frames; /**< [read-only] number of physic frames, i.e. the total number of calls to \ref simulation_step "simulation_step(...)" with at least one substep to perform. Usually in each graphic frame there is a single call to \ref simulation_step "simulation_step" and the number of physic frames can increase by one unit or remain constant (TODO: consider removing this, and renaming num_frames the num_total_substeps) */
unsigned long long num_total_substeps; /**< [read-only] the total number of physic substeps so far. In one physic frame there can be a number of substeps in the interval [0,max_num_substeps]; good value for benchmark measures */
double remaining_time_in_seconds; /**< [used internally] */
float time_step_minus_remaining_time; /**< [used intenally] */
unsigned num_substeps_in_last_frame; /**< [read-only] returned by \ref pre_simulation_step "pre_simulation_step(...)"; it's <= max_num_substeps, and it equals the number of substeps that next call to \ref simulation_step "simulation_step" will perform */
unsigned numsubsteps_overflow_in_last_frame; /**< [read-only] set in \ref simulation_step "simulation_step" */
};
/**
* @brief The GlobalDataMaskEnum enum
*/
enum GlobalDataMaskEnum {
GF_USE_GLOBAL_GRAVITY = 1<<0, /**< this flag disables per-body gravity and uses \ref GlobalData "GlobalData::gravity" instead (disabled by default) */
GF_DONT_RESET_AUX_BODIES = 1<<1 /**< if set nudge avoids resetting per-body \ref BodyInfo "BodyInfo::aux_bodies[]" (to -1) every frame (valid for dynamic bodies in the \ref ActiveBodies "c->active_bodies" list only): this allows the use of the \ref BodyInfo "BodyInfo::sk_user" field for dynamic bodies too (disabled by default) */
# ifdef NUDGE_GLOBALDATAMASK_ENUM_EXTRA_FIELDS
# define NUDGE_GLOBALDATAMASK_ENUM_EXTRA_FIELDS
# endif
};
/**
* @brief The GlobalData struct inglobes global fields that could not fit in the SimulationParams struct
*/
struct GlobalData {
float gravity[3]; /**< by default each body uses its own gravity (in its 'properties'), but by using the GF_USE_GLOBAL_GRAVITY flags, all the bodies share this gravity value (defaults to {0,-9.82,0}) */
uint32_t flags; /**< bit mask of \ref GlobalDataMaskEnum "GF_ flags"; please do not reset it, just set or reset flags inside it (because some flags could be set by default, and other flags could be added in the future) */
FlagMask exclude_smoothing_graphic_transform_flags; /**< bit mask of \ref BodyFlagEnum "BF_ flags"; default value is 0; this flag just affects body transform smoothing in two functions (\ref calculate_graphic_transform_for_body "calculate_graphic_transform_for_body(...)" and \ref calculate_graphic_transforms "calculate_graphic_transforms(...)"); note that in any case static bodies and dynamic sleeping bodies are always not smoothed, because they are still; possible values are usually: BF_IS_DYNAMIC and/or BF_IS_KINEMATIC (both together disable transform smoothing completely) */
uint32_t* removed_bodies; /**< [internal usage, \ref remove_body "remove_body(...)"] since we can't remove bodies properly, instead we put bodies in stand-by ready to be reused (when new bodies are added) and we free their colliders; removed bodies end in this list and can be filtered out using their BF_IS_REMOVED flag */
uint32_t removed_bodies_count; /**< [internal usage] */
uint32_t finalized_removed_bodies_count; /**< [internal usage] finalized_removed_bodies_count<=removed_bodies_count; finalization happens at the start of the \ref simulation_step "simulation_step(...)" function */
const uint32_t removed_bodies_capacity; /**< [internal usage] should be == c->MAX_NUM_BODIES */
};
/**
* @brief Main struct of the library.
* @note It should be initialized at program startup (see \ref init_context_with "init_context_with(...)" or \ref init_context "init_context(...)")
* @note It should be destroyed at program exit (see \ref destroy_context "destroy_context(...)")
*/
struct context_t {
// original nudge fields
Arena arena; /**< [internal usage] */
BodyData bodies; /**< accessor to the main physics data of the library */
ColliderData colliders; /**< accessor to the (global) collider (i.e. collision shape) (box and sphere) arrays. These arrays can be reordered by nudge, but their 'tags' are unique and are automatically assigned and preserved (please NEVER touch them); it's NOT safe to store array indices in colliders.boxes or collider.spheres! Always use c->bodies.infos[body].first_box_index and c->bodies.infos[body].num_boxes instead (same for spheres) */
ContactData contact_data; /**< accessor to the array of contacts, so that users can understand if a body is in contact with another. Please note that only dynamic non-sleeping bodies are guaranteed to report all their contacts every frame AFAIK */
ContactCache contact_cache; /**< accessor to the persistent (across frames) CachedContactImpulses that are used to implement warmstarting (used to slightly improved stacking AFAIK); users should simply ignore it */
ActiveBodies active_bodies; /**< accessor to an array of active bodies. AFAICU this array has something to do with bodies that have contacts between them (however for some strange reason even sleeping bodies can be in the list). I personally prefer using the official c->bodies array (more robust and thrustable) */
// extended stuff
KinematicData kinematic_data; /**< accessor to the KinematicData::key_frames array and the KinematicData::animations array that can be used to move kinamatic bodies in an automatic way */
GlobalData global_data; /**< accessor to some global fields that don't fit the SimulationParams category */
SimulationParams simulation_params; /**< accessor to some global fields that deal with the physic simulation, such as the simulation time_step, the max_num_substeps, sleeping thresholds, damping factors, etc. */
const unsigned MAX_NUM_BOXES; /**< fixed value of the max number of box colliders that can be used in the simulation; @see init_context_with(...); it must be: c->MAX_NUM_BOXES+c->MAX_NUM_SPHERES<8192 (the limitation seems to arise from the broadphase management) */
const unsigned MAX_NUM_SPHERES; /**< fixed value of the max number of sphere colliders that can be used in the simulation; @see init_context_with(...); it must be: c->MAX_NUM_BOXES+c->MAX_NUM_SPHERES<8192 (the limitation seems to arise from the broadphase management) */
const unsigned MAX_NUM_BODIES; /**< fixed value that should always be equal to: MAX_NUM_BOXES+MAX_NUM_SPHERES; this value is only reachable when a single collider per body is used */
# ifdef NUDGE_CONTEXT_STRUCT_EXTRA_FIELDS
NUDGE_CONTEXT_STRUCT_EXTRA_FIELDS /**< user stuff injected into the context_t struct */
# endif // NUDGE_CONTEXT_STRUCT_EXTRA_FIELDS
# ifndef NUDGE_CONTEXT_STRUCT_NO_USER_DATA
UserData64Bit user; /**< user data: a per-context user space in 11 different variable names that share the same space, so that ONLY one of them must be chosen and used */
# endif // NUDGE_CONTEXT_STRUCT_NO_USER_DATA
};
/**
* @brief The AxisEnum enum
*/
enum AxisEnum {AXIS_X=0,AXIS_Y=1,AXIS_Z=2};
# ifdef NUDGE_USE_TIME_CONTEXT
/**
* @brief Optional struct (not used at all in nudge.h)
*/
struct time_context_t {
// (How bad is proper cpp style with private variables and getters/setters... plain C rules!)
public:
// Usage: just call this ALWAYS once per frame
inline void update(double globalTimeInSeconds) {
double elapsedTime,elapsedNetTime,deltaTime;
double currentTime = totalTime;
// paused time code
if (wasPausedLastFrame!=paused) {
wasPausedLastFrame = paused;
if (paused) beginPausedTime=globalTimeInSeconds;
else {
beginNetTime+=globalTimeInSeconds-beginPausedTime;beginPausedTime = 0;
}
}
// time calculations
if (beginTime==0) beginTime = globalTimeInSeconds;
if (beginNetTime==0) beginNetTime = globalTimeInSeconds;
elapsedTime = globalTimeInSeconds;if (elapsedTime<beginTime) beginTime=elapsedTime;
elapsedTime-=beginTime;
totalTime = elapsedTime;
if (!paused) {
elapsedNetTime = globalTimeInSeconds;if (elapsedNetTime<beginNetTime) beginNetTime=elapsedNetTime;
elapsedNetTime-=beginNetTime;
totalTimeWithoutPause = elapsedNetTime;
}
deltaTime = elapsedTime;if (deltaTime<currentTime) currentTime=deltaTime;
deltaTime-=currentTime;
currentTime = elapsedTime;
instantFrameTime = deltaTime;
timeNow = globalTimeInSeconds;
++num_frames;
//assert(totalTime==currentTime);
}
inline double getInstantFrameTime() const {return instantFrameTime;}
inline double getTotalTime() const {return totalTime;}
inline double getTotalTimeWithoutPause() const {return totalTimeWithoutPause;}
inline double getBeginTime() const {return beginTime;}
inline double getTimeNow() const {return timeNow;}
inline double getInstantFPS() const {return instantFrameTime!=0?1.0/instantFrameTime:0;}
inline unsigned long getNumFrames() const {return num_frames;}
inline bool getPaused() const {return paused;}
inline void setPaused(bool flag) {paused = flag;}
inline void togglePaused() {paused = !paused;}
time_context_t() : instantFrameTime(16.2),totalTime(0),totalTimeWithoutPause(0),paused(false),
beginTime(0),beginNetTime(0),beginPausedTime(0),timeNow(0),num_frames(0),wasPausedLastFrame(false) {}
inline void restoreFrom(time_context_t* o) {
//const double deltaTime = totalTime - o->totalTime;
//beginTime += deltaTime;
beginNetTime += totalTimeWithoutPause - o->totalTimeWithoutPause;
totalTimeWithoutPause = o->totalTimeWithoutPause;
num_frames = o->num_frames;
//return deltaTime;
}
private:
double instantFrameTime; // get; seconds elapsed from last frame
double totalTime; // get; second elapsed from the start (including 'paused' time)
double totalTimeWithoutPause; // get; second elapsed from the start (excluding 'paused' time)
bool paused; // get/set
double beginTime,beginNetTime,beginPausedTime,timeNow;
unsigned long num_frames;
bool wasPausedLastFrame;
};
# endif //NUDGE_USE_TIME_CONTEXT
/**
* @defgroup context_group Context Functions
* @brief Set of functions regarding the nudge \ref context_t "context", and in general the program startup and shutdown functions
* @{
*/
/**
* @brief Displays basic info at program startup; very important call to detect the SIMD configuration of the program
*/
void show_info();
/**
* @brief Mandatory function to be called at program startup
* @param c the nudge context; best practice is to clear its memory before calling this function
* @param MAX_NUM_BOXES the max number of box colliders (i.e. box collision shapes) that can be used in the library (each physic body can contain one or more colliders and each collider is owned by a single physic body)
* @param MAX_NUM_SPHERES the max number of sphere colliders (i.e. sphere collision shapes) that can be used in the library (each physic body can contain one or more colliders and each collider is owned by a single physic body)
* @note It must be MAX_NUM_BOXES+MAX_NUM_SPHERES<=8192
*/
void init_context_with(context_t *c, unsigned MAX_NUM_BOXES,unsigned MAX_NUM_SPHERES);
/**
* @brief Mandatory function to be called at program startup
* @param c the nudge context; best practice is to clear its memory before calling this function
* @note It sets MAX_NUM_BOXES and MAX_NUM_SPHERES to some default value (see \ref init_context_with "init_context_with(...)")
*/
void init_context(context_t* c);
/**
* @brief Mandatory function to be called at program exit
* @param c the nudge context
* @note After this call \ref init_context "init_context(...)" and \ref init_context_with "init_context_with(...)" can be called again, but \ref restart_context "restart_context(...)" can't
*/
void destroy_context(context_t* c);
/**
* @brief Optional function that restarts a valid context, preserving the simulation settings and the allocated memory
* @param c a valid nudge context that must be inited with \ref init_context "init_context(...)" or \ref init_context_with "init_context_with(...)"
* @note This function is faster than calling in sequence \ref destroy_context "destroy_context(...)" and \ref init_context "init_context(...)" (no deallocations/allocations)
* @note If you want to restart the simulation frame/substep counters, please manually set: c->simulation_params.num_frames=0;c->simulation_params.num_total_substeps=0;
*/
void restart_context(context_t* c);
# ifndef NUDGE_NO_STDIO
/**
* @brief Saves the nudge context
* @param f the output file
* @param c the input context
* @note Experimental feature
* @note Available only when NUDGE_NO_STDIO is not defined
*/
void save_context(FILE* f,const context_t* c);
/**
* @brief Loads a saved nudge context
* @param f the input file
* @param c the output (inited) context
* @note Experimental feature, currently c must have a compatible c->MAX_NUM_BOXES and c->MAX_NUM_SPHERES to work (and user pointers must of course be handled by the user)
* @note Currently it just asserts on failing
* @note Available only when NUDGE_NO_STDIO is not defined
*/
void load_context(FILE* f,context_t* c);
# endif //NUDGE_NO_STDIO
/** @} */ // end of context_group
/**
* @defgroup main_group Main Functions
* @brief Set of functions regarding stepping the simulation and getting the body transforms back
* @{
*/
/**
* @brief Mandatory function that must be called once per frame
* @param c the nudge context
* @param elapsedSecondsFromLastCall time tn seconds elapsed from last call
* @return the number of simulation substeps (i.e. physic frame substeps) that will be executed in the next \ref simulation_step "simulation_step(...)" call
*/
unsigned pre_simulation_step(context_t* c,double elapsedSecondsFromLastCall);
/**
* @brief Mandatory function that must be called once per frame
* @param c the nudge context
* @note It's the main function of the whole library
*/
void simulation_step(context_t* c);
/**
* @brief Function that can be used to calculate the smoothed 16-float column-major model matrix of a single body
* @param c the nudge context
* @param body the input body index
* @param pModelMatrix16Out the output smoothed 16-float column-major model matrix
* @return the same as pModelMatrix16Out (for chaining the call only)
* @note This function must be used after calling \ref simulation_step "simulation_step(...)", and the returned matrix inglobes the center of mass offset if present (so that no offset operation is required on the user-side in most cases)
*/
float* calculate_graphic_transform_for_body(context_t* c,unsigned body,float* pModelMatrix16Out);
/**
* @brief Function that can be used to calculate the smoothed 16-float column-major model matrices of all the bodies together
* @param c the nudge context
* @param pModelMatricesOut a pointer to the output c->bodies.count*modelMatrixStrideInFloatUnits floats that represent the returned smoothed 16-float column-major model matrices of this function
* @param modelMatrixStrideInFloatUnits stride (in number of floats) between two 16-float matrices inside the pModelMatricesOut array (it must be at least 16)
* @param loopActiveBodiesOnly (experimental) if not zero, it only updates bodies present in the c->active_bodies list, i.e. not all the output matrices are updated (not recommended)
* @note This function must be used after calling \ref simulation_step "simulation_step(...)", and the returned matrices inglobe the center of mass offsets if present (so that no offset operation is required on the user-side in most cases)
*/
void calculate_graphic_transforms(context_t* c,float* pModelMatricesOut,unsigned modelMatrixStrideInFloatUnits,int loopActiveBodiesOnly=0);
/** @} */ // end of main_group
/**
* @defgroup add_group Add-Bodies Functions
* @brief Set of functions regarding creation and removal of physic bodies
* @{
*/
/**
* @brief Adds a new body to the simulation with a single box collider
* @param c the nudge context
* @param mass positive => dynamic; 0 => static; negative => kinematic (where the absolute value will be used as mass internally)
* @param hsizex half box size in the x direction
* @param hsizey half box size in the y direction
* @param hsizez half box size in the z direction
* @param T a pointer to a Transform
* @param comOffset an optional array of 3 floats that determines the center of mass offset of the body
* @return the body index, or \ref NUDGE_INVALID_BODY_ID "NUDGE_INVALID_BODY_ID" if no more boxes can be added
* @note Internally \ref BodyProperties "mass_inverse and inertia_inverse" are always stored as positive values (except for static bodies): this makes kinematic to dynamic body conversions a bit easier
* @note Every time an \ref add_group "add_xxx(...)" function is called, if c->global_data.finalized_removed_bodies_count>0, the body c->global_data.removed_bodies[0] is always reused and returned
*/
unsigned add_box(context_t* c,float mass, float hsizex, float hsizey, float hsizez, const Transform* T=NULL,const float comOffset[3]=NULL);
/**
* @overload
* @param mMatrix16WithoutScaling a pointer to a 4x4 column-major matrix with only translation and rotation
*/
unsigned add_box(context_t* c,float mass, float hsizex, float hsizey, float hsizez, const float* mMatrix16WithoutScaling,const float comOffset[3]=NULL);
/**
* @brief Adds a new body to the simulation with a single sphere collider
* @param c the nudge context
* @param mass positive => dynamic; 0 => static; negative => kinematic (where the absolute value will be used as mass internally)
* @param radius the sphere radius
* @param T a pointer to a Transform
* @param comOffset an optional array of 3 floats that determines the center of mass offset of the body
* @return the body index, or \ref NUDGE_INVALID_BODY_ID "NUDGE_INVALID_BODY_ID" if no more spheres can be added
* @note Internally \ref BodyProperties "mass_inverse and inertia_inverse" are always stored as positive values (except for static bodies): this makes kinematic to dynamic body conversions a bit easier
* @note Every time an \ref add_group "add_xxx(...)" function is called, if c->global_data.finalized_removed_bodies_count>0, the body c->global_data.removed_bodies[0] is always reused and returned
*/
unsigned add_sphere(context_t* c,float mass, float radius, const Transform* T=NULL,const float comOffset[3]=NULL);
/**
* @overload
* @param mMatrix16WithoutScaling a pointer to a 4x4 column-major matrix with only translation and rotation
*/
unsigned add_sphere(context_t* c,float mass, float radius, const float* mMatrix16WithoutScaling,const float comOffset[3]=NULL);
/**
* @brief Adds a new body to the simulation with a compound collider made up of num_boxes box colliders and num_spheres sphere colliders
* @param c the nudge context
* @param mass positive => dynamic; 0 => static; negative => kinematic (where the absolute value will be used as mass internally)
* @param inertia an inertia tensor in a 3-float array form that is used only if mass is not zero (see also the @ref inertia_group "inertia helper functions"); it can be NULL (in that case a box inertia on the body axis-aligned bounding box extents is used)
* @param num_boxes
* @param hsizeTriplets pointer to an array of size 3*num_boxes floats
* @param boxOffsetTransforms pointer to an array of num_boxes Transforms
* @param num_spheres
* @param radii pointer to an array of num_sphere floats
* @param sphereOffsetTransforms pointer to an array of num_sphere Transforms
* @param T a pointer to a Transform
* @param comOffset an optional input array of 3 floats that determines the center of mass offset of the body
* @param centerMeshAndRetrieveOldCenter3Out [experimental] an optional output array of 3 floats: if set, the input mesh is recentered (before applying the comOffset) and the axis-aligned bounding box center that has been subtracted from the mesh is returned
* @return the body index, or \ref NUDGE_INVALID_BODY_ID "NUDGE_INVALID_BODY_ID" if no more boxes can be added
* @note Internally \ref BodyProperties "mass_inverse and inertia_inverse" are always stored as positive values (except for static bodies): this makes kinematic to dynamic body conversions a bit easier
* @note Every time an \ref add_group "add_xxx(...)" function is called, if c->global_data.finalized_removed_bodies_count>0, the body c->global_data.removed_bodies[0] is always reused and returned
*/
unsigned add_compound(context_t* c, float mass, float inertia[3], unsigned num_boxes, const float* hsizeTriplets, const Transform* boxOffsetTransforms, unsigned num_spheres, const float* radii, const Transform* sphereOffsetTransforms, const Transform* T=NULL, const float comOffset[3]=NULL, float *centerMeshAndRetrieveOldCenter3Out = NULL);
/**
* @overload
* @param mMatrix16WithoutScaling a pointer to a 4x4 column-major matrix with only translation and rotation
*/
unsigned add_compound(context_t* c,float mass, float inertia[3],unsigned num_boxes,const float* hsizeTriplets,const float* boxOffsetMatrices16WithoutScaling,unsigned num_spheres,const float* radii,const float* sphereOffsetMatrices16WithoutScaling,const float* mMatrix16WithoutScaling=NULL, const float comOffset[3]=NULL, float *centerMeshAndRetrieveOldCenter3Out = NULL);
/**
* @brief [Experimental] Adds a new body to the simulation cloning an existing body
* @param c the nudge context
* @param body_to_clone the body to clone
* @param mass positive => dynamic; 0 => static; negative => kinematic (where the absolute value will be used as mass internally)
* @param T a pointer to a Transform
* @param scale_factor positive => the uniform scaling factor to apply (to each single axis); negative => scale so that the half bounding box y-component of the body becomes exactly -scaling_factor; 0 => invalid value (asserts)
* @param newComOffsetInPreScaledUnits if set, an absolute new center of mass offset will be added (replacing the old one if present) using the pre-scaled coordinates; otherwise the old center of mass offset (if present) is kept (and possibly scaled)
* @return the body index, or \ref NUDGE_INVALID_BODY_ID "NUDGE_INVALID_BODY_ID" if no more boxes can be added
* @note Internally \ref BodyProperties "mass_inverse and inertia_inverse" are always stored as positive values (except for static bodies): this makes kinematic to dynamic body conversions a bit easier
* @note Every time an \ref add_group "add_xxx(...)" function is called, if c->global_data.finalized_removed_bodies_count>0, the body c->global_data.removed_bodies[0] is always reused and returned
*/
unsigned add_clone(context_t* c,unsigned body_to_clone,float mass,const Transform* T=NULL,float scale_factor=1.f,const float newComOffsetInPreScaledUnits[3]=NULL);
/**
* @overload
* @param mMatrix16WithoutScaling a pointer to a 4x4 column-major matrix with only translation and rotation
*/
unsigned add_clone(context_t* c,unsigned body_to_clone,float mass,const float* mMatrix16WithoutScaling,float scale_factor=1.f,const float newComOffsetInPreScaledUnits[3]=NULL);
/**
* @brief Removes a body from the simulation
* @note The body is actually removed next time \ref simulation_step "simulation_step(...)" is called (the call 'finalizes' the removal of all pending bodies).
* The body can't be reused after this call and could still be present in ContactData for some (1?) frames.
* In any case user can detect it with: ((*body_get_flags(...))&BF_IS_REMOVED).
* Also removed bodies are NOT subtracted from c->bodies.count, but are reused when new bodies are added with: \ref add_group "add_xxx(...)".
* @note Internally, removed bodies are kept in the c->global_data.removed_bodies array.
* @note If you just want to reuse the body WITH THE SAME (optionally rescaled) collider(s) soon,
* you should not remove the body, but just change its properties (more efficient + no delay).
* @note Sometimes it's better to just disable a body, instead of removing it, using: (*body_get_flags(...))|=BF_IS_DISABLED: this way the body can be optionally put into a user-side custom list for later reusage/reactivation. This way the body colliders are preserved.
* @note Every time an \ref add_group "add_xxx(...)" function is called, if c->global_data.finalized_removed_bodies_count>0, the body: c->global_data.removed_bodies[0] is always returned.
* @note User data in the \ref BodyInfo "BodyInfo" struct are NOT reset when a body is removed, but most of the other data are reset when removed bodies are finalized at the beginning of next \ref simulation_step "simulation_step(...)" call.
* @note That means that when bodies are reused in \ref add_group "add_xxx(...)" functions, their old user data are preserved.
* @note Kinematic animations referencing removed bodies are assigned to \ref NUDGE_INVALID_BODY_ID "NUDGE_INVALID_BODY_ID" when removed bodies are finalized (there's an optional definition NUDGE_DELETE_KINEMATIC_ANIMATIONS_REFERENCING_REMOVED_BODIES to delete the kinematic animations instead).
*/
void remove_body(context_t* c,unsigned body);
/**
* @brief Return the number of box colliders that can still be added to the physic world
* @note The maximum number can be set in \ref init_context_with "init_context_with(...)" and can't be changed at runtime
*/
uint32_t colliders_get_num_remaining_boxes(context_t* c);
/**
* @brief Return the number of sphere colliders that can still be added to the physic world
* @note The maximum number can be set in \ref init_context_with "init_context_with(...)" and can't be changed at runtime
*/
uint32_t colliders_get_num_remaining_spheres(context_t* c);
/**
* @return 1 if \ref add_box "add_box(...)" can be called successfully
*/
inline int can_add_box(context_t* c) {return colliders_get_num_remaining_boxes(c)>=1;}
/**
* @return 1 if \ref add_sphere "add_sphere(...)" can be called successfully
*/
inline int can_add_sphere(context_t* c) {return colliders_get_num_remaining_spheres(c)>=1;}
/**
* @return 1 if \ref add_compound "add_compound(...)" can be called successfully with num_boxes and num_spheres
*/
inline int can_add_compound(context_t* c,unsigned num_boxes,unsigned num_spheres) {return (colliders_get_num_remaining_boxes(c)>=num_boxes && colliders_get_num_remaining_spheres(c)>=num_spheres);}
/**
* @return 1 if \ref add_clone "add_clone(...)" can be called successfully
*/
inline int can_add_clone(context_t* c,unsigned body_to_clone) {return (colliders_get_num_remaining_boxes(c)>=c->bodies.layouts[body_to_clone].num_boxes && colliders_get_num_remaining_spheres(c)>=c->bodies.layouts[body_to_clone].num_spheres);}
/**
* @brief Allows to peek the body index that is going to be returned in next \ref add_group "add_xxx(...)" call
* @param c the nudge context
* @return one of the following values: c->bodies.count, c->global_data.removed_bodies[0] or \ref NUDGE_INVALID_BODY_ID "NUDGE_INVALID_BODY_ID"
* @note Next call to any \ref add_group "add_xxx(...)" function can still return \ref NUDGE_INVALID_BODY_ID "NUDGE_INVALID_BODY_ID", if the number of available colliders runs out (that condition can be queried before adding the body using \ref colliders_get_num_remaining_boxes "colliders_get_num_remaining_boxes(...)", \ref colliders_get_num_remaining_spheres "colliders_get_num_remaining_spheres(...)" or \ref can_add_box "can_add_box(...)", \ref can_add_sphere "can_add_sphere(...)", \ref can_add_compound "can_add_compound(...)")
* @note The returned body is valid until next \ref simulation_step "simulation_step(...)" call
* @note A returned value of c->bodies.count can still be used, because the arrays are allocated at context init time, with a size of c->MAX_NUM_BODIES
*/
inline unsigned get_next_add_body_index(context_t* c) {return c->global_data.finalized_removed_bodies_count>0?c->global_data.removed_bodies[0]:(c->bodies.count>=c->MAX_NUM_BODIES?NUDGE_INVALID_BODY_ID:c->bodies.count);}