2016-03-04 15:03:26 -08:00
|
|
|
#include "zeus/Math.hpp"
|
|
|
|
#include "zeus/CTransform.hpp"
|
|
|
|
#include "zeus/CVector3f.hpp"
|
2016-08-31 21:08:46 -07:00
|
|
|
#include "zeus/CVector2f.hpp"
|
2015-11-10 12:02:25 -08:00
|
|
|
#if _WIN32
|
|
|
|
#include <intrin.h>
|
|
|
|
#else
|
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
|
|
|
|
2016-03-04 15:03:26 -08:00
|
|
|
namespace zeus
|
2015-10-07 17:21:38 -07:00
|
|
|
{
|
2015-11-02 10:44:46 -08:00
|
|
|
|
2016-10-01 16:19:48 -07:00
|
|
|
static bool isCPUInit = false;
|
2017-12-11 18:03:39 -08:00
|
|
|
static CPUInfo g_cpuFeatures = {};
|
|
|
|
static CPUInfo g_missingFeatures = {};
|
2015-11-02 10:44:46 -08:00
|
|
|
|
2017-12-26 16:47:31 -08:00
|
|
|
void getCpuInfo(int eax, int regs[4])
|
2015-11-02 10:44:46 -08:00
|
|
|
{
|
|
|
|
#if !GEKKO
|
|
|
|
#if _WIN32
|
2017-12-26 16:47:31 -08:00
|
|
|
__cpuid(regs, eax);
|
2015-11-02 10:44:46 -08:00
|
|
|
#else
|
2017-12-26 16:47:31 -08:00
|
|
|
__cpuid(eax, regs[0], regs[1], regs[2], regs[3]);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void getCpuInfoEx(int eax, int ecx, int regs[4])
|
|
|
|
{
|
|
|
|
#if !GEKKO
|
|
|
|
#if _WIN32
|
|
|
|
__cpuidex(regs, eax, ecx);
|
|
|
|
#else
|
|
|
|
__cpuid_count(eax, ecx, regs[0], regs[1], regs[2], regs[3]);
|
2015-11-02 10:44:46 -08:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void detectCPU()
|
|
|
|
{
|
|
|
|
#if !GEKKO
|
2016-10-01 16:19:48 -07:00
|
|
|
if (isCPUInit)
|
2015-11-02 10:44:46 -08:00
|
|
|
return;
|
|
|
|
|
2016-02-15 09:32:49 -08:00
|
|
|
int regs[4];
|
|
|
|
getCpuInfo(0, regs);
|
2018-01-01 20:23:04 -08:00
|
|
|
int highestFeature = regs[0];
|
2016-02-15 09:32:49 -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];
|
2016-02-16 18:20:17 -08:00
|
|
|
getCpuInfo(0x80000000, regs);
|
|
|
|
if (regs[0] >= 0x80000004)
|
2016-02-15 09:32:49 -08:00
|
|
|
{
|
2016-02-16 18:20:17 -08:00
|
|
|
for (unsigned int i = 0x80000002; i <= 0x80000004; i++)
|
|
|
|
{
|
|
|
|
getCpuInfo(i, regs);
|
|
|
|
// Interpret CPU brand string and cache information.
|
2016-07-08 11:42:42 -07:00
|
|
|
if (i == 0x80000002)
|
2016-02-16 18:20:17 -08:00
|
|
|
memcpy((char*)g_cpuFeatures.cpuBrand, regs, sizeof(regs));
|
2016-07-08 11:42:42 -07:00
|
|
|
else if (i == 0x80000003)
|
2016-02-16 18:20:17 -08:00
|
|
|
memcpy((char*)g_cpuFeatures.cpuBrand + 16, regs, sizeof(regs));
|
2016-07-08 11:42:42 -07:00
|
|
|
else if (i == 0x80000004)
|
2016-02-16 18:20:17 -08:00
|
|
|
memcpy((char*)g_cpuFeatures.cpuBrand + 32, regs, sizeof(regs));
|
|
|
|
}
|
2016-02-15 09:32:49 -08:00
|
|
|
}
|
|
|
|
|
2018-01-01 20:23:04 -08:00
|
|
|
if (highestFeature >= 1)
|
|
|
|
{
|
|
|
|
getCpuInfo(1, regs);
|
|
|
|
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);
|
|
|
|
}
|
2017-12-26 16:47:31 -08:00
|
|
|
|
2018-01-01 20:23:04 -08:00
|
|
|
if (highestFeature >= 7)
|
|
|
|
{
|
|
|
|
getCpuInfoEx(7, 0, regs);
|
|
|
|
memset((bool*)&g_cpuFeatures.AVX2, ((regs[1] & 0x00000020) != 0), 1);
|
|
|
|
}
|
2015-11-02 10:44:46 -08:00
|
|
|
|
2016-10-01 16:19:48 -07:00
|
|
|
isCPUInit = true;
|
2015-11-02 10:44:46 -08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-10-01 16:19:48 -07:00
|
|
|
const CPUInfo& cpuFeatures() { detectCPU(); return g_cpuFeatures; }
|
2015-11-02 10:44:46 -08:00
|
|
|
|
2017-12-11 18:03:39 -08:00
|
|
|
std::pair<bool, const CPUInfo&> validateCPU()
|
|
|
|
{
|
|
|
|
detectCPU();
|
|
|
|
bool ret = true;
|
|
|
|
|
2017-12-26 16:47:31 -08:00
|
|
|
#if __AVX2__
|
|
|
|
if (!g_cpuFeatures.AVX2)
|
|
|
|
{
|
|
|
|
*(bool*) &g_missingFeatures.AVX2 = true;
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if __AVX__
|
|
|
|
if (!g_cpuFeatures.AVX)
|
|
|
|
{
|
|
|
|
*(bool*) &g_missingFeatures.AVX = true;
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
#endif
|
2017-12-11 18:03:39 -08:00
|
|
|
#if __SSE4A__
|
|
|
|
if (!g_cpuFeatures.SSE4a)
|
|
|
|
{
|
|
|
|
*(bool*) &g_missingFeatures.SSE4a = true;
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if __SSE4_2__
|
|
|
|
if (!g_cpuFeatures.SSE42)
|
|
|
|
{
|
|
|
|
*(bool*) &g_missingFeatures.SSE42 = true;
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if __SSE4_1__
|
|
|
|
if (!g_cpuFeatures.SSE41)
|
|
|
|
{
|
|
|
|
*(bool*) &g_missingFeatures.SSE41 = true;
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if __SSSE3__
|
|
|
|
if (!g_cpuFeatures.SSSE3)
|
|
|
|
{
|
|
|
|
*(bool*) &g_missingFeatures.SSSE3 = true;
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if __SSE3__
|
|
|
|
if (!g_cpuFeatures.SSE3)
|
|
|
|
{
|
|
|
|
*(bool*) &g_missingFeatures.SSE3 = true;
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if __SSE2__
|
|
|
|
if (!g_cpuFeatures.SSE2)
|
|
|
|
{
|
|
|
|
*(bool*) &g_missingFeatures.SSE2 = true;
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if __SSE__
|
|
|
|
if (!g_cpuFeatures.SSE1)
|
|
|
|
{
|
|
|
|
*(bool*) &g_missingFeatures.SSE1 = true;
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return {ret, g_missingFeatures};
|
|
|
|
}
|
|
|
|
|
2015-10-07 17:21:38 -07:00
|
|
|
CTransform lookAt(const CVector3f& pos, const CVector3f& lookPos, const CVector3f& up)
|
2015-04-19 13:39:16 -07:00
|
|
|
{
|
2016-07-08 11:42:42 -07:00
|
|
|
CVector3f vLook, vRight, vUp;
|
|
|
|
|
2016-04-04 18:50:27 -07:00
|
|
|
vLook = lookPos - pos;
|
|
|
|
if (vLook.magnitude() < FLT_EPSILON)
|
|
|
|
vLook = {0.f, 1.f, 0.f};
|
2015-04-19 13:39:16 -07:00
|
|
|
vLook.normalize();
|
2016-07-08 11:42:42 -07:00
|
|
|
|
2016-04-04 18:50:27 -07:00
|
|
|
vRight = vLook.cross(up);
|
2015-04-19 13:39:16 -07:00
|
|
|
vRight.normalize();
|
2016-07-08 11:42:42 -07:00
|
|
|
|
2016-04-04 18:50:27 -07:00
|
|
|
vUp = vRight.cross(vLook);
|
|
|
|
|
|
|
|
CMatrix3f rmBasis(vRight, vLook, vUp);
|
|
|
|
return CTransform(rmBasis, pos);
|
2015-04-19 13:39:16 -07:00
|
|
|
}
|
2015-10-07 17:21:38 -07:00
|
|
|
|
2018-06-21 17:33:34 -07:00
|
|
|
CVector3f getBezierPoint(const CVector3f& a, const CVector3f& b,
|
|
|
|
const CVector3f& c, const CVector3f& d, float t)
|
2015-10-07 17:21:38 -07:00
|
|
|
{
|
2018-06-21 17:33:34 -07:00
|
|
|
const float omt = 1.f - t;
|
|
|
|
return ((a * omt + b * t) * omt + (b * omt + c * t) * t) * omt +
|
|
|
|
((b * omt + c * t) * omt + (c * omt + d * t) * t) * t;
|
2015-10-11 17:33:42 -07:00
|
|
|
}
|
|
|
|
|
2015-10-12 01:46:45 -07:00
|
|
|
int floorPowerOfTwo(int x)
|
|
|
|
{
|
|
|
|
if (x == 0)
|
|
|
|
return 0;
|
|
|
|
/*
|
|
|
|
* we want to ensure that we always get the previous power,
|
|
|
|
* but if we have values like 256, we'll always get the same value,
|
|
|
|
* x-1 ensures that we always get the previous power.
|
|
|
|
*/
|
|
|
|
x = (x - 1) | (x >> 1);
|
|
|
|
x = x | (x >> 2);
|
|
|
|
x = x | (x >> 4);
|
|
|
|
x = x | (x >> 8);
|
|
|
|
x = x | (x >> 16);
|
|
|
|
return x - (x >> 1);
|
|
|
|
}
|
|
|
|
|
2016-02-13 19:52:00 -08:00
|
|
|
int ceilingPowerOfTwo(int x)
|
|
|
|
{
|
|
|
|
if (x == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
x--;
|
|
|
|
x |= x >> 1;
|
|
|
|
x |= x >> 2;
|
|
|
|
x |= x >> 4;
|
|
|
|
x |= x >> 8;
|
|
|
|
x |= x >> 16;
|
|
|
|
x++;
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2015-10-12 01:46:45 -07:00
|
|
|
float getCatmullRomSplinePoint(float a, float b, float c, float d, float t)
|
|
|
|
{
|
|
|
|
if (t <= 0.0f)
|
|
|
|
return b;
|
2016-04-14 20:00:51 -07:00
|
|
|
if (t >= 1.0f)
|
2015-10-12 01:46:45 -07:00
|
|
|
return c;
|
|
|
|
|
2016-07-08 11:42:42 -07:00
|
|
|
const float t2 = t * t;
|
2015-10-12 01:46:45 -07:00
|
|
|
const float t3 = t2 * t;
|
|
|
|
|
2016-07-08 11:42:42 -07:00
|
|
|
return (a * (-0.5f * t3 + t2 - 0.5f * t) + b * (1.5f * t3 + -2.5f * t2 + 1.0f) + 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
|
|
|
}
|
|
|
|
|
|
|
|
CVector3f getCatmullRomSplinePoint(const CVector3f& a, const CVector3f& b, const CVector3f& c, const CVector3f& d, float t)
|
|
|
|
{
|
|
|
|
if (t <= 0.0f)
|
|
|
|
return b;
|
2016-04-14 20:00:51 -07:00
|
|
|
if (t >= 1.0f)
|
2015-10-12 01:46:45 -07:00
|
|
|
return c;
|
|
|
|
|
2016-07-08 11:42:42 -07:00
|
|
|
const float t2 = t * t;
|
2015-10-12 01:46:45 -07:00
|
|
|
const float t3 = t2 * t;
|
|
|
|
|
2016-07-08 11:42:42 -07:00
|
|
|
return (a * (-0.5f * t3 + t2 - 0.5f * t) + b * (1.5f * t3 + -2.5f * t2 + 1.0f) + c * (-1.5f * t3 + 2.0f * t2 + 0.5f * t) +
|
|
|
|
d * (0.5f * t3 - 0.5f * t2));
|
2015-10-07 17:21:38 -07:00
|
|
|
}
|
2015-10-11 17:33:42 -07:00
|
|
|
|
2015-10-12 02:38:34 -07:00
|
|
|
CVector3f getRoundCatmullRomSplinePoint(const CVector3f& a, const CVector3f& b, const CVector3f& c, const CVector3f& d, float t)
|
|
|
|
{
|
|
|
|
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();
|
2016-03-04 15:03:26 -08:00
|
|
|
return zeus::getCatmullRomSplinePoint(b, c, bVelocity * cbDistance, cVelocity * cbDistance, t);
|
2015-10-12 02:38:34 -07:00
|
|
|
}
|
|
|
|
|
2015-10-25 12:31:41 -07:00
|
|
|
CVector3f baryToWorld(const CVector3f& p0, const CVector3f& p1, const CVector3f& p2, const CVector3f& bary)
|
2016-07-08 11:42:42 -07:00
|
|
|
{
|
|
|
|
return bary.x * p0 + bary.y * p1 + bary.z * p2;
|
|
|
|
}
|
2016-08-31 21:08:46 -07:00
|
|
|
|
|
|
|
bool close_enough(const CVector3f& a, const CVector3f &b, float epsilon)
|
|
|
|
{
|
|
|
|
if (std::fabs(a.x - b.x) < epsilon && std::fabs(a.y - b.y) < epsilon && std::fabs(a.z - b.z) < epsilon)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool close_enough(const CVector2f& a, const CVector2f& b, float epsilon)
|
|
|
|
{
|
|
|
|
if (std::fabs(a.x - b.x) < epsilon && std::fabs(a.y - b.y) < epsilon)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2017-01-20 21:57:34 -08:00
|
|
|
|
|
|
|
template <> CVector3f min(const CVector3f& a, const CVector3f& b)
|
|
|
|
{
|
|
|
|
return {min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)};
|
|
|
|
}
|
|
|
|
|
|
|
|
template <> CVector3f max(const CVector3f& a, const CVector3f& b)
|
|
|
|
{
|
|
|
|
return {max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)};
|
|
|
|
}
|
2015-10-07 17:21:38 -07:00
|
|
|
}
|