168 lines
4.5 KiB
Text
168 lines
4.5 KiB
Text
/*
|
|
Vec is a generic set of N named values of type T (aka. a mathematical vector)
|
|
|
|
The values can be accessed via array index or their common component names:
|
|
|
|
- u, v
|
|
- x, y, z, w
|
|
- r, g, b, a
|
|
- c0, c1, c2, c3, ... cN
|
|
|
|
For most use cases, opt for the named variants of this type:
|
|
|
|
Vec2 : Vec(2, float)
|
|
Vec3 : Vec(3, float)
|
|
Vec4 : Vec(4, float)
|
|
Quat : Vec(4, float)
|
|
|
|
Sadly, Vec does *NOT* solve the problem of interfacing with
|
|
external vector types (including Jai's 'Math' module).
|
|
|
|
To fix this, create two helper macros:
|
|
|
|
to_jai :: (v: Vec4) -> jmath.Vector4 #expand {
|
|
return v.(jmath.Vector4,force);
|
|
}
|
|
to_jai :: (v: *Vec4) -> *jmath.Vector4 #expand {
|
|
return v.(*jmath.Vector4);
|
|
}
|
|
*/
|
|
Vec :: struct(N: int, T: Type)
|
|
#modify {
|
|
|
|
info := T.(*Type_Info);
|
|
return info.type == .INTEGER || info.type == .FLOAT, "Vec T must be a numeric type (int or float)";
|
|
} {
|
|
#assert (N > 0) "Vec N cannot be <= 0";
|
|
|
|
// Vecs are backed by an array internally. The #insert block below
|
|
// generates #place'd unions of named fields or cN fields when N is > 4.
|
|
#as components: [N]T;
|
|
|
|
#insert -> string {
|
|
b: basic.String_Builder;
|
|
basic.append(*b, "#place components;\n");
|
|
|
|
fields :: []string.[
|
|
string.[ "x", "r", "u" ],
|
|
string.[ "y", "g", "v" ],
|
|
string.[ "z", "b", "" ],
|
|
string.[ "w", "a", "" ],
|
|
];
|
|
|
|
for i: 0..N - 1 {
|
|
if i < fields.count {
|
|
basic.append(*b, "union {\n");
|
|
for field: fields[i] if field.count != 0 {
|
|
basic.print_to_builder(*b, "\t%: T = ---;\n", field);
|
|
}
|
|
basic.print_to_builder(*b, "\tc%: T = ---;\n", i);
|
|
basic.append(*b, "};\n");
|
|
}
|
|
else {
|
|
basic.print_to_builder(*b, "c%: T = ---;\n", i);
|
|
}
|
|
}
|
|
|
|
return basic.builder_to_string(*b);
|
|
};
|
|
}
|
|
|
|
operator [] :: (v: Vec, $$idx: int) -> v.T #no_abc {
|
|
bounds_check_index(idx, v.N);
|
|
return v.components[idx];
|
|
}
|
|
|
|
operator *[] :: (v: *Vec, $$idx: int) -> *v.T #no_abc {
|
|
bounds_check_index(idx, v.N);
|
|
return *v.components[idx];
|
|
}
|
|
|
|
operator []= :: (v: *Vec, $$idx: int, value: v.T) #no_abc {
|
|
bounds_check_index(idx, v.N);
|
|
v.components[idx] = value;
|
|
}
|
|
|
|
for_expansion :: (v: *Vec, body: Code, flags: For_Flags) #expand {
|
|
for i: 0..v.N - 1 {
|
|
`it_index := i;
|
|
#if flags & .POINTER {
|
|
`it := *v.components[i];
|
|
} else {
|
|
`it := v.components[i];
|
|
}
|
|
|
|
#insert,scope(body) body;
|
|
}
|
|
}
|
|
|
|
operator + :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
|
res: Vec(l.N, l.T) = ---;
|
|
for l res[it_index] = it + r[it_index];
|
|
return res;
|
|
}
|
|
|
|
operator - :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
|
res: Vec(l.N, l.T) = ---;
|
|
for l res[it_index] = it - r[it_index];
|
|
return res;
|
|
}
|
|
|
|
operator * :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
|
res: Vec(l.N, l.T) = ---;
|
|
for l res[it_index] = it * r[it_index];
|
|
return res;
|
|
}
|
|
|
|
operator / :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
|
res: Vec(l.N, l.T) = ---;
|
|
for l res[it_index] = it / r[it_index];
|
|
return res;
|
|
}
|
|
|
|
// Concrete vector types (the usual cases)
|
|
|
|
Vec2 :: Vec(2, float);
|
|
Vec3 :: Vec(3, float);
|
|
Vec4 :: Vec(4, float);
|
|
Quat :: Vec4;
|
|
|
|
v2f :: (x: $T = 0, y: T = 0) -> Vec2
|
|
#modify { return T.(*Type_Info).type == .FLOAT, "use v2i for integer arguments"; }
|
|
#expand {
|
|
return .{ x = x, y = y };
|
|
}
|
|
|
|
v2i :: (x: $T = 0, y: T = 0) -> Vec(2, T)
|
|
#modify { return T.(*Type_Info).type == .INTEGER, "use v2f for float arguments"; }
|
|
#expand {
|
|
return .{ x = x, y = y };
|
|
}
|
|
|
|
v3f :: (x: $T = 0, y: T = 0, z: T = 0) -> Vec3
|
|
#modify { return T.(*Type_Info).type == .FLOAT, "use v3i for integer arguments"; }
|
|
#expand {
|
|
return .{ x = x, y = y, z = z };
|
|
}
|
|
|
|
v3i :: (x: $T = 0, y: T = 0, z: T = 0) -> Vec(3, T)
|
|
#modify { return T.(*Type_Info).type == .INTEGER, "use v3f for float arguments"; }
|
|
#expand {
|
|
return .{ x = x, y = y, z = z };
|
|
}
|
|
|
|
v4f :: (x: $T = 0, y: T = 0, z: T = 0, w: T = 0) -> Vec4
|
|
#modify { return T.(*Type_Info).type == .FLOAT, "use v4i for integer arguments"; }
|
|
#expand {
|
|
return .{ x = x, y = y, z = z, w = w };
|
|
}
|
|
|
|
v4i :: (x: $T = 0, y: T = 0, z: T = 0, w: T = 0) -> Vec(4, T)
|
|
#modify { return T.(*Type_Info).type == .INTEGER, "use v4f for float arguments"; }
|
|
#expand {
|
|
return .{ x = x, y = y, z = z, w = w };
|
|
}
|
|
|
|
quat :: (x: float = 0, y: float = 0, z: float = 0, w: float = 0) -> Quat #expand {
|
|
return .{ x = x, y = y, z = z, w = w };
|
|
}
|