Skip to content

Instantly share code, notes, and snippets.

@run-dlang
Created September 20, 2020 17:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save run-dlang/4b4d4de81c20a082d72eb61307db2946 to your computer and use it in GitHub Desktop.
Save run-dlang/4b4d4de81c20a082d72eb61307db2946 to your computer and use it in GitHub Desktop.
Code shared from run.dlang.io.
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