From 16a67035d039222b95cab7d1b41007a7df0961b5 Mon Sep 17 00:00:00 2001
From: MarcEricMartel <74071476+MarcEricMartel@users.noreply.github.com>
Date: Sat, 2 Apr 2022 15:26:55 -0400
Subject: [PATCH] Changements pour v143 et autres corrections.
---
SQCSim2021/SQCSim2021.vcxproj | 12 +-
SQCSim2021/SQCSim2021.vcxproj.filters | 8 +-
SQCSim2021/chunk.cpp | 25 +-
SQCSim2021/chunk.h | 2 +
SQCSim2021/define.h | 6 +-
SQCSim2021/engine.cpp | 8 +-
SQCSim2021/opensimplex.cpp | 2542 +++++++++++++++++
SQCSim2021/opensimplex.h | 51 +
SQCSim2021/perlin.cpp | 262 --
SQCSim2021/perlin.h | 60 -
SQCSim2021/world.cpp | 11 +-
SQCSim2021/world.h | 15 +-
SQCSim2021/x64/Debug/SQCSim2021.exe.recipe | 11 +
.../SQCSim2021.tlog/SQCSim2021.lastbuildstate | 2 +
.../SQCSim2021.tlog/clang-cl.command.1.tlog | Bin 0 -> 9442 bytes
.../SQCSim2021.tlog/clang-cl.read.1.tlog | Bin 0 -> 1014910 bytes
.../SQCSim2021.tlog/clang-cl.write.1.tlog | Bin 0 -> 4484 bytes
.../SQCSim2021.tlog/lld-link.command.1.tlog | Bin 0 -> 3700 bytes
.../SQCSim2021.tlog/lld-link.read.2.tlog | Bin 0 -> 8886 bytes
.../SQCSim2021.tlog/lld-link.write.1.tlog | Bin 0 -> 2120 bytes
.../SQCSim2021.tlog/SQCSim2021.lastbuildstate | 4 +-
.../clang-cl.1032.delete.1.tlog | Bin 7458 -> 0 bytes
.../clang-cl.1032.write.1.tlog | Bin 3400 -> 0 bytes
.../clang-cl.11724.delete.1.tlog | Bin 7434 -> 0 bytes
.../clang-cl.13204.delete.1.tlog | Bin 7498 -> 0 bytes
.../clang-cl.14816.delete.1.tlog | Bin 7426 -> 0 bytes
.../clang-cl.16024.delete.1.tlog | Bin 7434 -> 0 bytes
.../clang-cl.16472.delete.1.tlog | Bin 7426 -> 0 bytes
.../clang-cl.18832.delete.1.tlog | Bin 7482 -> 0 bytes
.../clang-cl.19712.delete.1.tlog | Bin 7434 -> 0 bytes
.../clang-cl.24092.delete.1.tlog | Bin 7442 -> 0 bytes
.../clang-cl.25324.delete.1.tlog | Bin 7426 -> 0 bytes
.../clang-cl.26840.delete.1.tlog | Bin 7418 -> 0 bytes
.../clang-cl.31424.delete.1.tlog | Bin 7490 -> 0 bytes
.../clang-cl.33888.delete.1.tlog | Bin 7482 -> 0 bytes
.../clang-cl.34004.delete.1.tlog | Bin 7434 -> 0 bytes
.../clang-cl.34284.delete.1.tlog | Bin 7434 -> 0 bytes
.../clang-cl.36512.delete.1.tlog | Bin 7418 -> 0 bytes
.../clang-cl.7912.delete.1.tlog | Bin 7434 -> 0 bytes
.../SQCSim2021.tlog/clang-cl.command.1.tlog | Bin 9822 -> 10414 bytes
.../SQCSim2021.tlog/clang-cl.read.1.tlog | Bin 988046 -> 1028398 bytes
.../SQCSim2021.tlog/lld-link.command.1.tlog | Bin 3988 -> 4164 bytes
.../SQCSim2021.tlog/lld-link.delete.1.tlog | Bin 2514 -> 0 bytes
.../SQCSim2021.tlog/lld-link.read.1.tlog | Bin 10424 -> 0 bytes
.../SQCSim2021.tlog/lld-link.write.1.tlog | Bin 2082 -> 2200 bytes
.../SQCSim2021.vcxproj.FileListAbsolute.txt | 0
x64/Debug/DevIL.dll | Bin 0 -> 1762304 bytes
x64/Debug/ILU.dll | Bin 0 -> 109568 bytes
x64/Debug/ILUT.dll | Bin 0 -> 36352 bytes
x64/Debug/SQCSim2021.exe | Bin 0 -> 477696 bytes
x64/Debug/glew32.dll | Bin 0 -> 422912 bytes
x64/Debug/irrKlang.dll | Bin 0 -> 585216 bytes
x64/Debug/openal32.dll | Bin 0 -> 669696 bytes
x64/Debug/sfml-graphics-d-2.dll | Bin 0 -> 1840128 bytes
x64/Debug/sfml-network-d-2.dll | Bin 0 -> 434688 bytes
x64/Debug/sfml-system-d-2.dll | Bin 0 -> 238080 bytes
x64/Debug/sfml-window-d-2.dll | Bin 0 -> 433664 bytes
57 files changed, 2655 insertions(+), 364 deletions(-)
create mode 100644 SQCSim2021/opensimplex.cpp
create mode 100644 SQCSim2021/opensimplex.h
delete mode 100644 SQCSim2021/perlin.cpp
delete mode 100644 SQCSim2021/perlin.h
create mode 100644 SQCSim2021/x64/Debug/SQCSim2021.exe.recipe
create mode 100644 SQCSim2021/x64/Debug/SQCSim2021.tlog/SQCSim2021.lastbuildstate
create mode 100644 SQCSim2021/x64/Debug/SQCSim2021.tlog/clang-cl.command.1.tlog
create mode 100644 SQCSim2021/x64/Debug/SQCSim2021.tlog/clang-cl.read.1.tlog
create mode 100644 SQCSim2021/x64/Debug/SQCSim2021.tlog/clang-cl.write.1.tlog
create mode 100644 SQCSim2021/x64/Debug/SQCSim2021.tlog/lld-link.command.1.tlog
create mode 100644 SQCSim2021/x64/Debug/SQCSim2021.tlog/lld-link.read.2.tlog
create mode 100644 SQCSim2021/x64/Debug/SQCSim2021.tlog/lld-link.write.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.1032.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.1032.write.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.11724.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.13204.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.14816.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.16024.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.16472.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.18832.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.19712.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.24092.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.25324.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.26840.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.31424.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.33888.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.34004.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.34284.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.36512.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/clang-cl.7912.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/lld-link.delete.1.tlog
delete mode 100644 SQCSim2021/x64/Release/SQCSim2021.tlog/lld-link.read.1.tlog
create mode 100644 SQCSim2021/x64/Release/SQCSim2021.vcxproj.FileListAbsolute.txt
create mode 100644 x64/Debug/DevIL.dll
create mode 100644 x64/Debug/ILU.dll
create mode 100644 x64/Debug/ILUT.dll
create mode 100644 x64/Debug/SQCSim2021.exe
create mode 100644 x64/Debug/glew32.dll
create mode 100644 x64/Debug/irrKlang.dll
create mode 100644 x64/Debug/openal32.dll
create mode 100644 x64/Debug/sfml-graphics-d-2.dll
create mode 100644 x64/Debug/sfml-network-d-2.dll
create mode 100644 x64/Debug/sfml-system-d-2.dll
create mode 100644 x64/Debug/sfml-window-d-2.dll
diff --git a/SQCSim2021/SQCSim2021.vcxproj b/SQCSim2021/SQCSim2021.vcxproj
index 6283299..8a66eba 100644
--- a/SQCSim2021/SQCSim2021.vcxproj
+++ b/SQCSim2021/SQCSim2021.vcxproj
@@ -29,7 +29,7 @@
-
+
@@ -49,7 +49,7 @@
-
+
@@ -72,13 +72,13 @@
Application
true
Unicode
- v142
+ ClangCL
Application
true
Unicode
- v142
+ ClangCL
Application
@@ -117,8 +117,8 @@
true
- $(ProjectDir)\external\irrKlang-1.6.0\include$(MSBuildProjectDirectory)$(MSBuildProjectDirectory);external\devil178\include;external\sfml23\include;$(IncludePath)
- external\devil178\lib;external\sfml23\lib;$(LibraryPath);D:\Repos\SQCSim2021\SQCSim2021\external\irrKlang-1.6.0\lib\Win32-visualStudio
+ external\irrKlang-64bit-1.6.0\include;external\devil180\include;external\sfml251\include;external\glew210\include;$(IncludePath)
+ external\devil180\lib\x64\Release;external\glew210\lib\Release\x64;external\sfml251\lib;$(LibraryPath);external\irrKlang-64bit-1.6.0\lib\Winx64-visualStudio
false
diff --git a/SQCSim2021/SQCSim2021.vcxproj.filters b/SQCSim2021/SQCSim2021.vcxproj.filters
index 124abf1..4b2e6c9 100644
--- a/SQCSim2021/SQCSim2021.vcxproj.filters
+++ b/SQCSim2021/SQCSim2021.vcxproj.filters
@@ -68,10 +68,10 @@
Fichiers d%27en-tête
-
+
Fichiers d%27en-tête
-
+
Fichiers d%27en-tête
@@ -121,10 +121,10 @@
Fichiers sources
-
+
Fichiers sources
-
+
Fichiers sources
diff --git a/SQCSim2021/chunk.cpp b/SQCSim2021/chunk.cpp
index c524112..2a98568 100644
--- a/SQCSim2021/chunk.cpp
+++ b/SQCSim2021/chunk.cpp
@@ -7,24 +7,24 @@ Chunk::Chunk(unsigned int x, unsigned int y) : m_posX(x), m_posY(y) {
std::ifstream input(pos.str(), std::fstream::binary);
if (input.fail()) {
- Perlin perlin = Perlin(8, 45.f, 7.f, PERLIN_SEED);
+ OpenSimplexNoise::Noise simplex = OpenSimplexNoise::Noise(PERLIN_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) / (double)UINT16_MAX;
- ynoiz = (double)(iz + y * CHUNK_SIZE_Z) / (double)UINT16_MAX;
- float height = (perlin.Get(xnoiz, ynoiz)) * 20.f + 5.f;
+ xnoiz = (double)(ix + x * CHUNK_SIZE_X) / 256.;
+ ynoiz = (double)(iz + y * CHUNK_SIZE_Z) / 256.;
+ float height = (simplex.eval(xnoiz, ynoiz)) * 60.f + 5.f;
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) / (double)UINT16_MAX;
- ynoiz = (double)(iz + y * CHUNK_SIZE_Z) / (double)UINT16_MAX;
- float height = perlin.Get(xnoiz, ynoiz) * 5.f + 24.f;
+ xnoiz = (double)(ix + x * CHUNK_SIZE_X) / 64.;
+ ynoiz = (double)(iz + y * CHUNK_SIZE_Z) / 64.;
+ float height = simplex.eval(xnoiz, ynoiz) * 5.f + 24.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);
@@ -32,7 +32,7 @@ Chunk::Chunk(unsigned int x, unsigned int y) : m_posX(x), m_posY(y) {
}
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) {
+ for (int iy = 0; iy < 16; ++iy) {
if (GetBlock(ix, iy, iz) == BTYPE_AIR)
SetBlock(ix, iy, iz, BTYPE_ICE, nullptr);
}
@@ -40,15 +40,14 @@ Chunk::Chunk(unsigned int x, unsigned int y) : m_posX(x), m_posY(y) {
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) / (double)UINT16_MAX;
- ynoiz = (double)(ix * CHUNK_SIZE_Y + y * CHUNK_SIZE_Z) / (double)UINT16_MAX;
- bool tree = (int)(abs(perlin.Get(xnoiz, ynoiz)) * 17933.f) % CHUNK_SIZE_Y > 126 ? true : false;
-
+ 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(perlin.Get(xnoiz, ynoiz))) % 3 + 1; ++i)
+ for (int i = 0; i < (int)(abs(simplex.eval(xnoiz, ynoiz) * 65)) % 42 + 1; ++i)
SetBlock(ix, iy + i, iz, BTYPE_DIRT, nullptr);
break;
}
diff --git a/SQCSim2021/chunk.h b/SQCSim2021/chunk.h
index 5c0add3..f4d58b1 100644
--- a/SQCSim2021/chunk.h
+++ b/SQCSim2021/chunk.h
@@ -5,6 +5,8 @@
#include "array2d.h"
#include "vertexbuffer.h"
#include "blockinfo.h"
+#include "perlin.h"
+#include "opensimplex.h"
class World;
diff --git a/SQCSim2021/define.h b/SQCSim2021/define.h
index 63987e3..f3f0d93 100644
--- a/SQCSim2021/define.h
+++ b/SQCSim2021/define.h
@@ -36,8 +36,8 @@
#endif
#ifdef NDEBUG
-#define WORLD_SIZE_X 128
-#define WORLD_SIZE_Y 128
+#define WORLD_SIZE_X 64
+#define WORLD_SIZE_Y 64
#define FRAMES_RENDER_CHUNKS 1
#define FRAMES_UPDATE_CHUNKS 1
@@ -47,7 +47,7 @@
#define THREADS_UPDATE_CHUNKS 8
#define THREADS_DELETE_CHUNKS 10
-#define VIEW_DISTANCE 1024
+#define VIEW_DISTANCE 512
#define TEXTURE_SIZE 512
#define MAX_BULLETS 512
#endif
diff --git a/SQCSim2021/engine.cpp b/SQCSim2021/engine.cpp
index 65099e9..204d89e 100644
--- a/SQCSim2021/engine.cpp
+++ b/SQCSim2021/engine.cpp
@@ -186,12 +186,14 @@ int Engine::GetFps(float elapsedTime) const { return 1 / elapsedTime; }
void Engine::Render(float elapsedTime) {
static float gameTime = elapsedTime;
+ static float pollTime = 0;
static float bulletTime = 0;
static BlockType bloc = 1;
if (elapsedTime > 0.1f) return;
gameTime += elapsedTime;
+ pollTime += elapsedTime;
Transformation all;
Transformation skybox;
@@ -205,9 +207,13 @@ void Engine::Render(float elapsedTime) {
if (bulletTime > 0.f) bulletTime -= elapsedTime;
if (bulletTime < 0.f) bulletTime = 0.f;
+ if (pollTime >= .005f) {
m_player.ApplyPhysics(m_player.GetInput(m_keyW, m_keyS, m_keyA, m_keyD, m_keySpace, (bloc == BTYPE_LAST && bulletTime <= 0.f && m_mouseL), elapsedTime), m_world, elapsedTime, &m_audio);
m_audio.Update3DAudio(m_player.GetPOV(), m_player.GetDirection(), m_player.GetVelocity()); // Ajustement du positionnement 3D avec les coordonnées du joueur et
// son vecteur de vélocité (pour l'effet Doppler)
+ pollTime = 0;
+ }
+
m_player.ApplyTransformation(all);
m_player.ApplyTransformation(skybox, false); // Version d'ApplyTransformation qui ne tient compte que de la rotation
@@ -252,7 +258,7 @@ void Engine::Render(float elapsedTime) {
m_bullets[x] = nullptr;
}
- m_world.Update(m_renderCount, m_bullets, m_player, all, m_shader01, m_textureAtlas, m_perlin, m_blockinfo);
+ m_world.Update(m_renderCount, m_bullets, m_player, all, m_shader01, m_textureAtlas, m_blockinfo);
if (m_isSkybox) m_skybox.Render(skybox);
diff --git a/SQCSim2021/opensimplex.cpp b/SQCSim2021/opensimplex.cpp
new file mode 100644
index 0000000..a64d31f
--- /dev/null
+++ b/SQCSim2021/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/SQCSim2021/opensimplex.h b/SQCSim2021/opensimplex.h
new file mode 100644
index 0000000..4b1b1f4
--- /dev/null
+++ b/SQCSim2021/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/SQCSim2021/perlin.cpp b/SQCSim2021/perlin.cpp
deleted file mode 100644
index 6e62717..0000000
--- a/SQCSim2021/perlin.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/* coherent noise function over 1, 2 or 3 dimensions */
-/* (copyright Ken Perlin) */
-
-#include
-#include
-#include
-
-#include "perlin.h"
-
-#define B SAMPLE_SIZE
-#define BM (SAMPLE_SIZE-1)
-
-#define N 0x1000
-#define NP 12 /* 2^N */
-#define NM 0xfff
-
-#define s_curve(t) ( t * t * (3.0f - 2.0f * t) )
-#define lerp(t, a, b) ( a + t * (b - a) )
-
-#define setup(i,b0,b1,r0,r1)\
- t = vec[i] + N;\
-b0 = ((int)t) & BM;\
-b1 = (b0+1) & BM;\
-r0 = t - (int)t;\
-r1 = r0 - 1.0f;
-
-float Perlin::noise1(float arg)
-{
- int bx0, bx1;
- float rx0, rx1, sx, t, u, v, vec[1];
-
- vec[0] = arg;
-
- if (mStart)
- {
- srand(mSeed);
- mStart = false;
- init();
- }
-
- setup(0, bx0,bx1, rx0,rx1);
-
- sx = s_curve(rx0);
-
- u = rx0 * g1[ p[ bx0 ] ];
- v = rx1 * g1[ p[ bx1 ] ];
-
- return lerp(sx, u, v);
-}
-
-float Perlin::noise2(float vec[2])
-{
- int bx0, bx1, by0, by1, b00, b10, b01, b11;
- float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
- int i, j;
-
- if (mStart)
- {
- srand(mSeed);
- mStart = false;
- init();
- }
-
- setup(0,bx0,bx1,rx0,rx1);
- setup(1,by0,by1,ry0,ry1);
-
- i = p[bx0];
- j = p[bx1];
-
- b00 = p[i + by0];
- b10 = p[j + by0];
- b01 = p[i + by1];
- b11 = p[j + by1];
-
- sx = s_curve(rx0);
- sy = s_curve(ry0);
-
-#define at2(rx,ry) ( rx * q[0] + ry * q[1] )
-
- q = g2[b00];
- u = at2(rx0,ry0);
- q = g2[b10];
- v = at2(rx1,ry0);
- a = lerp(sx, u, v);
-
- q = g2[b01];
- u = at2(rx0,ry1);
- q = g2[b11];
- v = at2(rx1,ry1);
- b = lerp(sx, u, v);
-
- return lerp(sy, a, b);
-}
-
-float Perlin::noise3(float vec[3])
-{
- int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
- float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
- int i, j;
-
- if (mStart)
- {
- srand(mSeed);
- mStart = false;
- init();
- }
-
- setup(0, bx0,bx1, rx0,rx1);
- setup(1, by0,by1, ry0,ry1);
- setup(2, bz0,bz1, rz0,rz1);
-
- i = p[ bx0 ];
- j = p[ bx1 ];
-
- b00 = p[ i + by0 ];
- b10 = p[ j + by0 ];
- b01 = p[ i + by1 ];
- b11 = p[ j + by1 ];
-
- t = s_curve(rx0);
- sy = s_curve(ry0);
- sz = s_curve(rz0);
-
-#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
-
- q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0);
- q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0);
- a = lerp(t, u, v);
-
- q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0);
- q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0);
- b = lerp(t, u, v);
-
- c = lerp(sy, a, b);
-
- q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1);
- q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1);
- a = lerp(t, u, v);
-
- q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1);
- q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1);
- b = lerp(t, u, v);
-
- d = lerp(sy, a, b);
-
- return lerp(sz, c, d);
-}
-
-void Perlin::normalize2(float v[2])
-{
- float s;
-
- s = (float)sqrt(v[0] * v[0] + v[1] * v[1]);
- s = 1.0f/s;
- v[0] = v[0] * s;
- v[1] = v[1] * s;
-}
-
-void Perlin::normalize3(float v[3])
-{
- float s;
-
- s = (float)sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
- s = 1.0f/s;
-
- v[0] = v[0] * s;
- v[1] = v[1] * s;
- v[2] = v[2] * s;
-}
-
-void Perlin::init(void)
-{
- int i, j, k;
-
- for (i = 0 ; i < B ; i++)
- {
- p[i] = i;
- g1[i] = (float)((rand() % (B + B)) - B) / B;
- for (j = 0 ; j < 2 ; j++)
- g2[i][j] = (float)((rand() % (B + B)) - B) / B;
- normalize2(g2[i]);
- for (j = 0 ; j < 3 ; j++)
- g3[i][j] = (float)((rand() % (B + B)) - B) / B;
- normalize3(g3[i]);
- }
-
- while (--i)
- {
- k = p[i];
- p[i] = p[j = rand() % B];
- p[j] = k;
- }
-
- for (i = 0 ; i < B + 2 ; i++)
- {
- p[B + i] = p[i];
- g1[B + i] = g1[i];
- for (j = 0 ; j < 2 ; j++)
- g2[B + i][j] = g2[i][j];
- for (j = 0 ; j < 3 ; j++)
- g3[B + i][j] = g3[i][j];
- }
-
-}
-
-
-float Perlin::perlin_noise_2D(float vec[2])
-{
- int terms = mOctaves;
- //float freq = mFrequency;
- float result = 0.0f;
- float amp = mAmplitude;
-
- vec[0]*=mFrequency;
- vec[1]*=mFrequency;
-
- for( int i=0; i
-
-
-#define SAMPLE_SIZE 1024
-
-class Perlin
-{
-public:
-
- Perlin(int octaves,float freq,float amp,int seed);
-
-
- float Get(float x,float y)
- {
- float vec[2];
- vec[0] = x;
- vec[1] = y;
- return perlin_noise_2D(vec);
- };
-
- float Get(float x,float y, float z)
- {
- float vec[3];
- vec[0] = x;
- vec[1] = y;
- vec[2] = z;
- return perlin_noise_3D(vec);
- };
-
-private:
- void init_perlin(int n,float p);
- float perlin_noise_2D(float vec[2]);
- float perlin_noise_3D(float vec[3]);
-
- float noise1(float arg);
- float noise2(float vec[2]);
- float noise3(float vec[3]);
- void normalize2(float v[2]);
- void normalize3(float v[3]);
- void init(void);
-
- int mOctaves;
- float mFrequency;
- float mAmplitude;
- int mSeed;
-
- int p[SAMPLE_SIZE + SAMPLE_SIZE + 2];
- float g3[SAMPLE_SIZE + SAMPLE_SIZE + 2][3];
- float g2[SAMPLE_SIZE + SAMPLE_SIZE + 2][2];
- float g1[SAMPLE_SIZE + SAMPLE_SIZE + 2];
- bool mStart;
-
-};
-
-#endif
diff --git a/SQCSim2021/world.cpp b/SQCSim2021/world.cpp
index 5fa0880..3042df7 100644
--- a/SQCSim2021/world.cpp
+++ b/SQCSim2021/world.cpp
@@ -125,12 +125,12 @@ void World::GetScope(unsigned int& x, unsigned int& y) {
y = m_center[1];
}
-void World::Update(int& rendercount, Bullet* bullets[MAX_BULLETS], Player& player, Transformation& world, Shader& shader, TextureAtlas& atlas, Perlin& perlin, BlockInfo* blockinfo[BTYPE_LAST]) {
+void World::Update(int& rendercount, Bullet* bullets[MAX_BULLETS], Player& player, Transformation& world, Shader& shader, TextureAtlas& atlas, BlockInfo* blockinfo[BTYPE_LAST]) {
glStencilFunc(GL_EQUAL, 1, 0x00);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
atlas.Bind();
RenderWorld(rendercount, player, world, shader);
- UpdateWorld(player, perlin, blockinfo);
+ UpdateWorld(player, blockinfo);
TransposeWorld(player, bullets);
shader.Disable();
glStencilFunc(GL_GREATER, 1, 0xFF);
@@ -301,7 +301,7 @@ void World::RenderWorld(int& rendercount, Player& player, Transformation& world,
shader.Disable();
};
-void World::UpdateWorld(Player& player, Perlin& perlin, BlockInfo* blockinfo[BTYPE_LAST]) {
+void World::UpdateWorld(Player& player, BlockInfo* blockinfo[BTYPE_LAST]) {
int cx = player.GetPosition().x;
int cy = player.GetPosition().z;
static int frameGenerate = 0;
@@ -466,9 +466,10 @@ void World::UpdateWorld(Player& player, Perlin& perlin, BlockInfo* blockinfo[BTY
else m_tbDeleted.pop_back();
}
- for (int x = 0; x < threads; ++x)
+ for (int x = 0; x < threads; ++x) {
delThList[x].wait();
-
+ delThList[x].get();
+ }
}
int World::GettbDeleted() const { return m_tbDeleted.size(); }
\ No newline at end of file
diff --git a/SQCSim2021/world.h b/SQCSim2021/world.h
index ab37cf7..d4b1545 100644
--- a/SQCSim2021/world.h
+++ b/SQCSim2021/world.h
@@ -1,20 +1,19 @@
#ifndef WORLD_H__
#define WORLD_H__
+#include
+#include
+#include
+#include
+#include
#include "define.h"
#include "chunk.h"
#include "array2d.h"
#include "vector3.h"
#include "player.h"
#include "transformation.h"
-#include "perlin.h"
#include "shader.h"
#include "bullet.h"
#include "textureatlas.h"
-#include
-#include
-#include
-#include
-#include
class Chunk;
class Player;
@@ -33,7 +32,7 @@ public:
BlockType BlockAt(float x, float y, float z, BlockType defaultBlockType = BTYPE_AIR) const;
BlockType BlockAt(const Vector3f& pos, BlockType defaultBlockType = BTYPE_AIR) const;
- void Update(int& rendercount, Bullet* bullets[MAX_BULLETS], Player& player, Transformation& world, Shader& shader, TextureAtlas& atlas, Perlin& perlin, BlockInfo* blockinfo[BTYPE_LAST]);
+ void Update(int& rendercount, Bullet* bullets[MAX_BULLETS], Player& player, Transformation& world, Shader& shader, TextureAtlas& atlas, BlockInfo* blockinfo[BTYPE_LAST]);
void GetScope(unsigned int& x, unsigned int& y);
@@ -49,7 +48,7 @@ private:
void UpdateChunk(int& updates, unsigned int chx, unsigned int chy, BlockInfo* blockinfo[BTYPE_LAST]);
void RenderWorld(int& rendercount, Player& player, Transformation& world, Shader& shader);
- void UpdateWorld(Player& player, Perlin& perlin, BlockInfo* blockinfo[BTYPE_LAST]);
+ void UpdateWorld(Player& player, BlockInfo* blockinfo[BTYPE_LAST]);
void TransposeWorld(Player& player, Bullet* bullets[MAX_BULLETS]);
};
diff --git a/SQCSim2021/x64/Debug/SQCSim2021.exe.recipe b/SQCSim2021/x64/Debug/SQCSim2021.exe.recipe
new file mode 100644
index 0000000..2232cc6
--- /dev/null
+++ b/SQCSim2021/x64/Debug/SQCSim2021.exe.recipe
@@ -0,0 +1,11 @@
+
+
+
+
+ D:\Repos\SQCSim2021\x64\Debug\SQCSim2021.exe
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SQCSim2021/x64/Debug/SQCSim2021.tlog/SQCSim2021.lastbuildstate b/SQCSim2021/x64/Debug/SQCSim2021.tlog/SQCSim2021.lastbuildstate
new file mode 100644
index 0000000..34e6419
--- /dev/null
+++ b/SQCSim2021/x64/Debug/SQCSim2021.tlog/SQCSim2021.lastbuildstate
@@ -0,0 +1,2 @@
+PlatformToolSet=ClangCL:VCToolArchitecture=Native64Bit:VCToolsVersion=14.31.31103:TargetPlatformVersion=10.0.22000.0:
+C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\Llvm\x64|13.0.0|Debug|x64|D:\Repos\SQCSim2021\|
diff --git a/SQCSim2021/x64/Debug/SQCSim2021.tlog/clang-cl.command.1.tlog b/SQCSim2021/x64/Debug/SQCSim2021.tlog/clang-cl.command.1.tlog
new file mode 100644
index 0000000000000000000000000000000000000000..ea157ccdf8633a35e5a9cf660e51ac6585889624
GIT binary patch
literal 9442
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