using System; namespace Oni { internal struct Vector3 : IEquatable { public float X; public float Y; public float Z; public Vector3(float all) { X = all; Y = all; Z = all; } public Vector3(float x, float y, float z) { X = x; Y = y; Z = z; } public Vector3(float[] values, int index = 0) { int i = index * 3; X = values[i + 0]; Y = values[i + 1]; Z = values[i + 2]; } public void CopyTo(float[] values, int index = 0) { values[index + 0] = X; values[index + 1] = Y; values[index + 2] = Z; } public Vector2 XZ => new Vector2(X, Z); public static Vector3 operator +(Vector3 v1, Vector3 v2) { v1.X += v2.X; v1.Y += v2.Y; v1.Z += v2.Z; return v1; } public static Vector3 operator -(Vector3 v1, Vector3 v2) { v1.X -= v2.X; v1.Y -= v2.Y; v1.Z -= v2.Z; return v1; } public static Vector3 operator -(Vector3 v) { v.X = -v.X; v.Y = -v.Y; v.Z = -v.Z; return v; } public static Vector3 operator *(Vector3 v, float s) { v.X *= s; v.Y *= s; v.Z *= s; return v; } public static Vector3 operator *(float s, Vector3 v) { v.X *= s; v.Y *= s; v.Z *= s; return v; } public static Vector3 operator *(Vector3 v1, Vector3 v2) => new Vector3 { X = v1.X * v2.X, Y = v1.Y * v2.Y, Z = v1.Z * v2.Z, }; public static Vector3 operator /(Vector3 v, float s) => v * (1.0f / s); public static Vector3 operator /(Vector3 v1, Vector3 v2) => new Vector3 { X = v1.X /= v2.X, Y = v1.Y /= v2.Y, Z = v1.Z /= v2.Z }; public static void Add(ref Vector3 v1, ref Vector3 v2, out Vector3 r) { r.X = v1.X + v2.X; r.Y = v1.Y + v2.Y; r.Z = v1.Z + v2.Z; } public static void Substract(ref Vector3 v1, ref Vector3 v2, out Vector3 r) { r.X = v1.X - v2.X; r.Y = v1.Y - v2.Y; r.Z = v1.Z - v2.Z; } public static void Multiply(ref Vector3 v, float f, out Vector3 r) { r.X = v.X * f; r.Y = v.Y * f; r.Z = v.Z * f; } public void Scale(float scale) { X *= scale; Y *= scale; Z *= scale; } public static Vector3 Clamp(Vector3 v, Vector3 min, Vector3 max) { Vector3 r; float x = v.X; x = (x > max.X) ? max.X : x; x = (x < min.X) ? min.X : x; float y = v.Y; y = (y > max.Y) ? max.Y : y; y = (y < min.Y) ? min.Y : y; float z = v.Z; z = (z > max.Z) ? max.Z : z; z = (z < min.Z) ? min.Z : z; r.X = x; r.Y = y; r.Z = z; return r; } public static Vector3 Cross(Vector3 v1, Vector3 v2) { return new Vector3( v1.Y * v2.Z - v1.Z * v2.Y, v1.Z * v2.X - v1.X * v2.Z, v1.X * v2.Y - v1.Y * v2.X); } public static void Cross(ref Vector3 v1, ref Vector3 v2, out Vector3 r) { r = new Vector3( v1.Y * v2.Z - v1.Z * v2.Y, v1.Z * v2.X - v1.X * v2.Z, v1.X * v2.Y - v1.Y * v2.X); } public static float Dot(Vector3 v1, Vector3 v2) { return v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z; } public static float Dot(ref Vector3 v1, ref Vector3 v2) => v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z; public float Dot(ref Vector3 v) => X * v.X + Y * v.Y + Z * v.Z; public static Vector3 Transform(Vector3 v, Quaternion q) { Quaternion vq = new Quaternion(v, 0.0f); q = q * vq * Quaternion.Conjugate(q); return new Vector3(q.X, q.Y, q.Z); } public static Vector3 Transform(Vector3 v, ref Matrix m) { return new Vector3( v.X * m.M11 + v.Y * m.M21 + v.Z * m.M31 + m.M41, v.X * m.M12 + v.Y * m.M22 + v.Z * m.M32 + m.M42, v.X * m.M13 + v.Y * m.M23 + v.Z * m.M33 + m.M43); } public static void Transform(ref Vector3 v, ref Matrix m, out Vector3 r) { r.X = v.X * m.M11 + v.Y * m.M21 + v.Z * m.M31 + m.M41; r.Y = v.X * m.M12 + v.Y * m.M22 + v.Z * m.M32 + m.M42; r.Z = v.X * m.M13 + v.Y * m.M23 + v.Z * m.M33 + m.M43; } public static Vector3 TransformNormal(Vector3 v, ref Matrix m) { return new Vector3( v.X * m.M11 + v.Y * m.M21 + v.Z * m.M31, v.X * m.M12 + v.Y * m.M22 + v.Z * m.M32, v.X * m.M13 + v.Y * m.M23 + v.Z * m.M33); } public static void Transform(Vector3[] v, ref Matrix m, Vector3[] r) { for (int i = 0; i < v.Length; i++) { float x = v[i].X; float y = v[i].Y; float z = v[i].Z; r[i].X = x * m.M11 + y * m.M21 + z * m.M31 + m.M41; r[i].Y = x * m.M12 + y * m.M22 + z * m.M32 + m.M42; r[i].Z = x * m.M13 + y * m.M23 + z * m.M33 + m.M43; } } public static Vector3[] Transform(Vector3[] v, ref Matrix m) { var r = new Vector3[v.Length]; Transform(v, ref m, r); return r; } public static void TransformNormal(Vector3[] v, ref Matrix m, Vector3[] r) { for (int i = 0; i < v.Length; i++) { float x = v[i].X; float y = v[i].Y; float z = v[i].Z; r[i].X = x * m.M11 + y * m.M21 + z * m.M31; r[i].Y = x * m.M12 + y * m.M22 + z * m.M32; r[i].Z = x * m.M13 + y * m.M23 + z * m.M33; } } public static Vector3[] TransformNormal(Vector3[] v, ref Matrix m) { var r = new Vector3[v.Length]; TransformNormal(v, ref m, r); return r; } public static Vector3 Min(Vector3 v1, Vector3 v2) { if (v2.X < v1.X) v1.X = v2.X; if (v2.Y < v1.Y) v1.Y = v2.Y; if (v2.Z < v1.Z) v1.Z = v2.Z; return v1; } public static void Min(ref Vector3 v1, ref Vector3 v2, out Vector3 r) { r.X = (v1.X < v2.X) ? v1.X : v2.X; r.Y = (v1.Y < v2.Y) ? v1.Y : v2.Y; r.Z = (v1.Z < v2.Z) ? v1.Z : v2.Z; } public static Vector3 Max(Vector3 v1, Vector3 v2) { if (v2.X > v1.X) v1.X = v2.X; if (v2.Y > v1.Y) v1.Y = v2.Y; if (v2.Z > v1.Z) v1.Z = v2.Z; return v1; } public static void Max(ref Vector3 v1, ref Vector3 v2, out Vector3 r) { r.X = (v1.X > v2.X) ? v1.X : v2.X; r.Y = (v1.Y > v2.Y) ? v1.Y : v2.Y; r.Z = (v1.Z > v2.Z) ? v1.Z : v2.Z; } public static Vector3 Normalize(Vector3 v) => v * (1.0f / v.Length()); public void Normalize() { float k = 1.0f / Length(); X *= k; Y *= k; Z *= k; } public float LengthSquared() => X * X + Y * Y + Z * Z; public float Length() => FMath.Sqrt(LengthSquared()); public static float Distance(Vector3 v1, Vector3 v2) => FMath.Sqrt((v2 - v1).LengthSquared()); public static float DistanceSquared(Vector3 v1, Vector3 v2) => (v2 - v1).LengthSquared(); public static Vector3 Lerp(Vector3 v1, Vector3 v2, float amount) => v1 + (v2 - v1) * amount; public static bool EqualsEps(Vector3 v1, Vector3 v2) { Vector3 d = v2 - v1; float dx = Math.Abs(d.X); float dy = Math.Abs(d.Y); float dz = Math.Abs(d.Z); return (dx < 0.0001f && dy < 0.0001f && dz < 0.0001f); } public static bool operator ==(Vector3 v1, Vector3 v2) => v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z; public static bool operator !=(Vector3 v1, Vector3 v2) => v1.X != v2.X || v1.Y != v2.Y || v1.Z != v2.Z; public bool Equals(Vector3 other) => X == other.X && Y == other.Y && Z == other.Z; public override bool Equals(object obj) => obj is Vector3 && Equals((Vector3)obj); public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); public override string ToString() => $"{{{X} {Y} {Z}}}"; private static Vector3 zero = new Vector3(); private static Vector3 one = new Vector3(1.0f); private static Vector3 up = new Vector3(0.0f, 1.0f, 0.0f); private static Vector3 down = new Vector3(0.0f, -1.0f, 0.0f); private static Vector3 right = new Vector3(1.0f, 0.0f, 0.0f); private static Vector3 left = new Vector3(-1.0f, 0.0f, 0.0f); private static Vector3 backward = new Vector3(0.0f, 0.0f, 1.0f); private static Vector3 forward = new Vector3(0.0f, 0.0f, -1.0f); public static Vector3 Zero => zero; public static Vector3 One => one; public static Vector3 Up => up; public static Vector3 Down => down; public static Vector3 Left => left; public static Vector3 Right => right; public static Vector3 Backward => backward; public static Vector3 Forward => forward; public static Vector3 UnitX => right; public static Vector3 UnitY => up; public static Vector3 UnitZ => backward; public float this[int i] { get { if (i == 1) return Y; else if (i < 1) return X; else return Z; } } } }