Last active
February 1, 2018 23:04
-
-
Save Auburn/873eb532cef200d2cc77e65dab97924d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <functional> | |
#include <array> | |
#include <tuple> | |
#include <stdexcept> | |
#include <cstdint> | |
template<typename T, size_t Size> | |
class VecN; | |
template<typename T> | |
class VecN<T, 0> | |
{ | |
protected: | |
template<typename... A> | |
constexpr VecN( A... ) {} | |
template<typename... A> | |
void ForEach( A... ) const {} | |
template<typename... A> | |
void ForEachR( A... ) const {} | |
}; | |
template<typename T, size_t S> | |
class VecN : public VecN<T, S - 1> | |
{ | |
public: | |
static constexpr size_t Size = S; | |
typedef std::integral_constant<size_t, Size - 1> Index; | |
constexpr VecN() : Base(), value() {} | |
template<typename... A> | |
constexpr VecN( A... args ) : | |
Base( args... ), | |
value( std::get<Index::value>( std::make_tuple( args... ) ) ) | |
{ } | |
template<size_t I> | |
__forceinline std::enable_if_t<(I < Size), T&> At() | |
{ | |
return VecN<T, I + 1>::value; | |
} | |
template<size_t I> | |
__forceinline std::enable_if_t<(I < Size), T> At() const | |
{ | |
return VecN<T, I + 1>::value; | |
} | |
template<size_t I> | |
__forceinline std::enable_if_t<(I >= Size), T&> At() const | |
{ | |
throw std::out_of_range( "Index of of range" ); | |
} | |
template<typename F, typename... A> | |
__forceinline void ForEach( F&& func, A&&... other ) | |
{ | |
Base::ForEach( func, other... ); | |
func( Index(), value, (other.template At<Index::value>())... ); | |
} | |
template<typename F, typename... A> | |
__forceinline void ForEachR( F&& func, A&&... other ) | |
{ | |
func( Index(), value, (other.template At<Index::value>())... ); | |
Base::ForEachR( func, other... ); | |
} | |
protected: | |
typedef VecN<T, Size - 1> Base; | |
typedef std::integral_constant<size_t, Size - 1> Index; | |
T value; | |
}; | |
static float Lerp_( float a, float b, float t ) { return a + t * (b - a); } | |
static int FastFloor_( float f ) { return (f >= 0 ? (int)f : (int)f - 1); } | |
static float InterpQuinticFunc_( float t ) { return t*t*t*(t*(t * 6 - 15) + 10); } | |
const uint8_t perm[] = | |
{ | |
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, | |
225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, | |
120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, | |
88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, | |
139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, | |
105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, | |
73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, | |
164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, | |
147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, | |
28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, | |
155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, | |
178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, | |
191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, | |
199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, | |
205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, | |
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, | |
225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, | |
120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, | |
88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, | |
139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, | |
105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, | |
73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, | |
164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, | |
147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, | |
28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, | |
155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, | |
178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, | |
191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, | |
199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, | |
205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 | |
}; | |
template<typename T> | |
static constexpr T log2I( const T n ) | |
{ | |
return ((n < 2) ? 1 : 1 + log2I( n / 2 )); | |
} | |
template<size_t DIM> | |
struct GradN | |
{ | |
static constexpr size_t signBits = DIM - 1; | |
static constexpr size_t zeroBits = log2I( DIM - 1 ); | |
static constexpr size_t uniqueGrads = (1 << (signBits)) * DIM; | |
static constexpr size_t totalGrads = (1 << (signBits + zeroBits)); | |
static constexpr float IndexGen( const size_t gradIdx, const size_t axisIdx ) | |
{ | |
const size_t gradIdxClamped = gradIdx < uniqueGrads ? gradIdx : (gradIdx - uniqueGrads) * (uniqueGrads / (totalGrads > uniqueGrads ? (totalGrads - uniqueGrads) : 1)); | |
const size_t zeroPos = gradIdxClamped >> signBits; | |
const size_t signLookup = gradIdxClamped << (axisIdx > zeroPos ? 1 : 0); | |
return axisIdx == zeroPos ? 0.0f : ((((size_t)1 << axisIdx) & signLookup) ? -1.0f : 1.0f); | |
} | |
template<size_t... I> | |
static constexpr VecN<float, DIM> GradGen( const size_t idx, std::index_sequence<I...> ) | |
{ | |
return { IndexGen( idx, I )... }; | |
} | |
template<size_t... I> | |
static constexpr std::array<VecN<float, DIM>, sizeof...(I)> ArrayGen( std::index_sequence<I...> ) | |
{ | |
return { GradGen( I, std::make_index_sequence<DIM>() )... }; | |
} | |
static constexpr auto& gradArray = ArrayGen( std::make_index_sequence<totalGrads>() ); | |
}; | |
template<> | |
struct GradN<2> | |
{ | |
static constexpr size_t totalGrads = 8; | |
static constexpr VecN<float, 2> gradArray[totalGrads] = | |
{ | |
{ 1.0f, 1.0f }, | |
{ -1.0f, 1.0f }, | |
{ 1.0f, -1.0f }, | |
{ -1.0f, -1.0f }, | |
{ 0.0f, 1.0f }, | |
{ 0.0f, -1.0f }, | |
{ 1.0f, 0.0f }, | |
{ -1.0f, 0.0f }, | |
}; | |
}; | |
constexpr VecN<float, 2> GradN<2>::gradArray[]; | |
template<> | |
struct GradN<1> | |
{ | |
static constexpr size_t totalGrads = 4; | |
static constexpr VecN<float, 1> gradArray[totalGrads] = | |
{ | |
1.0f, -1.0f, 0.5f, -0.5f | |
}; | |
}; | |
constexpr VecN<float, 1> GradN<1>::gradArray[]; | |
template<size_t DIM> | |
__forceinline static float GradCoord( VecN<int, DIM>& posV, VecN<float, DIM>& deltaV ) | |
{ | |
uint8_t hash = 0; | |
posV.ForEach( [&hash]( auto, int i ) { hash = perm[hash + (i & 255)]; } ); | |
float dot = 0; | |
const auto& grad = GradN<DIM>::gradArray[(hash & (GradN<DIM>::totalGrads - 1))]; | |
deltaV.ForEach( [&dot, grad]( auto idx, float f, float g ) | |
{ | |
dot += f * g; | |
}, grad ); | |
return dot; | |
} | |
template<size_t DIM> | |
static float PerlinT( VecN<float, DIM> pos ) | |
{ | |
VecN<float, DIM> f0, f1, interp; | |
VecN<int, DIM> i0, i1; | |
pos.ForEach( []( auto, float fPos, float& ff0, float& ff1, int& ii0, int& ii1, float& fInterp ) | |
{ | |
ii0 = FastFloor_( fPos ); | |
ff0 = fPos - float( ii0 ); | |
ff1 = ff0 - 1; | |
ii1 = ii0 + 1; | |
fInterp = InterpQuinticFunc_( ff0 ); | |
}, f0, f1, i0, i1, interp ); | |
VecN<float, (1 << DIM)> gradPoints; | |
gradPoints.ForEachR( [&gradPoints, &interp, &i0, &i1, &f0, &f1]( auto gradIdx, float& grad ) | |
{ | |
VecN<int, DIM> posV; | |
VecN<float, DIM> deltaV; | |
posV.ForEach( [gradIdx]( auto idx, int& i, int ii0, int ii1, float& f, float ff0, float ff1 ) | |
{ | |
if( (1ull << decltype(idx)::value) & decltype(gradIdx)::value ) | |
{ | |
i = ii1; | |
f = ff1; | |
} | |
else | |
{ | |
i = ii0; | |
f = ff0; | |
} | |
}, i0, i1, deltaV, f0, f1 ); | |
grad = GradCoord( posV, deltaV ); | |
interp.ForEach( [&gradPoints, &grad, gradIdx]( auto dimIdx, float d ) | |
{ | |
if ( ((1ull << (decltype(dimIdx)::value + 1)) - 1) & decltype(gradIdx)::value ) | |
{ | |
return; | |
} | |
grad = Lerp_( grad, gradPoints.template At<(decltype(gradIdx)::value + (1ull << decltype(dimIdx)::value))>(), d ); | |
} ); | |
} ); | |
return gradPoints.template At<0>(); | |
} | |
template<size_t DIM> | |
static float SimplexT( VecN<float, DIM> pos ) | |
{ | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment