123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- import raylib;
- import std.math;
- mixin template Linear()
- {
- import std.algorithm : canFind, map;
- import std.range : join;
- import std.traits : FieldNameTuple;
- private static alias T = typeof(this);
- static T zero()
- {
- enum fragment = [FieldNameTuple!T].map!(field => "0.").join(",");
- return mixin("T(" ~ fragment ~ ")");
- }
- static T one()
- {
- enum fragment = [FieldNameTuple!T].map!(field => "1.").join(",");
- return mixin("T(" ~ fragment ~ ")");
- }
- T opUnary(string op)() if (["+", "-"].canFind(op))
- {
- enum fragment = [FieldNameTuple!T].map!(field => op ~ field).join(",");
- return mixin("T(" ~ fragment ~ ")");
- }
- T opBinary(string op)(T rhs) if (["+", "-", "*", "/"].canFind(op))
- {
- enum fragment = [FieldNameTuple!T].map!(field => field ~ op ~ "rhs." ~ field).join(",");
- return mixin("T(" ~ fragment ~ ")");
- }
- T opBinary(string op)(float rhs) if (["+", "-", "*", "/"].canFind(op))
- {
- enum fragment = [FieldNameTuple!T].map!(field => field ~ op ~ "rhs").join(",");
- return mixin("T(" ~ fragment ~ ")");
- }
- T opBinaryRight(string op)(float lhs) if (["+", "-", "*", "/"].canFind(op))
- {
- enum fragment = [FieldNameTuple!T].map!(field => "lhs" ~ op ~ field).join(",");
- return mixin("T(" ~ fragment ~ ")");
- }
- }
- import std.traits : FieldNameTuple;
- import std.algorithm : map;
- import std.range : join;
- float length(T)(T v)
- {
- enum fragment = [FieldNameTuple!T].map!(field => "v." ~ field ~ "*" ~ "v." ~ field).join("+");
- return mixin("sqrt(" ~ fragment ~ ")");
- }
- T normalize(T)(T v)
- {
- return v / v.length;
- }
- float distance(T)(T lhs, T rhs)
- {
- return (lhs - rhs).length;
- }
- T dot(T)(T lhs, T rhs)
- {
- return lhs * rhs;
- }
- unittest
- {
- assert(-Vector2(1, 2) == Vector2(-1, -2));
- assert(Vector3(1, 2, 9) + Vector3(3, 4, 9) == Vector3(4, 6, 18));
- assert(4.0f - Vector2.zero == Vector2(4, 4));
- assert(Vector2.one - 3.0f == Vector2(-2, -2));
- assert(Vector2(3, 4).length == 5.0);
- }
- /// Mix `amount` of `lhs` with `1-amount` of `rhs`
- /// `amount` should be between 0 and 1, but can be anything
- /// lerp(lhs, rhs, 0) == lhs
- /// lerp(lhs, rhs, 1) == rhs
- T lerp(T)(T lhs, T rhs, float amount)
- {
- return lhs + amount * (rhs - lhs);
- }
- float angle(Vector2 v)
- {
- return atan2(v.y, v.x);
- }
- /// Rotate on imaginary plane
- Vector2 rotate(Vector2 lhs, Vector2 rhs)
- {
- return Vector2(lhs.x * rhs.x - lhs.y * rhs.y, lhs.x * rhs.y + lhs.y * rhs.x);
- }
- Vector2 rotate(Vector2 v, float angle)
- {
- return Vector2(v.x * cos(angle) - v.y * sin(angle), v.x * sin(angle) + v.y * cos(angle));
- }
- Vector2 slide(Vector2 v, Vector2 along)
- {
- return along.normalize * dot(v, along);
- }
- Bivector2 wedge(Vector2 lhs, Vector2 rhs)
- {
- return Bivector2(lhs.x * rhs.y - lhs.y * rhs.x);
- }
- // dfmt off
- Bivector3 wedge(Vector3 lhs, Vector3 rhs)
- {
- return Bivector3(
- lhs.y * rhs.z - lhs.z * rhs.y,
- lhs.z * rhs.x - lhs.x * rhs.z,
- lhs.x * rhs.y - lhs.y * rhs.x,
- );
- }
- Vector3 transform(Vector3 v, Matrix4 mat)
- {
- with (v) with (mat)
- return Vector3(
- m0 * x + m4 * y + m8 * z + m12,
- m1 * x + m5 * y + m9 * z + m13,
- m2 * x + m6 * y + m10 * z + m14
- );
- }
- // dfmt on
- Vector3 cross(Vector3 lhs, Vector3 rhs)
- {
- auto v = wedge(lhs, rhs);
- return Vector3(v.yz, v.zx, v.xy);
- }
- // TODO implement rotor3
- // Vector3 rotate(Vector3 v, Rotor3 r) {
- // return ;
- // }
- unittest
- {
- import std.format;
- const v = Vector2.one;
- assert(v.length == sqrt(2.0f), "%s %s".format(v,v.length));
- }
|