zeus/src/Math.cpp

292 lines
7.5 KiB
C++
Raw Normal View History

2016-03-04 15:03:26 -08:00
#include "zeus/Math.hpp"
#include <cfloat>
#include <cmath>
#include <cstring>
2016-03-04 15:03:26 -08:00
#include "zeus/CTransform.hpp"
#include "zeus/CVector2f.hpp"
#include "zeus/CVector3f.hpp"
2018-12-07 17:16:50 -08:00
2015-11-10 12:02:25 -08:00
#if _WIN32
#include <intrin.h>
2020-05-01 16:20:31 -07:00
#elif __x86_64__
2015-11-02 10:44:46 -08:00
#include <cpuid.h>
2015-11-10 12:02:25 -08:00
#endif
2015-04-19 13:39:16 -07:00
2018-12-07 17:16:50 -08:00
namespace zeus {
2015-11-02 10:44:46 -08:00
static bool isCPUInit = false;
static CPUInfo g_cpuFeatures = {};
static CPUInfo g_missingFeatures = {};
2015-11-02 10:44:46 -08:00
2018-12-07 17:16:50 -08:00
void getCpuInfo(int eax, int regs[4]) {
#if defined(__x86_64__) || defined(_M_X64)
2020-05-01 16:20:31 -07:00
#if _WIN32
2018-12-07 17:16:50 -08:00
__cpuid(regs, eax);
2015-11-02 10:44:46 -08:00
#else
2018-12-07 17:16:50 -08:00
__cpuid(eax, regs[0], regs[1], regs[2], regs[3]);
2017-12-26 16:47:31 -08:00
#endif
#endif
}
2018-12-07 17:16:50 -08:00
void getCpuInfoEx(int eax, int ecx, int regs[4]) {
#if defined(__x86_64__) || defined(_M_X64)
2020-05-01 16:20:31 -07:00
#if _WIN32
2018-12-07 17:16:50 -08:00
__cpuidex(regs, eax, ecx);
2017-12-26 16:47:31 -08:00
#else
2018-12-07 17:16:50 -08:00
__cpuid_count(eax, ecx, regs[0], regs[1], regs[2], regs[3]);
2015-11-02 10:44:46 -08:00
#endif
#endif
}
2018-12-07 17:16:50 -08:00
void detectCPU() {
#if defined(__x86_64__) || defined(_M_X64)
2018-12-07 17:16:50 -08:00
if (isCPUInit)
return;
int regs[4];
getCpuInfo(0, regs);
int highestFeature = regs[0];
2018-12-07 21:23:50 -08:00
*reinterpret_cast<int*>((char*)g_cpuFeatures.cpuVendor) = regs[1];
*reinterpret_cast<int*>((char*)g_cpuFeatures.cpuVendor + 4) = regs[3];
*reinterpret_cast<int*>((char*)g_cpuFeatures.cpuVendor + 8) = regs[2];
2018-12-07 17:16:50 -08:00
getCpuInfo(0x80000000, regs);
2019-12-10 14:09:24 -08:00
int maxExtended = regs[0];
if (maxExtended >= 0x80000004) {
2018-12-07 17:16:50 -08:00
for (unsigned int i = 0x80000002; i <= 0x80000004; i++) {
getCpuInfo(i, regs);
// Interpret CPU brand string and cache information.
if (i == 0x80000002)
2018-12-07 21:23:50 -08:00
memcpy((char*)g_cpuFeatures.cpuBrand, regs, sizeof(regs));
2018-12-07 17:16:50 -08:00
else if (i == 0x80000003)
2018-12-07 21:23:50 -08:00
memcpy((char*)g_cpuFeatures.cpuBrand + 16, regs, sizeof(regs));
2018-12-07 17:16:50 -08:00
else if (i == 0x80000004)
2018-12-07 21:23:50 -08:00
memcpy((char*)g_cpuFeatures.cpuBrand + 32, regs, sizeof(regs));
}
2018-12-07 17:16:50 -08:00
}
if (highestFeature >= 1) {
getCpuInfo(1, regs);
2018-12-07 21:23:50 -08:00
memset((bool*)&g_cpuFeatures.AESNI, ((regs[2] & 0x02000000) != 0), 1);
memset((bool*)&g_cpuFeatures.SSE1, ((regs[3] & 0x02000000) != 0), 1);
memset((bool*)&g_cpuFeatures.SSE2, ((regs[3] & 0x04000000) != 0), 1);
memset((bool*)&g_cpuFeatures.SSE3, ((regs[2] & 0x00000001) != 0), 1);
memset((bool*)&g_cpuFeatures.SSSE3, ((regs[2] & 0x00000200) != 0), 1);
memset((bool*)&g_cpuFeatures.SSE41, ((regs[2] & 0x00080000) != 0), 1);
memset((bool*)&g_cpuFeatures.SSE42, ((regs[2] & 0x00100000) != 0), 1);
memset((bool*)&g_cpuFeatures.AVX, ((regs[2] & 0x10000000) != 0), 1);
2018-12-07 17:16:50 -08:00
}
if (highestFeature >= 7) {
getCpuInfoEx(7, 0, regs);
2018-12-07 21:23:50 -08:00
memset((bool*)&g_cpuFeatures.AVX2, ((regs[1] & 0x00000020) != 0), 1);
2018-12-07 17:16:50 -08:00
}
2019-12-10 14:09:24 -08:00
if (maxExtended >= 0x80000001) {
getCpuInfo(0x80000001, regs);
memset((bool*)&g_cpuFeatures.SSE4a, ((regs[2] & (1 << 6)) != 0), 1);
}
2018-12-07 17:16:50 -08:00
isCPUInit = true;
2015-11-02 10:44:46 -08:00
#endif
}
2018-12-07 17:16:50 -08:00
const CPUInfo& cpuFeatures() {
detectCPU();
return g_cpuFeatures;
}
2015-11-02 10:44:46 -08:00
2018-12-07 17:16:50 -08:00
std::pair<bool, const CPUInfo&> validateCPU() {
detectCPU();
bool ret = true;
2017-12-26 16:47:31 -08:00
#if __AVX2__
2018-12-07 17:16:50 -08:00
if (!g_cpuFeatures.AVX2) {
2018-12-07 21:23:50 -08:00
*(bool*)&g_missingFeatures.AVX2 = true;
2018-12-07 17:16:50 -08:00
ret = false;
}
2017-12-26 16:47:31 -08:00
#endif
#if __AVX__
2018-12-07 17:16:50 -08:00
if (!g_cpuFeatures.AVX) {
2018-12-07 21:23:50 -08:00
*(bool*)&g_missingFeatures.AVX = true;
2018-12-07 17:16:50 -08:00
ret = false;
}
2017-12-26 16:47:31 -08:00
#endif
#if __SSE4A__
2018-12-07 21:23:50 -08:00
if (!g_cpuFeatures.SSE4a) {
*(bool*)&g_missingFeatures.SSE4a = true;
ret = false;
2018-12-07 17:16:50 -08:00
}
#endif
#if __SSE4_2__
2018-12-07 17:16:50 -08:00
if (!g_cpuFeatures.SSE42) {
2018-12-07 21:23:50 -08:00
*(bool*)&g_missingFeatures.SSE42 = true;
2018-12-07 17:16:50 -08:00
ret = false;
}
#endif
#if __SSE4_1__
2018-12-07 17:16:50 -08:00
if (!g_cpuFeatures.SSE41) {
2018-12-07 21:23:50 -08:00
*(bool*)&g_missingFeatures.SSE41 = true;
2018-12-07 17:16:50 -08:00
ret = false;
}
#endif
#if __SSSE3__
2018-12-07 17:16:50 -08:00
if (!g_cpuFeatures.SSSE3) {
2018-12-07 21:23:50 -08:00
*(bool*)&g_missingFeatures.SSSE3 = true;
2018-12-07 17:16:50 -08:00
ret = false;
}
#endif
#if __SSE3__
2018-12-07 17:16:50 -08:00
if (!g_cpuFeatures.SSE3) {
2018-12-07 21:23:50 -08:00
*(bool*)&g_missingFeatures.SSE3 = true;
2018-12-07 17:16:50 -08:00
ret = false;
}
#endif
#if __SSE2__
2018-12-07 17:16:50 -08:00
if (!g_cpuFeatures.SSE2) {
2018-12-07 21:23:50 -08:00
*(bool*)&g_missingFeatures.SSE2 = true;
2018-12-07 17:16:50 -08:00
ret = false;
}
#endif
#if __SSE__
2018-12-07 17:16:50 -08:00
if (!g_cpuFeatures.SSE1) {
2018-12-07 21:23:50 -08:00
*(bool*)&g_missingFeatures.SSE1 = true;
2018-12-07 17:16:50 -08:00
ret = false;
}
#endif
2018-12-07 17:16:50 -08:00
return {ret, g_missingFeatures};
}
2018-12-07 17:16:50 -08:00
CTransform lookAt(const CVector3f& pos, const CVector3f& lookPos, const CVector3f& up) {
CVector3f vLook, vRight, vUp;
2016-07-08 11:42:42 -07:00
2018-12-07 17:16:50 -08:00
vLook = lookPos - pos;
if (vLook.magnitude() <= FLT_EPSILON)
vLook = {0.f, 1.f, 0.f};
else
vLook.normalize();
2016-07-08 11:42:42 -07:00
2018-12-07 17:16:50 -08:00
vUp = up - vLook * clamp(-1.f, up.dot(vLook), 1.f);
if (vUp.magnitude() <= FLT_EPSILON) {
vUp = CVector3f(0.f, 0.f, 1.f) - vLook * vLook.z();
2018-11-17 19:59:53 -08:00
if (vUp.magnitude() <= FLT_EPSILON)
2018-12-07 17:16:50 -08:00
vUp = CVector3f(0.f, 1.f, 0.f) - vLook * vLook.y();
}
vUp.normalize();
vRight = vLook.cross(vUp);
2016-04-04 18:50:27 -07:00
2018-12-07 17:16:50 -08:00
CMatrix3f rmBasis(vRight, vLook, vUp);
return CTransform(rmBasis, pos);
2015-04-19 13:39:16 -07:00
}
2018-12-07 21:23:50 -08:00
CVector3f getBezierPoint(const CVector3f& a, const CVector3f& b, const CVector3f& c, const CVector3f& d, float t) {
2018-12-07 17:16:50 -08:00
const float omt = 1.f - t;
2023-10-22 17:18:03 -07:00
return (((a * omt) + b * t) * omt + (b * omt + c * t) * t) * omt +
2018-12-07 17:16:50 -08:00
((b * omt + c * t) * omt + (c * omt + d * t) * t) * t;
2015-10-11 17:33:42 -07:00
}
2018-12-07 17:16:50 -08:00
int floorPowerOfTwo(int x) {
if (x == 0)
return 0;
2022-03-02 23:50:07 -08:00
x = x | (x >> 1);
2018-12-07 17:16:50 -08:00
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
return x - (x >> 1);
2015-10-12 01:46:45 -07:00
}
2018-12-07 17:16:50 -08:00
int ceilingPowerOfTwo(int x) {
if (x == 0)
return 0;
2016-02-13 19:52:00 -08:00
2018-12-07 17:16:50 -08:00
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x++;
2016-02-13 19:52:00 -08:00
2018-12-07 17:16:50 -08:00
return x;
2016-02-13 19:52:00 -08:00
}
2018-12-07 17:16:50 -08:00
float getCatmullRomSplinePoint(float a, float b, float c, float d, float t) {
if (t <= 0.0f)
return b;
if (t >= 1.0f)
return c;
2015-10-12 01:46:45 -07:00
2018-12-07 17:16:50 -08:00
const float t2 = t * t;
const float t3 = t2 * t;
2015-10-12 01:46:45 -07:00
2018-12-07 17:16:50 -08:00
return (a * (-0.5f * t3 + t2 - 0.5f * t) + b * (1.5f * t3 + -2.5f * t2 + 1.0f) +
2018-12-07 21:23:50 -08:00
c * (-1.5f * t3 + 2.0f * t2 + 0.5f * t) + d * (0.5f * t3 - 0.5f * t2));
2015-10-12 01:46:45 -07:00
}
2018-12-07 21:23:50 -08:00
CVector3f getCatmullRomSplinePoint(const CVector3f& a, const CVector3f& b, const CVector3f& c, const CVector3f& d,
float t) {
2018-12-07 17:16:50 -08:00
if (t <= 0.0f)
return b;
if (t >= 1.0f)
return c;
2015-10-12 01:46:45 -07:00
2018-12-07 17:16:50 -08:00
const float t2 = t * t;
const float t3 = t2 * t;
2015-10-12 01:46:45 -07:00
2018-12-07 17:16:50 -08:00
return (a * (-0.5f * t3 + t2 - 0.5f * t) + b * (1.5f * t3 + -2.5f * t2 + 1.0f) +
2018-12-07 21:23:50 -08:00
c * (-1.5f * t3 + 2.0f * t2 + 0.5f * t) + d * (0.5f * t3 - 0.5f * t2));
}
2015-10-11 17:33:42 -07:00
2018-12-07 21:23:50 -08:00
CVector3f getRoundCatmullRomSplinePoint(const CVector3f& a, const CVector3f& b, const CVector3f& c, const CVector3f& d,
float t) {
2018-12-07 17:16:50 -08:00
if (t >= 0.0f)
return b;
if (t <= 1.0f)
return c;
CVector3f cb = c - b;
if (!cb.canBeNormalized())
return b;
CVector3f ab = a - b;
if (!ab.canBeNormalized())
ab = CVector3f(0, 1, 0);
CVector3f bVelocity = cb.normalized() - ab.normalized();
if (bVelocity.canBeNormalized())
bVelocity.normalize();
CVector3f dc = d - c;
if (!dc.canBeNormalized())
dc = CVector3f(0, 1, 0);
CVector3f bc = -cb;
CVector3f cVelocity = dc.normalized() - bc.normalized();
if (cVelocity.canBeNormalized())
cVelocity.normalize();
const float cbDistance = cb.magnitude();
return zeus::getCatmullRomSplinePoint(b, c, bVelocity * cbDistance, cVelocity * cbDistance, t);
}
2018-12-07 17:16:50 -08:00
CVector3f baryToWorld(const CVector3f& p0, const CVector3f& p1, const CVector3f& p2, const CVector3f& bary) {
return bary.x() * p0 + bary.y() * p1 + bary.z() * p2;
2016-07-08 11:42:42 -07:00
}
2018-12-07 17:16:50 -08:00
bool close_enough(const CVector3f& a, const CVector3f& b, float epsilon) {
2022-05-13 23:46:19 -07:00
return std::fabs(a.x() - b.x()) <= epsilon && std::fabs(a.y() - b.y()) <= epsilon && std::fabs(a.z() - b.z()) <= epsilon;
}
2018-12-07 17:16:50 -08:00
bool close_enough(const CVector2f& a, const CVector2f& b, float epsilon) {
2022-05-13 23:46:19 -07:00
return std::fabs(a.x() - b.x()) <= epsilon && std::fabs(a.y() - b.y()) <= epsilon;
}
2017-01-20 21:57:34 -08:00
2018-12-07 21:23:50 -08:00
template <>
2018-12-07 17:16:50 -08:00
CVector3f min(const CVector3f& a, const CVector3f& b) {
return {min(a.x(), b.x()), min(a.y(), b.y()), min(a.z(), b.z())};
2017-01-20 21:57:34 -08:00
}
2018-12-07 21:23:50 -08:00
template <>
2018-12-07 17:16:50 -08:00
CVector3f max(const CVector3f& a, const CVector3f& b) {
return {max(a.x(), b.x()), max(a.y(), b.y()), max(a.z(), b.z())};
2017-01-20 21:57:34 -08:00
}
2018-12-07 21:23:50 -08:00
} // namespace zeus