q_vec3.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. #pragma once
  4. // q_vec3 - vec3 stuff
  5. #include <stdexcept>
  6. #include <type_traits>
  7. using nullptr_t = std::nullptr_t;
  8. struct vec3_t
  9. {
  10. float x, y, z;
  11. [[nodiscard]] constexpr const float &operator[](size_t i) const
  12. {
  13. if (i == 0)
  14. return x;
  15. else if (i == 1)
  16. return y;
  17. else if (i == 2)
  18. return z;
  19. throw std::out_of_range("i");
  20. }
  21. [[nodiscard]] constexpr float &operator[](size_t i)
  22. {
  23. if (i == 0)
  24. return x;
  25. else if (i == 1)
  26. return y;
  27. else if (i == 2)
  28. return z;
  29. throw std::out_of_range("i");
  30. }
  31. // comparison
  32. [[nodiscard]] constexpr bool equals(const vec3_t &v) const
  33. {
  34. return x == v.x && y == v.y && z == v.z;
  35. }
  36. [[nodiscard]] inline bool equals(const vec3_t &v, const float &epsilon) const
  37. {
  38. return fabsf(x - v.x) <= epsilon && fabsf(y - v.y) <= epsilon && fabsf(z - v.z) <= epsilon;
  39. }
  40. [[nodiscard]] constexpr bool operator==(const vec3_t &v) const
  41. {
  42. return equals(v);
  43. }
  44. [[nodiscard]] constexpr bool operator!=(const vec3_t &v) const
  45. {
  46. return !(*this == v);
  47. }
  48. [[nodiscard]] constexpr explicit operator bool() const
  49. {
  50. return x || y || z;
  51. }
  52. // dot
  53. [[nodiscard]] constexpr float dot(const vec3_t &v) const
  54. {
  55. return (x * v.x) + (y * v.y) + (z * v.z);
  56. }
  57. [[nodiscard]] constexpr vec3_t scaled(const vec3_t &v) const
  58. {
  59. return { x * v.x, y * v.y, z * v.z };
  60. }
  61. constexpr vec3_t &scale(const vec3_t &v)
  62. {
  63. *this = this->scaled(v);
  64. return *this;
  65. }
  66. // basic operators
  67. [[nodiscard]] constexpr vec3_t operator-(const vec3_t &v) const
  68. {
  69. return { x - v.x, y - v.y, z - v.z };
  70. }
  71. [[nodiscard]] constexpr vec3_t operator+(const vec3_t &v) const
  72. {
  73. return { x + v.x, y + v.y, z + v.z };
  74. }
  75. [[nodiscard]] constexpr vec3_t operator/(const vec3_t &v) const
  76. {
  77. return { x / v.x, y / v.y, z / v.z };
  78. }
  79. template<typename T, typename = std::enable_if_t<std::is_floating_point_v<T> || std::is_integral_v<T>>>
  80. [[nodiscard]] constexpr vec3_t operator/(const T &v) const
  81. {
  82. return { static_cast<float>(x / v), static_cast<float>(y / v), static_cast<float>(z / v) };
  83. }
  84. template<typename T, typename = std::enable_if_t<std::is_floating_point_v<T> || std::is_integral_v<T>>>
  85. [[nodiscard]] constexpr vec3_t operator*(const T &v) const
  86. {
  87. return { static_cast<float>(x * v), static_cast<float>(y * v), static_cast<float>(z * v) };
  88. }
  89. [[nodiscard]] constexpr vec3_t operator-() const
  90. {
  91. return { -x, -y, -z };
  92. }
  93. constexpr vec3_t &operator-=(const vec3_t &v)
  94. {
  95. *this = *this - v;
  96. return *this;
  97. }
  98. constexpr vec3_t &operator+=(const vec3_t &v)
  99. {
  100. *this = *this + v;
  101. return *this;
  102. }
  103. constexpr vec3_t &operator/=(const vec3_t &v)
  104. {
  105. *this = *this / v;
  106. return *this;
  107. }
  108. template<typename T, typename = std::enable_if_t<std::is_floating_point_v<T> || std::is_integral_v<T>>>
  109. constexpr vec3_t &operator/=(const T &v)
  110. {
  111. *this = *this / v;
  112. return *this;
  113. }
  114. template<typename T, typename = std::enable_if_t<std::is_floating_point_v<T> || std::is_integral_v<T>>>
  115. constexpr vec3_t &operator*=(const T &v)
  116. {
  117. *this = *this * v;
  118. return *this;
  119. }
  120. // operations
  121. [[nodiscard]] constexpr float lengthSquared() const
  122. {
  123. return this->dot(*this);
  124. }
  125. [[nodiscard]] inline float length() const
  126. {
  127. return sqrtf(lengthSquared());
  128. }
  129. [[nodiscard]] inline vec3_t normalized() const
  130. {
  131. float len = length();
  132. return len ? (*this * (1.f / len)) : *this;
  133. }
  134. [[nodiscard]] inline vec3_t normalized(float &len) const
  135. {
  136. len = length();
  137. return len ? (*this * (1.f / len)) : *this;
  138. }
  139. inline float normalize()
  140. {
  141. float len = length();
  142. if (len)
  143. *this *= (1.f / len);
  144. return len;
  145. }
  146. [[nodiscard]] constexpr vec3_t cross(const vec3_t &v) const
  147. {
  148. return {
  149. y * v.z - z * v.y,
  150. z * v.x - x * v.z,
  151. x * v.y - y * v.x
  152. };
  153. }
  154. };
  155. constexpr vec3_t vec3_origin{};
  156. inline void AngleVectors(const vec3_t &angles, vec3_t *forward, vec3_t *right, vec3_t *up)
  157. {
  158. float angle = angles[YAW] * (PIf * 2 / 360);
  159. float sy = sinf(angle);
  160. float cy = cosf(angle);
  161. angle = angles[PITCH] * (PIf * 2 / 360);
  162. float sp = sinf(angle);
  163. float cp = cosf(angle);
  164. angle = angles[ROLL] * (PIf * 2 / 360);
  165. float sr = sinf(angle);
  166. float cr = cosf(angle);
  167. if (forward)
  168. {
  169. forward->x = cp * cy;
  170. forward->y = cp * sy;
  171. forward->z = -sp;
  172. }
  173. if (right)
  174. {
  175. right->x = (-1 * sr * sp * cy + -1 * cr * -sy);
  176. right->y = (-1 * sr * sp * sy + -1 * cr * cy);
  177. right->z = -1 * sr * cp;
  178. }
  179. if (up)
  180. {
  181. up->x = (cr * sp * cy + -sr * -sy);
  182. up->y = (cr * sp * sy + -sr * cy);
  183. up->z = cr * cp;
  184. }
  185. }
  186. struct angle_vectors_t {
  187. vec3_t forward, right, up;
  188. };
  189. // for destructuring
  190. inline angle_vectors_t AngleVectors(const vec3_t &angles)
  191. {
  192. angle_vectors_t v;
  193. AngleVectors(angles, &v.forward, &v.right, &v.up);
  194. return v;
  195. }
  196. // silly wrappers to allow old C code to work
  197. inline void AngleVectors(const vec3_t &angles, vec3_t &forward, vec3_t &right, vec3_t &up)
  198. {
  199. AngleVectors(angles, &forward, &right, &up);
  200. }
  201. inline void AngleVectors(const vec3_t &angles, vec3_t &forward, vec3_t &right, nullptr_t)
  202. {
  203. AngleVectors(angles, &forward, &right, nullptr);
  204. }
  205. inline void AngleVectors(const vec3_t &angles, vec3_t &forward, nullptr_t, vec3_t &up)
  206. {
  207. AngleVectors(angles, &forward, nullptr, &up);
  208. }
  209. inline void AngleVectors(const vec3_t &angles, vec3_t &forward, nullptr_t, nullptr_t)
  210. {
  211. AngleVectors(angles, &forward, nullptr, nullptr);
  212. }
  213. inline void AngleVectors(const vec3_t &angles, nullptr_t, nullptr_t, vec3_t &up)
  214. {
  215. AngleVectors(angles, nullptr, nullptr, &up);
  216. }
  217. inline void AngleVectors(const vec3_t &angles, nullptr_t, vec3_t &right, nullptr_t)
  218. {
  219. AngleVectors(angles, nullptr, &right, nullptr);
  220. }
  221. inline void ClearBounds(vec3_t &mins, vec3_t &maxs)
  222. {
  223. mins[0] = mins[1] = mins[2] = std::numeric_limits<float>::infinity();
  224. maxs[0] = maxs[1] = maxs[2] = -std::numeric_limits<float>::infinity();
  225. }
  226. inline void AddPointToBounds(const vec3_t &v, vec3_t &mins, vec3_t &maxs)
  227. {
  228. for (int i = 0; i < 3; i++)
  229. {
  230. float val = v[i];
  231. if (val < mins[i])
  232. mins[i] = val;
  233. if (val > maxs[i])
  234. maxs[i] = val;
  235. }
  236. }
  237. [[nodiscard]] constexpr vec3_t ProjectPointOnPlane(const vec3_t &p, const vec3_t &normal)
  238. {
  239. float inv_denom = 1.0f / normal.dot(normal);
  240. float d = normal.dot(p) * inv_denom;
  241. return p - ((normal * inv_denom) * d);
  242. }
  243. /*
  244. ** assumes "src" is normalized
  245. */
  246. [[nodiscard]] inline vec3_t PerpendicularVector(const vec3_t &src)
  247. {
  248. int pos;
  249. int i;
  250. float minelem = 1.0F;
  251. vec3_t tempvec;
  252. /*
  253. ** find the smallest magnitude axially aligned vector
  254. */
  255. for (pos = 0, i = 0; i < 3; i++)
  256. {
  257. if (fabsf(src[i]) < minelem)
  258. {
  259. pos = i;
  260. minelem = fabsf(src[i]);
  261. }
  262. }
  263. tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
  264. tempvec[pos] = 1.0F;
  265. /*
  266. ** project the point onto the plane defined by src & normalize the result
  267. */
  268. return ProjectPointOnPlane(tempvec, src).normalized();
  269. }
  270. using mat3_t = std::array<std::array<float, 3>, 3>;
  271. /*
  272. ================
  273. R_ConcatRotations
  274. ================
  275. */
  276. [[nodiscard]] constexpr mat3_t R_ConcatRotations(const mat3_t &in1, const mat3_t &in2)
  277. {
  278. return {
  279. std::array<float, 3> {
  280. in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0],
  281. in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1],
  282. in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]
  283. },
  284. {
  285. in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0],
  286. in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1],
  287. in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2]
  288. },
  289. {
  290. in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0],
  291. in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1],
  292. in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]
  293. }
  294. };
  295. }
  296. [[nodiscard]] inline vec3_t RotatePointAroundVector(const vec3_t &dir, const vec3_t &point, float degrees)
  297. {
  298. mat3_t m;
  299. mat3_t im;
  300. mat3_t zrot;
  301. mat3_t rot;
  302. vec3_t vr, vup, vf;
  303. vf = dir;
  304. vr = PerpendicularVector(dir);
  305. vup = vr.cross(vf);
  306. m[0][0] = vr[0];
  307. m[1][0] = vr[1];
  308. m[2][0] = vr[2];
  309. m[0][1] = vup[0];
  310. m[1][1] = vup[1];
  311. m[2][1] = vup[2];
  312. m[0][2] = vf[0];
  313. m[1][2] = vf[1];
  314. m[2][2] = vf[2];
  315. im = m;
  316. im[0][1] = m[1][0];
  317. im[0][2] = m[2][0];
  318. im[1][0] = m[0][1];
  319. im[1][2] = m[2][1];
  320. im[2][0] = m[0][2];
  321. im[2][1] = m[1][2];
  322. zrot = {};
  323. zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
  324. zrot[0][0] = cosf(DEG2RAD(degrees));
  325. zrot[0][1] = sinf(DEG2RAD(degrees));
  326. zrot[1][0] = -sinf(DEG2RAD(degrees));
  327. zrot[1][1] = cosf(DEG2RAD(degrees));
  328. rot = R_ConcatRotations(R_ConcatRotations(m, zrot), im);
  329. return {
  330. rot[0][0] * point[0] + rot[0][1] * point[1] + rot[0][2] * point[2],
  331. rot[1][0] * point[0] + rot[1][1] * point[1] + rot[1][2] * point[2],
  332. rot[2][0] * point[0] + rot[2][1] * point[1] + rot[2][2] * point[2]
  333. };
  334. }
  335. [[nodiscard]] constexpr vec3_t closest_point_to_box(const vec3_t &from, const vec3_t &absmins, const vec3_t &absmaxs)
  336. {
  337. return {
  338. (from[0] < absmins[0]) ? absmins[0] : (from[0] > absmaxs[0]) ? absmaxs[0] : from[0],
  339. (from[1] < absmins[1]) ? absmins[1] : (from[1] > absmaxs[1]) ? absmaxs[1] : from[1],
  340. (from[2] < absmins[2]) ? absmins[2] : (from[2] > absmaxs[2]) ? absmaxs[2] : from[2]
  341. };
  342. }
  343. [[nodiscard]] inline float distance_between_boxes(const vec3_t &absminsa, const vec3_t &absmaxsa, const vec3_t &absminsb, const vec3_t &absmaxsb)
  344. {
  345. float len = 0;
  346. for (size_t i = 0; i < 3; i++)
  347. {
  348. if (absmaxsa[i] < absminsb[i])
  349. {
  350. float d = absmaxsa[i] - absminsb[i];
  351. len += d * d;
  352. }
  353. else if (absminsa[i] > absmaxsb[i])
  354. {
  355. float d = absminsa[i] - absmaxsb[i];
  356. len += d * d;
  357. }
  358. }
  359. return sqrt(len);
  360. }
  361. [[nodiscard]] constexpr bool boxes_intersect(const vec3_t &amins, const vec3_t &amaxs, const vec3_t &bmins, const vec3_t &bmaxs)
  362. {
  363. return amins.x <= bmaxs.x &&
  364. amaxs.x >= bmins.x &&
  365. amins.y <= bmaxs.y &&
  366. amaxs.y >= bmins.y &&
  367. amins.z <= bmaxs.z &&
  368. amaxs.z >= bmins.z;
  369. }
  370. /*
  371. ==================
  372. ClipVelocity
  373. Slide off of the impacting object
  374. ==================
  375. */
  376. constexpr float STOP_EPSILON = 0.1f;
  377. [[nodiscard]] constexpr vec3_t ClipVelocity(const vec3_t &in, const vec3_t &normal, float overbounce)
  378. {
  379. float dot = in.dot(normal);
  380. vec3_t out = in + (normal * (-2 * dot));
  381. out *= overbounce - 1.f;
  382. if (out.lengthSquared() < STOP_EPSILON * STOP_EPSILON)
  383. out = {};
  384. return out;
  385. }
  386. [[nodiscard]] constexpr vec3_t SlideClipVelocity(const vec3_t &in, const vec3_t &normal, float overbounce)
  387. {
  388. float backoff = in.dot(normal) * overbounce;
  389. vec3_t out = in - (normal * backoff);
  390. for (int i = 0; i < 3; i++)
  391. if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
  392. out[i] = 0;
  393. return out;
  394. }
  395. [[nodiscard]] inline float vectoyaw(const vec3_t &vec)
  396. {
  397. // PMM - fixed to correct for pitch of 0
  398. if (vec[PITCH] == 0)
  399. {
  400. if (vec[YAW] == 0)
  401. return 0.f;
  402. else if (vec[YAW] > 0)
  403. return 90.f;
  404. else
  405. return 270.f;
  406. }
  407. float yaw = (atan2(vec[YAW], vec[PITCH]) * (180.f / PIf));
  408. if (yaw < 0)
  409. yaw += 360;
  410. return yaw;
  411. }
  412. [[nodiscard]] inline vec3_t vectoangles(const vec3_t &vec)
  413. {
  414. float forward;
  415. float yaw, pitch;
  416. if (vec[1] == 0 && vec[0] == 0)
  417. {
  418. if (vec[2] > 0)
  419. return { -90.f, 0.f, 0.f };
  420. else
  421. return { -270.f, 0.f, 0.f };
  422. }
  423. // PMM - fixed to correct for pitch of 0
  424. if (vec[0])
  425. yaw = (atan2(vec[1], vec[0]) * (180.f / PIf));
  426. else if (vec[1] > 0)
  427. yaw = 90;
  428. else
  429. yaw = 270;
  430. if (yaw < 0)
  431. yaw += 360;
  432. forward = sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
  433. pitch = (atan2(vec[2], forward) * (180.f / PIf));
  434. if (pitch < 0)
  435. pitch += 360;
  436. return { -pitch, yaw, 0 };
  437. }
  438. [[nodiscard]] constexpr vec3_t G_ProjectSource(const vec3_t &point, const vec3_t &distance, const vec3_t &forward, const vec3_t &right)
  439. {
  440. return point + (forward * distance[0]) + (right * distance[1]) + vec3_t{0.f, 0.f, distance[2]};
  441. }
  442. [[nodiscard]] constexpr vec3_t G_ProjectSource2(const vec3_t &point, const vec3_t &distance, const vec3_t &forward, const vec3_t &right, const vec3_t &up)
  443. {
  444. return point + (forward * distance[0]) + (right * distance[1]) + (up * distance[2]);
  445. }
  446. [[nodiscard]] inline vec3_t slerp(const vec3_t &from, const vec3_t &to, float t)
  447. {
  448. float dot = from.dot(to);
  449. float aFactor;
  450. float bFactor;
  451. if (fabsf(dot) > 0.9995f)
  452. {
  453. aFactor = 1.0f - t;
  454. bFactor = t;
  455. }
  456. else
  457. {
  458. float ang = acos(dot);
  459. float sinOmega = sin(ang);
  460. float sinAOmega = sin((1.0f - t) * ang);
  461. float sinBOmega = sin(t * ang);
  462. aFactor = sinAOmega / sinOmega;
  463. bFactor = sinBOmega / sinOmega;
  464. }
  465. return from * aFactor + to * bFactor;
  466. }
  467. // Fmt support
  468. template<>
  469. struct fmt::formatter<vec3_t> : fmt::formatter<float>
  470. {
  471. template<typename FormatContext>
  472. auto format(const vec3_t &p, FormatContext &ctx) -> decltype(ctx.out())
  473. {
  474. auto out = fmt::formatter<float>::format(p.x, ctx);
  475. out = fmt::format_to(out, " ");
  476. ctx.advance_to(out);
  477. out = fmt::formatter<float>::format(p.y, ctx);
  478. out = fmt::format_to(out, " ");
  479. ctx.advance_to(out);
  480. return fmt::formatter<float>::format(p.z, ctx);
  481. }
  482. };