123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- /* ==========================================================================
- * Copyright (c) 2022 SuperTuxKart-Team
- *
- * 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.
- * ==========================================================================
- */
- #ifndef HEADER_MINI_GLM_HPP
- #define HEADER_MINI_GLM_HPP
- #include "LinearMath/btQuaternion.h"
- #include "LinearMath/btTransform.h"
- #include "LinearMath/btVector3.h"
- #include <algorithm>
- #include <array>
- #include <cassert>
- #include <cmath>
- #include <cstdint>
- #include <quaternion.h>
- #include <vector3d.h>
- #include "irrMath.h"
- using namespace irr;
- // GLM without template
- namespace MiniGLM
- {
- // ------------------------------------------------------------------------
- inline float overflow()
- {
- volatile float f = 1e10;
- for (int i = 0; i < 10; i++)
- f *= f; // this will overflow before the for loop terminates
- return f;
- } // overflow
- // ------------------------------------------------------------------------
- inline float toFloat32(short value)
- {
- int s = (value >> 15) & 0x00000001;
- int e = (value >> 10) & 0x0000001f;
- int m = value & 0x000003ff;
- if (e == 0)
- {
- if (m == 0)
- {
- //
- // Plus or minus zero
- //
- uint32_t tmp_data = (unsigned int)(s << 31);
- float ret;
- memcpy(&ret, &tmp_data, 4);
- return ret;
- }
- else
- {
- //
- // Denormalized number -- renormalize it
- //
- while(!(m & 0x00000400))
- {
- m <<= 1;
- e -= 1;
- }
- e += 1;
- m &= ~0x00000400;
- }
- }
- else if (e == 31)
- {
- if (m == 0)
- {
- //
- // Positive or negative infinity
- //
- uint32_t tmp_data = (unsigned int)((s << 31) | 0x7f800000);
- float ret;
- memcpy(&ret, &tmp_data, 4);
- return ret;
- }
- else
- {
- //
- // Nan -- preserve sign and significand bits
- //
- uint32_t tmp_data = (unsigned int)((s << 31) | 0x7f800000 |
- (m << 13));
- float ret;
- memcpy(&ret, &tmp_data, 4);
- return ret;
- }
- }
- //
- // Normalized number
- //
- e = e + (127 - 15);
- m = m << 13;
- //
- // Assemble s, e and m.
- //
- uint32_t tmp_data = (unsigned int)((s << 31) | (e << 23) | m);
- float ret;
- memcpy(&ret, &tmp_data, 4);
- return ret;
- } // toFloat32
- // ------------------------------------------------------------------------
- inline short toFloat16(float const & f)
- {
- int i;
- memcpy(&i, &f, 4);
- //
- // Our floating point number, f, is represented by the bit
- // pattern in integer i. Disassemble that bit pattern into
- // the sign, s, the exponent, e, and the significand, m.
- // Shift s into the position where it will go in in the
- // resulting half number.
- // Adjust e, accounting for the different exponent bias
- // of float and half (127 versus 15).
- //
- int s = (i >> 16) & 0x00008000;
- int e = ((i >> 23) & 0x000000ff) - (127 - 15);
- int m = i & 0x007fffff;
- //
- // Now reassemble s, e and m into a half:
- //
- if (e <= 0)
- {
- if (e < -10)
- {
- //
- // E is less than -10. The absolute value of f is
- // less than half_MIN (f may be a small normalized
- // float, a denormalized float or a zero).
- //
- // We convert f to a half zero.
- //
- return short(s);
- }
- //
- // E is between -10 and 0. F is a normalized float,
- // whose magnitude is less than __half_NRM_MIN.
- //
- // We convert f to a denormalized half.
- //
- m = (m | 0x00800000) >> (1 - e);
- //
- // Round to nearest, round "0.5" up.
- //
- // Rounding may cause the significand to overflow and make
- // our number normalized. Because of the way a half's bits
- // are laid out, we don't have to treat this case separately;
- // the code below will handle it correctly.
- //
- if (m & 0x00001000)
- m += 0x00002000;
- //
- // Assemble the half from s, e (zero) and m.
- //
- return short(s | (m >> 13));
- }
- else if (e == 0xff - (127 - 15))
- {
- if (m == 0)
- {
- //
- // F is an infinity; convert f to a half
- // infinity with the same sign as f.
- //
- return short(s | 0x7c00);
- }
- else
- {
- //
- // F is a NAN; we produce a half NAN that preserves
- // the sign bit and the 10 leftmost bits of the
- // significand of f, with one exception: If the 10
- // leftmost bits are all zero, the NAN would turn
- // into an infinity, so we have to set at least one
- // bit in the significand.
- //
- m >>= 13;
- return short(s | 0x7c00 | m | (m == 0));
- }
- }
- else
- {
- //
- // E is greater than zero. F is a normalized float.
- // We try to convert f to a normalized half.
- //
- //
- // Round to nearest, round "0.5" up
- //
- if (m & 0x00001000)
- {
- m += 0x00002000;
- if (m & 0x00800000)
- {
- m = 0; // overflow in significand,
- e += 1; // adjust exponent
- }
- }
- //
- // Handle exponent overflow
- //
- if (e > 30)
- {
- overflow(); // Cause a hardware floating point overflow;
- return short(s | 0x7c00);
- // if this returns, the half becomes an
- } // infinity with the same sign as f.
- //
- // Assemble the half from s, e and m.
- //
- return short(s | (e << 10) | (m >> 13));
- }
- } // toFloat16
- // ------------------------------------------------------------------------
- inline uint32_t normalizedSignedFloatsTo1010102
- (const std::array<float, 3>& src, int extra_2_bit = -1)
- {
- int part = 0;
- uint32_t packed = 0;
- float v = fminf(1.0f, fmaxf(-1.0f, src[0]));
- if (v > 0.0f)
- {
- part = (int)((v * 511.0f) + 0.5f);
- }
- else
- {
- part = (int)((v * 512.0f) - 0.5f);
- }
- packed |= ((uint32_t)part & 1023) << 0;
- v = fminf(1.0f, fmaxf(-1.0f, src[1]));
- if (v > 0.0f)
- {
- part = (int)((v * 511.0f) + 0.5f);
- }
- else
- {
- part = (int)((v * 512.0f) - 0.5f);
- }
- packed |= ((uint32_t)part & 1023) << 10;
- v = fminf(1.0f, fmaxf(-1.0f, src[2]));
- if (v > 0.0f)
- {
- part = (int)((v * 511.0f) + 0.5f);
- }
- else
- {
- part = (int)((v * 512.0f) - 0.5f);
- }
- packed |= ((uint32_t)part & 1023) << 20;
- if (extra_2_bit >= 0)
- {
- part = extra_2_bit;
- }
- else
- {
- part = (int)(-0.5f);
- }
- packed |= ((uint32_t)part & 3) << 30;
- return packed;
- } // normalizedSignedFloatsTo1010102
- // ------------------------------------------------------------------------
- inline std::array<short, 4> vertexType2101010RevTo4HF(uint32_t packed)
- {
- std::array<float, 4> ret;
- int part = packed & 1023;
- if (part & 512)
- {
- ret[0] = (float)(1024 - part) * (-1.0f / 512.0f);
- }
- else
- {
- ret[0] = (float)part * (1.0f / 511.0f);
- }
- part = (packed >> 10) & 1023;
- if (part & 512)
- {
- ret[1] = (float)(1024 - part) * (-1.0f / 512.0f);
- }
- else
- {
- ret[1] = (float)part * (1.0f / 511.0f);
- }
- part = (packed >> 20) & 1023;
- if (part & 512)
- {
- ret[2] = (float)(1024 - part) * (-1.0f / 512.0f);
- }
- else
- {
- ret[2] = (float)part * (1.0f / 511.0f);
- }
- part = (packed >> 30) & 3;
- if (part & 2)
- {
- ret[3] = (float)(4 - part) * (-1.0f / 2.0f);
- }
- else
- {
- ret[3] = (float)part;
- }
- std::array<short, 4> result;
- for (int i = 0; i < 4; i++)
- {
- result[i] = toFloat16(ret[i]);
- }
- return result;
- } // vertexType2101010RevTo4HF
- // ------------------------------------------------------------------------
- inline std::array<float, 4> extractNormalizedSignedFloats(uint32_t packed,
- bool calculate_w = false)
- {
- std::array<float, 4> ret = {};
- int part = packed & 1023;
- if (part & 512)
- {
- ret[0] = (float)(1024 - part) * (-1.0f / 512.0f);
- }
- else
- {
- ret[0] = (float)part * (1.0f / 511.0f);
- }
- part = (packed >> 10) & 1023;
- if (part & 512)
- {
- ret[1] = (float)(1024 - part) * (-1.0f / 512.0f);
- }
- else
- {
- ret[1] = (float)part * (1.0f / 511.0f);
- }
- part = (packed >> 20) & 1023;
- if (part & 512)
- {
- ret[2] = (float)(1024 - part) * (-1.0f / 512.0f);
- }
- else
- {
- ret[2] = (float)part * (1.0f / 511.0f);
- }
- if (calculate_w)
- {
- float inv_sqrt_2 = 1.0f / sqrtf(2.0f);
- ret[0] *= inv_sqrt_2;
- ret[1] *= inv_sqrt_2;
- ret[2] *= inv_sqrt_2;
- float largest_val = sqrtf(fmaxf(0.0f, 1.0f -
- (ret[0] * ret[0]) - (ret[1] * ret[1]) - (ret[2] * ret[2])));
- part = (packed >> 30) & 3;
- switch(part)
- {
- case 0:
- {
- auto tmp = ret;
- ret[0] = largest_val;
- ret[1] = tmp[0];
- ret[2] = tmp[1];
- ret[3] = tmp[2];
- break;
- }
- case 1:
- {
- auto tmp = ret;
- ret[0] = tmp[0];
- ret[1] = largest_val;
- ret[2] = tmp[1];
- ret[3] = tmp[2];
- break;
- }
- case 2:
- {
- auto tmp = ret;
- ret[0] = tmp[0];
- ret[1] = tmp[1];
- ret[2] = largest_val;
- ret[3] = tmp[2];
- break;
- }
- case 3:
- ret[3] = largest_val;
- break;
- default:
- assert(false);
- break;
- }
- }
- return ret;
- } // extractNormalizedSignedFloats
- // ------------------------------------------------------------------------
- // Please normalize vector before compressing
- // ------------------------------------------------------------------------
- inline uint32_t compressVector3(const irr::core::vector3df& vec)
- {
- return normalizedSignedFloatsTo1010102({{vec.X, vec.Y, vec.Z}});
- } // compressVector3
- // ------------------------------------------------------------------------
- inline core::vector3df decompressVector3(uint32_t packed)
- {
- const std::array<float, 4> out = extractNormalizedSignedFloats(packed);
- core::vector3df ret(out[0], out[1], out[2]);
- return ret.normalize();
- } // decompressVector3
- // ------------------------------------------------------------------------
- inline uint32_t compressQuaternion(const btQuaternion& q)
- {
- const float length = q.length();
- assert(length != 0.0f);
- std::array<float, 4> tmp_2 =
- {{
- q.x() / length,
- q.y() / length,
- q.z() / length,
- q.w() / length
- }};
- std::array<float, 3> tmp_3 = {};
- auto ret = std::max_element(tmp_2.begin(), tmp_2.end(),
- [](float a, float b) { return std::abs(a) < std::abs(b); });
- int extra_2_bit = int(std::distance(tmp_2.begin(), ret));
- float sqrt_2 = sqrtf(2.0f);
- switch (extra_2_bit)
- {
- case 0:
- {
- float neg = tmp_2[0] < 0.0f ? -1.0f : 1.0f;
- tmp_3[0] = tmp_2[1] * neg * sqrt_2;
- tmp_3[1] = tmp_2[2] * neg * sqrt_2;
- tmp_3[2] = tmp_2[3] * neg * sqrt_2;
- break;
- }
- case 1:
- {
- float neg = tmp_2[1] < 0.0f ? -1.0f : 1.0f;
- tmp_3[0] = tmp_2[0] * neg * sqrt_2;
- tmp_3[1] = tmp_2[2] * neg * sqrt_2;
- tmp_3[2] = tmp_2[3] * neg * sqrt_2;
- break;
- }
- case 2:
- {
- float neg = tmp_2[2] < 0.0f ? -1.0f : 1.0f;
- tmp_3[0] = tmp_2[0] * neg * sqrt_2;
- tmp_3[1] = tmp_2[1] * neg * sqrt_2;
- tmp_3[2] = tmp_2[3] * neg * sqrt_2;
- break;
- }
- case 3:
- {
- float neg = tmp_2[3] < 0.0f ? -1.0f : 1.0f;
- tmp_3[0] = tmp_2[0] * neg * sqrt_2;
- tmp_3[1] = tmp_2[1] * neg * sqrt_2;
- tmp_3[2] = tmp_2[2] * neg * sqrt_2;
- break;
- }
- default:
- assert(false);
- break;
- }
- return normalizedSignedFloatsTo1010102(tmp_3, extra_2_bit);
- } // compressQuaternion
- // ------------------------------------------------------------------------
- inline uint32_t compressIrrQuaternion(const core::quaternion& q)
- {
- return compressQuaternion(btQuaternion(q.X, q.Y, q.Z, q.W));
- }
- // ------------------------------------------------------------------------
- inline core::quaternion decompressQuaternion(uint32_t packed)
- {
- const std::array<float, 4> out = extractNormalizedSignedFloats(packed,
- true/*calculate_w*/);
- core::quaternion ret(out[0], out[1], out[2], out[3]);
- return ret.normalize();
- } // decompressQuaternion
- // ------------------------------------------------------------------------
- inline btQuaternion decompressbtQuaternion(uint32_t packed)
- {
- const std::array<float, 4> out = extractNormalizedSignedFloats(packed,
- true/*calculate_w*/);
- btQuaternion ret(out[0], out[1], out[2], out[3]);
- return ret.normalize();
- } // decompressbtQuaternion
- // ------------------------------------------------------------------------
- inline std::array<float, 4> getQuaternionInternal(const core::matrix4& m)
- {
- btVector3 row[3];
- memcpy(&row[0][0], &m[0], 12);
- memcpy(&row[1][0], &m[4], 12);
- memcpy(&row[2][0], &m[8], 12);
- std::array<float, 4> q;
- float root = row[0].x() + row[1].y() + row[2].z();
- const float trace = root;
- if (trace > 0.0f)
- {
- root = sqrtf(trace + 1.0f);
- q[3] = 0.5f * root;
- root = 0.5f / root;
- q[0] = root * (row[1].z() - row[2].y());
- q[1] = root * (row[2].x() - row[0].z());
- q[2] = root * (row[0].y() - row[1].x());
- }
- else
- {
- static int next[3] = {1, 2, 0};
- int i = 0;
- int j = 0;
- int k = 0;
- if (row[1].y() > row[0].x())
- {
- i = 1;
- }
- if (row[2].z() > row[i][i])
- {
- i = 2;
- }
- j = next[i];
- k = next[j];
- root = sqrtf(row[i][i] - row[j][j] - row[k][k] + 1.0f);
- q[i] = 0.5f * root;
- root = 0.5f / root;
- q[j] = root * (row[i][j] + row[j][i]);
- q[k] = root * (row[i][k] + row[k][i]);
- q[3] = root * (row[j][k] - row[k][j]);
- }
- return q;
- }
- // ------------------------------------------------------------------------
- inline core::quaternion getQuaternion(const core::matrix4& m)
- {
- std::array<float, 4> q = getQuaternionInternal(m);
- return core::quaternion(q[0], q[1], q[2], q[3]).normalize();
- }
- // ------------------------------------------------------------------------
- inline btQuaternion getBulletQuaternion(const core::matrix4& m)
- {
- std::array<float, 4> q = getQuaternionInternal(m);
- return btQuaternion(q[0], q[1], q[2], q[3]).normalize();
- }
- // ------------------------------------------------------------------------
- inline uint32_t quickTangent(uint32_t packed_normal)
- {
- core::vector3df normal = decompressVector3(packed_normal);
- core::vector3df tangent;
- core::vector3df c1 =
- normal.crossProduct(core::vector3df(0.0f, 0.0f, 1.0f));
- core::vector3df c2 =
- normal.crossProduct(core::vector3df(0.0f, 1.0f, 0.0f));
- if (c1.getLengthSQ() > c2.getLengthSQ())
- {
- tangent = c1;
- }
- else
- {
- tangent = c2;
- }
- tangent.normalize();
- // Assume bitangent sign is positive 1.0f
- return compressVector3(tangent) | 1 << 30;
- } // quickTangent
- // ------------------------------------------------------------------------
- /** Round and save compressed values (optionally) btTransform.
- * It will round with 2 digits with min / max +/- 2^23 / 100 for origin in
- * btTransform and call compressQuaternion above to compress the rotation
- * part, if compressed_data is provided, 3 24 bits and 1 32 bits of
- * compressed data will be written in an int[4] array.
- */
- inline void compressbtTransform(btTransform& cur_t,
- int* compressed_data = NULL)
- {
- int x = (int)(cur_t.getOrigin().x() * 100.0f);
- int y = (int)(cur_t.getOrigin().y() * 100.0f);
- int z = (int)(cur_t.getOrigin().z() * 100.0f);
- x = core::clamp(x, -0x800000, 0x7fffff);
- y = core::clamp(y, -0x800000, 0x7fffff);
- z = core::clamp(z, -0x800000, 0x7fffff);
- uint32_t compressed_q = compressQuaternion(cur_t.getRotation());
- cur_t.setOrigin(btVector3(
- (float)x / 100.0f,
- (float)y / 100.0f,
- (float)z / 100.0f));
- cur_t.setRotation(decompressbtQuaternion(compressed_q));
- if (compressed_data)
- {
- compressed_data[0] = x;
- compressed_data[1] = y;
- compressed_data[2] = z;
- compressed_data[3] = (int)compressed_q;
- }
- } // compressbtTransform
- // ------------------------------------------------------------------------
- inline btTransform decompressbtTransform(int* compressed_data)
- {
- btTransform trans;
- trans.setOrigin(btVector3(
- (float)compressed_data[0] / 100.0f,
- (float)compressed_data[1] / 100.0f,
- (float)compressed_data[2] / 100.0f));
- trans.setRotation(decompressbtQuaternion(
- (uint32_t)compressed_data[3]));
- return trans;
- } // decompressbtTransform
- // ------------------------------------------------------------------------
- void unitTesting();
- }
- #endif
|