﻿ using System; using System.Globalization; namespace FalcoEngine { //[StructLayout(LayoutKind.Sequential)] public struct Vector3 { public float x; public float y; public float z; public const float kEpsilon = 1E-05f; public const float kEpsilonNormalSqrt = 1E-15f; public Vector3(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public static Vector3 operator + (Vector3 a, Vector3 b) { return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z); } public static Vector3 operator -(Vector3 a, Vector3 b) { return new Vector3(a.x - b.x, a.y - b.y, a.z - b.z); } public static Vector3 operator -(Vector3 a) { return new Vector3(0f - a.x, 0f - a.y, 0f - a.z); } public static Vector3 operator *(Vector3 a, float b) { return new Vector3(a.x * b, a.y * b, a.z * b); } public static Vector3 operator *(float d, Vector3 a) { return new Vector3(a.x * d, a.y * d, a.z * d); } public static Vector3 operator /(Vector3 a, float d) { return new Vector3(a.x / d, a.y / d, a.z / d); } public static bool operator ==(Vector3 lhs, Vector3 rhs) { return SqrMagnitude(lhs - rhs) < 9.99999944E-11f; } public static bool operator !=(Vector3 lhs, Vector3 rhs) { return !(lhs == rhs); } /// /// Shorthand for writing Vector3(0, 0, 0). /// public static Vector3 zero { get; } = new Vector3(0f, 0f, 0f); /// /// Shorthand for writing Vector3(1, 1, 1). /// public static Vector3 one { get; } = new Vector3(1f, 1f, 1f); /// /// Shorthand for writing Vector3(0, 0, 1). /// public static Vector3 forward { get; } = new Vector3(0f, 0f, 1f); /// /// Shorthand for writing Vector3(0, 0, -1). /// public static Vector3 back { get; } = new Vector3(0f, 0f, -1f); /// /// Shorthand for writing Vector3(0, 1, 0). /// public static Vector3 up { get; } = new Vector3(0f, 1f, 0f); /// /// Shorthand for writing Vector3(0, -1, 0). /// public static Vector3 down { get; } = new Vector3(0f, -1f, 0f); /// /// Shorthand for writing Vector3(-1, 0, 0). /// public static Vector3 left { get; } = new Vector3(-1f, 0f, 0f); /// /// Shorthand for writing Vector3(1, 0, 0). /// public static Vector3 right { get; } = new Vector3(1f, 0f, 0f); /// /// Shorthand for writing Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity). /// public static Vector3 positiveInfinity { get; } = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); /// /// Shorthand for writing Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity). /// public static Vector3 negativeInfinity { get; } = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); public float magnitude => Mathf.Sqrt(x * x + y * y + z * z); /// /// Returns the squared length of this vector (Read Only). /// public float sqrMagnitude => x * x + y * y + z * z; /// /// Returns this vector with a magnitude of 1 (Read Only). /// public Vector3 normalized => Normalize(this); /// /// Linearly interpolates between two vectors. /// /// /// /// public static Vector3 Lerp(Vector3 a, Vector3 b, float t) { t = Mathf.Clamp01(t); return new Vector3(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t); } /// /// Linearly interpolates between two vectors. /// /// /// /// public static Vector3 LerpUnclamped(Vector3 a, Vector3 b, float t) { return new Vector3(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t); } /// /// Multiplies every component of this vector by the same component of scale. /// /// public void Scale(Vector3 scale) { x *= scale.x; y *= scale.y; z *= scale.z; } public override int GetHashCode() { return x.GetHashCode() ^ (y.GetHashCode() << 2) ^ (z.GetHashCode() >> 2); } /// /// Returns true if the given vector is exactly equal to this vector. /// /// public override bool Equals(object other) { if (!(other is Vector3)) { return false; } return Equals((Vector3)other); } public bool Equals(Vector3 other) { return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z); } /// /// Cross Product of two vectors. /// /// /// public static Vector3 Cross(Vector3 lhs, Vector3 rhs) { return new 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); } /// /// Reflects a vector off the plane defined by a normal. /// /// /// public static Vector3 Reflect(Vector3 inDirection, Vector3 inNormal) { return -2f * Dot(inNormal, inDirection) * inNormal + inDirection; } /// /// Makes this vector have a magnitude of 1. /// /// public static Vector3 Normalize(Vector3 value) { float num = Magnitude(value); if (num > 1E-05f) { return value / num; } return zero; } public void Normalize() { float num = Magnitude(this); if (num > 1E-05f) { this /= num; } else { this = zero; } } /// /// Dot Product of two vectors. /// /// /// public static float Dot(Vector3 lhs, Vector3 rhs) { return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; } /// /// Projects a vector onto another vector. /// /// /// public static Vector3 Project(Vector3 vector, Vector3 onNormal) { float num = Dot(onNormal, onNormal); if (num < kEpsilon) { return zero; } return onNormal * Dot(vector, onNormal) / num; } /// /// Projects a vector onto a plane defined by a normal orthogonal to the plane. /// /// /// public static Vector3 ProjectOnPlane(Vector3 vector, Vector3 planeNormal) { return vector - Project(vector, planeNormal); } /// /// Returns the angle in degrees between from and to. /// /// The vector from which the angular difference is measured. /// The vector to which the angular difference is measured. /// /// The angle in degrees between the two vectors. /// public static float Angle(Vector3 from, Vector3 to) { float num = Mathf.Sqrt(from.sqrMagnitude * to.sqrMagnitude); if (num < 1E-15f) { return 0f; } float f = Mathf.Clamp(Dot(from, to) / num, -1f, 1f); return Mathf.Acos(f) * 57.29578f; } /// /// Returns the signed angle in degrees between from and to. /// /// The vector from which the angular difference is measured. /// The vector to which the angular difference is measured. /// A vector around which the other vectors are rotated. public static float SignedAngle(Vector3 from, Vector3 to, Vector3 axis) { float num = Angle(from, to); float num2 = Mathf.Sign(Dot(axis, Cross(from, to))); return num * num2; } /// /// Returns the distance between a and b. /// /// /// public static float Distance(Vector3 a, Vector3 b) { Vector3 vector = new Vector3(a.x - b.x, a.y - b.y, a.z - b.z); return Mathf.Sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z); } /// /// Returns a copy of vector with its magnitude clamped to maxLength. /// /// /// public static Vector3 ClampMagnitude(Vector3 vector, float maxLength) { if (vector.sqrMagnitude > maxLength * maxLength) { return vector.normalized * maxLength; } return vector; } public static float Magnitude(Vector3 vector) { return Mathf.Sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z); } public static float SqrMagnitude(Vector3 vector) { return vector.x * vector.x + vector.y * vector.y + vector.z * vector.z; } /// /// Returns a vector that is made from the smallest components of two vectors. /// /// /// public static Vector3 Min(Vector3 lhs, Vector3 rhs) { return new Vector3(Mathf.Min(lhs.x, rhs.x), Mathf.Min(lhs.y, rhs.y), Mathf.Min(lhs.z, rhs.z)); } /// /// Returns a vector that is made from the largest components of two vectors. /// /// /// public static Vector3 Max(Vector3 lhs, Vector3 rhs) { return new Vector3(Mathf.Max(lhs.x, rhs.x), Mathf.Max(lhs.y, rhs.y), Mathf.Max(lhs.z, rhs.z)); } /// /// Returns a nicely formatted string for this vector. /// /// public override string ToString() { return String.Format("({0:F1}, {1:F1}, {2:F1})", x, y, z); } /// /// Returns a nicely formatted string for this vector. /// /// public string ToString(string format) { return String.Format("({0}, {1}, {2})", x.ToString(format, CultureInfo.InvariantCulture.NumberFormat), y.ToString(format, CultureInfo.InvariantCulture.NumberFormat), z.ToString(format, CultureInfo.InvariantCulture.NumberFormat)); } } }