Forráskód Böngészése

Add linear algebra functions

buckle2000 5 éve
szülő
commit
33878f596b
3 módosított fájl, 157 hozzáadás és 4 törlés
  1. 1 0
      .gitignore
  2. 27 4
      source/raylib.d
  3. 129 0
      source/raymath.d

+ 1 - 0
.gitignore

@@ -9,6 +9,7 @@ docs/
 *.a
 *.lib
 draylib-test-*
+raylib-d-test-*
 *.exe
 *.o
 *.obj

+ 27 - 4
source/raylib.d

@@ -2,6 +2,7 @@ module raylib;
 
 public {
     import rlgl;
+    import raymath;
 }
 /**********************************************************************************************
 *
@@ -153,6 +154,7 @@ struct Vector2
 {
     float x;
     float y;
+    mixin Linear;
 }
 
 // Vector3 type
@@ -161,8 +163,27 @@ struct Vector3
     float x;
     float y;
     float z;
+    mixin Linear;
 }
 
+// Bivector3 type
+struct Bivector3
+{
+    float yz;
+    float zx;    
+    float xy;
+    mixin Linear;
+}
+
+// Rotor type
+struct Rotor3
+{
+    float a;
+    Bivector3 b;
+    alias b this;
+}
+alias Quaternion = Rotor3;
+
 // Vector4 type
 struct Vector4
 {
@@ -170,13 +191,11 @@ struct Vector4
     float y;
     float z;
     float w;
+    mixin Linear;
 }
 
-// Quaternion type, same as Vector4
-alias Quaternion = Vector4;
-
 // Matrix type (OpenGL style 4x4 - right handed, column major)
-struct Matrix
+struct Matrix4
 {
     float m0;
     float m4;
@@ -195,6 +214,7 @@ struct Matrix
     float m11;
     float m15;
 }
+alias Matrix = Matrix4;
 
 // Color type, RGBA (32bit)
 struct Color
@@ -212,8 +232,11 @@ struct Rectangle
     float y;
     float width;
     float height;
+    alias w = width;
+    alias h = height;
 }
 
+
 // Image type, bpp always RGBA (32bit)
 // NOTE: Data stored in CPU memory (RAM)
 struct Image

+ 129 - 0
source/raymath.d

@@ -0,0 +1,129 @@
+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) if (__traits(compiles, v * v))
+{
+    enum fragment = [FieldNameTuple!T].map!(field => "v." ~ field ~ "*" ~ "v." ~ field).join("+");
+    return mixin("sqrt(" ~ fragment ~ ")");
+}
+
+T normalize(T)(T v)
+{
+    return v / this.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));
+}
+
+Vector3 cross(Vector3 lhs, Vector3 rhs)
+{
+    return Vector3(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z,
+            lhs.x * rhs.y - lhs.y * rhs.x);
+}
+
+// dfmt off
+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
+
+// TODO implement rotor3
+// Vector3 rotate(Vector3 v, Rotor3 r) {
+//     return ;
+// }