Skip to content

Instantly share code, notes, and snippets.

@Auburn
Last active February 1, 2018 23:04
Show Gist options
  • Save Auburn/873eb532cef200d2cc77e65dab97924d to your computer and use it in GitHub Desktop.
Save Auburn/873eb532cef200d2cc77e65dab97924d to your computer and use it in GitHub Desktop.
#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