tinyphysicsengine.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. #ifndef TINYPHYSICSENGINE_H
  2. #define TINYPHYSICSENGINE_H
  3. /**
  4. author: Miloslav Ciz
  5. license: CC0 1.0 (public domain)
  6. found at https://creativecommons.org/publicdomain/zero/1.0/
  7. + additional waiver of all IP
  8. version: 0.1d
  9. CONVENTIONS:
  10. - Compatibility and simple usage with small3dlib is intended, so most
  11. convention and data types copy those of small3dlib (which takes a lot of
  12. conventions of OpenGL).
  13. - No floating point is used, we instead use integers (effectively a fixed
  14. point). TPE_FRACTIONS_PER_UNIT is an equivalent to 1.0 in floating point and
  15. all numbers are normalized by this constant.
  16. - Units: for any measure only an abstract mathematical unit is used. This unit
  17. always has TPE_FRACTIONS_PER_UNIT parts. You can assign any correcpondence
  18. with real life units to these units. E.g. 1 spatial unit (which you can see
  19. as e.g. 1 meter) is equal to TPE_FRACTIONS_PER_UNIT. Same with temporatl
  20. (e.g. 1 second) and mass (e.g. 1 kilogram) units, and also any derived
  21. units, e.g. a unit of velocity (e.g. 1 m/s) is also equal to 1
  22. TPE_FRACTIONS_PER_UNIT. A full angle is also split into
  23. TPE_FRACTIONS_PER_UNIT parts (instead of 2 * PI or degrees).
  24. - Quaternions are represented as vec4 where x ~ i, y ~ j, z ~ k, w ~ real.
  25. */
  26. #include <stdint.h>
  27. typedef int32_t TPE_Unit;
  28. /** How many fractions a unit is split into. This is NOT SUPPOSED TO BE
  29. REDEFINED, so rather don't do it (otherwise things may overflow etc.). */
  30. #define TPE_FRACTIONS_PER_UNIT 512
  31. #define TPE_INFINITY 2147483647
  32. #define TPE_SHAPE_POINT 0 ///< single point in space
  33. #define TPE_SHAPE_SPHERE 1 ///< sphere, params.: radius
  34. #define TPE_SHAPE_CUBOID 2 ///< cuboid, params.: width, height, depth
  35. #define TPE_SHAPE_PLANE 3 ///< plane, params.: width, depth
  36. #define TPE_SHAPE_CYLINDER 4 ///< cylinder, params.: radius, height
  37. #define TPE_SHAPE_TRIMESH 5 /**< triangle mesh, params.:
  38. vertex count,
  39. triangle count
  40. vertices (int32_t pointer),
  41. indices (uint16_t pointer) */
  42. #define TPE_MAX_SHAPE_PARAMS 3
  43. #define TPE_MAX_SHAPE_PARAMPOINTERS 2
  44. #define TPE_BODY_FLAG_DISABLED 0x00 ///< won't take part in simul. at all
  45. #define TPE_BODY_FLAG_NONCOLLIDING 0x01 ///< simulated but won't collide
  46. TPE_Unit TPE_wrap(TPE_Unit value, TPE_Unit mod);
  47. TPE_Unit TPE_clamp(TPE_Unit v, TPE_Unit v1, TPE_Unit v2);
  48. static inline TPE_Unit TPE_nonZero(TPE_Unit x);
  49. /** Returns an integer square root of given value. */
  50. TPE_Unit TPE_sqrt(TPE_Unit value);
  51. /** Returns a sine of given arguments, both in TPE_Units (see the library
  52. conventions). */
  53. TPE_Unit TPE_sin(TPE_Unit x);
  54. TPE_Unit TPE_cos(TPE_Unit x);
  55. TPE_Unit TPE_asin(TPE_Unit x);
  56. TPE_Unit TPE_acos(TPE_Unit x);
  57. typedef struct
  58. {
  59. TPE_Unit x;
  60. TPE_Unit y;
  61. TPE_Unit z;
  62. TPE_Unit w;
  63. } TPE_Vec4;
  64. /** Initializes vec4 to a zero vector. */
  65. void TPE_initVec4(TPE_Vec4 *v);
  66. void TPE_vec4Set(TPE_Vec4 *v, TPE_Unit x, TPE_Unit y, TPE_Unit z, TPE_Unit w);
  67. void TPE_vec3Add(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result);
  68. void TPE_vec4Add(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result);
  69. void TPE_vec3Substract(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result);
  70. void TPE_vec4Substract(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result);
  71. void TPE_vec3Multiply(const TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result);
  72. void TPE_vec4Multiply(const TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result);
  73. TPE_Unit TPE_vec3Len(TPE_Vec4 v);
  74. TPE_Unit TPE_vec4Len(TPE_Vec4 v);
  75. TPE_Unit TPE_vec3DotProduct(const TPE_Vec4 v1, const TPE_Vec4 v2);
  76. void TPE_vec3Normalize(TPE_Vec4 *v);
  77. void TPE_vec4Normalize(TPE_Vec4 *v);
  78. void TPE_vec3Project(const TPE_Vec4 v, const TPE_Vec4 base, TPE_Vec4 *result);
  79. /** Holds a rotation state around a single axis, in a way that prevents rounding
  80. errors from distorting the rotation over time. In theory rotation of a body
  81. could be represented as
  82. [current orientation, axis of rotation,angular velocity]
  83. However applying the rotation and normalizing the orientation quaternion each
  84. simulation step leads to error cumulation and the rotation gets aligned with
  85. one principal axis after some time. Because of this we rather represent the
  86. rotation state as
  87. [original orientation, axis of rotation, angular velocity, current angle]
  88. From this we can at each simulation step compute the current orientation by
  89. applying rotation by current angle to the original rotation without error
  90. cumulation. */
  91. typedef struct
  92. {
  93. TPE_Vec4 originalOrientation; /**< quaternion holding the original
  94. orientation of the body at the time when it
  95. has taken on this rotational state */
  96. TPE_Vec4 axisVelocity; /**< axis of rotation (x,y,z) and a
  97. non-negative angular velocity around this
  98. axis (w), determined ny the right hand
  99. rule */
  100. TPE_Unit currentAngle; /**< angle the body has already rotated along
  101. the rotation axis (from the original
  102. orientation) */
  103. } TPE_RotationState;
  104. typedef struct
  105. {
  106. uint8_t shape;
  107. TPE_Unit shapeParams[TPE_MAX_SHAPE_PARAMS]; ///< parameters of the body type
  108. void *shapeParamPointers[TPE_MAX_SHAPE_PARAMPOINTERS]; ///< pointer parameters
  109. uint8_t flags;
  110. TPE_Unit mass; /**< body mass, setting this to TPE_INFINITY will
  111. make the object static (not moving at all)
  112. which may help performance */
  113. TPE_Vec4 position; ///< position of the body's center of mass
  114. TPE_Vec4 velocity; ///< linear velocity vector
  115. TPE_RotationState rotation; /**< holds the state related to rotation, i.e.
  116. the rotation axis, angular momentum and data
  117. from which current orientation can be
  118. inferred */
  119. } TPE_Body;
  120. /** Initializes a physical body, this should be called on all TPE_Bodys that
  121. are created.*/
  122. void TPE_bodyInit(TPE_Body *body);
  123. /** Computes a 4x4 transform matrix of given body. The matrix has the same
  124. format as S3L_Mat4 from small3dlib. */
  125. void TPE_bodyGetTransformMatrix(const TPE_Body *body, TPE_Unit matrix[4][4]);
  126. void TPE_bodyGetOrientation(const TPE_Body *body, TPE_Vec4 *quaternion);
  127. void TPE_bodyStep(TPE_Body *body);
  128. void TPE_bodySetRotation(TPE_Body *body, TPE_Vec4 axis, TPE_Unit velocity);
  129. #define TPE_PRINTF_VEC4(v) printf("[%d %d %d %d]\n",(v).x,(v).y,(v).z,(v).w);
  130. typedef struct
  131. {
  132. uint16_t bodyCount;
  133. TPE_Body *bodies;
  134. } TPE_PhysicsWorld;
  135. /** Multiplies two quaternions which can be seen as chaining two rotations
  136. represented by them. This is not commutative (a*b != b*a)! Rotations a is
  137. performed firth, then rotation b is performed. */
  138. void TPE_quaternionMultiply(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
  139. /** Initializes quaternion to the a rotation identity (i.e. NOT zero
  140. quaternion). */
  141. void TPE_quaternionInit(TPE_Vec4 *quaternion);
  142. /** Converts a rotation given as an axis and angle around this axis (by right
  143. hand rule) to a rotation quaternion. */
  144. void TPE_rotationToQuaternion(TPE_Vec4 axis, TPE_Unit angle,
  145. TPE_Vec4 *quaternion);
  146. void TPE_quaternionToRotation(TPE_Vec4 quaternion, TPE_Vec4 *axis,
  147. TPE_Unit *angle);
  148. /** Converts a rotation quaternion to a 4x4 rotation matrix. The matrix is
  149. indexed as [column][row] and is in the same format as S3L_Mat4 from
  150. small3dlib. */
  151. void TPE_quaternionToRotationMatrix(TPE_Vec4 quaternion, TPE_Unit matrix[4][4]);
  152. void TPE_getVelocitiesAfterCollision(
  153. TPE_Unit *v1,
  154. TPE_Unit *v2,
  155. TPE_Unit m1,
  156. TPE_Unit m2,
  157. TPE_Unit elasticity
  158. );
  159. //------------------------------------------------------------------------------
  160. void TPE_initVec4(TPE_Vec4 *v)
  161. {
  162. v->x = 0;
  163. v->y = 0;
  164. v->z = 0;
  165. v->w = 0;
  166. }
  167. void TPE_vec4Set(TPE_Vec4 *v, TPE_Unit x, TPE_Unit y, TPE_Unit z, TPE_Unit w)
  168. {
  169. v->x = x;
  170. v->y = y;
  171. v->z = z;
  172. v->w = w;
  173. }
  174. TPE_Unit TPE_wrap(TPE_Unit value, TPE_Unit mod)
  175. {
  176. return value >= 0 ? (value % mod) : (mod + (value % mod) - 1);
  177. }
  178. TPE_Unit TPE_clamp(TPE_Unit v, TPE_Unit v1, TPE_Unit v2)
  179. {
  180. return v >= v1 ? (v <= v2 ? v : v2) : v1;
  181. }
  182. TPE_Unit TPE_nonZero(TPE_Unit x)
  183. {
  184. return x + (x == 0);
  185. }
  186. #define TPE_SIN_TABLE_LENGTH 128
  187. static const TPE_Unit TPE_sinTable[TPE_SIN_TABLE_LENGTH] =
  188. {
  189. /* 511 was chosen here as a highest number that doesn't overflow during
  190. compilation for TPE_FRACTIONS_PER_UNIT == 1024 */
  191. (0*TPE_FRACTIONS_PER_UNIT)/511, (6*TPE_FRACTIONS_PER_UNIT)/511,
  192. (12*TPE_FRACTIONS_PER_UNIT)/511, (18*TPE_FRACTIONS_PER_UNIT)/511,
  193. (25*TPE_FRACTIONS_PER_UNIT)/511, (31*TPE_FRACTIONS_PER_UNIT)/511,
  194. (37*TPE_FRACTIONS_PER_UNIT)/511, (43*TPE_FRACTIONS_PER_UNIT)/511,
  195. (50*TPE_FRACTIONS_PER_UNIT)/511, (56*TPE_FRACTIONS_PER_UNIT)/511,
  196. (62*TPE_FRACTIONS_PER_UNIT)/511, (68*TPE_FRACTIONS_PER_UNIT)/511,
  197. (74*TPE_FRACTIONS_PER_UNIT)/511, (81*TPE_FRACTIONS_PER_UNIT)/511,
  198. (87*TPE_FRACTIONS_PER_UNIT)/511, (93*TPE_FRACTIONS_PER_UNIT)/511,
  199. (99*TPE_FRACTIONS_PER_UNIT)/511, (105*TPE_FRACTIONS_PER_UNIT)/511,
  200. (111*TPE_FRACTIONS_PER_UNIT)/511, (118*TPE_FRACTIONS_PER_UNIT)/511,
  201. (124*TPE_FRACTIONS_PER_UNIT)/511, (130*TPE_FRACTIONS_PER_UNIT)/511,
  202. (136*TPE_FRACTIONS_PER_UNIT)/511, (142*TPE_FRACTIONS_PER_UNIT)/511,
  203. (148*TPE_FRACTIONS_PER_UNIT)/511, (154*TPE_FRACTIONS_PER_UNIT)/511,
  204. (160*TPE_FRACTIONS_PER_UNIT)/511, (166*TPE_FRACTIONS_PER_UNIT)/511,
  205. (172*TPE_FRACTIONS_PER_UNIT)/511, (178*TPE_FRACTIONS_PER_UNIT)/511,
  206. (183*TPE_FRACTIONS_PER_UNIT)/511, (189*TPE_FRACTIONS_PER_UNIT)/511,
  207. (195*TPE_FRACTIONS_PER_UNIT)/511, (201*TPE_FRACTIONS_PER_UNIT)/511,
  208. (207*TPE_FRACTIONS_PER_UNIT)/511, (212*TPE_FRACTIONS_PER_UNIT)/511,
  209. (218*TPE_FRACTIONS_PER_UNIT)/511, (224*TPE_FRACTIONS_PER_UNIT)/511,
  210. (229*TPE_FRACTIONS_PER_UNIT)/511, (235*TPE_FRACTIONS_PER_UNIT)/511,
  211. (240*TPE_FRACTIONS_PER_UNIT)/511, (246*TPE_FRACTIONS_PER_UNIT)/511,
  212. (251*TPE_FRACTIONS_PER_UNIT)/511, (257*TPE_FRACTIONS_PER_UNIT)/511,
  213. (262*TPE_FRACTIONS_PER_UNIT)/511, (268*TPE_FRACTIONS_PER_UNIT)/511,
  214. (273*TPE_FRACTIONS_PER_UNIT)/511, (278*TPE_FRACTIONS_PER_UNIT)/511,
  215. (283*TPE_FRACTIONS_PER_UNIT)/511, (289*TPE_FRACTIONS_PER_UNIT)/511,
  216. (294*TPE_FRACTIONS_PER_UNIT)/511, (299*TPE_FRACTIONS_PER_UNIT)/511,
  217. (304*TPE_FRACTIONS_PER_UNIT)/511, (309*TPE_FRACTIONS_PER_UNIT)/511,
  218. (314*TPE_FRACTIONS_PER_UNIT)/511, (319*TPE_FRACTIONS_PER_UNIT)/511,
  219. (324*TPE_FRACTIONS_PER_UNIT)/511, (328*TPE_FRACTIONS_PER_UNIT)/511,
  220. (333*TPE_FRACTIONS_PER_UNIT)/511, (338*TPE_FRACTIONS_PER_UNIT)/511,
  221. (343*TPE_FRACTIONS_PER_UNIT)/511, (347*TPE_FRACTIONS_PER_UNIT)/511,
  222. (352*TPE_FRACTIONS_PER_UNIT)/511, (356*TPE_FRACTIONS_PER_UNIT)/511,
  223. (361*TPE_FRACTIONS_PER_UNIT)/511, (365*TPE_FRACTIONS_PER_UNIT)/511,
  224. (370*TPE_FRACTIONS_PER_UNIT)/511, (374*TPE_FRACTIONS_PER_UNIT)/511,
  225. (378*TPE_FRACTIONS_PER_UNIT)/511, (382*TPE_FRACTIONS_PER_UNIT)/511,
  226. (386*TPE_FRACTIONS_PER_UNIT)/511, (391*TPE_FRACTIONS_PER_UNIT)/511,
  227. (395*TPE_FRACTIONS_PER_UNIT)/511, (398*TPE_FRACTIONS_PER_UNIT)/511,
  228. (402*TPE_FRACTIONS_PER_UNIT)/511, (406*TPE_FRACTIONS_PER_UNIT)/511,
  229. (410*TPE_FRACTIONS_PER_UNIT)/511, (414*TPE_FRACTIONS_PER_UNIT)/511,
  230. (417*TPE_FRACTIONS_PER_UNIT)/511, (421*TPE_FRACTIONS_PER_UNIT)/511,
  231. (424*TPE_FRACTIONS_PER_UNIT)/511, (428*TPE_FRACTIONS_PER_UNIT)/511,
  232. (431*TPE_FRACTIONS_PER_UNIT)/511, (435*TPE_FRACTIONS_PER_UNIT)/511,
  233. (438*TPE_FRACTIONS_PER_UNIT)/511, (441*TPE_FRACTIONS_PER_UNIT)/511,
  234. (444*TPE_FRACTIONS_PER_UNIT)/511, (447*TPE_FRACTIONS_PER_UNIT)/511,
  235. (450*TPE_FRACTIONS_PER_UNIT)/511, (453*TPE_FRACTIONS_PER_UNIT)/511,
  236. (456*TPE_FRACTIONS_PER_UNIT)/511, (459*TPE_FRACTIONS_PER_UNIT)/511,
  237. (461*TPE_FRACTIONS_PER_UNIT)/511, (464*TPE_FRACTIONS_PER_UNIT)/511,
  238. (467*TPE_FRACTIONS_PER_UNIT)/511, (469*TPE_FRACTIONS_PER_UNIT)/511,
  239. (472*TPE_FRACTIONS_PER_UNIT)/511, (474*TPE_FRACTIONS_PER_UNIT)/511,
  240. (476*TPE_FRACTIONS_PER_UNIT)/511, (478*TPE_FRACTIONS_PER_UNIT)/511,
  241. (481*TPE_FRACTIONS_PER_UNIT)/511, (483*TPE_FRACTIONS_PER_UNIT)/511,
  242. (485*TPE_FRACTIONS_PER_UNIT)/511, (487*TPE_FRACTIONS_PER_UNIT)/511,
  243. (488*TPE_FRACTIONS_PER_UNIT)/511, (490*TPE_FRACTIONS_PER_UNIT)/511,
  244. (492*TPE_FRACTIONS_PER_UNIT)/511, (494*TPE_FRACTIONS_PER_UNIT)/511,
  245. (495*TPE_FRACTIONS_PER_UNIT)/511, (497*TPE_FRACTIONS_PER_UNIT)/511,
  246. (498*TPE_FRACTIONS_PER_UNIT)/511, (499*TPE_FRACTIONS_PER_UNIT)/511,
  247. (501*TPE_FRACTIONS_PER_UNIT)/511, (502*TPE_FRACTIONS_PER_UNIT)/511,
  248. (503*TPE_FRACTIONS_PER_UNIT)/511, (504*TPE_FRACTIONS_PER_UNIT)/511,
  249. (505*TPE_FRACTIONS_PER_UNIT)/511, (506*TPE_FRACTIONS_PER_UNIT)/511,
  250. (507*TPE_FRACTIONS_PER_UNIT)/511, (507*TPE_FRACTIONS_PER_UNIT)/511,
  251. (508*TPE_FRACTIONS_PER_UNIT)/511, (509*TPE_FRACTIONS_PER_UNIT)/511,
  252. (509*TPE_FRACTIONS_PER_UNIT)/511, (510*TPE_FRACTIONS_PER_UNIT)/511,
  253. (510*TPE_FRACTIONS_PER_UNIT)/511, (510*TPE_FRACTIONS_PER_UNIT)/511,
  254. (510*TPE_FRACTIONS_PER_UNIT)/511, (510*TPE_FRACTIONS_PER_UNIT)/511
  255. };
  256. #define TPE_SIN_TABLE_UNIT_STEP\
  257. (TPE_FRACTIONS_PER_UNIT / (TPE_SIN_TABLE_LENGTH * 4))
  258. TPE_Unit TPE_sqrt(TPE_Unit value)
  259. {
  260. int8_t sign = 1;
  261. if (value < 0)
  262. {
  263. sign = -1;
  264. value *= -1;
  265. }
  266. uint32_t result = 0;
  267. uint32_t a = value;
  268. uint32_t b = 1u << 30;
  269. while (b > a)
  270. b >>= 2;
  271. while (b != 0)
  272. {
  273. if (a >= result + b)
  274. {
  275. a -= result + b;
  276. result = result + 2 * b;
  277. }
  278. b >>= 2;
  279. result >>= 1;
  280. }
  281. return result * sign;
  282. }
  283. TPE_Unit TPE_sin(TPE_Unit x)
  284. {
  285. x = TPE_wrap(x / TPE_SIN_TABLE_UNIT_STEP,TPE_SIN_TABLE_LENGTH * 4);
  286. int8_t positive = 1;
  287. if (x < TPE_SIN_TABLE_LENGTH)
  288. {
  289. }
  290. else if (x < TPE_SIN_TABLE_LENGTH * 2)
  291. {
  292. x = TPE_SIN_TABLE_LENGTH * 2 - x - 1;
  293. }
  294. else if (x < TPE_SIN_TABLE_LENGTH * 3)
  295. {
  296. x = x - TPE_SIN_TABLE_LENGTH * 2;
  297. positive = 0;
  298. }
  299. else
  300. {
  301. x = TPE_SIN_TABLE_LENGTH - (x - TPE_SIN_TABLE_LENGTH * 3) - 1;
  302. positive = 0;
  303. }
  304. return positive ? TPE_sinTable[x] : -1 * TPE_sinTable[x];
  305. }
  306. TPE_Unit TPE_cos(TPE_Unit x)
  307. {
  308. return TPE_sin(x + TPE_FRACTIONS_PER_UNIT / 4);
  309. }
  310. void TPE_bodyInit(TPE_Body *body)
  311. {
  312. // TODO
  313. TPE_initVec4(&(body->position));
  314. TPE_initVec4(&(body->velocity));
  315. // init orientation to identity unit quaternion (1,0,0,0):
  316. TPE_quaternionInit(&(body->rotation.originalOrientation));
  317. TPE_vec4Set(&(body->rotation.axisVelocity),TPE_FRACTIONS_PER_UNIT,0,0,0);
  318. body->rotation.currentAngle = 0;
  319. }
  320. void TPE_bodyGetOrientation(const TPE_Body *body, TPE_Vec4 *quaternion)
  321. {
  322. TPE_Vec4 axisRotation;
  323. TPE_rotationToQuaternion(
  324. body->rotation.axisVelocity,
  325. body->rotation.currentAngle,
  326. &axisRotation);
  327. TPE_quaternionMultiply(
  328. body->rotation.originalOrientation,
  329. axisRotation,
  330. quaternion);
  331. TPE_vec4Normalize(quaternion);
  332. }
  333. void TPE_bodyStep(TPE_Body *body)
  334. {
  335. TPE_vec3Add(body->position,body->velocity,&(body->position));
  336. body->rotation.currentAngle += body->rotation.axisVelocity.w;
  337. }
  338. void TPE_bodySetRotation(TPE_Body *body, TPE_Vec4 axis, TPE_Unit velocity)
  339. {
  340. TPE_bodyGetOrientation(body,&(body->rotation.originalOrientation));
  341. if (velocity < 0)
  342. {
  343. axis.x *= -1;
  344. axis.y *= -1;
  345. axis.z *= -1;
  346. velocity *= -1;
  347. }
  348. body->rotation.axisVelocity = axis;
  349. body->rotation.axisVelocity.w = velocity;
  350. body->rotation.currentAngle = 0;
  351. }
  352. void TPE_quaternionMultiply(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result)
  353. {
  354. TPE_Vec4 r; // in case result is identical to a or b
  355. r.x =
  356. (a.w * b.x +
  357. a.x * b.w +
  358. a.y * b.z -
  359. a.z * b.y) / TPE_FRACTIONS_PER_UNIT;
  360. r.y =
  361. (a.w * b.y -
  362. a.x * b.z +
  363. a.y * b.w +
  364. a.z * b.x) / TPE_FRACTIONS_PER_UNIT;
  365. r.z =
  366. (a.w * b.z +
  367. a.x * b.y -
  368. a.y * b.x +
  369. a.z * b.w) / TPE_FRACTIONS_PER_UNIT;
  370. r.w =
  371. (a.w * b.w -
  372. a.x * b.x -
  373. a.y * b.y -
  374. a.z * b.z) / TPE_FRACTIONS_PER_UNIT;
  375. result->x = r.x;
  376. result->y = r.y;
  377. result->z = r.z;
  378. result->w = r.w;
  379. }
  380. void TPE_rotationToQuaternion(TPE_Vec4 axis, TPE_Unit angle, TPE_Vec4 *quaternion)
  381. {
  382. TPE_vec3Normalize(&axis);
  383. angle /= 2;
  384. TPE_Unit s = TPE_sin(angle);
  385. quaternion->x = (s * axis.x) / TPE_FRACTIONS_PER_UNIT;
  386. quaternion->y = (s * axis.y) / TPE_FRACTIONS_PER_UNIT;
  387. quaternion->z = (s * axis.z) / TPE_FRACTIONS_PER_UNIT;
  388. quaternion->w = TPE_cos(angle);
  389. }
  390. TPE_Unit TPE_asin(TPE_Unit x)
  391. {
  392. x = TPE_clamp(x,-TPE_FRACTIONS_PER_UNIT,TPE_FRACTIONS_PER_UNIT);
  393. int8_t sign = 1;
  394. if (x < 0)
  395. {
  396. sign = -1;
  397. x *= -1;
  398. }
  399. int16_t low = 0;
  400. int16_t high = TPE_SIN_TABLE_LENGTH -1;
  401. int16_t middle;
  402. while (low <= high) // binary search
  403. {
  404. middle = (low + high) / 2;
  405. TPE_Unit v = TPE_sinTable[middle];
  406. if (v > x)
  407. high = middle - 1;
  408. else if (v < x)
  409. low = middle + 1;
  410. else
  411. break;
  412. }
  413. middle *= TPE_SIN_TABLE_UNIT_STEP;
  414. return sign * middle;
  415. }
  416. TPE_Unit TPE_acos(TPE_Unit x)
  417. {
  418. return TPE_asin(-1 * x) + TPE_FRACTIONS_PER_UNIT / 4;
  419. }
  420. void TPE_quaternionToRotation(TPE_Vec4 quaternion, TPE_Vec4 *axis, TPE_Unit *angle)
  421. {
  422. *angle = 2 * TPE_acos(quaternion.x);
  423. TPE_Unit tmp =
  424. TPE_nonZero(TPE_sqrt(
  425. (TPE_FRACTIONS_PER_UNIT -
  426. (quaternion.x * quaternion.x) / TPE_FRACTIONS_PER_UNIT
  427. ) * TPE_FRACTIONS_PER_UNIT));
  428. axis->x = (quaternion.x * TPE_FRACTIONS_PER_UNIT) / tmp;
  429. axis->y = (quaternion.y * TPE_FRACTIONS_PER_UNIT) / tmp;
  430. axis->z = (quaternion.z * TPE_FRACTIONS_PER_UNIT) / tmp;
  431. }
  432. void TPE_quaternionToRotationMatrix(TPE_Vec4 quaternion, TPE_Unit matrix[4][4])
  433. {
  434. TPE_Unit
  435. _2x2 = (2 * quaternion.x * quaternion.x) / TPE_FRACTIONS_PER_UNIT,
  436. _2y2 = (2 * quaternion.y * quaternion.y) / TPE_FRACTIONS_PER_UNIT,
  437. _2z2 = (2 * quaternion.z * quaternion.z) / TPE_FRACTIONS_PER_UNIT,
  438. _2xy = (2 * quaternion.x * quaternion.y) / TPE_FRACTIONS_PER_UNIT,
  439. _2xw = (2 * quaternion.x * quaternion.w) / TPE_FRACTIONS_PER_UNIT,
  440. _2zw = (2 * quaternion.z * quaternion.w) / TPE_FRACTIONS_PER_UNIT,
  441. _2xz = (2 * quaternion.x * quaternion.z) / TPE_FRACTIONS_PER_UNIT,
  442. _2yw = (2 * quaternion.y * quaternion.w) / TPE_FRACTIONS_PER_UNIT,
  443. _2yz = (2 * quaternion.y * quaternion.z) / TPE_FRACTIONS_PER_UNIT;
  444. #define ONE TPE_FRACTIONS_PER_UNIT
  445. matrix[0][0] = ONE - _2y2 - _2z2;
  446. matrix[1][0] = _2xy - _2zw;
  447. matrix[2][0] = _2xz + _2yw;
  448. matrix[3][0] = 0;
  449. matrix[0][1] = _2xy + _2zw;
  450. matrix[1][1] = ONE - _2x2 - _2z2;
  451. matrix[2][1] = _2yz - _2xw;
  452. matrix[3][1] = 0;
  453. matrix[0][2] = _2xz - _2yw;
  454. matrix[1][2] = _2yz + _2xw;
  455. matrix[2][2] = ONE - _2x2 - _2y2;
  456. matrix[3][2] = 0;
  457. matrix[0][3] = 0;
  458. matrix[1][3] = 0;
  459. matrix[2][3] = 0;
  460. matrix[3][3] = ONE;
  461. #undef ONE
  462. }
  463. void TPE_vec3Add(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result)
  464. {
  465. result->x = a.x + b.x;
  466. result->y = a.y + b.y;
  467. result->z = a.z + b.z;
  468. }
  469. void TPE_vec4Add(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result)
  470. {
  471. result->x = a.x + b.x;
  472. result->y = a.y + b.y;
  473. result->z = a.z + b.z;
  474. result->w = a.w + b.w;
  475. }
  476. void TPE_vec3Substract(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result)
  477. {
  478. result->x = a.x - b.x;
  479. result->y = a.y - b.y;
  480. result->z = a.z - b.z;
  481. }
  482. void TPE_vec4Substract(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result)
  483. {
  484. result->x = a.x - b.x;
  485. result->y = a.y - b.y;
  486. result->z = a.z - b.z;
  487. result->w = a.w - b.w;
  488. }
  489. void TPE_vec3Multiply(const TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result)
  490. {
  491. result->x = (v.x * f) / TPE_FRACTIONS_PER_UNIT;
  492. result->y = (v.y * f) / TPE_FRACTIONS_PER_UNIT;
  493. result->z = (v.z * f) / TPE_FRACTIONS_PER_UNIT;
  494. }
  495. void TPE_vec4Multiply(const TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result)
  496. {
  497. result->x = (v.x * f) / TPE_FRACTIONS_PER_UNIT;
  498. result->y = (v.y * f) / TPE_FRACTIONS_PER_UNIT;
  499. result->z = (v.z * f) / TPE_FRACTIONS_PER_UNIT;
  500. result->w = (v.w * f) / TPE_FRACTIONS_PER_UNIT;
  501. }
  502. TPE_Unit TPE_vec3Len(TPE_Vec4 v)
  503. {
  504. return TPE_sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
  505. }
  506. TPE_Unit TPE_vec4Len(TPE_Vec4 v)
  507. {
  508. return TPE_sqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
  509. }
  510. TPE_Unit TPE_vec3DotProduct(const TPE_Vec4 v1, const TPE_Vec4 v2)
  511. {
  512. return
  513. (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z) / TPE_FRACTIONS_PER_UNIT;
  514. }
  515. void TPE_vec3Normalize(TPE_Vec4 *v)
  516. {
  517. TPE_Unit l = TPE_vec3Len(*v);
  518. if (l == 0)
  519. {
  520. v->x = TPE_FRACTIONS_PER_UNIT;
  521. return;
  522. }
  523. v->x = (v->x * TPE_FRACTIONS_PER_UNIT) / l;
  524. v->y = (v->y * TPE_FRACTIONS_PER_UNIT) / l;
  525. v->z = (v->z * TPE_FRACTIONS_PER_UNIT) / l;
  526. }
  527. void TPE_vec4Normalize(TPE_Vec4 *v)
  528. {
  529. TPE_Unit l = TPE_vec4Len(*v);
  530. if (l == 0)
  531. {
  532. v->x = TPE_FRACTIONS_PER_UNIT;
  533. return;
  534. }
  535. v->x = (v->x * TPE_FRACTIONS_PER_UNIT) / l;
  536. v->y = (v->y * TPE_FRACTIONS_PER_UNIT) / l;
  537. v->z = (v->z * TPE_FRACTIONS_PER_UNIT) / l;
  538. v->w = (v->w * TPE_FRACTIONS_PER_UNIT) / l;
  539. }
  540. void TPE_vec3Project(const TPE_Vec4 v, const TPE_Vec4 base, TPE_Vec4 *result)
  541. {
  542. TPE_Unit p = TPE_vec3DotProduct(v,base);
  543. result->x = (p * base.x) / TPE_FRACTIONS_PER_UNIT;
  544. result->y = (p * base.y) / TPE_FRACTIONS_PER_UNIT;
  545. result->z = (p * base.z) / TPE_FRACTIONS_PER_UNIT;
  546. }
  547. void TPE_getVelocitiesAfterCollision(
  548. TPE_Unit *v1,
  549. TPE_Unit *v2,
  550. TPE_Unit m1,
  551. TPE_Unit m2,
  552. TPE_Unit elasticity
  553. )
  554. {
  555. /* in the following a lot of TPE_FRACTIONS_PER_UNIT cancel out, feel free to
  556. check if confused */
  557. #define ANTI_OVERFLOW 30000
  558. #define ANTI_OVERFLOW_SCALE 128
  559. uint8_t overflowDanger = m1 > ANTI_OVERFLOW || *v1 > ANTI_OVERFLOW ||
  560. m2 > ANTI_OVERFLOW || *v2 > ANTI_OVERFLOW;
  561. if (overflowDanger)
  562. {
  563. m1 = (m1 != 0) ? TPE_nonZero(m1 / ANTI_OVERFLOW_SCALE) : 0;
  564. m2 = (m2 != 0) ? TPE_nonZero(m2 / ANTI_OVERFLOW_SCALE) : 0;
  565. *v1 = (*v1 != 0) ? TPE_nonZero(*v1 / ANTI_OVERFLOW_SCALE) : 0;
  566. *v2 = (*v2 != 0) ? TPE_nonZero(*v2 / ANTI_OVERFLOW_SCALE) : 0;
  567. }
  568. TPE_Unit m1Pm2 = m1 + m2;
  569. TPE_Unit v2Mv1 = *v2 - *v1;
  570. TPE_Unit m1v1Pm2v2 = ((m1 * *v1) + (m2 * *v2));
  571. *v1 = (((elasticity * m2 / TPE_FRACTIONS_PER_UNIT) * v2Mv1)
  572. + m1v1Pm2v2) / m1Pm2;
  573. *v2 = (((elasticity * m1 / TPE_FRACTIONS_PER_UNIT) * -1 * v2Mv1)
  574. + m1v1Pm2v2) / m1Pm2;
  575. if (overflowDanger)
  576. {
  577. *v1 *= ANTI_OVERFLOW_SCALE;
  578. *v2 *= ANTI_OVERFLOW_SCALE;
  579. }
  580. #undef ANTI_OVERFLOW
  581. #undef ANTI_OVERFLOW_SCALE
  582. }
  583. void TPE_resolvePointCollision(
  584. const TPE_Vec4 collisionPoint,
  585. const TPE_Vec4 collisionNormal,
  586. TPE_Unit elasticity,
  587. TPE_Vec4 linVelocity1,
  588. TPE_Vec4 rotVelocity1,
  589. TPE_Unit m1,
  590. TPE_Vec4 linVelocity2,
  591. TPE_Vec4 rotVelocity2,
  592. TPE_Unit m2)
  593. {
  594. TPE_Vec4 v1, v2, v1New, v2New;
  595. TPE_initVec4(&v1);
  596. TPE_initVec4(&v2);
  597. TPE_initVec4(&v1New);
  598. TPE_initVec4(&v2New);
  599. // add lin. and rot. velocities to get the overall vel. of both points:
  600. TPE_vec4Add(linVelocity1,rotVelocity1,&v1);
  601. TPE_vec4Add(linVelocity2,rotVelocity2,&v2);
  602. /* project both of these velocities to the collision normal as we'll apply
  603. the collision equation only in the direction of this normal: */
  604. TPE_vec3Project(v1,collisionNormal,&v1New);
  605. TPE_vec3Project(v2,collisionNormal,&v2New);
  606. // get the velocities of the components
  607. TPE_Unit
  608. v1NewMag = TPE_vec3Len(v1New),
  609. v2NewMag = TPE_vec3Len(v2New);
  610. /* now also substract this component from the original velocity (so that it
  611. will now be in the collision plane), we'll later add back the updated
  612. velocity to it */
  613. TPE_vec4Substract(v1,v1New,&v1);
  614. TPE_vec4Substract(v2,v2New,&v2);
  615. // apply the 1D collision equation to velocities along the normal:
  616. TPE_getVelocitiesAfterCollision(
  617. &v1NewMag,
  618. &v2NewMag,
  619. m1,
  620. m2,
  621. elasticity);
  622. // add back the updated velocities to get the new overall velocities:
  623. v1New.x += (collisionNormal.x * v1NewMag) / TPE_FRACTIONS_PER_UNIT;
  624. v1New.y += (collisionNormal.y * v1NewMag) / TPE_FRACTIONS_PER_UNIT;
  625. v1New.z += (collisionNormal.z * v1NewMag) / TPE_FRACTIONS_PER_UNIT;
  626. v2New.x += (collisionNormal.x * v2NewMag) / TPE_FRACTIONS_PER_UNIT;
  627. v2New.y += (collisionNormal.y * v2NewMag) / TPE_FRACTIONS_PER_UNIT;
  628. v2New.z += (collisionNormal.z * v2NewMag) / TPE_FRACTIONS_PER_UNIT;
  629. // TODO
  630. }
  631. void TPE_bodyGetTransformMatrix(const TPE_Body *body, TPE_Unit matrix[4][4])
  632. {
  633. TPE_Vec4 orientation;
  634. TPE_bodyGetOrientation(body,&orientation);
  635. TPE_quaternionToRotationMatrix(orientation,matrix);
  636. matrix[0][3] = body->position.x;
  637. matrix[1][3] = body->position.y;
  638. matrix[2][3] = body->position.z;
  639. }
  640. void TPE_quaternionInit(TPE_Vec4 *quaternion)
  641. {
  642. quaternion->x = 0;
  643. quaternion->y = 0;
  644. quaternion->z = 0;
  645. quaternion->w = TPE_FRACTIONS_PER_UNIT;
  646. }
  647. #endif // guard