tinyphysicsengine.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  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_setVec4(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_vec3Multiplay(const TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result);
  72. void TPE_vec4Multiplay(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. typedef struct
  80. {
  81. uint8_t shape;
  82. TPE_Unit shapeParams[TPE_MAX_SHAPE_PARAMS]; ///< parameters of the body type
  83. void *shapeParamPointers[TPE_MAX_SHAPE_PARAMPOINTERS]; ///< pointer parameters
  84. uint8_t flags;
  85. TPE_Unit mass; /**< body mass, setting this to TPE_INFINITY will
  86. make the object static (not moving at all)
  87. which may help performance */
  88. TPE_Vec4 position; ///< position of the body's center of mass
  89. TPE_Vec4 orientation; ///< orientation as a quaternion
  90. TPE_Vec4 velocity; ///< linear velocity vector
  91. TPE_Vec4 rotation; /**< current rotational state: X, Y and Z are the
  92. normalized axis of rotation (we only allow
  93. one), W is a non-negative angular speed around
  94. this axis (one angle unit per temporal unit) in
  95. the direction given by right hand rule
  96. (mathematically we could have just X, Y and Z
  97. with the size of vector being angular speed,
  98. but for computational/performance it's better
  99. this way), DO NOT SET THIS MANUALLY (use a
  100. function) */
  101. } TPE_Body;
  102. /** Initializes a physical body, this should be called on all TPE_Bodys that
  103. are created.*/
  104. void TPE_initBody(TPE_Body *body);
  105. /** Computes a 4x4 transform matrix of given body. The matrix has the same
  106. format as S3L_Mat4 from small3dlib. */
  107. void TPE_bodyGetTransformMatrix(TPE_Body *body, TPE_Unit matrix[4][4]);
  108. #define TPE_PRINTF_VEC4(v) printf("[%d %d %d %d]\n",v.x,v.y,v.z,v.w);
  109. typedef struct
  110. {
  111. uint16_t bodyCount;
  112. TPE_Body *bodies;
  113. } TPE_PhysicsWorld;
  114. void TPE_quaternionMultiply(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
  115. /** Converts a rotation given as an axis and angle around this axis (by right
  116. hand rule) to a rotation quaternion. */
  117. void TPE_rotationToQuaternion(TPE_Vec4 axis, TPE_Unit angle,
  118. TPE_Vec4 *quaternion);
  119. void TPE_quaternionToRotation(TPE_Vec4 quaternion, TPE_Vec4 *axis,
  120. TPE_Unit *angle);
  121. /** Converts a rotation quaternion to a 4x4 rotation matrix. The matrix is
  122. indexed as [column][row] and is in the same format as S3L_Mat4 from
  123. small3dlib. */
  124. void TPE_quaternionToRotationMatrix(TPE_Vec4 quaternion, TPE_Unit matrix[4][4]);
  125. void TPE_getVelocitiesAfterCollision(
  126. TPE_Unit *v1,
  127. TPE_Unit *v2,
  128. TPE_Unit m1,
  129. TPE_Unit m2,
  130. TPE_Unit elasticity
  131. );
  132. //------------------------------------------------------------------------------
  133. void TPE_initVec4(TPE_Vec4 *v)
  134. {
  135. v->x = 0;
  136. v->y = 0;
  137. v->z = 0;
  138. v->w = 0;
  139. }
  140. void TPE_setVec4(TPE_Vec4 *v, TPE_Unit x, TPE_Unit y, TPE_Unit z, TPE_Unit w)
  141. {
  142. v->x = x;
  143. v->y = y;
  144. v->z = z;
  145. v->w = w;
  146. }
  147. TPE_Unit TPE_wrap(TPE_Unit value, TPE_Unit mod)
  148. {
  149. return value >= 0 ? (value % mod) : (mod + (value % mod) - 1);
  150. }
  151. TPE_Unit TPE_clamp(TPE_Unit v, TPE_Unit v1, TPE_Unit v2)
  152. {
  153. return v >= v1 ? (v <= v2 ? v : v2) : v1;
  154. }
  155. TPE_Unit TPE_nonZero(TPE_Unit x)
  156. {
  157. return x + (x == 0);
  158. }
  159. #define TPE_SIN_TABLE_LENGTH 128
  160. static const TPE_Unit TPE_sinTable[TPE_SIN_TABLE_LENGTH] =
  161. {
  162. /* 511 was chosen here as a highest number that doesn't overflow during
  163. compilation for TPE_FRACTIONS_PER_UNIT == 1024 */
  164. (0*TPE_FRACTIONS_PER_UNIT)/511, (6*TPE_FRACTIONS_PER_UNIT)/511,
  165. (12*TPE_FRACTIONS_PER_UNIT)/511, (18*TPE_FRACTIONS_PER_UNIT)/511,
  166. (25*TPE_FRACTIONS_PER_UNIT)/511, (31*TPE_FRACTIONS_PER_UNIT)/511,
  167. (37*TPE_FRACTIONS_PER_UNIT)/511, (43*TPE_FRACTIONS_PER_UNIT)/511,
  168. (50*TPE_FRACTIONS_PER_UNIT)/511, (56*TPE_FRACTIONS_PER_UNIT)/511,
  169. (62*TPE_FRACTIONS_PER_UNIT)/511, (68*TPE_FRACTIONS_PER_UNIT)/511,
  170. (74*TPE_FRACTIONS_PER_UNIT)/511, (81*TPE_FRACTIONS_PER_UNIT)/511,
  171. (87*TPE_FRACTIONS_PER_UNIT)/511, (93*TPE_FRACTIONS_PER_UNIT)/511,
  172. (99*TPE_FRACTIONS_PER_UNIT)/511, (105*TPE_FRACTIONS_PER_UNIT)/511,
  173. (111*TPE_FRACTIONS_PER_UNIT)/511, (118*TPE_FRACTIONS_PER_UNIT)/511,
  174. (124*TPE_FRACTIONS_PER_UNIT)/511, (130*TPE_FRACTIONS_PER_UNIT)/511,
  175. (136*TPE_FRACTIONS_PER_UNIT)/511, (142*TPE_FRACTIONS_PER_UNIT)/511,
  176. (148*TPE_FRACTIONS_PER_UNIT)/511, (154*TPE_FRACTIONS_PER_UNIT)/511,
  177. (160*TPE_FRACTIONS_PER_UNIT)/511, (166*TPE_FRACTIONS_PER_UNIT)/511,
  178. (172*TPE_FRACTIONS_PER_UNIT)/511, (178*TPE_FRACTIONS_PER_UNIT)/511,
  179. (183*TPE_FRACTIONS_PER_UNIT)/511, (189*TPE_FRACTIONS_PER_UNIT)/511,
  180. (195*TPE_FRACTIONS_PER_UNIT)/511, (201*TPE_FRACTIONS_PER_UNIT)/511,
  181. (207*TPE_FRACTIONS_PER_UNIT)/511, (212*TPE_FRACTIONS_PER_UNIT)/511,
  182. (218*TPE_FRACTIONS_PER_UNIT)/511, (224*TPE_FRACTIONS_PER_UNIT)/511,
  183. (229*TPE_FRACTIONS_PER_UNIT)/511, (235*TPE_FRACTIONS_PER_UNIT)/511,
  184. (240*TPE_FRACTIONS_PER_UNIT)/511, (246*TPE_FRACTIONS_PER_UNIT)/511,
  185. (251*TPE_FRACTIONS_PER_UNIT)/511, (257*TPE_FRACTIONS_PER_UNIT)/511,
  186. (262*TPE_FRACTIONS_PER_UNIT)/511, (268*TPE_FRACTIONS_PER_UNIT)/511,
  187. (273*TPE_FRACTIONS_PER_UNIT)/511, (278*TPE_FRACTIONS_PER_UNIT)/511,
  188. (283*TPE_FRACTIONS_PER_UNIT)/511, (289*TPE_FRACTIONS_PER_UNIT)/511,
  189. (294*TPE_FRACTIONS_PER_UNIT)/511, (299*TPE_FRACTIONS_PER_UNIT)/511,
  190. (304*TPE_FRACTIONS_PER_UNIT)/511, (309*TPE_FRACTIONS_PER_UNIT)/511,
  191. (314*TPE_FRACTIONS_PER_UNIT)/511, (319*TPE_FRACTIONS_PER_UNIT)/511,
  192. (324*TPE_FRACTIONS_PER_UNIT)/511, (328*TPE_FRACTIONS_PER_UNIT)/511,
  193. (333*TPE_FRACTIONS_PER_UNIT)/511, (338*TPE_FRACTIONS_PER_UNIT)/511,
  194. (343*TPE_FRACTIONS_PER_UNIT)/511, (347*TPE_FRACTIONS_PER_UNIT)/511,
  195. (352*TPE_FRACTIONS_PER_UNIT)/511, (356*TPE_FRACTIONS_PER_UNIT)/511,
  196. (361*TPE_FRACTIONS_PER_UNIT)/511, (365*TPE_FRACTIONS_PER_UNIT)/511,
  197. (370*TPE_FRACTIONS_PER_UNIT)/511, (374*TPE_FRACTIONS_PER_UNIT)/511,
  198. (378*TPE_FRACTIONS_PER_UNIT)/511, (382*TPE_FRACTIONS_PER_UNIT)/511,
  199. (386*TPE_FRACTIONS_PER_UNIT)/511, (391*TPE_FRACTIONS_PER_UNIT)/511,
  200. (395*TPE_FRACTIONS_PER_UNIT)/511, (398*TPE_FRACTIONS_PER_UNIT)/511,
  201. (402*TPE_FRACTIONS_PER_UNIT)/511, (406*TPE_FRACTIONS_PER_UNIT)/511,
  202. (410*TPE_FRACTIONS_PER_UNIT)/511, (414*TPE_FRACTIONS_PER_UNIT)/511,
  203. (417*TPE_FRACTIONS_PER_UNIT)/511, (421*TPE_FRACTIONS_PER_UNIT)/511,
  204. (424*TPE_FRACTIONS_PER_UNIT)/511, (428*TPE_FRACTIONS_PER_UNIT)/511,
  205. (431*TPE_FRACTIONS_PER_UNIT)/511, (435*TPE_FRACTIONS_PER_UNIT)/511,
  206. (438*TPE_FRACTIONS_PER_UNIT)/511, (441*TPE_FRACTIONS_PER_UNIT)/511,
  207. (444*TPE_FRACTIONS_PER_UNIT)/511, (447*TPE_FRACTIONS_PER_UNIT)/511,
  208. (450*TPE_FRACTIONS_PER_UNIT)/511, (453*TPE_FRACTIONS_PER_UNIT)/511,
  209. (456*TPE_FRACTIONS_PER_UNIT)/511, (459*TPE_FRACTIONS_PER_UNIT)/511,
  210. (461*TPE_FRACTIONS_PER_UNIT)/511, (464*TPE_FRACTIONS_PER_UNIT)/511,
  211. (467*TPE_FRACTIONS_PER_UNIT)/511, (469*TPE_FRACTIONS_PER_UNIT)/511,
  212. (472*TPE_FRACTIONS_PER_UNIT)/511, (474*TPE_FRACTIONS_PER_UNIT)/511,
  213. (476*TPE_FRACTIONS_PER_UNIT)/511, (478*TPE_FRACTIONS_PER_UNIT)/511,
  214. (481*TPE_FRACTIONS_PER_UNIT)/511, (483*TPE_FRACTIONS_PER_UNIT)/511,
  215. (485*TPE_FRACTIONS_PER_UNIT)/511, (487*TPE_FRACTIONS_PER_UNIT)/511,
  216. (488*TPE_FRACTIONS_PER_UNIT)/511, (490*TPE_FRACTIONS_PER_UNIT)/511,
  217. (492*TPE_FRACTIONS_PER_UNIT)/511, (494*TPE_FRACTIONS_PER_UNIT)/511,
  218. (495*TPE_FRACTIONS_PER_UNIT)/511, (497*TPE_FRACTIONS_PER_UNIT)/511,
  219. (498*TPE_FRACTIONS_PER_UNIT)/511, (499*TPE_FRACTIONS_PER_UNIT)/511,
  220. (501*TPE_FRACTIONS_PER_UNIT)/511, (502*TPE_FRACTIONS_PER_UNIT)/511,
  221. (503*TPE_FRACTIONS_PER_UNIT)/511, (504*TPE_FRACTIONS_PER_UNIT)/511,
  222. (505*TPE_FRACTIONS_PER_UNIT)/511, (506*TPE_FRACTIONS_PER_UNIT)/511,
  223. (507*TPE_FRACTIONS_PER_UNIT)/511, (507*TPE_FRACTIONS_PER_UNIT)/511,
  224. (508*TPE_FRACTIONS_PER_UNIT)/511, (509*TPE_FRACTIONS_PER_UNIT)/511,
  225. (509*TPE_FRACTIONS_PER_UNIT)/511, (510*TPE_FRACTIONS_PER_UNIT)/511,
  226. (510*TPE_FRACTIONS_PER_UNIT)/511, (510*TPE_FRACTIONS_PER_UNIT)/511,
  227. (510*TPE_FRACTIONS_PER_UNIT)/511, (510*TPE_FRACTIONS_PER_UNIT)/511
  228. };
  229. #define TPE_SIN_TABLE_UNIT_STEP\
  230. (TPE_FRACTIONS_PER_UNIT / (TPE_SIN_TABLE_LENGTH * 4))
  231. TPE_Unit TPE_sqrt(TPE_Unit value)
  232. {
  233. int8_t sign = 1;
  234. if (value < 0)
  235. {
  236. sign = -1;
  237. value *= -1;
  238. }
  239. uint32_t result = 0;
  240. uint32_t a = value;
  241. uint32_t b = 1u << 30;
  242. while (b > a)
  243. b >>= 2;
  244. while (b != 0)
  245. {
  246. if (a >= result + b)
  247. {
  248. a -= result + b;
  249. result = result + 2 * b;
  250. }
  251. b >>= 2;
  252. result >>= 1;
  253. }
  254. return result * sign;
  255. }
  256. TPE_Unit TPE_sin(TPE_Unit x)
  257. {
  258. x = TPE_wrap(x / TPE_SIN_TABLE_UNIT_STEP,TPE_SIN_TABLE_LENGTH * 4);
  259. int8_t positive = 1;
  260. if (x < TPE_SIN_TABLE_LENGTH)
  261. {
  262. }
  263. else if (x < TPE_SIN_TABLE_LENGTH * 2)
  264. {
  265. x = TPE_SIN_TABLE_LENGTH * 2 - x - 1;
  266. }
  267. else if (x < TPE_SIN_TABLE_LENGTH * 3)
  268. {
  269. x = x - TPE_SIN_TABLE_LENGTH * 2;
  270. positive = 0;
  271. }
  272. else
  273. {
  274. x = TPE_SIN_TABLE_LENGTH - (x - TPE_SIN_TABLE_LENGTH * 3) - 1;
  275. positive = 0;
  276. }
  277. return positive ? TPE_sinTable[x] : -1 * TPE_sinTable[x];
  278. }
  279. TPE_Unit TPE_cos(TPE_Unit x)
  280. {
  281. return TPE_sin(x + TPE_FRACTIONS_PER_UNIT / 4);
  282. }
  283. void TPE_initBody(TPE_Body *body)
  284. {
  285. // TODO
  286. // init orientation to identity unit quaternion (1,0,0,0):
  287. body->orientation.x = 0;
  288. body->orientation.y = 0;
  289. body->orientation.z = 0;
  290. body->orientation.w = TPE_FRACTIONS_PER_UNIT;
  291. }
  292. void TPE_quaternionMultiply(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result)
  293. {
  294. result->x =
  295. (a.x * b.x -
  296. a.y * b.y -
  297. a.z * b.z -
  298. a.w * b.w) / TPE_FRACTIONS_PER_UNIT;
  299. result->y =
  300. (a.y * b.x +
  301. a.x * b.y +
  302. a.z * b.w -
  303. a.w * b.z) / TPE_FRACTIONS_PER_UNIT;
  304. result->z =
  305. (a.x * b.z -
  306. a.y * b.w +
  307. a.z * b.x +
  308. a.w * b.y) / TPE_FRACTIONS_PER_UNIT;
  309. result->w =
  310. (a.x * b.w +
  311. a.y * b.z -
  312. a.z * b.y +
  313. a.w * b.x) / TPE_FRACTIONS_PER_UNIT;
  314. }
  315. void TPE_rotationToQuaternion(TPE_Vec4 axis, TPE_Unit angle, TPE_Vec4 *quaternion)
  316. {
  317. TPE_vec3Normalize(&axis);
  318. angle /= 2;
  319. TPE_Unit s = TPE_sin(angle);
  320. quaternion->x = (s * axis.x) / TPE_FRACTIONS_PER_UNIT;
  321. quaternion->y = (s * axis.y) / TPE_FRACTIONS_PER_UNIT;
  322. quaternion->z = (s * axis.z) / TPE_FRACTIONS_PER_UNIT;
  323. quaternion->w = TPE_cos(angle);
  324. }
  325. TPE_Unit TPE_asin(TPE_Unit x)
  326. {
  327. x = TPE_clamp(x,-TPE_FRACTIONS_PER_UNIT,TPE_FRACTIONS_PER_UNIT);
  328. int8_t sign = 1;
  329. if (x < 0)
  330. {
  331. sign = -1;
  332. x *= -1;
  333. }
  334. int16_t low = 0;
  335. int16_t high = TPE_SIN_TABLE_LENGTH -1;
  336. int16_t middle;
  337. while (low <= high) // binary search
  338. {
  339. middle = (low + high) / 2;
  340. TPE_Unit v = TPE_sinTable[middle];
  341. if (v > x)
  342. high = middle - 1;
  343. else if (v < x)
  344. low = middle + 1;
  345. else
  346. break;
  347. }
  348. middle *= TPE_SIN_TABLE_UNIT_STEP;
  349. return sign * middle;
  350. }
  351. TPE_Unit TPE_acos(TPE_Unit x)
  352. {
  353. return TPE_asin(-1 * x) + TPE_FRACTIONS_PER_UNIT / 4;
  354. }
  355. void TPE_quaternionToRotation(TPE_Vec4 quaternion, TPE_Vec4 *axis, TPE_Unit *angle)
  356. {
  357. *angle = 2 * TPE_acos(quaternion.x);
  358. TPE_Unit tmp =
  359. TPE_nonZero(TPE_sqrt(
  360. (TPE_FRACTIONS_PER_UNIT -
  361. (quaternion.x * quaternion.x) / TPE_FRACTIONS_PER_UNIT
  362. ) * TPE_FRACTIONS_PER_UNIT));
  363. axis->x = (quaternion.x * TPE_FRACTIONS_PER_UNIT) / tmp;
  364. axis->y = (quaternion.y * TPE_FRACTIONS_PER_UNIT) / tmp;
  365. axis->z = (quaternion.z * TPE_FRACTIONS_PER_UNIT) / tmp;
  366. }
  367. void TPE_quaternionToRotationMatrix(TPE_Vec4 quaternion, TPE_Unit matrix[4][4])
  368. {
  369. TPE_Unit
  370. _2x2 = (2 * quaternion.x * quaternion.x) / TPE_FRACTIONS_PER_UNIT,
  371. _2y2 = (2 * quaternion.y * quaternion.y) / TPE_FRACTIONS_PER_UNIT,
  372. _2z2 = (2 * quaternion.z * quaternion.z) / TPE_FRACTIONS_PER_UNIT,
  373. _2xy = (2 * quaternion.x * quaternion.y) / TPE_FRACTIONS_PER_UNIT,
  374. _2xw = (2 * quaternion.x * quaternion.w) / TPE_FRACTIONS_PER_UNIT,
  375. _2zw = (2 * quaternion.z * quaternion.w) / TPE_FRACTIONS_PER_UNIT,
  376. _2xz = (2 * quaternion.x * quaternion.z) / TPE_FRACTIONS_PER_UNIT,
  377. _2yw = (2 * quaternion.y * quaternion.w) / TPE_FRACTIONS_PER_UNIT,
  378. _2yz = (2 * quaternion.y * quaternion.z) / TPE_FRACTIONS_PER_UNIT;
  379. #define ONE TPE_FRACTIONS_PER_UNIT
  380. matrix[0][0] = ONE - _2y2 - _2z2;
  381. matrix[1][0] = _2xy - _2zw;
  382. matrix[2][0] = _2xz + _2yw;
  383. matrix[3][0] = 0;
  384. matrix[0][1] = _2xy + _2zw;
  385. matrix[1][1] = ONE - _2x2 - _2z2;
  386. matrix[2][1] = _2yz - _2xw;
  387. matrix[3][1] = 0;
  388. matrix[0][2] = _2xz - _2yw;
  389. matrix[1][2] = _2yz + _2xw;
  390. matrix[2][2] = ONE - _2x2 - _2y2;
  391. matrix[3][2] = 0;
  392. matrix[0][3] = 0;
  393. matrix[1][3] = 0;
  394. matrix[2][3] = 0;
  395. matrix[3][3] = ONE;
  396. #undef ONE
  397. }
  398. void TPE_vec3Add(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result)
  399. {
  400. result->x = a.x + b.x;
  401. result->y = a.y + b.y;
  402. result->z = a.z + b.z;
  403. }
  404. void TPE_vec4Add(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result)
  405. {
  406. result->x = a.x + b.x;
  407. result->y = a.y + b.y;
  408. result->z = a.z + b.z;
  409. result->w = a.w + b.w;
  410. }
  411. void TPE_vec3Substract(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result)
  412. {
  413. result->x = a.x - b.x;
  414. result->y = a.y - b.y;
  415. result->z = a.z - b.z;
  416. }
  417. void TPE_vec4Substract(const TPE_Vec4 a, const TPE_Vec4 b, TPE_Vec4 *result)
  418. {
  419. result->x = a.x - b.x;
  420. result->y = a.y - b.y;
  421. result->z = a.z - b.z;
  422. result->w = a.w - b.w;
  423. }
  424. void TPE_vec3Multiplay(const TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result)
  425. {
  426. result->x = (v.x * f) / TPE_FRACTIONS_PER_UNIT;
  427. result->y = (v.y * f) / TPE_FRACTIONS_PER_UNIT;
  428. result->z = (v.z * f) / TPE_FRACTIONS_PER_UNIT;
  429. }
  430. void TPE_vec4Multiplay(const TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result)
  431. {
  432. result->x = (v.x * f) / TPE_FRACTIONS_PER_UNIT;
  433. result->y = (v.y * f) / TPE_FRACTIONS_PER_UNIT;
  434. result->z = (v.z * f) / TPE_FRACTIONS_PER_UNIT;
  435. result->w = (v.w * f) / TPE_FRACTIONS_PER_UNIT;
  436. }
  437. TPE_Unit TPE_vec3Len(TPE_Vec4 v)
  438. {
  439. return TPE_sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
  440. }
  441. TPE_Unit TPE_vec4Len(TPE_Vec4 v)
  442. {
  443. return TPE_sqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
  444. }
  445. TPE_Unit TPE_vec3DotProduct(const TPE_Vec4 v1, const TPE_Vec4 v2)
  446. {
  447. return
  448. (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z) / TPE_FRACTIONS_PER_UNIT;
  449. }
  450. void TPE_vec3Normalize(TPE_Vec4 *v)
  451. {
  452. TPE_Unit l = TPE_vec3Len(*v);
  453. if (l == 0)
  454. {
  455. v->x = TPE_FRACTIONS_PER_UNIT;
  456. return;
  457. }
  458. v->x = (v->x * TPE_FRACTIONS_PER_UNIT) / l;
  459. v->y = (v->y * TPE_FRACTIONS_PER_UNIT) / l;
  460. v->z = (v->z * TPE_FRACTIONS_PER_UNIT) / l;
  461. }
  462. void TPE_vec4Normalize(TPE_Vec4 v)
  463. {
  464. TPE_Unit l = TPE_vec4Len(v);
  465. if (l == 0)
  466. {
  467. v.x = TPE_FRACTIONS_PER_UNIT;
  468. return;
  469. }
  470. v.x = (v.x * TPE_FRACTIONS_PER_UNIT) / l;
  471. v.y = (v.y * TPE_FRACTIONS_PER_UNIT) / l;
  472. v.z = (v.z * TPE_FRACTIONS_PER_UNIT) / l;
  473. v.w = (v.w * TPE_FRACTIONS_PER_UNIT) / l;
  474. }
  475. void TPE_vec3Project(const TPE_Vec4 v, const TPE_Vec4 base, TPE_Vec4 *result)
  476. {
  477. TPE_Unit p = TPE_vec3DotProduct(v,base);
  478. result->x = (p * base.x) / TPE_FRACTIONS_PER_UNIT;
  479. result->y = (p * base.y) / TPE_FRACTIONS_PER_UNIT;
  480. result->z = (p * base.z) / TPE_FRACTIONS_PER_UNIT;
  481. }
  482. void TPE_getVelocitiesAfterCollision(
  483. TPE_Unit *v1,
  484. TPE_Unit *v2,
  485. TPE_Unit m1,
  486. TPE_Unit m2,
  487. TPE_Unit elasticity
  488. )
  489. {
  490. /* in the following a lot of TPE_FRACTIONS_PER_UNIT cancel out, feel free to
  491. check if confused */
  492. #define ANTI_OVERFLOW 30000
  493. #define ANTI_OVERFLOW_SCALE 128
  494. uint8_t overflowDanger = m1 > ANTI_OVERFLOW || *v1 > ANTI_OVERFLOW ||
  495. m2 > ANTI_OVERFLOW || *v2 > ANTI_OVERFLOW;
  496. if (overflowDanger)
  497. {
  498. m1 = (m1 != 0) ? TPE_nonZero(m1 / ANTI_OVERFLOW_SCALE) : 0;
  499. m2 = (m2 != 0) ? TPE_nonZero(m2 / ANTI_OVERFLOW_SCALE) : 0;
  500. *v1 = (*v1 != 0) ? TPE_nonZero(*v1 / ANTI_OVERFLOW_SCALE) : 0;
  501. *v2 = (*v2 != 0) ? TPE_nonZero(*v2 / ANTI_OVERFLOW_SCALE) : 0;
  502. }
  503. TPE_Unit m1Pm2 = m1 + m2;
  504. TPE_Unit v2Mv1 = *v2 - *v1;
  505. TPE_Unit m1v1Pm2v2 = ((m1 * *v1) + (m2 * *v2));
  506. *v1 = (((elasticity * m2 / TPE_FRACTIONS_PER_UNIT) * v2Mv1)
  507. + m1v1Pm2v2) / m1Pm2;
  508. *v2 = (((elasticity * m1 / TPE_FRACTIONS_PER_UNIT) * -1 * v2Mv1)
  509. + m1v1Pm2v2) / m1Pm2;
  510. if (overflowDanger)
  511. {
  512. *v1 *= ANTI_OVERFLOW_SCALE;
  513. *v2 *= ANTI_OVERFLOW_SCALE;
  514. }
  515. #undef ANTI_OVERFLOW
  516. #undef ANTI_OVERFLOW_SCALE
  517. }
  518. void TPE_resolvePointCollision(
  519. const TPE_Vec4 collisionPoint,
  520. const TPE_Vec4 collisionNormal,
  521. TPE_Unit elasticity,
  522. TPE_Vec4 linVelocity1,
  523. TPE_Vec4 rotVelocity1,
  524. TPE_Unit m1,
  525. TPE_Vec4 linVelocity2,
  526. TPE_Vec4 rotVelocity2,
  527. TPE_Unit m2)
  528. {
  529. TPE_Vec4 v1, v2, v1New, v2New;
  530. TPE_initVec4(&v1);
  531. TPE_initVec4(&v2);
  532. TPE_initVec4(&v1New);
  533. TPE_initVec4(&v2New);
  534. // add lin. and rot. velocities to get the overall vel. of both points:
  535. TPE_vec4Add(linVelocity1,rotVelocity1,&v1);
  536. TPE_vec4Add(linVelocity2,rotVelocity2,&v2);
  537. /* project both of these velocities to the collision normal as we'll apply
  538. the collision equation only in the direction of this normal: */
  539. TPE_vec3Project(v1,collisionNormal,&v1New);
  540. TPE_vec3Project(v2,collisionNormal,&v2New);
  541. // get the velocities of the components
  542. TPE_Unit
  543. v1NewMag = TPE_vec3Len(v1New),
  544. v2NewMag = TPE_vec3Len(v2New);
  545. /* now also substract this component from the original velocity (so that it
  546. will now be in the collision plane), we'll later add back the updated
  547. velocity to it */
  548. TPE_vec4Substract(v1,v1New,&v1);
  549. TPE_vec4Substract(v2,v2New,&v2);
  550. // apply the 1D collision equation to velocities along the normal:
  551. TPE_getVelocitiesAfterCollision(
  552. &v1NewMag,
  553. &v2NewMag,
  554. m1,
  555. m2,
  556. elasticity);
  557. // add back the updated velocities to get the new overall velocities:
  558. v1New.x += (collisionNormal.x * v1NewMag) / TPE_FRACTIONS_PER_UNIT;
  559. v1New.y += (collisionNormal.y * v1NewMag) / TPE_FRACTIONS_PER_UNIT;
  560. v1New.z += (collisionNormal.z * v1NewMag) / TPE_FRACTIONS_PER_UNIT;
  561. v2New.x += (collisionNormal.x * v2NewMag) / TPE_FRACTIONS_PER_UNIT;
  562. v2New.y += (collisionNormal.y * v2NewMag) / TPE_FRACTIONS_PER_UNIT;
  563. v2New.z += (collisionNormal.z * v2NewMag) / TPE_FRACTIONS_PER_UNIT;
  564. // TODO
  565. }
  566. void TPE_bodyGetTransformMatrix(TPE_Body *body, TPE_Unit matrix[4][4])
  567. {
  568. TPE_quaternionToRotationMatrix(body->orientation,matrix);
  569. matrix[3][0] = body->position.x;
  570. matrix[3][1] = body->position.y;
  571. matrix[3][2] = body->position.z;
  572. }
  573. #endif // guard