diff --git a/SQCSim-common/SQCSim-common.vcxproj b/SQCSim-common/SQCSim-common.vcxproj
new file mode 100644
index 0000000..5db21d0
--- /dev/null
+++ b/SQCSim-common/SQCSim-common.vcxproj
@@ -0,0 +1,154 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {ee91ab12-4225-4a4d-931d-69d72f6d91fb}
+ SQCSimcommon
+ 10.0
+
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SQCSim-common/SQCSim-common.vcxproj.filters b/SQCSim-common/SQCSim-common.vcxproj.filters
new file mode 100644
index 0000000..af8b625
--- /dev/null
+++ b/SQCSim-common/SQCSim-common.vcxproj.filters
@@ -0,0 +1,72 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Fichiers d%27en-tête
+
+
+ Fichiers d%27en-tête
+
+
+ Fichiers d%27en-tête
+
+
+ Fichiers d%27en-tête
+
+
+ Fichiers d%27en-tête
+
+
+ Fichiers d%27en-tête
+
+
+ Fichiers d%27en-tête
+
+
+ Fichiers d%27en-tête
+
+
+ Fichiers d%27en-tête
+
+
+ Fichiers d%27en-tête
+
+
+ Fichiers d%27en-tête
+
+
+
+
+ Fichiers sources
+
+
+ Fichiers sources
+
+
+ Fichiers sources
+
+
+ Fichiers sources
+
+
+ Fichiers sources
+
+
+ Fichiers sources
+
+
+
\ No newline at end of file
diff --git a/SQCSim-common/array2d.h b/SQCSim-common/array2d.h
new file mode 100644
index 0000000..7451365
--- /dev/null
+++ b/SQCSim-common/array2d.h
@@ -0,0 +1,61 @@
+#ifndef ARRAY2D_H__
+#define ARRAY2D_H__
+
+#include "define.h"
+
+template
+class Array2d {
+ public:
+ Array2d(int x, int y);
+ ~Array2d();
+ Array2d(const Array2d& array);
+
+ void Set(int x, int y, T type);
+ T Get(int x, int y) const;
+ T Remove(int x, int y);
+
+ void Reset(T type);
+
+ private:
+ int m_x, m_y;
+ T* m_array;
+
+ int To1dIndex(int x, int y) const;
+};
+
+template
+Array2d::Array2d(int x, int y) : m_x(x), m_y(y) { m_array = new T[m_x * m_y]; }
+
+template
+Array2d::~Array2d() { delete[] m_array; }
+
+template
+Array2d::Array2d(const Array2d& array) : m_x(array.m_x), m_y(array.m_y) {
+ m_array = new T[m_x * m_y];
+ for (int i = 0; i < m_x * m_y; ++i)
+ m_array[i] = array.m_array[i];
+}
+
+template
+void Array2d::Set(int x, int y, T type) { m_array[To1dIndex(x, y)] = type; }
+
+template
+T Array2d::Get(int x, int y) const { return m_array[To1dIndex(x, y)]; }
+
+template
+T Array2d::Remove(int x, int y) {
+ T thing = std::move(m_array[To1dIndex(x, y)]);
+ m_array[To1dIndex(x, y)] = nullptr;
+ return thing;
+}
+
+template
+void Array2d::Reset(T type) {
+ for (int i = 0; i < m_x * m_y; ++i)
+ m_array[i] = type;
+}
+
+template
+int Array2d::To1dIndex(int x, int y) const { return x + (y * m_x); }
+
+#endif // ARRAY2D_H__
diff --git a/SQCSim-common/array3d.h b/SQCSim-common/array3d.h
new file mode 100644
index 0000000..97603ef
--- /dev/null
+++ b/SQCSim-common/array3d.h
@@ -0,0 +1,55 @@
+#ifndef ARRAY3D_H__
+#define ARRAY3D_H__
+
+#include "define.h"
+
+template
+class Array3d {
+ public:
+ Array3d(int x, int y, int z);
+ ~Array3d();
+ Array3d(const Array3d& array);
+
+ void Set(int x, int y, int z, T type);
+ T Get(int x, int y, int z) const;
+
+ void Reset(T type);
+
+ private:
+ int m_x, m_y, m_z;
+ T* m_array;
+
+ int To1dIndex(int x, int y, int z) const;
+};
+
+template
+Array3d::Array3d(int x, int y, int z) : m_x(x), m_y(y), m_z(z) { m_array = new T[m_x * m_y * m_z]; }
+
+template
+Array3d::~Array3d() { delete[] m_array; }
+
+template
+Array3d::Array3d(const Array3d& array) : m_x(array.m_x), m_y(array.m_y), m_z(array.m_z) {
+ m_array = new T[m_x * m_y * m_z];
+ for (int i = 0; i < m_x * m_y * m_z; ++i)
+ m_array[i] = array.m_array[i];
+}
+
+template
+void Array3d::Set(int x, int y, int z, T type) {
+ m_array[To1dIndex(x, y, z)] = type;
+}
+
+template
+T Array3d::Get(int x, int y, int z) const { return m_array[To1dIndex(x, y, z)]; }
+
+template
+void Array3d::Reset(T type) {
+ for (int i = 0; i < m_x * m_y * m_z; ++i)
+ m_array[i] = type;
+}
+
+template
+int Array3d::To1dIndex(int x, int y, int z) const { return x + (z * m_x) + (y * m_z * m_x); }
+
+#endif // ARRAY3D_H__
diff --git a/SQCSim-common/blockinfo.cpp b/SQCSim-common/blockinfo.cpp
new file mode 100644
index 0000000..1e42825
--- /dev/null
+++ b/SQCSim-common/blockinfo.cpp
@@ -0,0 +1,42 @@
+#include "blockinfo.h"
+#include
+
+BlockInfo::BlockInfo(BlockType type, const std::string& name, float u, float v, float s, int dur) : m_type(type), m_name(name), m_u(u), m_v(v), m_s(s), m_durability(dur)
+{
+}
+
+BlockInfo::~BlockInfo()
+{
+}
+
+BlockType BlockInfo::GetType() const
+{
+ return m_type;
+}
+
+void BlockInfo::SetDurability(int durability)
+{
+ m_durability = durability;
+}
+
+int BlockInfo::GetDurability() const
+{
+ return m_durability;
+}
+
+void BlockInfo::GetTexture(float& u, float& v, float& s)
+{
+ u = m_u;
+ v = m_v;
+ s = m_s;
+}
+
+void BlockInfo::Show() const
+{
+ std::cout << "Type: " << m_type << std::endl;
+ std::cout << "Nom: " << m_name << std::endl;
+ std::cout << "Durabilite: " << m_durability << std::endl;
+ std::cout << "Coordonnees Texture: " << m_u << ", " << m_v << ", " << m_s << std::endl;
+}
+
+
diff --git a/SQCSim-common/blockinfo.h b/SQCSim-common/blockinfo.h
new file mode 100644
index 0000000..8a2afe7
--- /dev/null
+++ b/SQCSim-common/blockinfo.h
@@ -0,0 +1,32 @@
+#ifndef BLOCKINFO_H__
+#define BLOCKINFO_H__
+
+#include
+#include "define.h"
+
+class BlockInfo
+{
+ public:
+ BlockInfo(BlockType type, const std::string& name, float u, float v, float s, int dur);
+ ~BlockInfo();
+
+ BlockType GetType() const;
+
+ void SetDurability(int durability);
+ int GetDurability() const;
+
+ void GetTexture(float& u, float& v, float& s);
+
+ void Show() const;
+
+ private:
+ BlockType m_type;
+ float m_u;
+ float m_v;
+ float m_s;
+ std::string m_name;
+ int m_durability;
+
+};
+
+#endif // BLOCKINFO_H__
diff --git a/SQCSim-common/bullet.cpp b/SQCSim-common/bullet.cpp
new file mode 100644
index 0000000..c06c9e7
--- /dev/null
+++ b/SQCSim-common/bullet.cpp
@@ -0,0 +1,32 @@
+#include "bullet.h"
+#include "world.h"
+
+Bullet::Bullet(Player& player) {
+ m_startpos = m_currentpos = player.GetPOV() + player.GetDirection();
+ m_velocity = player.GetDirection();
+}
+
+Bullet::~Bullet() {}
+
+bool Bullet::Update(World* world, float elapsedtime) {
+ for (int x = 0; x < 1000; ++x) {
+ m_currentpos += m_velocity * elapsedtime;
+
+ if (!world->ChunkAt(m_currentpos))
+ return true;
+ else if (world->BlockAt(m_currentpos) != BTYPE_AIR) {
+ world->ChangeBlockAtPosition(BTYPE_AIR, m_currentpos);
+ return true;
+ }
+ else if ((m_currentpos - m_startpos).Length() > VIEW_DISTANCE) return true;
+ }
+
+ return false;
+}
+
+void Bullet::Transpose(int& x, int& z) {
+ m_currentpos.x -= x * CHUNK_SIZE_X;
+ m_currentpos.z -= z * CHUNK_SIZE_Z;
+ m_startpos.x -= x * CHUNK_SIZE_X;
+ m_startpos.z -= z * CHUNK_SIZE_Z;
+}
diff --git a/SQCSim-common/bullet.h b/SQCSim-common/bullet.h
new file mode 100644
index 0000000..de2e14c
--- /dev/null
+++ b/SQCSim-common/bullet.h
@@ -0,0 +1,23 @@
+#ifndef BULLET_H__
+#define BULLET_H__
+
+#include "player.h"
+
+class World;
+
+class Bullet {
+public:
+ Bullet(Player& player);
+ ~Bullet();
+
+ bool Update(World* world, float elapsedtime);
+ void Transpose(int& x, int& z);
+
+private:
+ Vector3f m_startpos;
+ Vector3f m_currentpos;
+ Vector3f m_velocity;
+};
+
+#endif // BULLET_H__
+
diff --git a/SQCSim-common/chunk.cpp b/SQCSim-common/chunk.cpp
new file mode 100644
index 0000000..7bfc690
--- /dev/null
+++ b/SQCSim-common/chunk.cpp
@@ -0,0 +1,111 @@
+#include "chunk.h"
+#include "world.h"
+
+Chunk::Chunk(unsigned int x, unsigned int y) : m_posX(x), m_posY(y) {
+ //std::ostringstream pos; // Vérifie l'existence d'un fichier .chunk avec sa position.
+ //pos << CHUNK_PATH << x << '_' << y << ".chunk";
+ //std::ifstream input(pos.str(), std::fstream::binary);
+
+ //if (input.fail()) {
+ OpenSimplexNoise::Noise simplex = OpenSimplexNoise::Noise(SEED);
+ m_blocks.Reset(BTYPE_AIR);
+
+ for (int ix = 0; ix < CHUNK_SIZE_X; ++ix) // Montagnes
+ for (int iz = 0; iz < CHUNK_SIZE_Z; ++iz) {
+ float xnoiz, ynoiz;
+ xnoiz = (double)(ix + x * CHUNK_SIZE_X) / 4096.;
+ ynoiz = (double)(iz + y * CHUNK_SIZE_Z) / 4096.;
+ double height = 0;
+ for (int x = 0; x < 39; ++x) {
+ height += simplex.eval(xnoiz, ynoiz);
+ height *= .79;
+ xnoiz *= 1.139;
+ ynoiz *= 1.139;
+ }
+ height = height * 2000. * simplex.eval((double)(ix + x * CHUNK_SIZE_X) / 512., (double)(iz + y * CHUNK_SIZE_Z) / 512.);
+ height /= (CHUNK_SIZE_Y / 1.9);
+ height += 15.;
+ for (int iy = 0; iy <= (int)height % CHUNK_SIZE_Y; ++iy)
+ SetBlock(ix, iy, iz, BTYPE_METAL, nullptr);
+ }
+ for (int ix = 0; ix < CHUNK_SIZE_X; ++ix) // Collines
+ for (int iz = 0; iz < CHUNK_SIZE_Z; ++iz) {
+ float xnoiz, ynoiz;
+ xnoiz = (double)(ix + x * CHUNK_SIZE_X) / 512.;
+ ynoiz = (double)(iz + y * CHUNK_SIZE_Z) / 512.;
+ float height = simplex.eval(xnoiz, ynoiz) * 50.f;// +1.f;
+ for (int iy = 0; iy <= (int)height % CHUNK_SIZE_Y; ++iy) {
+ if (GetBlock(ix, iy, iz) == BTYPE_AIR)
+ SetBlock(ix, iy, iz, BTYPE_GRASS, nullptr);
+ }
+ }
+ for (int ix = 0; ix < CHUNK_SIZE_X; ++ix) // "Lacs"
+ for (int iz = 0; iz < CHUNK_SIZE_Z; ++iz) {
+ for (int iy = 0; iy < 13; ++iy) {
+ if (GetBlock(ix, iy, iz) == BTYPE_AIR)
+ SetBlock(ix, iy, iz, BTYPE_ICE, nullptr);
+ }
+ }
+ //for (int ix = 0; ix < CHUNK_SIZE_X; ++ix) // "Arbres"
+ // for (int iz = 0; iz < CHUNK_SIZE_Z; ++iz) {
+ // float xnoiz, ynoiz;
+ // xnoiz = (double)(iz * CHUNK_SIZE_Y + x * CHUNK_SIZE_X) / 256.;
+ // ynoiz = (double)(ix * CHUNK_SIZE_Y + y * CHUNK_SIZE_Z) / 256.;
+ // bool tree = (int)(abs(simplex.eval(xnoiz, ynoiz)) * 17933.f) % CHUNK_SIZE_Y > 126 ? true : false;
+ // for (int iy = 0; iy < CHUNK_SIZE_Y - 10; ++iy)
+ // if (GetBlock(ix, iy, iz) == BTYPE_AIR)
+ // if (GetBlock(ix, iy - 1, iz) == BTYPE_GRASS)
+ // if (tree) {
+ // for (int i = 0; i < (int)(abs(simplex.eval(xnoiz, ynoiz) * 4)) % 42 + 1; ++i)
+ // SetBlock(ix, iy + i, iz, BTYPE_DIRT, nullptr);
+ // break;
+ // }
+ // }
+ /* }
+ else {
+ input.seekg(0, std::ios_base::end);
+ int size = input.tellg();
+ input.seekg(0, std::ios_base::beg);
+
+ char data[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
+ input.read(data, size);
+ input.close();
+
+ for (int ix = 0; ix < CHUNK_SIZE_X; ++ix)
+ for (int iz = 0; iz < CHUNK_SIZE_Z; ++iz)
+ for (int iy = 0; iy < CHUNK_SIZE_Y; ++iy)
+ m_blocks.Set(ix, iy, iz, data[ix + (iz * CHUNK_SIZE_X) + (iy * CHUNK_SIZE_Z * CHUNK_SIZE_X)]);
+ }*/
+}
+
+Chunk::~Chunk() {
+ /*if (m_isModified) {
+ char data[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
+
+ for (int x = 0; x < CHUNK_SIZE_X; ++x)
+ for (int z = 0; z < CHUNK_SIZE_Z; ++z)
+ for (int y = 0; y < CHUNK_SIZE_Y; ++y)
+ data[x + (z * CHUNK_SIZE_X) + (y * CHUNK_SIZE_Z * CHUNK_SIZE_X)] = (char)GetBlock(x, y, z);
+
+ std::ostringstream pos;
+ pos << CHUNK_PATH << m_posX << '_' << m_posY << ".chunk";
+
+ std::ofstream output(pos.str(), std::fstream::binary);
+ output.write(data, sizeof(data));
+ output.close();
+ }*/
+}
+
+void Chunk::RemoveBlock(int x, int y, int z, World* world) {
+ m_blocks.Set(x, y, z, BTYPE_AIR);
+}
+
+void Chunk::SetBlock(int x, int y, int z, BlockType type, World* world) {
+ m_blocks.Set(x, y, z, type);
+}
+
+BlockType Chunk::GetBlock(int x, int y, int z) { return m_blocks.Get(x, y, z); }
+
+void Chunk::GetPosition(unsigned int& x, unsigned int& y) const { x = m_posX; y = m_posY; }
+
+void Chunk::MakeModified() { m_isModified = true; }
diff --git a/SQCSim-common/chunk.h b/SQCSim-common/chunk.h
new file mode 100644
index 0000000..ec015ba
--- /dev/null
+++ b/SQCSim-common/chunk.h
@@ -0,0 +1,31 @@
+#ifndef CHUNK_H__
+#define CHUNK_H__
+#include "define.h"
+#include "array3d.h"
+#include "array2d.h"
+#include "blockinfo.h"
+#include "opensimplex.h"
+
+class World;
+
+class Chunk {
+ protected:
+ Array3d m_blocks = Array3d(CHUNK_SIZE_X, CHUNK_SIZE_Y, CHUNK_SIZE_Z);
+ bool m_isModified = false;
+
+ unsigned int m_posX; // Position du chunk dans l'array constituant le monde.
+ unsigned int m_posY;
+
+ public:
+ Chunk(unsigned int x, unsigned int y);
+ ~Chunk();
+
+ void RemoveBlock(int x, int y, int z, World* world);
+ void SetBlock(int x, int y, int z, BlockType type, World* world);
+ BlockType GetBlock(int x, int y, int z);
+ void GetPosition(unsigned int& x, unsigned int& y) const;
+
+ void MakeModified();
+};
+
+#endif // CHUNK_H__
diff --git a/SQCSim-common/define.h b/SQCSim-common/define.h
new file mode 100644
index 0000000..aea5ea2
--- /dev/null
+++ b/SQCSim-common/define.h
@@ -0,0 +1,49 @@
+#ifndef DEFINE_H__
+#define DEFINE_H__
+
+#include
+
+#define CHUNK_SIZE_X 16
+#define CHUNK_SIZE_Y 128
+#define CHUNK_SIZE_Z 16
+#define MAX_SELECTION_DISTANCE 5
+#define SEED 12345
+
+#ifdef _DEBUG
+#define WORLD_SIZE_X 64
+#define WORLD_SIZE_Y 64
+
+#define FRAMES_RENDER_CHUNKS 4
+#define FRAMES_UPDATE_CHUNKS 4
+#define FRAMES_DELETE_CHUNKS 4
+
+#define THREADS_GENERATE_CHUNKS 1
+#define THREADS_UPDATE_CHUNKS 1
+#define THREADS_DELETE_CHUNKS 1
+
+#define VIEW_DISTANCE 256
+#define TEXTURE_SIZE 128
+#define MAX_BULLETS 64
+#endif
+
+#ifdef NDEBUG
+#define WORLD_SIZE_X 16
+#define WORLD_SIZE_Y 16
+
+#define FRAMES_RENDER_CHUNKS 1
+#define FRAMES_UPDATE_CHUNKS 1
+#define FRAMES_DELETE_CHUNKS 1
+
+#define THREADS_GENERATE_CHUNKS 12
+#define THREADS_UPDATE_CHUNKS 5
+#define THREADS_DELETE_CHUNKS 2
+
+#define VIEW_DISTANCE 1024
+#define TEXTURE_SIZE 512
+#define MAX_BULLETS 512
+#endif
+
+typedef uint8_t BlockType;
+enum BLOCK_TYPE { BTYPE_AIR, BTYPE_DIRT, BTYPE_GRASS, BTYPE_METAL, BTYPE_ICE, BTYPE_LAST };
+
+#endif // DEFINE_H__
diff --git a/SQCSim-common/matrix4.h b/SQCSim-common/matrix4.h
new file mode 100644
index 0000000..a0d911a
--- /dev/null
+++ b/SQCSim-common/matrix4.h
@@ -0,0 +1,571 @@
+#ifndef MATRIX4_H__
+#define MATRIX4_H__
+
+#include
+#include
+#include
+
+#include "define.h"
+#include "vector3.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265f
+#endif
+
+#define DEGTORAD(x) ((x * M_PI) / 180.f)
+#define RADTODEG(x) ((180.f * x) / M_PI)
+
+template
+class Matrix4
+{
+ public:
+ typedef T Type;
+
+ public:
+ static const Matrix4 ZERO;
+ static const Matrix4 IDENTITY;
+
+ public:
+ Matrix4();
+ Matrix4(const T& v);
+ Matrix4(const Matrix4& m);
+ Matrix4(const T& m_11, const T& m_12, const T& m_13, const T& m_14,
+ const T& m_21, const T& m_22, const T& m_23, const T& m_24,
+ const T& m_31, const T& m_32, const T& m_33, const T& m_34,
+ const T& m_41, const T& m_42, const T& m_43, const T& m_44);
+
+ const T& Get11() const;
+ const T& Get12() const;
+ const T& Get13() const;
+ const T& Get14() const;
+ const T& Get21() const;
+ const T& Get22() const;
+ const T& Get23() const;
+ const T& Get24() const;
+ const T& Get31() const;
+ const T& Get32() const;
+ const T& Get33() const;
+ const T& Get34() const;
+ const T& Get41() const;
+ const T& Get42() const;
+ const T& Get43() const;
+ const T& Get44() const;
+
+ Matrix4& operator=(const Matrix4& m);
+
+ Matrix4 operator+(const Matrix4& m) const;
+ const Matrix4& operator+=(const Matrix4& m);
+
+ Matrix4 operator-(const Matrix4& m) const;
+ Matrix4 operator-() const;
+ const Matrix4& operator-=(const Matrix4& m);
+
+ Matrix4 operator*(const Matrix4& m) const;
+ Matrix4 operator*(const T& v) const;
+ const Matrix4& operator*=(const Matrix4& m);
+ const Matrix4& operator*=(const T& v);
+
+ Matrix4 operator/(const T& v) const;
+ const Matrix4& operator/=(const T& v);
+
+ bool operator==(const Matrix4& m) const;
+ bool operator!=(const Matrix4& m) const;
+
+ void SetZero();
+ void SetIdentity();
+ void SetPerspectiveProjection(const T& fov, const T& aspect, const T& nearPlane, const T& farPlane);
+ void SetOrthographicProjection(const T& left, const T& right, const T& bottom, const T& top, const T& nearPlane, const T& farPlane);
+
+ void SetLookAt(const Vector3& eyePosition, const Vector3& lookAtPosition, Vector3 upVector = Vector3(T(0), T(1), T(0)));
+
+ bool IsZero() const;
+ bool IsIdentity() const;
+
+ void ApplyTranslation(const T& x, const T& y, const T& z);
+ void ApplyRotation(const T& angle, const T& x, const T& y, const T& z);
+ void ApplyScale(const T& x, const T& y, const T& z);
+
+ Vector3 GetTranslation() const;
+
+ const T* GetInternalValues() const;
+ T* GetInternalValues();
+ std::string ToString(const std::string& lineBegin = "|", const std::string& lineEnd = "|\n") const;
+
+ private:
+ union {
+ // column-major matrix
+ struct
+ {
+ T m_11, m_21, m_31, m_41, m_12, m_22, m_32, m_42, m_13, m_23, m_33, m_43, m_14, m_24, m_34, m_44;
+ };
+ T m_values[16];
+ };
+};
+
+typedef Matrix4 Matrix4i;
+typedef Matrix4 Matrix4f;
+typedef Matrix4 Matrix4d;
+
+template
+const Matrix4 Matrix4::ZERO = Matrix4(0);
+
+template
+const Matrix4 Matrix4::IDENTITY = Matrix4(
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+
+ template
+std::ostream& operator<<(std::ostream& out, const Matrix4& m)
+{
+ out << m.ToString();
+ return out;
+}
+
+ template
+Matrix4::Matrix4()
+{
+ // Leave matrix uninitialized
+}
+
+ template
+Matrix4::Matrix4(const T& v)
+{
+ for(int i = 0; i < 16; ++i)
+ m_values[i] = v;
+}
+
+ template
+Matrix4::Matrix4(const Matrix4& m)
+{
+ for(int i = 0; i < 16; ++i)
+ m_values[i] = m.m_values[i];
+}
+
+ template
+Matrix4::Matrix4(const T& m_11, const T& m_12, const T& m_13, const T& m_14,
+ const T& m_21, const T& m_22, const T& m_23, const T& m_24,
+ const T& m_31, const T& m_32, const T& m_33, const T& m_34,
+ const T& m_41, const T& m_42, const T& m_43, const T& m_44)
+{
+ this->m_11 = m_11;
+ this->m_12 = m_12;
+ this->m_13 = m_13;
+ this->m_14 = m_14;
+ this->m_21 = m_21;
+ this->m_22 = m_22;
+ this->m_23 = m_23;
+ this->m_24 = m_24;
+ this->m_31 = m_31;
+ this->m_32 = m_32;
+ this->m_33 = m_33;
+ this->m_34 = m_34;
+ this->m_41 = m_41;
+ this->m_42 = m_42;
+ this->m_43 = m_43;
+ this->m_44 = m_44;
+}
+
+template
+const T& Matrix4::Get11() const
+{
+ return m_11;
+}
+
+template
+const T& Matrix4::Get12() const
+{
+ return m_12;
+}
+
+template
+const T& Matrix4::Get13() const
+{
+ return m_13;
+}
+
+template
+const T& Matrix4::Get14() const
+{
+ return m_14;
+}
+
+template
+const T& Matrix4::Get21() const
+{
+ return m_21;
+}
+
+template
+const T& Matrix4::Get22() const
+{
+ return m_22;
+}
+
+template
+const T& Matrix4::Get23() const
+{
+ return m_23;
+}
+
+template
+const T& Matrix4::Get24() const
+{
+ return m_24;
+}
+
+template
+const T& Matrix4::Get31() const
+{
+ return m_31;
+}
+
+template
+const T& Matrix4::Get32() const
+{
+ return m_32;
+}
+
+template
+const T& Matrix4::Get33() const
+{
+ return m_33;
+}
+
+template
+const T& Matrix4::Get34() const
+{
+ return m_34;
+}
+
+template
+const T& Matrix4::Get41() const
+{
+ return m_41;
+}
+
+template
+const T& Matrix4::Get42() const
+{
+ return m_42;
+}
+
+template
+const T& Matrix4::Get43() const
+{
+ return m_43;
+}
+
+template
+const T& Matrix4::Get44() const
+{
+ return m_44;
+}
+
+ template
+Matrix4& Matrix4::operator=(const Matrix4& m)
+{
+ if(this != &m)
+ {
+ for(int i = 0; i < 16; ++i)
+ m_values[i] = m.m_values[i];
+ }
+
+ return *this;
+}
+
+template
+Matrix4 Matrix4::operator+(const Matrix4& m) const
+{
+ return Matrix4(
+ m_11 + m.m_11, m_12 + m.m_12, m_13 + m.m_13, m_14 + m.m_14,
+ m_21 + m.m_21, m_22 + m.m_22, m_23 + m.m_23, m_24 + m.m_24,
+ m_31 + m.m_31, m_32 + m.m_32, m_33 + m.m_33, m_34 + m.m_34,
+ m_41 + m.m_41, m_42 + m.m_42, m_43 + m.m_43, m_44 + m.m_44);
+}
+
+ template
+const Matrix4& Matrix4::operator+=(const Matrix4& m)
+{
+ *this = *this + m;
+ return *this;
+}
+
+template
+Matrix4 Matrix4::operator-(const Matrix4& m) const
+{
+ return Matrix4(
+ m_11 - m.m_11, m_12 - m.m_12, m_13 - m.m_13, m_14 - m.m_14,
+ m_21 - m.m_21, m_22 - m.m_22, m_23 - m.m_23, m_24 - m.m_24,
+ m_31 - m.m_31, m_32 - m.m_32, m_33 - m.m_33, m_34 - m.m_34,
+ m_41 - m.m_41, m_42 - m.m_42, m_43 - m.m_43, m_44 - m.m_44);
+}
+
+template
+Matrix4 Matrix4::operator-() const
+{
+ return Matrix4(
+ -m_11, -m_12, -m_13, -m_14,
+ -m_21, -m_22, -m_23, -m_24,
+ -m_31, -m_32, -m_33, -m_34,
+ -m_41, -m_42, -m_43, -m_44);
+}
+
+ template
+const Matrix4& Matrix4::operator-=(const Matrix4& m)
+{
+ *this = *this - m;
+ return *this;
+}
+
+template
+Matrix4 Matrix4::operator*(const Matrix4& m) const
+{
+ return Matrix4(
+ m_11 * m.m_11 + m_12 * m.m_21 + m_13 * m.m_31 + m_14 * m.m_41,
+ m_11 * m.m_12 + m_12 * m.m_22 + m_13 * m.m_32 + m_14 * m.m_42,
+ m_11 * m.m_13 + m_12 * m.m_23 + m_13 * m.m_33 + m_14 * m.m_43,
+ m_11 * m.m_14 + m_12 * m.m_24 + m_13 * m.m_34 + m_14 * m.m_44,
+
+ m_21 * m.m_11 + m_22 * m.m_21 + m_23 * m.m_31 + m_24 * m.m_41,
+ m_21 * m.m_12 + m_22 * m.m_22 + m_23 * m.m_32 + m_24 * m.m_42,
+ m_21 * m.m_13 + m_22 * m.m_23 + m_23 * m.m_33 + m_24 * m.m_43,
+ m_21 * m.m_14 + m_22 * m.m_24 + m_23 * m.m_34 + m_24 * m.m_44,
+
+ m_31 * m.m_11 + m_32 * m.m_21 + m_33 * m.m_31 + m_34 * m.m_41,
+ m_31 * m.m_12 + m_32 * m.m_22 + m_33 * m.m_32 + m_34 * m.m_42,
+ m_31 * m.m_13 + m_32 * m.m_23 + m_33 * m.m_33 + m_34 * m.m_43,
+ m_31 * m.m_14 + m_32 * m.m_24 + m_33 * m.m_34 + m_34 * m.m_44,
+
+ m_41 * m.m_11 + m_42 * m.m_21 + m_43 * m.m_31 + m_44 * m.m_41,
+ m_41 * m.m_12 + m_42 * m.m_22 + m_43 * m.m_32 + m_44 * m.m_42,
+ m_41 * m.m_13 + m_42 * m.m_23 + m_43 * m.m_33 + m_44 * m.m_43,
+ m_41 * m.m_14 + m_42 * m.m_24 + m_43 * m.m_34 + m_44 * m.m_44);
+}
+
+template
+Matrix4 Matrix4::operator*(const T& v) const
+{
+ return Matrix4(
+ m_11 * v, m_12 * v, m_13 * v, m_14 * v,
+ m_21 * v, m_22 * v, m_23 * v, m_24 * v,
+ m_31 * v, m_32 * v, m_33 * v, m_34 * v,
+ m_41 * v, m_42 * v, m_43 * v, m_44 * v);
+}
+
+ template
+const Matrix4& Matrix4::operator*=(const Matrix4& m)
+{
+ *this = *this * m;
+ return *this;
+}
+
+ template
+const Matrix4& Matrix4::operator*=(const T& v)
+{
+ *this = *this * v;
+ return *this;
+}
+
+template
+Matrix4 Matrix4::operator/(const T& v) const
+{
+ return Matrix4(
+ m_11 / v, m_12 / v, m_13 / v, m_14 / v,
+ m_21 / v, m_22 / v, m_23 / v, m_24 / v,
+ m_31 / v, m_32 / v, m_33 / v, m_34 / v,
+ m_41 / v, m_42 / v, m_43 / v, m_44 / v);
+}
+
+ template
+const Matrix4& Matrix4::operator/=(const T& v)
+{
+ *this = *this / v;
+ return *this;
+}
+
+template
+bool Matrix4::operator==(const Matrix4& m) const
+{
+ for(int i = 0; i < 16; ++i)
+ if(m_values[i] != m.m_values[i])
+ return false;
+
+ return true;
+}
+
+template
+bool Matrix4::operator!=(const Matrix4& m) const
+{
+ return !(*this == m);
+}
+
+ template
+void Matrix4::SetZero()
+{
+ *this = ZERO;
+}
+
+ template
+void Matrix4::SetIdentity()
+{
+ *this = IDENTITY;
+}
+
+ template
+void Matrix4::SetPerspectiveProjection(const T& fov, const T& aspect, const T& nearPlane, const T& farPlane)
+{
+ const float h = T(1) / tan(fov * T(M_PI / 360.f));
+ T negDepth = nearPlane - farPlane;
+
+ SetZero();
+
+ m_11 = h / aspect;
+ m_22 = h;
+ m_33 = (farPlane + nearPlane) / negDepth;
+ m_34 = T(2) * (nearPlane * farPlane) / negDepth;
+ m_43 = -T(1);
+}
+
+ template
+void Matrix4::SetOrthographicProjection(const T& left, const T& right, const T& bottom, const T& top, const T& nearPlane, const T& farPlane)
+{
+ m_11 = T(2) / (right - left);
+ m_12 = T(0);
+ m_13 = T(0);
+ m_14 = -(right + left) / (right - left);
+
+ m_21 = T(0);
+ m_22 = T(2) / (top - bottom);
+ m_23 = T(0);
+ m_24 = -(top + bottom) / (top - bottom);
+
+ m_31 = T(0);
+ m_32 = T(0);
+ m_33 = -T(2) / (farPlane - nearPlane);
+ m_34 = -(farPlane + nearPlane) / (farPlane - nearPlane);
+
+ m_41 = T(0);
+ m_42 = T(0);
+ m_43 = T(0);
+ m_44 = T(1);
+}
+
+ template
+void Matrix4::SetLookAt(const Vector3& eyePosition, const Vector3& lookAtPosition, Vector3 upVector)
+{
+ Vector3f L = lookAtPosition - eyePosition;
+ L.Normalize();
+
+ upVector.Normalize();
+ Vector3f S = L.Cross(upVector);
+ S.Normalize();
+
+ Vector3f U = S.Cross(L);
+
+ Matrix4 M;
+ M.m_11 = S.x;
+ M.m_12 = S.y;
+ M.m_13 = S.z;
+ M.m_14 = 0;
+
+ M.m_21 = U.x;
+ M.m_22 = U.y;
+ M.m_23 = U.z;
+ M.m_24 = 0;
+
+ M.m_31 = -L.x;
+ M.m_32 = -L.y;
+ M.m_33 = -L.z;
+ M.m_34 = 0;
+
+ M.m_41 = 0;
+ M.m_42 = 0;
+ M.m_43 = 0;
+ M.m_44 = 1.f;
+
+ SetIdentity();
+ *this *= M;
+ ApplyTranslation(-eyePosition.x, -eyePosition.y, -eyePosition.z);
+}
+
+ template
+void Matrix4::ApplyTranslation(const T& x, const T& y, const T& z)
+{
+ Matrix4 tmp(
+ 1, 0, 0, x,
+ 0, 1, 0, y,
+ 0, 0, 1, z,
+ 0, 0, 0, 1);
+
+ *this *= tmp;
+}
+
+ template
+void Matrix4::ApplyRotation(const T& angle, const T& x, const T& y, const T& z)
+{
+ // TODO axis (x, y, z) must be normalized...
+
+ T s = sin(DEGTORAD(angle));
+ T c = cos(DEGTORAD(angle));
+ T ic = T(1) - c;
+
+ Matrix4 tmp(
+ x * x * ic + c, y * x * ic + (z * s), z * x * ic - (y * s), 0,
+ x * y * ic - (z * s), y * y * ic + c, z * y * ic + (x * s), 0,
+ x * z * ic + (y * s), y * z * ic - (x * s), z * z * ic + c, 0,
+ 0, 0, 0, 1);
+
+ *this *= tmp;
+}
+
+ template
+void Matrix4::ApplyScale(const T& x, const T& y, const T& z)
+{
+ Matrix4 tmp(
+ x, 0, 0, 0,
+ 0, y, 0, 0,
+ 0, 0, z, 0,
+ 0, 0, 0, 1);
+
+ *this *= tmp;
+}
+
+template
+Vector3 Matrix4::GetTranslation() const
+{
+ // NOTE: Works only if the matrix doesn't contains scale information (only rotation and translation)
+ // Reference: http://www.gamedev.net/topic/397751-how-to-get-camera-position/
+ T x = -(m_11 * m_14 + m_21 * m_24 + m_31 * m_34);
+ T y = -(m_12 * m_14 + m_22 * m_24 + m_32 * m_34);
+ T z = -(m_13 * m_14 + m_23 * m_24 + m_33 * m_34);
+
+ return Vector3(x, y, z);
+}
+
+ template
+T* Matrix4::GetInternalValues()
+{
+ return m_values;
+}
+
+template
+const T* Matrix4::GetInternalValues() const
+{
+ return m_values;
+}
+
+template
+std::string Matrix4::ToString(const std::string& lineBegin, const std::string& lineEnd) const
+{
+ std::ostringstream ss;
+ ss << lineBegin << m_11 << " " << m_12 << " " << m_13 << " " << m_14 << lineEnd;
+ ss << lineBegin << m_21 << " " << m_22 << " " << m_23 << " " << m_24 << lineEnd;
+ ss << lineBegin << m_31 << " " << m_32 << " " << m_33 << " " << m_34 << lineEnd;
+ ss << lineBegin << m_41 << " " << m_42 << " " << m_43 << " " << m_44 << lineEnd;
+
+ return ss.str();
+}
+
+#endif // MATRIX4_H__
diff --git a/SQCSim-common/opensimplex.cpp b/SQCSim-common/opensimplex.cpp
new file mode 100644
index 0000000..a64d31f
--- /dev/null
+++ b/SQCSim-common/opensimplex.cpp
@@ -0,0 +1,2542 @@
+#include "opensimplex.h"
+
+#include
+namespace OpenSimplexNoise
+{
+ using namespace std;
+
+ Noise::Noise()
+ : m_stretch2d(-0.211324865405187) //(1/Math.sqrt(2+1)-1)/2;
+ , m_squish2d(0.366025403784439) //(Math.sqrt(2+1)-1)/2;
+ , m_stretch3d(-1.0 / 6) //(1/Math.sqrt(3+1)-1)/3;
+ , m_squish3d(1.0 / 3) //(Math.sqrt(3+1)-1)/3;
+ , m_stretch4d(-0.138196601125011) //(1/Math.sqrt(4+1)-1)/4;
+ , m_squish4d(0.309016994374947) //(Math.sqrt(4+1)-1)/4;
+ , m_norm2d(47)
+ , m_norm3d(103)
+ , m_norm4d(30)
+ , m_defaultSeed(0)
+ , m_perm{0}
+ , m_permGradIndex3d{0}
+ , m_gradients2d{ 5, 2, 2, 5,
+ -5, 2, -2, 5,
+ 5, -2, 2, -5,
+ -5, -2, -2, -5, }
+ , m_gradients3d{-11, 4, 4, -4, 11, 4, -4, 4, 11,
+ 11, 4, 4, 4, 11, 4, 4, 4, 11,
+ -11, -4, 4, -4, -11, 4, -4, -4, 11,
+ 11, -4, 4, 4, -11, 4, 4, -4, 11,
+ -11, 4, -4, -4, 11, -4, -4, 4, -11,
+ 11, 4, -4, 4, 11, -4, 4, 4, -11,
+ -11, -4, -4, -4, -11, -4, -4, -4, -11,
+ 11, -4, -4, 4, -11, -4, 4, -4, -11, }
+ , m_gradients4d{ 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3,
+ -3, 1, 1, 1, -1, 3, 1, 1, -1, 1, 3, 1, -1, 1, 1, 3,
+ 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3, 1, 1, -1, 1, 3,
+ -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3,
+ 3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3,
+ -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3,
+ 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3,
+ -3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3,
+ 3, 1, 1, -1, 1, 3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3,
+ -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3, -1, -1, 1, 1, -3,
+ 3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3,
+ -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3,
+ 3, 1, -1, -1, 1, 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3,
+ -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3,
+ 3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3,
+ -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3, }
+ {
+ }
+
+ Noise::Noise(int64_t seed)
+ : Noise()
+ {
+ short source[256];
+ for (short i = 0; i < 256; i++)
+ {
+ source[i] = i;
+ }
+ seed = seed * 6364136223846793005l + 1442695040888963407l;
+ seed = seed * 6364136223846793005l + 1442695040888963407l;
+ seed = seed * 6364136223846793005l + 1442695040888963407l;
+ for (int i = 255; i >= 0; i--)
+ {
+ seed = seed * 6364136223846793005l + 1442695040888963407l;
+ int r = static_cast((seed + 31) % (i + 1));
+ if (r < 0)
+ {
+ r += (i + 1);
+ }
+ m_perm[i] = source[r];
+ m_permGradIndex3d[i] = static_cast((m_perm[i] % (m_gradients3d.size() / 3)) * 3);
+ source[r] = source[i];
+ }
+ }
+
+ double Noise::eval(double x, double y) const
+ {
+ //Place input coordinates onto grid.
+ double stretchOffset = (x + y) * m_stretch2d;
+ double xs = x + stretchOffset;
+ double ys = y + stretchOffset;
+
+ //Floor to get grid coordinates of rhombus (stretched square) super-cell origin.
+ int xsb = static_cast(floor(xs));
+ int ysb = static_cast(floor(ys));
+
+ //Skew out to get actual coordinates of rhombus origin. We'll need these later.
+ double squishOffset = (xsb + ysb) * m_squish2d;
+ double xb = xsb + squishOffset;
+ double yb = ysb + squishOffset;
+
+ //Compute grid coordinates relative to rhombus origin.
+ double xins = xs - xsb;
+ double yins = ys - ysb;
+
+ //Sum those together to get a value that determines which region we're in.
+ double inSum = xins + yins;
+
+ //Positions relative to origin point.
+ double dx0 = x - xb;
+ double dy0 = y - yb;
+
+ //We'll be defining these inside the next block and using them afterwards.
+ double dx_ext, dy_ext;
+ int xsv_ext, ysv_ext;
+
+ double value = 0;
+
+ //Contribution (1,0)
+ double dx1 = dx0 - 1 - m_squish2d;
+ double dy1 = dy0 - 0 - m_squish2d;
+ double attn1 = 2 - dx1 * dx1 - dy1 * dy1;
+ if (attn1 > 0)
+ {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, dx1, dy1);
+ }
+
+ //Contribution (0,1)
+ double dx2 = dx0 - 0 - m_squish2d;
+ double dy2 = dy0 - 1 - m_squish2d;
+ double attn2 = 2 - dx2 * dx2 - dy2 * dy2;
+ if (attn2 > 0)
+ {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, dx2, dy2);
+ }
+
+ if (inSum <= 1)
+ { //We're inside the triangle (2-Simplex) at (0,0)
+ double zins = 1 - inSum;
+ if (zins > xins || zins > yins)
+ { //(0,0) is one of the closest two triangular vertices
+ if (xins > yins)
+ {
+ xsv_ext = xsb + 1;
+ ysv_ext = ysb - 1;
+ dx_ext = dx0 - 1;
+ dy_ext = dy0 + 1;
+ }
+ else
+ {
+ xsv_ext = xsb - 1;
+ ysv_ext = ysb + 1;
+ dx_ext = dx0 + 1;
+ dy_ext = dy0 - 1;
+ }
+ }
+ else
+ { //(1,0) and (0,1) are the closest two vertices.
+ xsv_ext = xsb + 1;
+ ysv_ext = ysb + 1;
+ dx_ext = dx0 - 1 - 2 * m_squish2d;
+ dy_ext = dy0 - 1 - 2 * m_squish2d;
+ }
+ }
+ else
+ { //We're inside the triangle (2-Simplex) at (1,1)
+ double zins = 2 - inSum;
+ if (zins < xins || zins < yins)
+ { //(0,0) is one of the closest two triangular vertices
+ if (xins > yins)
+ {
+ xsv_ext = xsb + 2;
+ ysv_ext = ysb + 0;
+ dx_ext = dx0 - 2 - 2 * m_squish2d;
+ dy_ext = dy0 + 0 - 2 * m_squish2d;
+ }
+ else
+ {
+ xsv_ext = xsb + 0;
+ ysv_ext = ysb + 2;
+ dx_ext = dx0 + 0 - 2 * m_squish2d;
+ dy_ext = dy0 - 2 - 2 * m_squish2d;
+ }
+ }
+ else
+ { //(1,0) and (0,1) are the closest two vertices.
+ dx_ext = dx0;
+ dy_ext = dy0;
+ xsv_ext = xsb;
+ ysv_ext = ysb;
+ }
+ xsb += 1;
+ ysb += 1;
+ dx0 = dx0 - 1 - 2 * m_squish2d;
+ dy0 = dy0 - 1 - 2 * m_squish2d;
+ }
+
+ //Contribution (0,0) or (1,1)
+ double attn0 = 2 - dx0 * dx0 - dy0 * dy0;
+ if (attn0 > 0)
+ {
+ attn0 *= attn0;
+ value += attn0 * attn0 * extrapolate(xsb, ysb, dx0, dy0);
+ }
+
+ //Extra Vertex
+ double attn_ext = 2 - dx_ext * dx_ext - dy_ext * dy_ext;
+ if (attn_ext > 0)
+ {
+ attn_ext *= attn_ext;
+ value += attn_ext * attn_ext * extrapolate(xsv_ext, ysv_ext, dx_ext, dy_ext);
+ }
+
+ return value / m_norm2d;
+ }
+
+ double Noise::eval(double x, double y, double z) const
+ {
+ //Place input coordinates on simplectic honeycomb.
+ double stretchOffset = (x + y + z) * m_stretch3d;
+ double xs = x + stretchOffset;
+ double ys = y + stretchOffset;
+ double zs = z + stretchOffset;
+
+ //static_cast(floor to get simplectic honeycomb coordinates of rhombohedron (stretched cube) super-cell origin.
+ int xsb = static_cast(floor(xs));
+ int ysb = static_cast(floor(ys));
+ int zsb = static_cast(floor(zs));
+
+ //Skew out to get actual coordinates of rhombohedron origin. We'll need these later.
+ double squishOffset = (xsb + ysb + zsb) * m_squish3d;
+ double xb = xsb + squishOffset;
+ double yb = ysb + squishOffset;
+ double zb = zsb + squishOffset;
+
+ //Compute simplectic honeycomb coordinates relative to rhombohedral origin.
+ double xins = xs - xsb;
+ double yins = ys - ysb;
+ double zins = zs - zsb;
+
+ //Sum those together to get a value that determines which region we're in.
+ double inSum = xins + yins + zins;
+
+ //Positions relative to origin point.
+ double dx0 = x - xb;
+ double dy0 = y - yb;
+ double dz0 = z - zb;
+
+ //We'll be defining these inside the next block and using them afterwards.
+ double dx_ext0, dy_ext0, dz_ext0;
+ double dx_ext1, dy_ext1, dz_ext1;
+ int xsv_ext0, ysv_ext0, zsv_ext0;
+ int xsv_ext1, ysv_ext1, zsv_ext1;
+
+ double value = 0;
+ if (inSum <= 1)
+ { //We're inside the tetrahedron (3-Simplex) at (0,0,0)
+
+//Determine which two of (0,0,1), (0,1,0), (1,0,0) are closest.
+ char aPoint = 0x01;
+ double aScore = xins;
+ char bPoint = 0x02;
+ double bScore = yins;
+ if (aScore >= bScore && zins > bScore)
+ {
+ bScore = zins;
+ bPoint = 0x04;
+ }
+ else if (aScore < bScore && zins > aScore)
+ {
+ aScore = zins;
+ aPoint = 0x04;
+ }
+
+ //Now we determine the two lattice points not part of the tetrahedron that may contribute.
+ //This depends on the closest two tetrahedral vertices, including (0,0,0)
+ double wins = 1 - inSum;
+ if (wins > aScore || wins > bScore)
+ { //(0,0,0) is one of the closest two tetrahedral vertices.
+ char c = (bScore > aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b.
+
+ if ((c & 0x01) == 0)
+ {
+ xsv_ext0 = xsb - 1;
+ xsv_ext1 = xsb;
+ dx_ext0 = dx0 + 1;
+ dx_ext1 = dx0;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsb + 1;
+ dx_ext0 = dx_ext1 = dx0 - 1;
+ }
+
+ if ((c & 0x02) == 0)
+ {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0;
+ if ((c & 0x01) == 0)
+ {
+ ysv_ext1 -= 1;
+ dy_ext1 += 1;
+ }
+ else
+ {
+ ysv_ext0 -= 1;
+ dy_ext0 += 1;
+ }
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1;
+ }
+
+ if ((c & 0x04) == 0)
+ {
+ zsv_ext0 = zsb;
+ zsv_ext1 = zsb - 1;
+ dz_ext0 = dz0;
+ dz_ext1 = dz0 + 1;
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz0 - 1;
+ }
+ }
+ else
+ { //(0,0,0) is not one of the closest two tetrahedral vertices.
+ char c = static_cast(aPoint | bPoint); //Our two extra vertices are determined by the closest two.
+
+ if ((c & 0x01) == 0)
+ {
+ xsv_ext0 = xsb;
+ xsv_ext1 = xsb - 1;
+ dx_ext0 = dx0 - 2 * m_squish3d;
+ dx_ext1 = dx0 + 1 - m_squish3d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsb + 1;
+ dx_ext0 = dx0 - 1 - 2 * m_squish3d;
+ dx_ext1 = dx0 - 1 - m_squish3d;
+ }
+
+ if ((c & 0x02) == 0)
+ {
+ ysv_ext0 = ysb;
+ ysv_ext1 = ysb - 1;
+ dy_ext0 = dy0 - 2 * m_squish3d;
+ dy_ext1 = dy0 + 1 - m_squish3d;
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy0 - 1 - 2 * m_squish3d;
+ dy_ext1 = dy0 - 1 - m_squish3d;
+ }
+
+ if ((c & 0x04) == 0)
+ {
+ zsv_ext0 = zsb;
+ zsv_ext1 = zsb - 1;
+ dz_ext0 = dz0 - 2 * m_squish3d;
+ dz_ext1 = dz0 + 1 - m_squish3d;
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz0 - 1 - 2 * m_squish3d;
+ dz_ext1 = dz0 - 1 - m_squish3d;
+ }
+ }
+
+ //Contribution (0,0,0)
+ double attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0;
+ if (attn0 > 0)
+ {
+ attn0 *= attn0;
+ value += attn0 * attn0 * extrapolate(xsb + 0, ysb + 0, zsb + 0, dx0, dy0, dz0);
+ }
+
+ //Contribution (1,0,0)
+ double dx1 = dx0 - 1 - m_squish3d;
+ double dy1 = dy0 - 0 - m_squish3d;
+ double dz1 = dz0 - 0 - m_squish3d;
+ double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
+ if (attn1 > 0)
+ {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, dx1, dy1, dz1);
+ }
+
+ //Contribution (0,1,0)
+ double dx2 = dx0 - 0 - m_squish3d;
+ double dy2 = dy0 - 1 - m_squish3d;
+ double dz2 = dz1;
+ double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
+ if (attn2 > 0)
+ {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, dx2, dy2, dz2);
+ }
+
+ //Contribution (0,0,1)
+ double dx3 = dx2;
+ double dy3 = dy1;
+ double dz3 = dz0 - 1 - m_squish3d;
+ double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
+ if (attn3 > 0)
+ {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, dx3, dy3, dz3);
+ }
+ }
+ else if (inSum >= 2)
+ { //We're inside the tetrahedron (3-Simplex) at (1,1,1)
+
+//Determine which two tetrahedral vertices are the closest, out of (1,1,0), (1,0,1), (0,1,1) but not (1,1,1).
+ char aPoint = 0x06;
+ double aScore = xins;
+ char bPoint = 0x05;
+ double bScore = yins;
+ if (aScore <= bScore && zins < bScore)
+ {
+ bScore = zins;
+ bPoint = 0x03;
+ }
+ else if (aScore > bScore && zins < aScore)
+ {
+ aScore = zins;
+ aPoint = 0x03;
+ }
+
+ //Now we determine the two lattice points not part of the tetrahedron that may contribute.
+ //This depends on the closest two tetrahedral vertices, including (1,1,1)
+ double wins = 3 - inSum;
+ if (wins < aScore || wins < bScore)
+ { //(1,1,1) is one of the closest two tetrahedral vertices.
+ char c = (bScore < aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b.
+
+ if ((c & 0x01) != 0)
+ {
+ xsv_ext0 = xsb + 2;
+ xsv_ext1 = xsb + 1;
+ dx_ext0 = dx0 - 2 - 3 * m_squish3d;
+ dx_ext1 = dx0 - 1 - 3 * m_squish3d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsb;
+ dx_ext0 = dx_ext1 = dx0 - 3 * m_squish3d;
+ }
+
+ if ((c & 0x02) != 0)
+ {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1 - 3 * m_squish3d;
+ if ((c & 0x01) != 0)
+ {
+ ysv_ext1 += 1;
+ dy_ext1 -= 1;
+ }
+ else
+ {
+ ysv_ext0 += 1;
+ dy_ext0 -= 1;
+ }
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0 - 3 * m_squish3d;
+ }
+
+ if ((c & 0x04) != 0)
+ {
+ zsv_ext0 = zsb + 1;
+ zsv_ext1 = zsb + 2;
+ dz_ext0 = dz0 - 1 - 3 * m_squish3d;
+ dz_ext1 = dz0 - 2 - 3 * m_squish3d;
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz_ext1 = dz0 - 3 * m_squish3d;
+ }
+ }
+ else
+ { //(1,1,1) is not one of the closest two tetrahedral vertices.
+ char c = static_cast(aPoint & bPoint); //Our two extra vertices are determined by the closest two.
+
+ if ((c & 0x01) != 0)
+ {
+ xsv_ext0 = xsb + 1;
+ xsv_ext1 = xsb + 2;
+ dx_ext0 = dx0 - 1 - m_squish3d;
+ dx_ext1 = dx0 - 2 - 2 * m_squish3d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsb;
+ dx_ext0 = dx0 - m_squish3d;
+ dx_ext1 = dx0 - 2 * m_squish3d;
+ }
+
+ if ((c & 0x02) != 0)
+ {
+ ysv_ext0 = ysb + 1;
+ ysv_ext1 = ysb + 2;
+ dy_ext0 = dy0 - 1 - m_squish3d;
+ dy_ext1 = dy0 - 2 - 2 * m_squish3d;
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy0 - m_squish3d;
+ dy_ext1 = dy0 - 2 * m_squish3d;
+ }
+
+ if ((c & 0x04) != 0)
+ {
+ zsv_ext0 = zsb + 1;
+ zsv_ext1 = zsb + 2;
+ dz_ext0 = dz0 - 1 - m_squish3d;
+ dz_ext1 = dz0 - 2 - 2 * m_squish3d;
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz0 - m_squish3d;
+ dz_ext1 = dz0 - 2 * m_squish3d;
+ }
+ }
+
+ //Contribution (1,1,0)
+ double dx3 = dx0 - 1 - 2 * m_squish3d;
+ double dy3 = dy0 - 1 - 2 * m_squish3d;
+ double dz3 = dz0 - 0 - 2 * m_squish3d;
+ double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
+ if (attn3 > 0)
+ {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate(xsb + 1, ysb + 1, zsb + 0, dx3, dy3, dz3);
+ }
+
+ //Contribution (1,0,1)
+ double dx2 = dx3;
+ double dy2 = dy0 - 0 - 2 * m_squish3d;
+ double dz2 = dz0 - 1 - 2 * m_squish3d;
+ double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
+ if (attn2 > 0)
+ {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate(xsb + 1, ysb + 0, zsb + 1, dx2, dy2, dz2);
+ }
+
+ //Contribution (0,1,1)
+ double dx1 = dx0 - 0 - 2 * m_squish3d;
+ double dy1 = dy3;
+ double dz1 = dz2;
+ double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
+ if (attn1 > 0)
+ {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate(xsb + 0, ysb + 1, zsb + 1, dx1, dy1, dz1);
+ }
+
+ //Contribution (1,1,1)
+ dx0 = dx0 - 1 - 3 * m_squish3d;
+ dy0 = dy0 - 1 - 3 * m_squish3d;
+ dz0 = dz0 - 1 - 3 * m_squish3d;
+ double attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0;
+ if (attn0 > 0)
+ {
+ attn0 *= attn0;
+ value += attn0 * attn0 * extrapolate(xsb + 1, ysb + 1, zsb + 1, dx0, dy0, dz0);
+ }
+ }
+ else
+ { //We're inside the octahedron (Rectified 3-Simplex) in between.
+ double aScore;
+ char aPoint;
+ bool aIsFurtherSide;
+ double bScore;
+ char bPoint;
+ bool bIsFurtherSide;
+
+ //Decide between point (0,0,1) and (1,1,0) as closest
+ double p1 = xins + yins;
+ if (p1 > 1)
+ {
+ aScore = p1 - 1;
+ aPoint = 0x03;
+ aIsFurtherSide = true;
+ }
+ else
+ {
+ aScore = 1 - p1;
+ aPoint = 0x04;
+ aIsFurtherSide = false;
+ }
+
+ //Decide between point (0,1,0) and (1,0,1) as closest
+ double p2 = xins + zins;
+ if (p2 > 1)
+ {
+ bScore = p2 - 1;
+ bPoint = 0x05;
+ bIsFurtherSide = true;
+ }
+ else
+ {
+ bScore = 1 - p2;
+ bPoint = 0x02;
+ bIsFurtherSide = false;
+ }
+
+ //The closest out of the two (1,0,0) and (0,1,1) will replace the furthest out of the two decided above, if closer.
+ double p3 = yins + zins;
+ if (p3 > 1)
+ {
+ double score = p3 - 1;
+ if (aScore <= bScore && aScore < score)
+ {
+ aScore = score;
+ aPoint = 0x06;
+ aIsFurtherSide = true;
+ }
+ else if (aScore > bScore && bScore < score)
+ {
+ bScore = score;
+ bPoint = 0x06;
+ bIsFurtherSide = true;
+ }
+ }
+ else
+ {
+ double score = 1 - p3;
+ if (aScore <= bScore && aScore < score)
+ {
+ aScore = score;
+ aPoint = 0x01;
+ aIsFurtherSide = false;
+ }
+ else if (aScore > bScore && bScore < score)
+ {
+ bScore = score;
+ bPoint = 0x01;
+ bIsFurtherSide = false;
+ }
+ }
+
+ //Where each of the two closest points are determines how the extra two vertices are calculated.
+ if (aIsFurtherSide == bIsFurtherSide)
+ {
+ if (aIsFurtherSide)
+ { //Both closest points on (1,1,1) side
+
+//One of the two extra points is (1,1,1)
+ dx_ext0 = dx0 - 1 - 3 * m_squish3d;
+ dy_ext0 = dy0 - 1 - 3 * m_squish3d;
+ dz_ext0 = dz0 - 1 - 3 * m_squish3d;
+ xsv_ext0 = xsb + 1;
+ ysv_ext0 = ysb + 1;
+ zsv_ext0 = zsb + 1;
+
+ //Other extra point is based on the shared axis.
+ char c = static_cast(aPoint & bPoint);
+ if ((c & 0x01) != 0)
+ {
+ dx_ext1 = dx0 - 2 - 2 * m_squish3d;
+ dy_ext1 = dy0 - 2 * m_squish3d;
+ dz_ext1 = dz0 - 2 * m_squish3d;
+ xsv_ext1 = xsb + 2;
+ ysv_ext1 = ysb;
+ zsv_ext1 = zsb;
+ }
+ else if ((c & 0x02) != 0)
+ {
+ dx_ext1 = dx0 - 2 * m_squish3d;
+ dy_ext1 = dy0 - 2 - 2 * m_squish3d;
+ dz_ext1 = dz0 - 2 * m_squish3d;
+ xsv_ext1 = xsb;
+ ysv_ext1 = ysb + 2;
+ zsv_ext1 = zsb;
+ }
+ else
+ {
+ dx_ext1 = dx0 - 2 * m_squish3d;
+ dy_ext1 = dy0 - 2 * m_squish3d;
+ dz_ext1 = dz0 - 2 - 2 * m_squish3d;
+ xsv_ext1 = xsb;
+ ysv_ext1 = ysb;
+ zsv_ext1 = zsb + 2;
+ }
+ }
+ else
+ {//Both closest points on (0,0,0) side
+
+ //One of the two extra points is (0,0,0)
+ dx_ext0 = dx0;
+ dy_ext0 = dy0;
+ dz_ext0 = dz0;
+ xsv_ext0 = xsb;
+ ysv_ext0 = ysb;
+ zsv_ext0 = zsb;
+
+ //Other extra point is based on the omitted axis.
+ char c = static_cast(aPoint | bPoint);
+ if ((c & 0x01) == 0)
+ {
+ dx_ext1 = dx0 + 1 - m_squish3d;
+ dy_ext1 = dy0 - 1 - m_squish3d;
+ dz_ext1 = dz0 - 1 - m_squish3d;
+ xsv_ext1 = xsb - 1;
+ ysv_ext1 = ysb + 1;
+ zsv_ext1 = zsb + 1;
+ }
+ else if ((c & 0x02) == 0)
+ {
+ dx_ext1 = dx0 - 1 - m_squish3d;
+ dy_ext1 = dy0 + 1 - m_squish3d;
+ dz_ext1 = dz0 - 1 - m_squish3d;
+ xsv_ext1 = xsb + 1;
+ ysv_ext1 = ysb - 1;
+ zsv_ext1 = zsb + 1;
+ }
+ else
+ {
+ dx_ext1 = dx0 - 1 - m_squish3d;
+ dy_ext1 = dy0 - 1 - m_squish3d;
+ dz_ext1 = dz0 + 1 - m_squish3d;
+ xsv_ext1 = xsb + 1;
+ ysv_ext1 = ysb + 1;
+ zsv_ext1 = zsb - 1;
+ }
+ }
+ }
+ else
+ { //One point on (0,0,0) side, one point on (1,1,1) side
+ char c1, c2;
+ if (aIsFurtherSide)
+ {
+ c1 = aPoint;
+ c2 = bPoint;
+ }
+ else
+ {
+ c1 = bPoint;
+ c2 = aPoint;
+ }
+
+ //One contribution is a permutation of (1,1,-1)
+ if ((c1 & 0x01) == 0)
+ {
+ dx_ext0 = dx0 + 1 - m_squish3d;
+ dy_ext0 = dy0 - 1 - m_squish3d;
+ dz_ext0 = dz0 - 1 - m_squish3d;
+ xsv_ext0 = xsb - 1;
+ ysv_ext0 = ysb + 1;
+ zsv_ext0 = zsb + 1;
+ }
+ else if ((c1 & 0x02) == 0)
+ {
+ dx_ext0 = dx0 - 1 - m_squish3d;
+ dy_ext0 = dy0 + 1 - m_squish3d;
+ dz_ext0 = dz0 - 1 - m_squish3d;
+ xsv_ext0 = xsb + 1;
+ ysv_ext0 = ysb - 1;
+ zsv_ext0 = zsb + 1;
+ }
+ else
+ {
+ dx_ext0 = dx0 - 1 - m_squish3d;
+ dy_ext0 = dy0 - 1 - m_squish3d;
+ dz_ext0 = dz0 + 1 - m_squish3d;
+ xsv_ext0 = xsb + 1;
+ ysv_ext0 = ysb + 1;
+ zsv_ext0 = zsb - 1;
+ }
+
+ //One contribution is a permutation of (0,0,2)
+ dx_ext1 = dx0 - 2 * m_squish3d;
+ dy_ext1 = dy0 - 2 * m_squish3d;
+ dz_ext1 = dz0 - 2 * m_squish3d;
+ xsv_ext1 = xsb;
+ ysv_ext1 = ysb;
+ zsv_ext1 = zsb;
+ if ((c2 & 0x01) != 0)
+ {
+ dx_ext1 -= 2;
+ xsv_ext1 += 2;
+ }
+ else if ((c2 & 0x02) != 0)
+ {
+ dy_ext1 -= 2;
+ ysv_ext1 += 2;
+ }
+ else
+ {
+ dz_ext1 -= 2;
+ zsv_ext1 += 2;
+ }
+ }
+
+ //Contribution (1,0,0)
+ double dx1 = dx0 - 1 - m_squish3d;
+ double dy1 = dy0 - 0 - m_squish3d;
+ double dz1 = dz0 - 0 - m_squish3d;
+ double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
+ if (attn1 > 0)
+ {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, dx1, dy1, dz1);
+ }
+
+ //Contribution (0,1,0)
+ double dx2 = dx0 - 0 - m_squish3d;
+ double dy2 = dy0 - 1 - m_squish3d;
+ double dz2 = dz1;
+ double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
+ if (attn2 > 0)
+ {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, dx2, dy2, dz2);
+ }
+
+ //Contribution (0,0,1)
+ double dx3 = dx2;
+ double dy3 = dy1;
+ double dz3 = dz0 - 1 - m_squish3d;
+ double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
+ if (attn3 > 0)
+ {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, dx3, dy3, dz3);
+ }
+
+ //Contribution (1,1,0)
+ double dx4 = dx0 - 1 - 2 * m_squish3d;
+ double dy4 = dy0 - 1 - 2 * m_squish3d;
+ double dz4 = dz0 - 0 - 2 * m_squish3d;
+ double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4;
+ if (attn4 > 0)
+ {
+ attn4 *= attn4;
+ value += attn4 * attn4 * extrapolate(xsb + 1, ysb + 1, zsb + 0, dx4, dy4, dz4);
+ }
+
+ //Contribution (1,0,1)
+ double dx5 = dx4;
+ double dy5 = dy0 - 0 - 2 * m_squish3d;
+ double dz5 = dz0 - 1 - 2 * m_squish3d;
+ double attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5;
+ if (attn5 > 0)
+ {
+ attn5 *= attn5;
+ value += attn5 * attn5 * extrapolate(xsb + 1, ysb + 0, zsb + 1, dx5, dy5, dz5);
+ }
+
+ //Contribution (0,1,1)
+ double dx6 = dx0 - 0 - 2 * m_squish3d;
+ double dy6 = dy4;
+ double dz6 = dz5;
+ double attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6;
+ if (attn6 > 0)
+ {
+ attn6 *= attn6;
+ value += attn6 * attn6 * extrapolate(xsb + 0, ysb + 1, zsb + 1, dx6, dy6, dz6);
+ }
+ }
+
+ //First extra vertex
+ double attn_ext0 = 2 - dx_ext0 * dx_ext0 - dy_ext0 * dy_ext0 - dz_ext0 * dz_ext0;
+ if (attn_ext0 > 0)
+ {
+ attn_ext0 *= attn_ext0;
+ value += attn_ext0 * attn_ext0 * extrapolate(xsv_ext0, ysv_ext0, zsv_ext0, dx_ext0, dy_ext0, dz_ext0);
+ }
+
+ //Second extra vertex
+ double attn_ext1 = 2 - dx_ext1 * dx_ext1 - dy_ext1 * dy_ext1 - dz_ext1 * dz_ext1;
+ if (attn_ext1 > 0)
+ {
+ attn_ext1 *= attn_ext1;
+ value += attn_ext1 * attn_ext1 * extrapolate(xsv_ext1, ysv_ext1, zsv_ext1, dx_ext1, dy_ext1, dz_ext1);
+ }
+
+ return value / m_norm3d;
+ }
+
+ double Noise::eval(double x, double y, double z, double w) const
+ {
+ //Place input coordinates on simplectic honeycomb.
+ double stretchOffset = (x + y + z + w) * m_stretch4d;
+ double xs = x + stretchOffset;
+ double ys = y + stretchOffset;
+ double zs = z + stretchOffset;
+ double ws = w + stretchOffset;
+
+ //static_cast(floor to get simplectic honeycomb coordinates of rhombo-hypercube super-cell origin.
+ int xsb = static_cast(floor(xs));
+ int ysb = static_cast(floor(ys));
+ int zsb = static_cast(floor(zs));
+ int wsb = static_cast(floor(ws));
+
+ //Skew out to get actual coordinates of stretched rhombo-hypercube origin. We'll need these later.
+ double squishOffset = (xsb + ysb + zsb + wsb) * m_squish4d;
+ double xb = xsb + squishOffset;
+ double yb = ysb + squishOffset;
+ double zb = zsb + squishOffset;
+ double wb = wsb + squishOffset;
+
+ //Compute simplectic honeycomb coordinates relative to rhombo-hypercube origin.
+ double xins = xs - xsb;
+ double yins = ys - ysb;
+ double zins = zs - zsb;
+ double wins = ws - wsb;
+
+ //Sum those together to get a value that determines which region we're in.
+ double inSum = xins + yins + zins + wins;
+
+ //Positions relative to origin point.
+ double dx0 = x - xb;
+ double dy0 = y - yb;
+ double dz0 = z - zb;
+ double dw0 = w - wb;
+
+ //We'll be defining these inside the next block and using them afterwards.
+ double dx_ext0, dy_ext0, dz_ext0, dw_ext0;
+ double dx_ext1, dy_ext1, dz_ext1, dw_ext1;
+ double dx_ext2, dy_ext2, dz_ext2, dw_ext2;
+ int xsv_ext0, ysv_ext0, zsv_ext0, wsv_ext0;
+ int xsv_ext1, ysv_ext1, zsv_ext1, wsv_ext1;
+ int xsv_ext2, ysv_ext2, zsv_ext2, wsv_ext2;
+
+ double value = 0;
+ if (inSum <= 1)
+ { //We're inside the pentachoron (4-Simplex) at (0,0,0,0)
+
+//Determine which two of (0,0,0,1), (0,0,1,0), (0,1,0,0), (1,0,0,0) are closest.
+ char aPoint = 0x01;
+ double aScore = xins;
+ char bPoint = 0x02;
+ double bScore = yins;
+ if (aScore >= bScore && zins > bScore)
+ {
+ bScore = zins;
+ bPoint = 0x04;
+ }
+ else if (aScore < bScore && zins > aScore)
+ {
+ aScore = zins;
+ aPoint = 0x04;
+ }
+ if (aScore >= bScore && wins > bScore)
+ {
+ bScore = wins;
+ bPoint = 0x08;
+ }
+ else if (aScore < bScore && wins > aScore)
+ {
+ aScore = wins;
+ aPoint = 0x08;
+ }
+
+ //Now we determine the three lattice points not part of the pentachoron that may contribute.
+ //This depends on the closest two pentachoron vertices, including (0,0,0,0)
+ double uins = 1 - inSum;
+ if (uins > aScore || uins > bScore)
+ { //(0,0,0,0) is one of the closest two pentachoron vertices.
+ char c = (bScore > aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b.
+ if ((c & 0x01) == 0)
+ {
+ xsv_ext0 = xsb - 1;
+ xsv_ext1 = xsv_ext2 = xsb;
+ dx_ext0 = dx0 + 1;
+ dx_ext1 = dx_ext2 = dx0;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb + 1;
+ dx_ext0 = dx_ext1 = dx_ext2 = dx0 - 1;
+ }
+
+ if ((c & 0x02) == 0)
+ {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
+ dy_ext0 = dy_ext1 = dy_ext2 = dy0;
+ if ((c & 0x01) == 0x01)
+ {
+ ysv_ext0 -= 1;
+ dy_ext0 += 1;
+ }
+ else
+ {
+ ysv_ext1 -= 1;
+ dy_ext1 += 1;
+ }
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 1;
+ }
+
+ if ((c & 0x04) == 0)
+ {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
+ dz_ext0 = dz_ext1 = dz_ext2 = dz0;
+ if ((c & 0x03) != 0)
+ {
+ if ((c & 0x03) == 0x03)
+ {
+ zsv_ext0 -= 1;
+ dz_ext0 += 1;
+ }
+ else
+ {
+ zsv_ext1 -= 1;
+ dz_ext1 += 1;
+ }
+ }
+ else
+ {
+ zsv_ext2 -= 1;
+ dz_ext2 += 1;
+ }
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 1;
+ }
+
+ if ((c & 0x08) == 0)
+ {
+ wsv_ext0 = wsv_ext1 = wsb;
+ wsv_ext2 = wsb - 1;
+ dw_ext0 = dw_ext1 = dw0;
+ dw_ext2 = dw0 + 1;
+ }
+ else
+ {
+ wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb + 1;
+ dw_ext0 = dw_ext1 = dw_ext2 = dw0 - 1;
+ }
+ }
+ else
+ { //(0,0,0,0) is not one of the closest two pentachoron vertices.
+ char c = static_cast(aPoint | bPoint); //Our three extra vertices are determined by the closest two.
+
+ if ((c & 0x01) == 0)
+ {
+ xsv_ext0 = xsv_ext2 = xsb;
+ xsv_ext1 = xsb - 1;
+ dx_ext0 = dx0 - 2 * m_squish4d;
+ dx_ext1 = dx0 + 1 - m_squish4d;
+ dx_ext2 = dx0 - m_squish4d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb + 1;
+ dx_ext0 = dx0 - 1 - 2 * m_squish4d;
+ dx_ext1 = dx_ext2 = dx0 - 1 - m_squish4d;
+ }
+
+ if ((c & 0x02) == 0)
+ {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
+ dy_ext0 = dy0 - 2 * m_squish4d;
+ dy_ext1 = dy_ext2 = dy0 - m_squish4d;
+ if ((c & 0x01) == 0x01)
+ {
+ ysv_ext1 -= 1;
+ dy_ext1 += 1;
+ }
+ else
+ {
+ ysv_ext2 -= 1;
+ dy_ext2 += 1;
+ }
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
+ dy_ext0 = dy0 - 1 - 2 * m_squish4d;
+ dy_ext1 = dy_ext2 = dy0 - 1 - m_squish4d;
+ }
+
+ if ((c & 0x04) == 0)
+ {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
+ dz_ext0 = dz0 - 2 * m_squish4d;
+ dz_ext1 = dz_ext2 = dz0 - m_squish4d;
+ if ((c & 0x03) == 0x03)
+ {
+ zsv_ext1 -= 1;
+ dz_ext1 += 1;
+ }
+ else
+ {
+ zsv_ext2 -= 1;
+ dz_ext2 += 1;
+ }
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
+ dz_ext0 = dz0 - 1 - 2 * m_squish4d;
+ dz_ext1 = dz_ext2 = dz0 - 1 - m_squish4d;
+ }
+
+ if ((c & 0x08) == 0)
+ {
+ wsv_ext0 = wsv_ext1 = wsb;
+ wsv_ext2 = wsb - 1;
+ dw_ext0 = dw0 - 2 * m_squish4d;
+ dw_ext1 = dw0 - m_squish4d;
+ dw_ext2 = dw0 + 1 - m_squish4d;
+ }
+ else
+ {
+ wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb + 1;
+ dw_ext0 = dw0 - 1 - 2 * m_squish4d;
+ dw_ext1 = dw_ext2 = dw0 - 1 - m_squish4d;
+ }
+ }
+
+ //Contribution (0,0,0,0)
+ double attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0 - dw0 * dw0;
+ if (attn0 > 0)
+ {
+ attn0 *= attn0;
+ value += attn0 * attn0 * extrapolate(xsb + 0, ysb + 0, zsb + 0, wsb + 0, dx0, dy0, dz0, dw0);
+ }
+
+ //Contribution (1,0,0,0)
+ double dx1 = dx0 - 1 - m_squish4d;
+ double dy1 = dy0 - 0 - m_squish4d;
+ double dz1 = dz0 - 0 - m_squish4d;
+ double dw1 = dw0 - 0 - m_squish4d;
+ double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
+ if (attn1 > 0)
+ {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 0, dx1, dy1, dz1, dw1);
+ }
+
+ //Contribution (0,1,0,0)
+ double dx2 = dx0 - 0 - m_squish4d;
+ double dy2 = dy0 - 1 - m_squish4d;
+ double dz2 = dz1;
+ double dw2 = dw1;
+ double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
+ if (attn2 > 0)
+ {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 0, dx2, dy2, dz2, dw2);
+ }
+
+ //Contribution (0,0,1,0)
+ double dx3 = dx2;
+ double dy3 = dy1;
+ double dz3 = dz0 - 1 - m_squish4d;
+ double dw3 = dw1;
+ double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
+ if (attn3 > 0)
+ {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 0, dx3, dy3, dz3, dw3);
+ }
+
+ //Contribution (0,0,0,1)
+ double dx4 = dx2;
+ double dy4 = dy1;
+ double dz4 = dz1;
+ double dw4 = dw0 - 1 - m_squish4d;
+ double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
+ if (attn4 > 0)
+ {
+ attn4 *= attn4;
+ value += attn4 * attn4 * extrapolate(xsb + 0, ysb + 0, zsb + 0, wsb + 1, dx4, dy4, dz4, dw4);
+ }
+ }
+ else if (inSum >= 3)
+ { //We're inside the pentachoron (4-Simplex) at (1,1,1,1)
+//Determine which two of (1,1,1,0), (1,1,0,1), (1,0,1,1), (0,1,1,1) are closest.
+ char aPoint = 0x0E;
+ double aScore = xins;
+ char bPoint = 0x0D;
+ double bScore = yins;
+ if (aScore <= bScore && zins < bScore)
+ {
+ bScore = zins;
+ bPoint = 0x0B;
+ }
+ else if (aScore > bScore && zins < aScore)
+ {
+ aScore = zins;
+ aPoint = 0x0B;
+ }
+ if (aScore <= bScore && wins < bScore)
+ {
+ bScore = wins;
+ bPoint = 0x07;
+ }
+ else if (aScore > bScore && wins < aScore)
+ {
+ aScore = wins;
+ aPoint = 0x07;
+ }
+
+ //Now we determine the three lattice points not part of the pentachoron that may contribute.
+ //This depends on the closest two pentachoron vertices, including (0,0,0,0)
+ double uins = 4 - inSum;
+ if (uins < aScore || uins < bScore)
+ { //(1,1,1,1) is one of the closest two pentachoron vertices.
+ char c = (bScore < aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b.
+
+ if ((c & 0x01) != 0)
+ {
+ xsv_ext0 = xsb + 2;
+ xsv_ext1 = xsv_ext2 = xsb + 1;
+ dx_ext0 = dx0 - 2 - 4 * m_squish4d;
+ dx_ext1 = dx_ext2 = dx0 - 1 - 4 * m_squish4d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb;
+ dx_ext0 = dx_ext1 = dx_ext2 = dx0 - 4 * m_squish4d;
+ }
+
+ if ((c & 0x02) != 0)
+ {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 1 - 4 * m_squish4d;
+ if ((c & 0x01) != 0)
+ {
+ ysv_ext1 += 1;
+ dy_ext1 -= 1;
+ }
+ else
+ {
+ ysv_ext0 += 1;
+ dy_ext0 -= 1;
+ }
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
+ dy_ext0 = dy_ext1 = dy_ext2 = dy0 - 4 * m_squish4d;
+ }
+
+ if ((c & 0x04) != 0)
+ {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 1 - 4 * m_squish4d;
+ if ((c & 0x03) != 0x03)
+ {
+ if ((c & 0x03) == 0)
+ {
+ zsv_ext0 += 1;
+ dz_ext0 -= 1;
+ }
+ else
+ {
+ zsv_ext1 += 1;
+ dz_ext1 -= 1;
+ }
+ }
+ else
+ {
+ zsv_ext2 += 1;
+ dz_ext2 -= 1;
+ }
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
+ dz_ext0 = dz_ext1 = dz_ext2 = dz0 - 4 * m_squish4d;
+ }
+
+ if ((c & 0x08) != 0)
+ {
+ wsv_ext0 = wsv_ext1 = wsb + 1;
+ wsv_ext2 = wsb + 2;
+ dw_ext0 = dw_ext1 = dw0 - 1 - 4 * m_squish4d;
+ dw_ext2 = dw0 - 2 - 4 * m_squish4d;
+ }
+ else
+ {
+ wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb;
+ dw_ext0 = dw_ext1 = dw_ext2 = dw0 - 4 * m_squish4d;
+ }
+ }
+ else
+ { //(1,1,1,1) is not one of the closest two pentachoron vertices.
+ char c = static_cast(aPoint & bPoint); //Our three extra vertices are determined by the closest two.
+
+ if ((c & 0x01) != 0)
+ {
+ xsv_ext0 = xsv_ext2 = xsb + 1;
+ xsv_ext1 = xsb + 2;
+ dx_ext0 = dx0 - 1 - 2 * m_squish4d;
+ dx_ext1 = dx0 - 2 - 3 * m_squish4d;
+ dx_ext2 = dx0 - 1 - 3 * m_squish4d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsv_ext2 = xsb;
+ dx_ext0 = dx0 - 2 * m_squish4d;
+ dx_ext1 = dx_ext2 = dx0 - 3 * m_squish4d;
+ }
+
+ if ((c & 0x02) != 0)
+ {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb + 1;
+ dy_ext0 = dy0 - 1 - 2 * m_squish4d;
+ dy_ext1 = dy_ext2 = dy0 - 1 - 3 * m_squish4d;
+ if ((c & 0x01) != 0)
+ {
+ ysv_ext2 += 1;
+ dy_ext2 -= 1;
+ }
+ else
+ {
+ ysv_ext1 += 1;
+ dy_ext1 -= 1;
+ }
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysv_ext2 = ysb;
+ dy_ext0 = dy0 - 2 * m_squish4d;
+ dy_ext1 = dy_ext2 = dy0 - 3 * m_squish4d;
+ }
+
+ if ((c & 0x04) != 0)
+ {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb + 1;
+ dz_ext0 = dz0 - 1 - 2 * m_squish4d;
+ dz_ext1 = dz_ext2 = dz0 - 1 - 3 * m_squish4d;
+ if ((c & 0x03) != 0)
+ {
+ zsv_ext2 += 1;
+ dz_ext2 -= 1;
+ }
+ else
+ {
+ zsv_ext1 += 1;
+ dz_ext1 -= 1;
+ }
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsv_ext2 = zsb;
+ dz_ext0 = dz0 - 2 * m_squish4d;
+ dz_ext1 = dz_ext2 = dz0 - 3 * m_squish4d;
+ }
+
+ if ((c & 0x08) != 0)
+ {
+ wsv_ext0 = wsv_ext1 = wsb + 1;
+ wsv_ext2 = wsb + 2;
+ dw_ext0 = dw0 - 1 - 2 * m_squish4d;
+ dw_ext1 = dw0 - 1 - 3 * m_squish4d;
+ dw_ext2 = dw0 - 2 - 3 * m_squish4d;
+ }
+ else
+ {
+ wsv_ext0 = wsv_ext1 = wsv_ext2 = wsb;
+ dw_ext0 = dw0 - 2 * m_squish4d;
+ dw_ext1 = dw_ext2 = dw0 - 3 * m_squish4d;
+ }
+ }
+
+ //Contribution (1,1,1,0)
+ double dx4 = dx0 - 1 - 3 * m_squish4d;
+ double dy4 = dy0 - 1 - 3 * m_squish4d;
+ double dz4 = dz0 - 1 - 3 * m_squish4d;
+ double dw4 = dw0 - 3 * m_squish4d;
+ double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
+ if (attn4 > 0)
+ {
+ attn4 *= attn4;
+ value += attn4 * attn4 * extrapolate(xsb + 1, ysb + 1, zsb + 1, wsb + 0, dx4, dy4, dz4, dw4);
+ }
+
+ //Contribution (1,1,0,1)
+ double dx3 = dx4;
+ double dy3 = dy4;
+ double dz3 = dz0 - 3 * m_squish4d;
+ double dw3 = dw0 - 1 - 3 * m_squish4d;
+ double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
+ if (attn3 > 0)
+ {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 1, dx3, dy3, dz3, dw3);
+ }
+
+ //Contribution (1,0,1,1)
+ double dx2 = dx4;
+ double dy2 = dy0 - 3 * m_squish4d;
+ double dz2 = dz4;
+ double dw2 = dw3;
+ double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
+ if (attn2 > 0)
+ {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 1, dx2, dy2, dz2, dw2);
+ }
+
+ //Contribution (0,1,1,1)
+ double dx1 = dx0 - 3 * m_squish4d;
+ double dz1 = dz4;
+ double dy1 = dy4;
+ double dw1 = dw3;
+ double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
+ if (attn1 > 0)
+ {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 1, dx1, dy1, dz1, dw1);
+ }
+
+ //Contribution (1,1,1,1)
+ dx0 = dx0 - 1 - 4 * m_squish4d;
+ dy0 = dy0 - 1 - 4 * m_squish4d;
+ dz0 = dz0 - 1 - 4 * m_squish4d;
+ dw0 = dw0 - 1 - 4 * m_squish4d;
+ double attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0 - dw0 * dw0;
+ if (attn0 > 0)
+ {
+ attn0 *= attn0;
+ value += attn0 * attn0 * extrapolate(xsb + 1, ysb + 1, zsb + 1, wsb + 1, dx0, dy0, dz0, dw0);
+ }
+ }
+ else if (inSum <= 2)
+ { //We're inside the first dispentachoron (Rectified 4-Simplex)
+ double aScore;
+ char aPoint;
+ bool aIsBiggerSide = true;
+ double bScore;
+ char bPoint;
+ bool bIsBiggerSide = true;
+
+ //Decide between (1,1,0,0) and (0,0,1,1)
+ if (xins + yins > zins + wins)
+ {
+ aScore = xins + yins;
+ aPoint = 0x03;
+ }
+ else
+ {
+ aScore = zins + wins;
+ aPoint = 0x0C;
+ }
+
+ //Decide between (1,0,1,0) and (0,1,0,1)
+ if (xins + zins > yins + wins)
+ {
+ bScore = xins + zins;
+ bPoint = 0x05;
+ }
+ else
+ {
+ bScore = yins + wins;
+ bPoint = 0x0A;
+ }
+
+ //Closer between (1,0,0,1) and (0,1,1,0) will replace the further of a and b, if closer.
+ if (xins + wins > yins + zins)
+ {
+ double score = xins + wins;
+ if (aScore >= bScore && score > bScore)
+ {
+ bScore = score;
+ bPoint = 0x09;
+ }
+ else if (aScore < bScore && score > aScore)
+ {
+ aScore = score;
+ aPoint = 0x09;
+ }
+ }
+ else
+ {
+ double score = yins + zins;
+ if (aScore >= bScore && score > bScore)
+ {
+ bScore = score;
+ bPoint = 0x06;
+ }
+ else if (aScore < bScore && score > aScore)
+ {
+ aScore = score;
+ aPoint = 0x06;
+ }
+ }
+
+ //Decide if (1,0,0,0) is closer.
+ double p1 = 2 - inSum + xins;
+ if (aScore >= bScore && p1 > bScore)
+ {
+ bScore = p1;
+ bPoint = 0x01;
+ bIsBiggerSide = false;
+ }
+ else if (aScore < bScore && p1 > aScore)
+ {
+ aScore = p1;
+ aPoint = 0x01;
+ aIsBiggerSide = false;
+ }
+
+ //Decide if (0,1,0,0) is closer.
+ double p2 = 2 - inSum + yins;
+ if (aScore >= bScore && p2 > bScore)
+ {
+ bScore = p2;
+ bPoint = 0x02;
+ bIsBiggerSide = false;
+ }
+ else if (aScore < bScore && p2 > aScore)
+ {
+ aScore = p2;
+ aPoint = 0x02;
+ aIsBiggerSide = false;
+ }
+
+ //Decide if (0,0,1,0) is closer.
+ double p3 = 2 - inSum + zins;
+ if (aScore >= bScore && p3 > bScore)
+ {
+ bScore = p3;
+ bPoint = 0x04;
+ bIsBiggerSide = false;
+ }
+ else if (aScore < bScore && p3 > aScore)
+ {
+ aScore = p3;
+ aPoint = 0x04;
+ aIsBiggerSide = false;
+ }
+
+ //Decide if (0,0,0,1) is closer.
+ double p4 = 2 - inSum + wins;
+ if (aScore >= bScore && p4 > bScore)
+ {
+ bScore = p4;
+ bPoint = 0x08;
+ bIsBiggerSide = false;
+ }
+ else if (aScore < bScore && p4 > aScore)
+ {
+ aScore = p4;
+ aPoint = 0x08;
+ aIsBiggerSide = false;
+ }
+
+ //Where each of the two closest points are determines how the extra three vertices are calculated.
+ if (aIsBiggerSide == bIsBiggerSide)
+ {
+ if (aIsBiggerSide)
+ { //Both closest points on the bigger side
+ char c1 = static_cast(aPoint | bPoint);
+ char c2 = static_cast(aPoint & bPoint);
+ if ((c1 & 0x01) == 0)
+ {
+ xsv_ext0 = xsb;
+ xsv_ext1 = xsb - 1;
+ dx_ext0 = dx0 - 3 * m_squish4d;
+ dx_ext1 = dx0 + 1 - 2 * m_squish4d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsb + 1;
+ dx_ext0 = dx0 - 1 - 3 * m_squish4d;
+ dx_ext1 = dx0 - 1 - 2 * m_squish4d;
+ }
+
+ if ((c1 & 0x02) == 0)
+ {
+ ysv_ext0 = ysb;
+ ysv_ext1 = ysb - 1;
+ dy_ext0 = dy0 - 3 * m_squish4d;
+ dy_ext1 = dy0 + 1 - 2 * m_squish4d;
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy0 - 1 - 3 * m_squish4d;
+ dy_ext1 = dy0 - 1 - 2 * m_squish4d;
+ }
+
+ if ((c1 & 0x04) == 0)
+ {
+ zsv_ext0 = zsb;
+ zsv_ext1 = zsb - 1;
+ dz_ext0 = dz0 - 3 * m_squish4d;
+ dz_ext1 = dz0 + 1 - 2 * m_squish4d;
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz0 - 1 - 3 * m_squish4d;
+ dz_ext1 = dz0 - 1 - 2 * m_squish4d;
+ }
+
+ if ((c1 & 0x08) == 0)
+ {
+ wsv_ext0 = wsb;
+ wsv_ext1 = wsb - 1;
+ dw_ext0 = dw0 - 3 * m_squish4d;
+ dw_ext1 = dw0 + 1 - 2 * m_squish4d;
+ }
+ else
+ {
+ wsv_ext0 = wsv_ext1 = wsb + 1;
+ dw_ext0 = dw0 - 1 - 3 * m_squish4d;
+ dw_ext1 = dw0 - 1 - 2 * m_squish4d;
+ }
+
+ //One combination is a permutation of (0,0,0,2) based on c2
+ xsv_ext2 = xsb;
+ ysv_ext2 = ysb;
+ zsv_ext2 = zsb;
+ wsv_ext2 = wsb;
+ dx_ext2 = dx0 - 2 * m_squish4d;
+ dy_ext2 = dy0 - 2 * m_squish4d;
+ dz_ext2 = dz0 - 2 * m_squish4d;
+ dw_ext2 = dw0 - 2 * m_squish4d;
+ if ((c2 & 0x01) != 0)
+ {
+ xsv_ext2 += 2;
+ dx_ext2 -= 2;
+ }
+ else if ((c2 & 0x02) != 0)
+ {
+ ysv_ext2 += 2;
+ dy_ext2 -= 2;
+ }
+ else if ((c2 & 0x04) != 0)
+ {
+ zsv_ext2 += 2;
+ dz_ext2 -= 2;
+ }
+ else
+ {
+ wsv_ext2 += 2;
+ dw_ext2 -= 2;
+ }
+
+ }
+ else
+ { //Both closest points on the smaller side
+ //One of the two extra points is (0,0,0,0)
+ xsv_ext2 = xsb;
+ ysv_ext2 = ysb;
+ zsv_ext2 = zsb;
+ wsv_ext2 = wsb;
+ dx_ext2 = dx0;
+ dy_ext2 = dy0;
+ dz_ext2 = dz0;
+ dw_ext2 = dw0;
+
+ //Other two points are based on the omitted axes.
+ char c = static_cast(aPoint | bPoint);
+
+ if ((c & 0x01) == 0)
+ {
+ xsv_ext0 = xsb - 1;
+ xsv_ext1 = xsb;
+ dx_ext0 = dx0 + 1 - m_squish4d;
+ dx_ext1 = dx0 - m_squish4d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsb + 1;
+ dx_ext0 = dx_ext1 = dx0 - 1 - m_squish4d;
+ }
+
+ if ((c & 0x02) == 0)
+ {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0 - m_squish4d;
+ if ((c & 0x01) == 0x01)
+ {
+ ysv_ext0 -= 1;
+ dy_ext0 += 1;
+ }
+ else
+ {
+ ysv_ext1 -= 1;
+ dy_ext1 += 1;
+ }
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1 - m_squish4d;
+ }
+
+ if ((c & 0x04) == 0)
+ {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz_ext1 = dz0 - m_squish4d;
+ if ((c & 0x03) == 0x03)
+ {
+ zsv_ext0 -= 1;
+ dz_ext0 += 1;
+ }
+ else
+ {
+ zsv_ext1 -= 1;
+ dz_ext1 += 1;
+ }
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz0 - 1 - m_squish4d;
+ }
+
+ if ((c & 0x08) == 0)
+ {
+ wsv_ext0 = wsb;
+ wsv_ext1 = wsb - 1;
+ dw_ext0 = dw0 - m_squish4d;
+ dw_ext1 = dw0 + 1 - m_squish4d;
+ }
+ else
+ {
+ wsv_ext0 = wsv_ext1 = wsb + 1;
+ dw_ext0 = dw_ext1 = dw0 - 1 - m_squish4d;
+ }
+
+ }
+ }
+ else
+ { //One point on each "side"
+ char c1, c2;
+ if (aIsBiggerSide)
+ {
+ c1 = aPoint;
+ c2 = bPoint;
+ }
+ else
+ {
+ c1 = bPoint;
+ c2 = aPoint;
+ }
+
+ //Two contributions are the bigger-sided point with each 0 replaced with -1.
+ if ((c1 & 0x01) == 0)
+ {
+ xsv_ext0 = xsb - 1;
+ xsv_ext1 = xsb;
+ dx_ext0 = dx0 + 1 - m_squish4d;
+ dx_ext1 = dx0 - m_squish4d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsb + 1;
+ dx_ext0 = dx_ext1 = dx0 - 1 - m_squish4d;
+ }
+
+ if ((c1 & 0x02) == 0)
+ {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0 - m_squish4d;
+ if ((c1 & 0x01) == 0x01)
+ {
+ ysv_ext0 -= 1;
+ dy_ext0 += 1;
+ }
+ else
+ {
+ ysv_ext1 -= 1;
+ dy_ext1 += 1;
+ }
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1 - m_squish4d;
+ }
+
+ if ((c1 & 0x04) == 0)
+ {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz_ext1 = dz0 - m_squish4d;
+ if ((c1 & 0x03) == 0x03)
+ {
+ zsv_ext0 -= 1;
+ dz_ext0 += 1;
+ }
+ else
+ {
+ zsv_ext1 -= 1;
+ dz_ext1 += 1;
+ }
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz0 - 1 - m_squish4d;
+ }
+
+ if ((c1 & 0x08) == 0)
+ {
+ wsv_ext0 = wsb;
+ wsv_ext1 = wsb - 1;
+ dw_ext0 = dw0 - m_squish4d;
+ dw_ext1 = dw0 + 1 - m_squish4d;
+ }
+ else
+ {
+ wsv_ext0 = wsv_ext1 = wsb + 1;
+ dw_ext0 = dw_ext1 = dw0 - 1 - m_squish4d;
+ }
+
+ //One contribution is a permutation of (0,0,0,2) based on the smaller-sided point
+ xsv_ext2 = xsb;
+ ysv_ext2 = ysb;
+ zsv_ext2 = zsb;
+ wsv_ext2 = wsb;
+ dx_ext2 = dx0 - 2 * m_squish4d;
+ dy_ext2 = dy0 - 2 * m_squish4d;
+ dz_ext2 = dz0 - 2 * m_squish4d;
+ dw_ext2 = dw0 - 2 * m_squish4d;
+ if ((c2 & 0x01) != 0)
+ {
+ xsv_ext2 += 2;
+ dx_ext2 -= 2;
+ }
+ else if ((c2 & 0x02) != 0)
+ {
+ ysv_ext2 += 2;
+ dy_ext2 -= 2;
+ }
+ else if ((c2 & 0x04) != 0)
+ {
+ zsv_ext2 += 2;
+ dz_ext2 -= 2;
+ }
+ else
+ {
+ wsv_ext2 += 2;
+ dw_ext2 -= 2;
+ }
+ }
+
+ //Contribution (1,0,0,0)
+ double dx1 = dx0 - 1 - m_squish4d;
+ double dy1 = dy0 - 0 - m_squish4d;
+ double dz1 = dz0 - 0 - m_squish4d;
+ double dw1 = dw0 - 0 - m_squish4d;
+ double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
+ if (attn1 > 0)
+ {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 0, dx1, dy1, dz1, dw1);
+ }
+
+ //Contribution (0,1,0,0)
+ double dx2 = dx0 - 0 - m_squish4d;
+ double dy2 = dy0 - 1 - m_squish4d;
+ double dz2 = dz1;
+ double dw2 = dw1;
+ double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
+ if (attn2 > 0)
+ {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 0, dx2, dy2, dz2, dw2);
+ }
+
+ //Contribution (0,0,1,0)
+ double dx3 = dx2;
+ double dy3 = dy1;
+ double dz3 = dz0 - 1 - m_squish4d;
+ double dw3 = dw1;
+ double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
+ if (attn3 > 0)
+ {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 0, dx3, dy3, dz3, dw3);
+ }
+
+ //Contribution (0,0,0,1)
+ double dx4 = dx2;
+ double dy4 = dy1;
+ double dz4 = dz1;
+ double dw4 = dw0 - 1 - m_squish4d;
+ double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
+ if (attn4 > 0)
+ {
+ attn4 *= attn4;
+ value += attn4 * attn4 * extrapolate(xsb + 0, ysb + 0, zsb + 0, wsb + 1, dx4, dy4, dz4, dw4);
+ }
+
+ //Contribution (1,1,0,0)
+ double dx5 = dx0 - 1 - 2 * m_squish4d;
+ double dy5 = dy0 - 1 - 2 * m_squish4d;
+ double dz5 = dz0 - 0 - 2 * m_squish4d;
+ double dw5 = dw0 - 0 - 2 * m_squish4d;
+ double attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5 - dw5 * dw5;
+ if (attn5 > 0)
+ {
+ attn5 *= attn5;
+ value += attn5 * attn5 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 0, dx5, dy5, dz5, dw5);
+ }
+
+ //Contribution (1,0,1,0)
+ double dx6 = dx0 - 1 - 2 * m_squish4d;
+ double dy6 = dy0 - 0 - 2 * m_squish4d;
+ double dz6 = dz0 - 1 - 2 * m_squish4d;
+ double dw6 = dw0 - 0 - 2 * m_squish4d;
+ double attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6 - dw6 * dw6;
+ if (attn6 > 0)
+ {
+ attn6 *= attn6;
+ value += attn6 * attn6 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 0, dx6, dy6, dz6, dw6);
+ }
+
+ //Contribution (1,0,0,1)
+ double dx7 = dx0 - 1 - 2 * m_squish4d;
+ double dy7 = dy0 - 0 - 2 * m_squish4d;
+ double dz7 = dz0 - 0 - 2 * m_squish4d;
+ double dw7 = dw0 - 1 - 2 * m_squish4d;
+ double attn7 = 2 - dx7 * dx7 - dy7 * dy7 - dz7 * dz7 - dw7 * dw7;
+ if (attn7 > 0)
+ {
+ attn7 *= attn7;
+ value += attn7 * attn7 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 1, dx7, dy7, dz7, dw7);
+ }
+
+ //Contribution (0,1,1,0)
+ double dx8 = dx0 - 0 - 2 * m_squish4d;
+ double dy8 = dy0 - 1 - 2 * m_squish4d;
+ double dz8 = dz0 - 1 - 2 * m_squish4d;
+ double dw8 = dw0 - 0 - 2 * m_squish4d;
+ double attn8 = 2 - dx8 * dx8 - dy8 * dy8 - dz8 * dz8 - dw8 * dw8;
+ if (attn8 > 0)
+ {
+ attn8 *= attn8;
+ value += attn8 * attn8 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 0, dx8, dy8, dz8, dw8);
+ }
+
+ //Contribution (0,1,0,1)
+ double dx9 = dx0 - 0 - 2 * m_squish4d;
+ double dy9 = dy0 - 1 - 2 * m_squish4d;
+ double dz9 = dz0 - 0 - 2 * m_squish4d;
+ double dw9 = dw0 - 1 - 2 * m_squish4d;
+ double attn9 = 2 - dx9 * dx9 - dy9 * dy9 - dz9 * dz9 - dw9 * dw9;
+ if (attn9 > 0)
+ {
+ attn9 *= attn9;
+ value += attn9 * attn9 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 1, dx9, dy9, dz9, dw9);
+ }
+
+ //Contribution (0,0,1,1)
+ double dx10 = dx0 - 0 - 2 * m_squish4d;
+ double dy10 = dy0 - 0 - 2 * m_squish4d;
+ double dz10 = dz0 - 1 - 2 * m_squish4d;
+ double dw10 = dw0 - 1 - 2 * m_squish4d;
+ double attn10 = 2 - dx10 * dx10 - dy10 * dy10 - dz10 * dz10 - dw10 * dw10;
+ if (attn10 > 0)
+ {
+ attn10 *= attn10;
+ value += attn10 * attn10 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 1, dx10, dy10, dz10, dw10);
+ }
+ }
+ else
+ { //We're inside the second dispentachoron (Rectified 4-Simplex)
+ double aScore;
+ char aPoint;
+ bool aIsBiggerSide = true;
+ double bScore;
+ char bPoint;
+ bool bIsBiggerSide = true;
+
+ //Decide between (0,0,1,1) and (1,1,0,0)
+ if (xins + yins < zins + wins)
+ {
+ aScore = xins + yins;
+ aPoint = 0x0C;
+ }
+ else
+ {
+ aScore = zins + wins;
+ aPoint = 0x03;
+ }
+
+ //Decide between (0,1,0,1) and (1,0,1,0)
+ if (xins + zins < yins + wins)
+ {
+ bScore = xins + zins;
+ bPoint = 0x0A;
+ }
+ else
+ {
+ bScore = yins + wins;
+ bPoint = 0x05;
+ }
+
+ //Closer between (0,1,1,0) and (1,0,0,1) will replace the further of a and b, if closer.
+ if (xins + wins < yins + zins)
+ {
+ double score = xins + wins;
+ if (aScore <= bScore && score < bScore)
+ {
+ bScore = score;
+ bPoint = 0x06;
+ }
+ else if (aScore > bScore && score < aScore)
+ {
+ aScore = score;
+ aPoint = 0x06;
+ }
+ }
+ else
+ {
+ double score = yins + zins;
+ if (aScore <= bScore && score < bScore)
+ {
+ bScore = score;
+ bPoint = 0x09;
+ }
+ else if (aScore > bScore && score < aScore)
+ {
+ aScore = score;
+ aPoint = 0x09;
+ }
+ }
+
+ //Decide if (0,1,1,1) is closer.
+ double p1 = 3 - inSum + xins;
+ if (aScore <= bScore && p1 < bScore)
+ {
+ bScore = p1;
+ bPoint = 0x0E;
+ bIsBiggerSide = false;
+ }
+ else if (aScore > bScore && p1 < aScore)
+ {
+ aScore = p1;
+ aPoint = 0x0E;
+ aIsBiggerSide = false;
+ }
+
+ //Decide if (1,0,1,1) is closer.
+ double p2 = 3 - inSum + yins;
+ if (aScore <= bScore && p2 < bScore)
+ {
+ bScore = p2;
+ bPoint = 0x0D;
+ bIsBiggerSide = false;
+ }
+ else if (aScore > bScore && p2 < aScore)
+ {
+ aScore = p2;
+ aPoint = 0x0D;
+ aIsBiggerSide = false;
+ }
+
+ //Decide if (1,1,0,1) is closer.
+ double p3 = 3 - inSum + zins;
+ if (aScore <= bScore && p3 < bScore)
+ {
+ bScore = p3;
+ bPoint = 0x0B;
+ bIsBiggerSide = false;
+ }
+ else if (aScore > bScore && p3 < aScore)
+ {
+ aScore = p3;
+ aPoint = 0x0B;
+ aIsBiggerSide = false;
+ }
+
+ //Decide if (1,1,1,0) is closer.
+ double p4 = 3 - inSum + wins;
+ if (aScore <= bScore && p4 < bScore)
+ {
+ bScore = p4;
+ bPoint = 0x07;
+ bIsBiggerSide = false;
+ }
+ else if (aScore > bScore && p4 < aScore)
+ {
+ aScore = p4;
+ aPoint = 0x07;
+ aIsBiggerSide = false;
+ }
+
+ //Where each of the two closest points are determines how the extra three vertices are calculated.
+ if (aIsBiggerSide == bIsBiggerSide)
+ {
+ if (aIsBiggerSide)
+ { //Both closest points on the bigger side
+ char c1 = static_cast(aPoint & bPoint);
+ char c2 = static_cast(aPoint | bPoint);
+
+ //Two contributions are permutations of (0,0,0,1) and (0,0,0,2) based on c1
+ xsv_ext0 = xsv_ext1 = xsb;
+ ysv_ext0 = ysv_ext1 = ysb;
+ zsv_ext0 = zsv_ext1 = zsb;
+ wsv_ext0 = wsv_ext1 = wsb;
+ dx_ext0 = dx0 - m_squish4d;
+ dy_ext0 = dy0 - m_squish4d;
+ dz_ext0 = dz0 - m_squish4d;
+ dw_ext0 = dw0 - m_squish4d;
+ dx_ext1 = dx0 - 2 * m_squish4d;
+ dy_ext1 = dy0 - 2 * m_squish4d;
+ dz_ext1 = dz0 - 2 * m_squish4d;
+ dw_ext1 = dw0 - 2 * m_squish4d;
+ if ((c1 & 0x01) != 0)
+ {
+ xsv_ext0 += 1;
+ dx_ext0 -= 1;
+ xsv_ext1 += 2;
+ dx_ext1 -= 2;
+ }
+ else if ((c1 & 0x02) != 0)
+ {
+ ysv_ext0 += 1;
+ dy_ext0 -= 1;
+ ysv_ext1 += 2;
+ dy_ext1 -= 2;
+ }
+ else if ((c1 & 0x04) != 0)
+ {
+ zsv_ext0 += 1;
+ dz_ext0 -= 1;
+ zsv_ext1 += 2;
+ dz_ext1 -= 2;
+ }
+ else
+ {
+ wsv_ext0 += 1;
+ dw_ext0 -= 1;
+ wsv_ext1 += 2;
+ dw_ext1 -= 2;
+ }
+
+ //One contribution is a permutation of (1,1,1,-1) based on c2
+ xsv_ext2 = xsb + 1;
+ ysv_ext2 = ysb + 1;
+ zsv_ext2 = zsb + 1;
+ wsv_ext2 = wsb + 1;
+ dx_ext2 = dx0 - 1 - 2 * m_squish4d;
+ dy_ext2 = dy0 - 1 - 2 * m_squish4d;
+ dz_ext2 = dz0 - 1 - 2 * m_squish4d;
+ dw_ext2 = dw0 - 1 - 2 * m_squish4d;
+ if ((c2 & 0x01) == 0)
+ {
+ xsv_ext2 -= 2;
+ dx_ext2 += 2;
+ }
+ else if ((c2 & 0x02) == 0)
+ {
+ ysv_ext2 -= 2;
+ dy_ext2 += 2;
+ }
+ else if ((c2 & 0x04) == 0)
+ {
+ zsv_ext2 -= 2;
+ dz_ext2 += 2;
+ }
+ else
+ {
+ wsv_ext2 -= 2;
+ dw_ext2 += 2;
+ }
+ }
+ else
+ { //Both closest points on the smaller side
+ //One of the two extra points is (1,1,1,1)
+ xsv_ext2 = xsb + 1;
+ ysv_ext2 = ysb + 1;
+ zsv_ext2 = zsb + 1;
+ wsv_ext2 = wsb + 1;
+ dx_ext2 = dx0 - 1 - 4 * m_squish4d;
+ dy_ext2 = dy0 - 1 - 4 * m_squish4d;
+ dz_ext2 = dz0 - 1 - 4 * m_squish4d;
+ dw_ext2 = dw0 - 1 - 4 * m_squish4d;
+
+ //Other two points are based on the shared axes.
+ char c = static_cast(aPoint & bPoint);
+
+ if ((c & 0x01) != 0)
+ {
+ xsv_ext0 = xsb + 2;
+ xsv_ext1 = xsb + 1;
+ dx_ext0 = dx0 - 2 - 3 * m_squish4d;
+ dx_ext1 = dx0 - 1 - 3 * m_squish4d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsb;
+ dx_ext0 = dx_ext1 = dx0 - 3 * m_squish4d;
+ }
+
+ if ((c & 0x02) != 0)
+ {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1 - 3 * m_squish4d;
+ if ((c & 0x01) == 0)
+ {
+ ysv_ext0 += 1;
+ dy_ext0 -= 1;
+ }
+ else
+ {
+ ysv_ext1 += 1;
+ dy_ext1 -= 1;
+ }
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0 - 3 * m_squish4d;
+ }
+
+ if ((c & 0x04) != 0)
+ {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz0 - 1 - 3 * m_squish4d;
+ if ((c & 0x03) == 0)
+ {
+ zsv_ext0 += 1;
+ dz_ext0 -= 1;
+ }
+ else
+ {
+ zsv_ext1 += 1;
+ dz_ext1 -= 1;
+ }
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz_ext1 = dz0 - 3 * m_squish4d;
+ }
+
+ if ((c & 0x08) != 0)
+ {
+ wsv_ext0 = wsb + 1;
+ wsv_ext1 = wsb + 2;
+ dw_ext0 = dw0 - 1 - 3 * m_squish4d;
+ dw_ext1 = dw0 - 2 - 3 * m_squish4d;
+ }
+ else
+ {
+ wsv_ext0 = wsv_ext1 = wsb;
+ dw_ext0 = dw_ext1 = dw0 - 3 * m_squish4d;
+ }
+ }
+ }
+ else
+ { //One point on each "side"
+ char c1, c2;
+ if (aIsBiggerSide)
+ {
+ c1 = aPoint;
+ c2 = bPoint;
+ }
+ else
+ {
+ c1 = bPoint;
+ c2 = aPoint;
+ }
+
+ //Two contributions are the bigger-sided point with each 1 replaced with 2.
+ if ((c1 & 0x01) != 0)
+ {
+ xsv_ext0 = xsb + 2;
+ xsv_ext1 = xsb + 1;
+ dx_ext0 = dx0 - 2 - 3 * m_squish4d;
+ dx_ext1 = dx0 - 1 - 3 * m_squish4d;
+ }
+ else
+ {
+ xsv_ext0 = xsv_ext1 = xsb;
+ dx_ext0 = dx_ext1 = dx0 - 3 * m_squish4d;
+ }
+
+ if ((c1 & 0x02) != 0)
+ {
+ ysv_ext0 = ysv_ext1 = ysb + 1;
+ dy_ext0 = dy_ext1 = dy0 - 1 - 3 * m_squish4d;
+ if ((c1 & 0x01) == 0)
+ {
+ ysv_ext0 += 1;
+ dy_ext0 -= 1;
+ }
+ else
+ {
+ ysv_ext1 += 1;
+ dy_ext1 -= 1;
+ }
+ }
+ else
+ {
+ ysv_ext0 = ysv_ext1 = ysb;
+ dy_ext0 = dy_ext1 = dy0 - 3 * m_squish4d;
+ }
+
+ if ((c1 & 0x04) != 0)
+ {
+ zsv_ext0 = zsv_ext1 = zsb + 1;
+ dz_ext0 = dz_ext1 = dz0 - 1 - 3 * m_squish4d;
+ if ((c1 & 0x03) == 0)
+ {
+ zsv_ext0 += 1;
+ dz_ext0 -= 1;
+ }
+ else
+ {
+ zsv_ext1 += 1;
+ dz_ext1 -= 1;
+ }
+ }
+ else
+ {
+ zsv_ext0 = zsv_ext1 = zsb;
+ dz_ext0 = dz_ext1 = dz0 - 3 * m_squish4d;
+ }
+
+ if ((c1 & 0x08) != 0)
+ {
+ wsv_ext0 = wsb + 1;
+ wsv_ext1 = wsb + 2;
+ dw_ext0 = dw0 - 1 - 3 * m_squish4d;
+ dw_ext1 = dw0 - 2 - 3 * m_squish4d;
+ }
+ else
+ {
+ wsv_ext0 = wsv_ext1 = wsb;
+ dw_ext0 = dw_ext1 = dw0 - 3 * m_squish4d;
+ }
+
+ //One contribution is a permutation of (1,1,1,-1) based on the smaller-sided point
+ xsv_ext2 = xsb + 1;
+ ysv_ext2 = ysb + 1;
+ zsv_ext2 = zsb + 1;
+ wsv_ext2 = wsb + 1;
+ dx_ext2 = dx0 - 1 - 2 * m_squish4d;
+ dy_ext2 = dy0 - 1 - 2 * m_squish4d;
+ dz_ext2 = dz0 - 1 - 2 * m_squish4d;
+ dw_ext2 = dw0 - 1 - 2 * m_squish4d;
+ if ((c2 & 0x01) == 0)
+ {
+ xsv_ext2 -= 2;
+ dx_ext2 += 2;
+ }
+ else if ((c2 & 0x02) == 0)
+ {
+ ysv_ext2 -= 2;
+ dy_ext2 += 2;
+ }
+ else if ((c2 & 0x04) == 0)
+ {
+ zsv_ext2 -= 2;
+ dz_ext2 += 2;
+ }
+ else
+ {
+ wsv_ext2 -= 2;
+ dw_ext2 += 2;
+ }
+ }
+
+ //Contribution (1,1,1,0)
+ double dx4 = dx0 - 1 - 3 * m_squish4d;
+ double dy4 = dy0 - 1 - 3 * m_squish4d;
+ double dz4 = dz0 - 1 - 3 * m_squish4d;
+ double dw4 = dw0 - 3 * m_squish4d;
+ double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4 - dw4 * dw4;
+ if (attn4 > 0)
+ {
+ attn4 *= attn4;
+ value += attn4 * attn4 * extrapolate(xsb + 1, ysb + 1, zsb + 1, wsb + 0, dx4, dy4, dz4, dw4);
+ }
+
+ //Contribution (1,1,0,1)
+ double dx3 = dx4;
+ double dy3 = dy4;
+ double dz3 = dz0 - 3 * m_squish4d;
+ double dw3 = dw0 - 1 - 3 * m_squish4d;
+ double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3 - dw3 * dw3;
+ if (attn3 > 0)
+ {
+ attn3 *= attn3;
+ value += attn3 * attn3 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 1, dx3, dy3, dz3, dw3);
+ }
+
+ //Contribution (1,0,1,1)
+ double dx2 = dx4;
+ double dy2 = dy0 - 3 * m_squish4d;
+ double dz2 = dz4;
+ double dw2 = dw3;
+ double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2 - dw2 * dw2;
+ if (attn2 > 0)
+ {
+ attn2 *= attn2;
+ value += attn2 * attn2 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 1, dx2, dy2, dz2, dw2);
+ }
+
+ //Contribution (0,1,1,1)
+ double dx1 = dx0 - 3 * m_squish4d;
+ double dz1 = dz4;
+ double dy1 = dy4;
+ double dw1 = dw3;
+ double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1 - dw1 * dw1;
+ if (attn1 > 0)
+ {
+ attn1 *= attn1;
+ value += attn1 * attn1 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 1, dx1, dy1, dz1, dw1);
+ }
+
+ //Contribution (1,1,0,0)
+ double dx5 = dx0 - 1 - 2 * m_squish4d;
+ double dy5 = dy0 - 1 - 2 * m_squish4d;
+ double dz5 = dz0 - 0 - 2 * m_squish4d;
+ double dw5 = dw0 - 0 - 2 * m_squish4d;
+ double attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5 - dw5 * dw5;
+ if (attn5 > 0)
+ {
+ attn5 *= attn5;
+ value += attn5 * attn5 * extrapolate(xsb + 1, ysb + 1, zsb + 0, wsb + 0, dx5, dy5, dz5, dw5);
+ }
+
+ //Contribution (1,0,1,0)
+ double dx6 = dx0 - 1 - 2 * m_squish4d;
+ double dy6 = dy0 - 0 - 2 * m_squish4d;
+ double dz6 = dz0 - 1 - 2 * m_squish4d;
+ double dw6 = dw0 - 0 - 2 * m_squish4d;
+ double attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6 - dw6 * dw6;
+ if (attn6 > 0)
+ {
+ attn6 *= attn6;
+ value += attn6 * attn6 * extrapolate(xsb + 1, ysb + 0, zsb + 1, wsb + 0, dx6, dy6, dz6, dw6);
+ }
+
+ //Contribution (1,0,0,1)
+ double dx7 = dx0 - 1 - 2 * m_squish4d;
+ double dy7 = dy0 - 0 - 2 * m_squish4d;
+ double dz7 = dz0 - 0 - 2 * m_squish4d;
+ double dw7 = dw0 - 1 - 2 * m_squish4d;
+ double attn7 = 2 - dx7 * dx7 - dy7 * dy7 - dz7 * dz7 - dw7 * dw7;
+ if (attn7 > 0)
+ {
+ attn7 *= attn7;
+ value += attn7 * attn7 * extrapolate(xsb + 1, ysb + 0, zsb + 0, wsb + 1, dx7, dy7, dz7, dw7);
+ }
+
+ //Contribution (0,1,1,0)
+ double dx8 = dx0 - 0 - 2 * m_squish4d;
+ double dy8 = dy0 - 1 - 2 * m_squish4d;
+ double dz8 = dz0 - 1 - 2 * m_squish4d;
+ double dw8 = dw0 - 0 - 2 * m_squish4d;
+ double attn8 = 2 - dx8 * dx8 - dy8 * dy8 - dz8 * dz8 - dw8 * dw8;
+ if (attn8 > 0)
+ {
+ attn8 *= attn8;
+ value += attn8 * attn8 * extrapolate(xsb + 0, ysb + 1, zsb + 1, wsb + 0, dx8, dy8, dz8, dw8);
+ }
+
+ //Contribution (0,1,0,1)
+ double dx9 = dx0 - 0 - 2 * m_squish4d;
+ double dy9 = dy0 - 1 - 2 * m_squish4d;
+ double dz9 = dz0 - 0 - 2 * m_squish4d;
+ double dw9 = dw0 - 1 - 2 * m_squish4d;
+ double attn9 = 2 - dx9 * dx9 - dy9 * dy9 - dz9 * dz9 - dw9 * dw9;
+ if (attn9 > 0)
+ {
+ attn9 *= attn9;
+ value += attn9 * attn9 * extrapolate(xsb + 0, ysb + 1, zsb + 0, wsb + 1, dx9, dy9, dz9, dw9);
+ }
+
+ //Contribution (0,0,1,1)
+ double dx10 = dx0 - 0 - 2 * m_squish4d;
+ double dy10 = dy0 - 0 - 2 * m_squish4d;
+ double dz10 = dz0 - 1 - 2 * m_squish4d;
+ double dw10 = dw0 - 1 - 2 * m_squish4d;
+ double attn10 = 2 - dx10 * dx10 - dy10 * dy10 - dz10 * dz10 - dw10 * dw10;
+ if (attn10 > 0)
+ {
+ attn10 *= attn10;
+ value += attn10 * attn10 * extrapolate(xsb + 0, ysb + 0, zsb + 1, wsb + 1, dx10, dy10, dz10, dw10);
+ }
+ }
+
+ //First extra vertex
+ double attn_ext0 = 2 - dx_ext0 * dx_ext0 - dy_ext0 * dy_ext0 - dz_ext0 * dz_ext0 - dw_ext0 * dw_ext0;
+ if (attn_ext0 > 0)
+ {
+ attn_ext0 *= attn_ext0;
+ value += attn_ext0 * attn_ext0 * extrapolate(xsv_ext0, ysv_ext0, zsv_ext0, wsv_ext0, dx_ext0, dy_ext0, dz_ext0, dw_ext0);
+ }
+
+ //Second extra vertex
+ double attn_ext1 = 2 - dx_ext1 * dx_ext1 - dy_ext1 * dy_ext1 - dz_ext1 * dz_ext1 - dw_ext1 * dw_ext1;
+ if (attn_ext1 > 0)
+ {
+ attn_ext1 *= attn_ext1;
+ value += attn_ext1 * attn_ext1 * extrapolate(xsv_ext1, ysv_ext1, zsv_ext1, wsv_ext1, dx_ext1, dy_ext1, dz_ext1, dw_ext1);
+ }
+
+ //Third extra vertex
+ double attn_ext2 = 2 - dx_ext2 * dx_ext2 - dy_ext2 * dy_ext2 - dz_ext2 * dz_ext2 - dw_ext2 * dw_ext2;
+ if (attn_ext2 > 0)
+ {
+ attn_ext2 *= attn_ext2;
+ value += attn_ext2 * attn_ext2 * extrapolate(xsv_ext2, ysv_ext2, zsv_ext2, wsv_ext2, dx_ext2, dy_ext2, dz_ext2, dw_ext2);
+ }
+
+ return value / m_norm4d;
+ }
+
+ double Noise::extrapolate(int xsb, int ysb, double dx, double dy) const
+ {
+ int index = m_perm[(m_perm[xsb & 0xFF] + ysb) & 0xFF] & 0x0E;
+ return m_gradients2d[index] * dx
+ + m_gradients2d[index + 1] * dy;
+ }
+
+ double Noise::extrapolate(int xsb, int ysb, int zsb, double dx, double dy, double dz) const
+ {
+ int index = m_permGradIndex3d[(m_perm[(m_perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF];
+ return m_gradients3d[index] * dx
+ + m_gradients3d[index + 1] * dy
+ + m_gradients3d[index + 2] * dz;
+ }
+
+ double Noise::extrapolate(int xsb, int ysb, int zsb, int wsb, double dx, double dy, double dz, double dw) const
+ {
+ int index = m_perm[(m_perm[(m_perm[(m_perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF] + wsb) & 0xFF] & 0xFC;
+ return m_gradients4d[index] * dx
+ + m_gradients4d[index + 1] * dy
+ + m_gradients4d[index + 2] * dz
+ + m_gradients4d[index + 3] * dw;
+ }
+
+}
\ No newline at end of file
diff --git a/SQCSim-common/opensimplex.h b/SQCSim-common/opensimplex.h
new file mode 100644
index 0000000..4b1b1f4
--- /dev/null
+++ b/SQCSim-common/opensimplex.h
@@ -0,0 +1,51 @@
+/**
+ Open Simple Noise for C++
+
+ Port to C++ from https://gist.github.com/KdotJPG/b1270127455a94ac5d19
+ by Rickard Lundberg, 2019.
+*/
+#ifndef _OPENSIMPLEX_H__
+#define _OPENSIMPLEX_H__
+
+#include
+#include
+
+namespace OpenSimplexNoise
+{
+ class Noise
+ {
+ public:
+ Noise();
+ Noise(int64_t seed);
+ //2D Open Simplex Noise.
+ double eval(const double x, const double y) const;
+ //3D Open Simplex Noise.
+ double eval(double x, double y, double z) const;
+ //4D Open Simplex Noise.
+ double eval(double x, double y, double z, double w) const;
+ private:
+ const double m_stretch2d;
+ const double m_squish2d;
+ const double m_stretch3d;
+ const double m_squish3d;
+ const double m_stretch4d;
+ const double m_squish4d;
+
+ const double m_norm2d;
+ const double m_norm3d;
+ const double m_norm4d;
+
+ const long m_defaultSeed;
+
+ std::array m_perm;
+ std::array m_permGradIndex3d;
+ std::array m_gradients2d;
+ std::array m_gradients3d;
+ std::array m_gradients4d;
+ double extrapolate(int xsb, int ysb, double dx, double dy) const;
+ double extrapolate(int xsb, int ysb, int zsb, double dx, double dy, double dz) const;
+ double extrapolate(int xsb, int ysb, int zsb, int wsb, double dx, double dy, double dz, double dw) const;
+ };
+}
+
+#endif // _OPENSIMPLEX_H__
\ No newline at end of file
diff --git a/SQCSim-common/player.cpp b/SQCSim-common/player.cpp
new file mode 100644
index 0000000..080fc2d
--- /dev/null
+++ b/SQCSim-common/player.cpp
@@ -0,0 +1,160 @@
+#include "player.h"
+#include "world.h"
+
+Player::Player(const Vector3f& position, float rotX, float rotY) : m_position(position), m_rotX(rotX), m_rotY(rotY) {
+ m_velocity = Vector3f(0, 0, 0);
+ m_airborne = true;
+}
+
+void Player::TurnLeftRight(float value) {
+ m_rotY += value;
+ if (m_rotY > 360) m_rotY = 0;
+ else if (m_rotY < -360) m_rotY = 0;
+}
+
+void Player::TurnTopBottom(float value) {
+ m_rotX += value;
+ if (m_rotX > 80) m_rotX = 80;
+ else if (m_rotX < -80) m_rotX = -80;
+}
+
+Vector3f Player::GetInput(bool front, bool back, bool left, bool right, bool jump, bool shoot, float elapsedTime) {
+
+ Vector3f delta = Vector3f(0, 0, 0);
+
+ float yrotrad = (m_rotY / 57.2957795056f); // 180/Pi = 57.295...
+ float xrotrad = (m_rotX / 57.2957795056f);
+
+ m_direction = Vector3f(cos(xrotrad) * sin(yrotrad),
+ -sin(xrotrad),
+ cos(xrotrad) * -cos(yrotrad));
+
+ m_direction.Normalize();
+
+ if (front) {
+ delta.x += float(sin(yrotrad)) * elapsedTime * 10.f;
+ delta.z += float(-cos(yrotrad)) * elapsedTime * 10.f;
+ }
+ else if (back) {
+ delta.x += float(-sin(yrotrad)) * elapsedTime * 10.f;
+ delta.z += float(cos(yrotrad)) * elapsedTime * 10.f;
+ }
+
+ if (left) {
+ delta.x += float(-cos(yrotrad)) * elapsedTime * 10.f;
+ delta.z += float(-sin(yrotrad)) * elapsedTime * 10.f;
+ }
+ else if (right) {
+ delta.x += float(cos(yrotrad)) * elapsedTime * 10.f;
+ delta.z += float(sin(yrotrad)) * elapsedTime * 10.f;
+ }
+
+ delta.Normalize();
+ delta.x *= .6f;
+ delta.z *= .6f;
+
+ if ((jump || shoot ) && !m_airborne) {
+ delta.y += jump? .32f: shoot? .1f : 0.f;
+ m_airborne = true;
+ }
+
+ if (shoot) // Recoil!
+ TurnTopBottom(-1);
+
+ return delta;
+}
+
+void Player::ApplyPhysics(Vector3f input, World* world, float elapsedTime) {
+ static float timing = 0.f;
+ /* Gestion de collisions */
+ BlockType bt1, bt2, bt3;
+
+ bt1 = world->BlockAt(GetPosition().x, GetPosition().y + input.y, GetPosition().z);
+ bt2 = world->BlockAt(GetPosition().x, GetPosition().y + input.y - 0.9f, GetPosition().z);
+ bt3 = world->BlockAt(GetPosition().x, GetPosition().y + input.y - 1.7f, GetPosition().z);
+ if ((bt1 != BTYPE_AIR || bt2 != BTYPE_AIR || bt3 != BTYPE_AIR) && m_position.y < 129.7f) {
+ bt1 = world->BlockAt(GetPosition().x, GetPosition().y + .3f, GetPosition().z);
+ if (bt1 == BTYPE_AIR) m_position.y = (int)m_position.y + .7f;
+ m_velocity.y = input.y = 0;
+ m_airborne = false;
+ }
+ else {
+ if (abs(m_velocity.y) < 1.1f) m_velocity.y += input.y - 1.1f * elapsedTime;
+ bt3 = world->BlockAt(GetPosition().x, GetPosition().y + m_velocity.y - 1.7f, GetPosition().z);
+ bt1 = world->BlockAt(GetPosition().x, GetPosition().y + .3f, GetPosition().z);
+ if (bt3 != BTYPE_AIR) {
+ m_velocity.y = 0;
+ if (timing == 0.f) {
+ timing = .3f;
+ }
+ m_airborne = false;
+ }
+ else if (bt1 != BTYPE_AIR) {
+ m_velocity.y = -.1f;
+ }
+ else m_airborne = true;
+ }
+
+ if (timing > 0.f) timing -= elapsedTime;
+ if (timing < 0.f) timing = 0.f;
+
+ bt1 = world->BlockAt(GetPosition().x + input.x, GetPosition().y, GetPosition().z);
+ bt2 = world->BlockAt(GetPosition().x + input.x, GetPosition().y - 0.9f, GetPosition().z);
+ bt3 = world->BlockAt(GetPosition().x + input.x, GetPosition().y - 1.7f, GetPosition().z);
+ if (bt1 != BTYPE_AIR || bt2 != BTYPE_AIR || bt3 != BTYPE_AIR) {
+ input.x = m_velocity.x = 0;
+ m_velocity.z *= .5f;
+ }
+
+ bt1 = world->BlockAt(GetPosition().x, GetPosition().y, GetPosition().z + input.z);
+ bt2 = world->BlockAt(GetPosition().x, GetPosition().y - 0.9f, GetPosition().z + input.z);
+ bt3 = world->BlockAt(GetPosition().x, GetPosition().y - 1.7f, GetPosition().z + input.z);
+ if (bt1 != BTYPE_AIR || bt2 != BTYPE_AIR || bt3 != BTYPE_AIR) {
+ input.z = m_velocity.z = 0;
+ m_velocity.x *= .5f;
+ }
+
+ /* Fin gestion de collisions */
+ /* Gestion de la friction */
+
+ if (!m_airborne) {
+ m_velocity.x += input.x * 2.f * elapsedTime;
+ m_velocity.z += input.z * 2.f * elapsedTime;
+
+ if (input.x == 0.f)
+ m_velocity.x *= .8f;
+
+ if (input.z == 0.f)
+ m_velocity.z *= .8f;
+ }
+ else {
+ m_velocity.x += input.x * .4f * elapsedTime; // Techniquement contre les lois de la physique, mais c'est beaucoup moins chiant pour grimper sur les blocs.
+ m_velocity.z += input.z * .4f * elapsedTime;
+ m_velocity.x *= .99f;
+ m_velocity.z *= .99f;
+ }
+
+ /* Fin gestion de la friction */
+
+ float vy = m_velocity.y;
+ m_velocity.y = 1.f; // Padding pour limiter le x et z lors du Normalize().
+ if (m_velocity.Length() >= 1.f) m_velocity.Normalize(); // Limiteur de vitesse en x/z.
+ m_velocity.y = 0;
+ if (m_velocity.Length() < .005f) m_velocity.Zero(); // Threshold en x/z.
+ m_velocity.y = vy;
+
+ m_position += m_velocity;
+}
+
+Vector3f Player::GetPosition() const { return Vector3f(m_position.x + CHUNK_SIZE_X * WORLD_SIZE_X / 2, m_position.y, m_position.z + CHUNK_SIZE_Z * WORLD_SIZE_Y / 2); }
+
+Vector3f Player::GetVelocity() const { return m_velocity; }
+
+Vector3f Player::GetPOV() const { return Vector3f(GetPosition().x, m_POV, GetPosition().z); }
+
+Vector3f Player::GetDirection() const { return m_direction; }
+
+void Player::Teleport(int& x, int& z) {
+ m_position.x -= x * CHUNK_SIZE_X;
+ m_position.z -= z * CHUNK_SIZE_Z;
+}
diff --git a/SQCSim-common/player.h b/SQCSim-common/player.h
new file mode 100644
index 0000000..f889b68
--- /dev/null
+++ b/SQCSim-common/player.h
@@ -0,0 +1,34 @@
+#ifndef _PLAYER_H__
+#define _PLAYER_H__
+#include "vector3.h"
+#include
+
+class World;
+
+class Player {
+public:
+ Player(const Vector3f& position, float rotX = 0, float rotY = 0);
+ void TurnLeftRight(float value);
+ void TurnTopBottom(float value);
+ Vector3f GetInput(bool front, bool back, bool left, bool right, bool jump, bool dash, float elapsedTime);
+ void ApplyPhysics(Vector3f input, World* world, float elapsedTime);
+
+ Vector3f GetPosition() const;
+ Vector3f GetDirection() const;
+ Vector3f GetVelocity() const;
+ Vector3f GetPOV() const;
+ void Teleport(int& x, int& z);
+
+protected:
+ Vector3f m_position;
+ Vector3f m_velocity;
+ Vector3f m_direction;
+
+ float m_rotX = 0;
+ float m_rotY = 0;
+ float m_POV;
+
+ bool m_airborne;
+};
+#endif //_PLAYER_H__
+
diff --git a/SQCSim-common/vector3.h b/SQCSim-common/vector3.h
new file mode 100644
index 0000000..b191681
--- /dev/null
+++ b/SQCSim-common/vector3.h
@@ -0,0 +1,219 @@
+#ifndef VECTOR3_H__
+#define VECTOR3_H__
+
+#include
+#include
+
+template
+class Vector3
+{
+public:
+ Vector3();
+ Vector3(const T& x, const T& y, const T& z);
+ ~Vector3();
+
+ T Length() const;
+ void Normalize();
+ void Zero();
+
+ T Dot(const Vector3& v) const;
+ Vector3 Cross(const Vector3& v) const;
+
+ Vector3