Last active
December 17, 2015 14:39
-
-
Save rubber-duck/5625611 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| module toybox.math.vector; | |
| private | |
| { | |
| import std.stdio, std.string, std.metastrings, std.typecons, std.traits; | |
| static import std.math, std.algorithm; | |
| import toybox.math.matrix; | |
| } | |
| template IsComponentType(T) { static if(is(T == float) || is(T == double) || is(T == int) || is(T == uint) || is(T == bool)) { enum IsComponentType = true; } else { enum IsComponentType = false; } } | |
| template IsFloat(T) { static if(is(T == float) || is(T == double)) { enum IsFloat = true; } else { enum IsFloat = false; } } | |
| template IsInteger(T) { static if(is(T == int) || is(T == uint)) { enum IsInteger = true; } else { enum IsInteger = false; } } | |
| template IsScalar(T) { static if(is(T == float) || is(T == double) || is(T == int) || is(T == uint)) { enum IsScalar = true; } else { enum IsScalar = false; } } | |
| struct VectorTN(T, int N) | |
| if(IsComponentType!T && N > 1 && N <= 4) | |
| { | |
| alias N dimensions; | |
| alias T memberType; | |
| /** Vector members as N dimensional static array of type T, by default initialize members to 0 */ | |
| T[N] members = 0; | |
| /** Create a vector with every member set to value specified */ | |
| this(U)(U value) pure nothrow | |
| if(IsComponentType!U) | |
| { | |
| auto valueT = cast(T)value; | |
| foreach(i; 0 .. N) | |
| members[i] = valueT; | |
| } | |
| /** Construct a vector with every member value provided in values */ | |
| this(U)(const U[] values) pure nothrow | |
| if(IsComponentType!U) | |
| { | |
| foreach(i; 0 .. N < values.length ? N : values.length) | |
| members[i] = cast(T)values[i]; | |
| } | |
| /** Construct a vector with members copied from other vector (cast to T) or 0 if other vector is smaller than this */ | |
| this(U, int M)(const auto ref VectorTN!(U, M) other) pure nothrow | |
| if(IsComponentType!U) | |
| { | |
| foreach(i; 0 .. N < M ? N : M) | |
| members[i] = cast(T)other[i]; | |
| } | |
| /** Construct a vector with two component values (rest are 0 if vector dimensions > 2) */ | |
| this(U1, U2)(const U1 x, const U2 y) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2) | |
| { | |
| members[0] = cast(T)x; | |
| members[1] = cast(T)y; | |
| } | |
| static if(N > 2) | |
| { | |
| /** Construct a vector with three component values (rest are 0 if vector dimensions > 3) */ | |
| this(U1, U2, U3)(const U1 x, const U2 y, const U3 z) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2 && IsComponentType!U3) | |
| { | |
| members[0] = cast(T)x; | |
| members[1] = cast(T)y; | |
| members[2] = cast(T)z; | |
| } | |
| /** Construct a vector with three component values (rest are 0 if vector dimensions > 3) */ | |
| this(U1, U2)(const VectorTN!(U1, 2) xy, const U2 z) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2) | |
| { | |
| members[0] = cast(T)xy[0]; | |
| members[1] = cast(T)xy[1]; | |
| members[2] = cast(T)z; | |
| } | |
| /** Construct a vector with three component values (rest are 0 if vector dimensions > 3) */ | |
| this(U1, U2)(const U1 x, const VectorTN!(U2, 2) yz) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2) | |
| { | |
| members[0] = cast(T)x; | |
| members[1] = cast(T)yz[0]; | |
| members[2] = cast(T)yz[1]; | |
| } | |
| } | |
| static if(N > 3) | |
| { | |
| /** Construct a vector with four component values */ | |
| this(U1, U2, U3, U4)(const U1 x, const U2 y, const U3 z, const U4 w) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2 && IsComponentType!U3 && IsComponentType!U4) | |
| { | |
| members[0] = cast(T)x; | |
| members[1] = cast(T)y; | |
| members[2] = cast(T)z; | |
| members[3] = cast(T)w; | |
| } | |
| /** Construct a vector with four component values */ | |
| this(U1, U2)(const auto ref VectorTN!(U1, 2) xy, const auto ref VectorTN!(U2, 2) zw) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2) | |
| { | |
| members[0] = cast(T)xy[0]; | |
| members[1] = cast(T)xy[1]; | |
| members[2] = cast(T)zw[0]; | |
| members[3] = cast(T)zw[1]; | |
| } | |
| /** Construct a vector with four component values */ | |
| this(U1, U2, U3)(const auto ref VectorTN!(U1, 2) xy, const U2 z, const U3 w) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2 && IsComponentType!U3) | |
| { | |
| members[0] = cast(T)xy[0]; | |
| members[1] = cast(T)xy[1]; | |
| members[2] = cast(T)z; | |
| members[3] = cast(T)w; | |
| } | |
| /** Construct a vector with four component values */ | |
| this(U1, U2, U3)(const U1 x, const auto ref VectorTN!(U2, 2) yz, const U3 w) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2 && IsComponentType!U3) | |
| { | |
| members[0] = cast(T)x; | |
| members[1] = cast(T)yz[0]; | |
| members[2] = cast(T)yz[1]; | |
| members[3] = cast(T)w; | |
| } | |
| /** Construct a vector with four component values */ | |
| this(U1, U2, U3)(const U1 x, const U2 y, const auto ref VectorTN!(U3, 2) zw) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2 && IsComponentType!U3) | |
| { | |
| members[0] = cast(T)x; | |
| members[1] = cast(T)y; | |
| members[2] = cast(T)zw[0]; | |
| members[3] = cast(T)zw[1]; | |
| } | |
| /** Construct a vector with four component values */ | |
| this(U1, U2)(const auto ref VectorTN!(U1, 3) xyz, const U2 w) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2) | |
| { | |
| members[0] = cast(T)xyz[0]; | |
| members[1] = cast(T)xyz[1]; | |
| members[2] = cast(T)xyz[2]; | |
| members[3] = cast(T)w; | |
| } | |
| /** Construct a vector with four component values */ | |
| this(U1, U2)(const U1 x, const auto ref VectorTN!(U2, 3) yzw) pure nothrow | |
| if(IsComponentType!U1 && IsComponentType!U2) | |
| { | |
| members[0] = cast(T)x; | |
| members[1] = cast(T)yzw[0]; | |
| members[2] = cast(T)yzw[1]; | |
| members[3] = cast(T)yzw[2]; | |
| } | |
| } | |
| /** Return number of dimensions for this vector, implemented as a function this to be compatible with GLSL */ | |
| @property int length() pure const nothrow { return N; } | |
| /** Index member access operator, simply returns a ref to members[index] */ | |
| ref T opIndex(size_t index) pure nothrow { return members[index]; } | |
| /** Index member access operator, simply returns a const ref to members[index] */ | |
| ref const(T) opIndex(size_t index) pure const nothrow { return members[index]; } | |
| /** Returns a pointer to the first element in vector */ | |
| @property T* ptr() pure { return members.ptr; } | |
| /** Returns a const pointer to the first element in vector */ | |
| @property const(T)* ptr() pure const { return members.ptr; } | |
| /** Binary functions only make sense when T is scalar */ | |
| static if(IsScalar!T) | |
| { | |
| /** Binary vector with scalar operator, returns result of op applied to this with scalar for each member in a new vector */ | |
| VectorTN!(T, N) opBinary(string op)(const T scalar) pure const nothrow | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = mixin("members[i]" ~ op ~ "scalar"); | |
| return result; | |
| } | |
| /** Binary vector with vector operator, returns the result of this op other for each member in a new vector */ | |
| VectorTN!(T, N) opBinary(string op)(const auto ref VectorTN!(T, N) other) pure const nothrow | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = mixin("members[i]" ~ op ~ "other[i]"); | |
| return result; | |
| } | |
| /** Binary vector with matrix multiplication operator, implementing left side multiplication (row vector * matrix) */ | |
| VectorTN!(T, N) opBinary(string op)(const auto ref MatrixTN!(T, N) other) pure const nothrow | |
| if(op == "*") | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = dot(this, other.columns[i]); | |
| return result; | |
| } | |
| } | |
| // Internal template implementation details for opDispatch member accessors | |
| private | |
| { | |
| static int coordIndex(char c)() pure nothrow | |
| { | |
| switch(c) | |
| { | |
| case 'x': return 0; | |
| case 'y': return 1; | |
| case 'z': return N > 2 ? 2 : -1; | |
| case 'w': return N > 3 ? 3 : -1; | |
| default: | |
| return -1; | |
| } | |
| } | |
| static bool coordValid(char c)() pure nothrow { return coordIndex!c != -1; } | |
| static bool coordsValidGetter(string coords)() pure nothrow | |
| if(coords.length > 0 && coords.length <= 4) | |
| { | |
| foreach(i; 0 .. coords.length) | |
| if(!coordValid!(coords[i])) | |
| return false; | |
| return true; | |
| } | |
| static bool coordsValidSetter(string coords)() pure nothrow | |
| { | |
| if(!coordsValidGetter!(coords)) | |
| return false; | |
| switch(coords.length) | |
| { | |
| case 1: return true; | |
| case 2: return coords[0] != coords[1]; | |
| case 3: return N > 2 && coords[0] != coords[1] && coords[0] != coords[2] && coords[1] != coords[2]; | |
| case 4: return N > 3 && coords[0] != coords[1] && coords[0] != coords[2] && coords[0] != coords[3] && coords[1] != coords[2] && coords[1] != coords[3] && coords[2] != coords[3]; | |
| default: return false; | |
| } | |
| } | |
| } | |
| /** Single member getter returns value ref not 1d vector */ | |
| @property ref T opDispatch(string coords)() pure nothrow | |
| if(coords.length == 1 && coordValid!(coords[0])) | |
| { | |
| return members[coordIndex!(coords[0])]; | |
| } | |
| /** Const version of single member getter returns value const ref not 1d vector */ | |
| @property ref const(T) opDispatch(string coords)() pure const nothrow | |
| if(coords.length == 1 && coordValid!(coords[0])) | |
| { | |
| return members[coordIndex!(coords[0])]; | |
| } | |
| /** Template swizzling property access */ | |
| @property VectorTN!(T, coords.length) opDispatch(string coords)() pure const nothrow | |
| if(coords.length > 1 && coords.length <= 4 && coordsValidGetter!coords) | |
| { | |
| VectorTN!(T, coords.length) result; | |
| result[0] = members[coordIndex!(coords[0])]; | |
| result[1] = members[coordIndex!(coords[1])]; | |
| static if(coords.length > 2) | |
| result[2] = members[coordIndex!(coords[2])]; | |
| static if(coords.length > 3) | |
| result[3] = members[coordIndex!(coords[3])]; | |
| return result; | |
| } | |
| /** Subvector value setter, eg v4.xz = 1 will set x and z to 1, also implements named member setter (ie. vec.x = value, vec.y = value ...) */ | |
| @property void opDispatch(string coords, U)(const U value) pure nothrow | |
| if(coords.length > 1 && coords.length <= 4 && coordsValidSetter!coords) | |
| { | |
| members[coordIndex!(coords[0])] = cast(T)value; | |
| static if(coords.length > 1) | |
| members[coordIndex!(coords[1])] = cast(T)value; | |
| static if(coords.length > 2) | |
| members[coordIndex!(coords[2])] = cast(T)value; | |
| static if(coords.length > 3) | |
| members[coordIndex!(coords[3])] = cast(T)value; | |
| } | |
| /** Swizzling copy setter eg. v3.xz = v3.zx will swap x and z, */ | |
| @property void opDispatch(string coords, U)(const VectorTN!(U, coords.length) other) pure nothrow | |
| if(coords.length > 1 && coords.length <= 4 && coordsValidSetter!coords) | |
| { | |
| members[coordIndex!(coords[0])] = cast(T)other[0]; | |
| members[coordIndex!(coords[1])] = cast(T)other[1]; | |
| static if(coords.length > 2) | |
| members[coordIndex!(coords[2])] = cast(T)other[2]; | |
| static if(coords.length > 3) | |
| members[coordIndex!(coords[3])] = cast(T)other[3]; | |
| } | |
| } | |
| // | |
| // Alias VectorTN instances to corresponding GLSL types | |
| // | |
| alias VectorTN!(float, 2) vec2; | |
| alias VectorTN!(float, 3) vec3; | |
| alias VectorTN!(float, 4) vec4; | |
| alias VectorTN!(double, 2) dvec2; | |
| alias VectorTN!(double, 3) dvec3; | |
| alias VectorTN!(double, 4) dvec4; | |
| alias VectorTN!(int, 2) ivec2; | |
| alias VectorTN!(int, 3) ivec3; | |
| alias VectorTN!(int, 4) ivec4; | |
| alias VectorTN!(uint, 2) uivec2; | |
| alias VectorTN!(uint, 3) uivec3; | |
| alias VectorTN!(uint, 4) uivec4; | |
| alias VectorTN!(bool, 2) bvec2; | |
| alias VectorTN!(bool, 3) bvec3; | |
| alias VectorTN!(bool, 4) bvec4; | |
| // | |
| // GLSL functions that operate on vectors and scalars | |
| // | |
| // Internal implementation templates that generate functions that apply Fn to vectors per member and return a result vector | |
| private | |
| { | |
| mixin template FnX(alias Fn, alias TCons, bool Pure = true) | |
| { | |
| static if(Pure) | |
| { | |
| T fnX(T)(const T x) nothrow pure if(TCons!T) { return Fn(x); } | |
| VectorTN!(T, N) fnX(T, int N)(const auto ref VectorTN!(T, N) x) nothrow pure | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = Fn(x[i]); | |
| return result; | |
| } | |
| } | |
| else | |
| { | |
| T fnX(T)(const T x) nothrow if(TCons!T) { return Fn(x); } | |
| VectorTN!(T, N) fnX(T, int N)(const auto ref VectorTN!(T, N) x) nothrow | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = Fn(x[i]); | |
| return result; | |
| } | |
| } | |
| } | |
| mixin template FnXY(alias Fn, alias TCons, bool Pure = true) | |
| { | |
| static if(Pure) | |
| { | |
| T fnXY(T) (const T x, const T y) pure nothrow if(TCons!T) { return Fn(x, y); } | |
| VectorTN!(T, N) fnXY(T, int N)(const auto ref VectorTN!(T, N) x, const T y) pure nothrow | |
| if(TCons!T) | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = Fn(x[i], y); | |
| return result; | |
| } | |
| VectorTN!(T, N) fnXY(T, int N)(const auto ref VectorTN!(T, N) x, const auto ref VectorTN!(T, N) y) pure nothrow | |
| if(TCons!T) | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = Fn(x[i], y[i]); | |
| return result; | |
| } | |
| } | |
| else | |
| { | |
| T fnXY(T) (const T x, const T y) nothrow if(TCons!T) { return Fn(x, y); } | |
| VectorTN!(T, N) fnXY(T, int N)(const auto ref VectorTN!(T, N) x, const T y) nothrow | |
| if(TCons!T) | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = Fn(x[i], y); | |
| return result; | |
| } | |
| VectorTN!(T, N) fnXY(T, int N)(const auto ref VectorTN!(T, N) x, const auto ref VectorTN!(T, N) y) nothrow | |
| if(TCons!T) | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = Fn(x[i], y[i]); | |
| return result; | |
| } | |
| } | |
| } | |
| } | |
| // Wrappers for most std.math functions are generated using macros | |
| mixin FnX!(std.math.sin, IsFloat) Sin; alias Sin.fnX sin; | |
| mixin FnX!(std.math.cos, IsFloat) Cos; alias Cos.fnX cos; | |
| mixin FnX!(std.math.tan, IsFloat) Tan; alias Tan.fnX tan; | |
| mixin FnX!(std.math.asin, IsFloat) ASin; alias ASin.fnX asin; | |
| mixin FnX!(std.math.acos, IsFloat) ACos; alias ACos.fnX acos; | |
| mixin FnX!(std.math.atan, IsFloat) ATan; alias ATan.fnX atan; | |
| mixin FnX!(std.math.sinh, IsFloat) SinH; alias SinH.fnX sinh; | |
| mixin FnX!(std.math.cosh, IsFloat) CosH; alias CosH.fnX cosh; | |
| mixin FnX!(std.math.tanh, IsFloat) TanH; alias TanH.fnX tanh; | |
| mixin FnX!(std.math.asinh, IsFloat) ASinH; alias ASinH.fnX asinh; | |
| mixin FnX!(std.math.acosh, IsFloat) ACosH; alias ACosH.fnX acosh; | |
| mixin FnX!(std.math.atanh, IsFloat) ATanH; alias ATanH.fnX atanh; | |
| mixin FnXY!(std.math.pow, IsFloat) Pow; alias Pow.fnXY pow; | |
| mixin FnX!(std.math.exp, IsFloat) Exp; alias Exp.fnX exp; | |
| mixin FnX!(std.math.log, IsFloat) Log; alias Log.fnX log; | |
| mixin FnX!(std.math.exp2, IsFloat) Exp2; alias Exp2.fnX exp2; | |
| mixin FnX!(std.math.log2, IsFloat) Log2; alias Log2.fnX log2; | |
| mixin FnX!(std.math.sqrt, IsFloat) Sqrt; alias Sqrt.fnX sqrt; | |
| mixin FnX!(std.math.abs, IsScalar) Abs; alias Abs.fnX abs; | |
| mixin FnX!(std.math.sgn, IsScalar) Sign; alias Sign.fnX sign; | |
| mixin FnX!(std.math.floor, IsFloat, false) Floor; alias Floor.fnX floor; | |
| mixin FnX!(std.math.trunc, IsFloat, false) Trunc; alias Trunc.fnX trunc; | |
| mixin FnX!(std.math.round, IsFloat, false) Round; alias Round.fnX round; alias Round.fnX roundEven; | |
| mixin FnX!(std.math.ceil, IsFloat) Ceil; alias Ceil.fnX ceil; | |
| mixin FnXY!(std.algorithm.min, IsScalar) Min; alias Min.fnXY min; | |
| mixin FnXY!(std.algorithm.max, IsScalar) Max; alias Max.fnXY max; | |
| mixin FnXY!(std.algorithm.fmod, IsScalar, false) Mod; alias Mod.fnXY mod; | |
| /** Returns x - floor(x) */ | |
| T fract(T)(const T x) nothrow if(IsFloat!T) { return x - floor(x); } | |
| /** Returns x - floor(x) */ | |
| VectorTN!(T, N) fract(T, int N)(const auto ref VectorTN!(T, N) x) nothrow if(IsFloat!T) { return x - floor(x); } | |
| /** Template generalization for std.math.modf, returns integer part of x in ip and fraction in return value */ | |
| T modf(T)(const T x, out T ip) nothrow | |
| if(IsFloat!T) | |
| { | |
| real result, tmpip; | |
| result = std.math.modf(x, tmpip); | |
| ip = tmpip; | |
| return result; | |
| } | |
| /** Vector version of modf */ | |
| VectorTN!(T, N) modf(T, int N)(const auto ref VectorTN!(T, N) x, out VectorTN!(T, N) ip) nothrow | |
| if(IsFloat!T) | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = modf(x[i], ip[i]); | |
| return result; | |
| } | |
| /** Returns min(max(x, minVal), maxVal) */ | |
| VectorTN!(T, N) clamp(T, int N)(const auto ref VectorTN!(T, N) x, const auto ref VectorTN!(T, N) minVal, const auto ref VectorTN!(T, N) maxVal) pure nothrow | |
| if(IsScalar!T) | |
| { | |
| return min(max(x, minVal), maxVal); | |
| } | |
| /** Returns min(max(x, minVal), maxVal) */ | |
| VectorTN!(T, N) clamp(T, int N)(const auto ref VectorTN!(T, N) x, const T minVal, const T maxVal) pure nothrow | |
| if(IsScalar!T) | |
| { | |
| return min(max(x, minVal), maxVal); | |
| } | |
| /** Return a linear blend of x and y based on a, x * (1 - a) + y * a */ | |
| VectorTN!(T, N) mix(T, int N)(const auto ref VectorTN!(T, N) x, const auto ref VectorTN!(T, N) y, const auto ref VectorTN!(T, N) a) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| return x * (VectorTN!(T, N)(1) - a) - y * a; | |
| } | |
| /** Return a linear blend of x and y based on a, x * (1 - a) + y * a */ | |
| VectorTN!(T, N) mix(T, int N)(const auto ref VectorTN!(T, N) x, const auto ref VectorTN!(T, N) y, const T a) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| return x * (1 - a) - y * a; | |
| } | |
| /** Selects components from x and y based on values in a, if a[i] is false then result[i] = x[i], otherwise it's y[i] */ | |
| VectorTN!(T, N) mix(T, int N)(const auto ref VectorTN!(T, N) x, const auto ref VectorTN!(T, N) y, const auto ref VectorTN!(bool, N) a) pure nothrow | |
| if(IsScalar!T) | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = a[i] ? y[i] : x[i]; | |
| return result; | |
| } | |
| /** Returns 0 if x < edge, 1 otherwise */ | |
| VectorTN!(T, N) step(T, int N)(const auto ref VectorTN!(T, N) edge, const auto ref VectorTN!(T, N) x) pure nothrow | |
| if(IsScalar!T) | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = x[i] < edge[i] ? 0 : 1; | |
| return result; | |
| } | |
| /** Returns 0 if x < edge, 1 otherwise */ | |
| VectorTN!(T, N) step(T, int N)(const T edge, const auto ref VectorTN!(T, N) x) pure nothrow | |
| if(IsScalar!T) | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = x[i] < edge ? 0 : 1; | |
| return result; | |
| } | |
| /** Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth Hermite interpolation between 0 and 1 when edge0 < x < edge1. */ | |
| VectorTN!(T, N) smoothstep(T, int N)(const auto ref VectorTN!(T, N) edge0, const auto ref VectorTN!(T, N) edge1, const auto ref VectorTN!(T, N) x) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| auto t = clamp((x - edge0) / (edge1 - edge0), 0, 1); | |
| return t * t * (VectorTN!(T, N)(3) - t * 2); | |
| } | |
| /** Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth Hermite interpolation between 0 and 1 when edge0 < x < edge1. */ | |
| VectorTN!(T, N) smoothstep(T, int N)(const T edge0, const T edge1, const auto ref VectorTN!(T, N) x) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| auto t = clamp((x - edge0) / (edge1 - edge0), 0, 1); | |
| return t * t * (VectorTN!(T, N)(3) - t * 2); | |
| } | |
| /** Returns true if x is nan, false otherwise */ | |
| bool isnan(T)(const T x) pure nothrow if(IsFloat!T) { return std.math.isNaN(x); } | |
| /** Return member is true if input member is nan, false otherwise. */ | |
| VectorTN!(bool, N) isnan(T, int N)(const auto ref VectorTN!(T, N) x) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| VectorTN!(bool, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = isnan(x[0]); | |
| return result; | |
| } | |
| /** Return true if x is infinity (positive or negative), false otherwise */ | |
| bool isinfinity(T)(const T x) pure nothrow if(IsFloat!T) { return std.math.isInfinity(x); } | |
| /** Return member is true if input member is infinity (positive or negative), false otherwise. */ | |
| VectorTN!(bool, N) isnan(T, int N)(const auto ref VectorTN!(T, N) x) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| VectorTN!(bool, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = isinfinity(x[0]); | |
| return result; | |
| } | |
| /** Internal reinterpret cast template for vectors */ | |
| private | |
| { | |
| mixin template reinterpretCast(T, U) | |
| if(IsScalar!T && IsScalar!U) | |
| { | |
| U reinterpretCast()(const T x) pure nothrow { return *cast(U*)&x; } | |
| VectorTN!(U, N) reinterpretCast(int N)(const auto ref VectorTN!(T, N) x) pure nothrow | |
| { | |
| VectorTN!(U, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = reinterpretCast(x[i]); | |
| return result; | |
| } | |
| } | |
| } | |
| /** Reinterpret cast instances defined by GLSL */ | |
| mixin reinterpretCast!(float, int) FloatBitsToInt; alias FloatBitsToInt.reinterpretCast floatBitsToInt; | |
| mixin reinterpretCast!(float, uint) FloatBitsToUInt; alias FloatBitsToUInt.reinterpretCast floatBitsToUInt; | |
| mixin reinterpretCast!(int, float) IntBitsToFloat; alias IntBitsToFloat.reinterpretCast intBitsToFloat; | |
| mixin reinterpretCast!(uint, float) UIntBitsToFloat; alias UIntBitsToFloat.reinterpretCast uintBitsToFloat; | |
| /** Multiply add, multiply x and y and add z returning result */ | |
| T fma(T)(const T a, const T b, const T c) pure nothrow if(IsFloat!T) { return a * b + c; } | |
| /** Multiply add, multiply x and y and add z returning result */ | |
| T fma(T, int N)(const auto ref VectorTN!(T, N) a, const auto ref VectorTN!(T, N) b, const auto ref VectorTN!(T, N) c) pure nothrow if (IsFloat!T) { return a * b + c; } | |
| /** Split x in to a significand in range [0.5, 1) and a int exponent of two such that : x = significand * 2 ^ exp */ | |
| T frexp(T)(const T x, out int exp) pure nothrow if(IsFloat!T) { return std.math.frexp(x, exp); } | |
| /** Vector component version of frexp */ | |
| VectorTN!(T, N) frexp(T, int N)(const auto ref VectorTN!(T, N) x, out VectorTN!(int, N) exp) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = frexp(x[i], exp[i]); | |
| return result; | |
| } | |
| /** Joins the results of frexp return original valie, ie. returns x * 2^exp */ | |
| T ldexp(T)(const T x, const int exp) pure nothrow if(IsFloat!T) { return std.math.ldexp(x, exp); } | |
| /** Vector component version of ldexp */ | |
| VectorTN!(T, N) ldexp(T, int N)(const auto ref VectorTN!(T, N) x, const auto ref VectorTN!(int, N) exp) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| VectorTN!(T, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = ldexp(x[i], exp[i]); | |
| return result; | |
| } | |
| /** Convert degrees to radians */ | |
| T radians(T)(const T deg) pure nothrow if(IsFloat!T) { return deg * (std.math.PI / 180); } | |
| /** Convert degrees to radians */ | |
| VectorTN!(T, N) radians(T, int N)(const auto ref VectorTN!(T, N) deg) pure nothrow if(IsFloat!T) { return deg * (std.math.PI / 180); } | |
| /** Convert radians to degrees */ | |
| T degrees(T)(const T rad) pure nothrow if(IsFloat!T) { return rad * (180 / std.math.PI); } | |
| /** Convert radians to degrees */ | |
| VectorTN!(T, N) degrees(T, int N)(const auto ref VectorTN!(T, N) rad) pure nothrow if(IsFloat!T) { return rad * (180 / std.math.PI); } | |
| /** Dot product of two vectors */ | |
| T dot(T, int N) (const auto ref VectorTN!(T, N) x, const auto ref VectorTN!(T, N) y) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| T result = 0; | |
| foreach(i; 0 .. N) | |
| result += x[i] * y[i]; | |
| return result; | |
| } | |
| /** Vector length */ | |
| T length(T, int N) (const auto ref VectorTN!(T, N) x) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| return sqrt(dot(vec, vec)); | |
| } | |
| /** Distance between p0 and p1, equivalent to length(p0 - p1) */ | |
| T distance(T, int N) (const auto ref VectorTN!(T, N) p0, const auto ref VectorTN!(T, N) p1) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| return length(p0 - p1); | |
| } | |
| /** Return a vector perpendicular to x and y */ | |
| VectorTN!(T, 3) cross(T) (const auto ref VectorTN!(T, 3) x, const auto ref VectorTN!(T, 3) y) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| return VectorTN!(T, 3)( | |
| x.y * y.z - x.z * y.y, | |
| x.z * y.x - x.x * y.z, | |
| x.x * y.y - x.y * y.x); | |
| } | |
| /** Return a vector in same direction as x but with length of 1 */ | |
| VectorTN!(T, N) normalize(T, int N) (const auto ref VectorTN!(T, N) x) pure nothrow | |
| if (IsFloat!T) | |
| { | |
| return x * (1 / length(x)); | |
| } | |
| /** If dot(nref, ind) < 0 return norm, otherwise return –norm. */ | |
| VectorTN!(T, N) faceforward(T, int N)(const auto ref VectorTN!(T, N) norm, const auto ref VectorTN!(T, N) incd, const auto ref VectorTN!(T, N) nref) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| if(dot(nref, incd) < 0) | |
| return norm; | |
| else | |
| return -norm; | |
| } | |
| /** Reflection of incd vector arround normal */ | |
| VectorTN!(T, N) reflect(T, int N)(const auto ref VectorTN!(T, N) incd, const auto ref VectorTN!(T, N) norm) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| return incd - norm * dot(norm, incd) * 2; | |
| } | |
| /** Refract */ | |
| VectorTN!(T, N) refract(T, int N)(const auto ref VectorTN!(T, N) incd, const auto ref VectorTN!(T, N) norm, const T eta) pure nothrow | |
| if(IsFloat!T) | |
| { | |
| T niprod = dot(norm, incd); | |
| T k = 1 - eta * eta * (1 - niprod * niprod); | |
| if(k < 0) | |
| return VectorTN!(T, N)(0); | |
| else | |
| return incd * eta - norm * (eta * niprod + sqrt(k)); | |
| } | |
| /** Implement component based boolean functions using templates */ | |
| private | |
| { | |
| template boolFnXY(string op, alias TCons) | |
| { | |
| bool boolFnXY(T)(const T x, const T y) pure nothrow | |
| if(TCons!T) | |
| { | |
| return mixin("x " ~ op ~ " y"); | |
| } | |
| VectorTN!(bool, N) boolFnXY(T, int N)(const auto ref VectorTN!(T, N) x, const auto ref VectorTN!(T, N) y) pure nothrow | |
| if(TCons!T) | |
| { | |
| VectorTN!(bool, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = boolFnXY(x[i], y[i]); | |
| return result; | |
| } | |
| VectorTN!(bool, N) boolFnXY(T, int N)(const auto ref VectorTN!(T, N) x, const T y) pure nothrow | |
| if(TCons!T) | |
| { | |
| VectorTN!(bool, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = boolFnXY(x[i], y); | |
| return result; | |
| } | |
| } | |
| } | |
| mixin boolFnXY!("<", IsScalar) LessThan; alias LessThan.boolFnXY lessThan; | |
| mixin boolFnXY!("<=", IsScalar) LessThanEqual; alias LessThanEqual.boolFnXY lessThanEqual; | |
| mixin boolFnXY!(">", IsScalar) GreaterThan; alias GreaterThan.boolFnXY greaterThan; | |
| mixin boolFnXY!(">=", IsScalar) GreaterThanEqual; alias GreaterThanEqual.boolFnXY greaterThanEqual; | |
| mixin boolFnXY!("==", IsScalar) Equal; alias Equal.boolFnXY equal; | |
| mixin boolFnXY!("!=", IsScalar) NotEqual; alias NotEqual.boolFnXY notEqual; | |
| /** Returns logical complement of x */ | |
| bool not()(bool x) pure nothrow { return !x; } | |
| /** Returns the component-wise logical complement of x. */ | |
| VectorTN!(bool, N) not(int N)(const auto ref VectorTN!(bool, N) x) pure nothrow | |
| { | |
| VectorTN!(bool, N) result; | |
| foreach(i; 0 .. N) | |
| result[i] = !x[i]; | |
| return result; | |
| } | |
| /** Return true if any of vector components are true */ | |
| bool any(int N)(const auto ref VectorTN!(bool, N) x) pure nothrow | |
| { | |
| bool result = false; | |
| foreach(i; 0 .. N) | |
| result |= x[i]; | |
| return result; | |
| } | |
| /** Returns true only if all components of x are true. */ | |
| bool all(int N)(const auto ref VectorTN!(bool, N) x) pure nothrow | |
| { | |
| bool result = true; | |
| foreach(i; 0 .. N) | |
| result &= x[i]; | |
| return result; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment