Created
September 20, 2020 17:53
-
-
Save run-dlang/4b4d4de81c20a082d72eb61307db2946 to your computer and use it in GitHub Desktop.
Code shared from run.dlang.io.
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
import std.stdio, std.range, std.algorithm, std.traits, std.meta, std.conv, std.string, std.uni, std.meta, std.functional, std.exception; | |
void main(){ | |
immutable a = vec3(1,2,3); | |
//a.x++; //Error: cannot modify const expression a.x() | |
writeln(a.toString); //vec3(1, 2, 3) | |
auto b = a.yz10; | |
writeln(b); //vec4(2, 3, 1, 0) | |
b.w += 99; //No error, accessed as reference | |
writeln(b); //vec4(2, 3, 1, 99) | |
b.yz = [5, 6]; //it eats an array too | |
writeln(b); | |
b.yz = 55; //side effect: b.y and b.y both = 55 | |
writeln(b); | |
} | |
bool inRange(T)(const T val, const T mi, const T ma) pure{ return val>=mi && val<=ma; } | |
auto lc(dchar s) pure{ return s.toLower; } | |
private enum swizzleRegs = ["xyzw", "rgba", "stpq"]; | |
private bool validLvalueSwizzle(string def){ return swizzleRegs.map!(r => canFind(r, def)).any; } | |
private enum ComponentTypePrefix(CT) = is(CT==float) ? "" : is(CT==double) ? "d" : is(CT==bool) ? "b" : is(CT==int) ? "i" : is(CT==uint) ? "u" : CT.stringof; | |
private bool validRvalueSwizzle(string def){ | |
if(def.startsWith('_')) def = def[1..$]; //_ is allowed at the start because of the constants 0 and 1 | |
if(!def.length.inRange(1, 4) || validLvalueSwizzle(def)) return false; | |
return swizzleRegs.map!(r => def.map!(ch => "01".canFind(ch) || r.canFind(ch.lc)).all).any; | |
} | |
struct Vec(CT, int N) | |
if(N.inRange(2, 4)){ | |
alias VectorType = typeof(this); | |
alias ComponentType = CT; | |
enum VectorTypeName = ComponentTypePrefix!CT ~ "vec" ~ N.text; | |
CT[N] array = [0].replicate(N).array; //default is 0,0,0, not NaN. Just like in GLSL. | |
alias array this; | |
enum length = N; | |
string toString() const { return VectorTypeName ~ "(" ~ array[].map!text.join(", ") ~ ")"; } | |
private void construct(int i, T, Tail...)(in T head, in Tail tail){ // this is based on the gl3n package | |
void receiveValue(int i, T)(in T a){ array[i] = a.to!CT; construct!(i + 1 )(tail); } | |
void receiveArray(int i, T)(in T a){ array[i..i+a.length] = a[].to!(CT[]); static if(isStaticArray!T) construct!(i + a.length)(tail); } | |
static if(i >= length) { | |
static assert(false, "Too many arguments passed to constructor"); | |
}else static if(isDynamicArray!T) { | |
static assert((Tail.length == 0), "Dynamic array can only be the last argument."); | |
enforce(i+head.length <= array.length, "Out of range"); | |
receiveArray!i(head); | |
}else static if(isStaticArray!T) { | |
receiveArray!i(head); | |
}else static if(__traits(compiles, receiveArray!i(head.array))) { //another vecN | |
receiveArray!i(head.array); | |
}else static if(__traits(compiles, receiveValue!i(head))){ | |
receiveValue!i(head); | |
}else{ | |
static assert(false, "Vector constructor unable to process argument of type: " ~ T.stringof); | |
} | |
} | |
private void construct(int i)() { } // less than enough args are allowed, just like GLSL. | |
this(A...)(in A args){ | |
construct!0(args); | |
} | |
enum Null = typeof(this).init; | |
bool isNull() const { return this == Null; } | |
static auto basis(int n){ VectorType v; v[n] = 1.to!ComponentType; return v; } | |
// swizzling /////////////////////// | |
static foreach(regs; swizzleRegs) | |
static foreach(len; 1..N+1) | |
static foreach(i; 0..N-len+1) | |
static if(len==1){ | |
mixin(format!q{auto %s() const { return array[%s]; }}(regs[i], i)); | |
mixin(format!q{ref %s() { return array[%s]; }}(regs[i], i)); | |
}else{ | |
mixin(format!q{auto %s() const { return Vec!(CT, %s) (array[%s..%s]) ; }}(regs[i..i+len], len, i, i+len)); | |
mixin(format!q{ref %s() { return *(cast(Vec!(CT, %s)*) (array[%s..%s])); }}(regs[i..i+len], len, i, i+len)); | |
} | |
auto opDispatch(string def)() const | |
if(validRvalueSwizzle(def)) | |
{ | |
static if(def.startsWith('_')){ | |
return opDispatch!(def[1..$]); | |
}else{ | |
Vec!(CT, mixin(def.length)) res; | |
static foreach(i, ch; def) | |
res[i] = mixin(ch==ch.lc ? "" : "-", ch.lc); | |
return res; | |
} | |
} | |
} | |
private alias vectorElementTypes = AliasSeq!(float, double, bool, int, uint); | |
private enum vectorElementCounts = [2, 3, 4]; | |
static foreach(T; vectorElementTypes) | |
static foreach(N; vectorElementCounts) | |
mixin(format!q{alias %s = %s;}(Vec!(T, N).VectorTypeName, Vec!(T, N).stringof)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment