using UnityEngine; using System.Collections; using System.IO; namespace Rokid.UXR.Utility { public static partial class Utils { public class Event { public delegate void Handler(params object[] args); public static void Listen(string message, Handler action) { var actions = listeners[message] as Handler; if (actions != null) { listeners[message] = actions + action; } else { listeners[message] = action; } } public static void Remove(string message, Handler action) { var actions = listeners[message] as Handler; if (actions != null) { listeners[message] = actions - action; } } public static void Send(string message, params object[] args) { var actions = listeners[message] as Handler; if (actions != null) { actions(args); } } private static Hashtable listeners = new Hashtable(); } /// /// Smooths from source to goal, provided lerptime and a deltaTime. /// /// Current value /// "goal" value which will be lerped to /// Smoothing/lerp amount. Smoothing of 0 means no smoothing, and max value means no change at all. /// Delta time. Usually would be set to Time.deltaTime /// Smoothed value public static Vector3 SmoothTo(Vector3 source, Vector3 goal, float lerpTime, float deltaTime) { return Vector3.Lerp(source, goal, (lerpTime == 0f) ? 1f : 1f - Mathf.Pow(lerpTime, deltaTime)); } /// /// Smooths from source to goal, provided slerptime and a deltaTime. /// /// Current value /// "goal" value which will be lerped to /// Smoothing/lerp amount. Smoothing of 0 means no smoothing, and max value means no change at all. /// Delta time. Usually would be set to Time.deltaTime /// Smoothed value public static Quaternion SmoothTo(Quaternion source, Quaternion goal, float slerpTime, float deltaTime) { return Quaternion.Slerp(source, goal, (slerpTime == 0f) ? 1f : 1f - Mathf.Pow(slerpTime, deltaTime)); } public static bool IsValid(Vector3 vector) { return (float.IsNaN(vector.x) == false && float.IsNaN(vector.y) == false && float.IsNaN(vector.z) == false); } public static bool IsValid(Quaternion rotation) { return (float.IsNaN(rotation.x) == false && float.IsNaN(rotation.y) == false && float.IsNaN(rotation.z) == false && float.IsNaN(rotation.w) == false) && (rotation.x != 0 || rotation.y != 0 || rotation.z != 0 || rotation.w != 0); } // this version does not clamp [0..1] public static Quaternion Slerp(Quaternion A, Quaternion B, float t) { var cosom = Mathf.Clamp(A.x * B.x + A.y * B.y + A.z * B.z + A.w * B.w, -1.0f, 1.0f); if (cosom < 0.0f) { B = new Quaternion(-B.x, -B.y, -B.z, -B.w); cosom = -cosom; } float sclp, sclq; if ((1.0f - cosom) > 0.0001f) { var omega = Mathf.Acos(cosom); var sinom = Mathf.Sin(omega); sclp = Mathf.Sin((1.0f - t) * omega) / sinom; sclq = Mathf.Sin(t * omega) / sinom; } else { // "from" and "to" very close, so do linear interp sclp = 1.0f - t; sclq = t; } return new Quaternion( sclp * A.x + sclq * B.x, sclp * A.y + sclq * B.y, sclp * A.z + sclq * B.z, sclp * A.w + sclq * B.w); } public static Vector3 Lerp(Vector3 A, Vector3 B, float t) { return new Vector3( Lerp(A.x, B.x, t), Lerp(A.y, B.y, t), Lerp(A.z, B.z, t)); } public static float Lerp(float A, float B, float t) { return A + (B - A) * t; } public static double Lerp(double A, double B, double t) { return A + (B - A) * t; } public static float InverseLerp(Vector3 A, Vector3 B, Vector3 result) { return Vector3.Dot(result - A, B - A); } public static float InverseLerp(float A, float B, float result) { return (result - A) / (B - A); } public static double InverseLerp(double A, double B, double result) { return (result - A) / (B - A); } public static float Saturate(float A) { return (A < 0) ? 0 : (A > 1) ? 1 : A; } public static Vector2 Saturate(Vector2 A) { return new Vector2(Saturate(A.x), Saturate(A.y)); } public static float Abs(float A) { return (A < 0) ? -A : A; } public static Vector2 Abs(Vector2 A) { return new Vector2(Abs(A.x), Abs(A.y)); } private static float _copysign(float sizeval, float signval) { return Mathf.Sign(signval) == 1 ? Mathf.Abs(sizeval) : -Mathf.Abs(sizeval); } public static Quaternion GetRotation(this Matrix4x4 matrix) { Quaternion q = new Quaternion(); q.w = Mathf.Sqrt(Mathf.Max(0, 1 + matrix.m00 + matrix.m11 + matrix.m22)) / 2; q.x = Mathf.Sqrt(Mathf.Max(0, 1 + matrix.m00 - matrix.m11 - matrix.m22)) / 2; q.y = Mathf.Sqrt(Mathf.Max(0, 1 - matrix.m00 + matrix.m11 - matrix.m22)) / 2; q.z = Mathf.Sqrt(Mathf.Max(0, 1 - matrix.m00 - matrix.m11 + matrix.m22)) / 2; q.x = _copysign(q.x, matrix.m21 - matrix.m12); q.y = _copysign(q.y, matrix.m02 - matrix.m20); q.z = _copysign(q.z, matrix.m10 - matrix.m01); return q; } public static Vector3 GetPosition(this Matrix4x4 matrix) { var x = matrix.m03; var y = matrix.m13; var z = matrix.m23; return new Vector3(x, y, z); } public static Vector3 GetScale(this Matrix4x4 m) { var x = Mathf.Sqrt(m.m00 * m.m00 + m.m01 * m.m01 + m.m02 * m.m02); var y = Mathf.Sqrt(m.m10 * m.m10 + m.m11 * m.m11 + m.m12 * m.m12); var z = Mathf.Sqrt(m.m20 * m.m20 + m.m21 * m.m21 + m.m22 * m.m22); return new Vector3(x, y, z); } public static float GetLossyScale(Transform t) { return t.lossyScale.x; } private const string secretKey = "foobar"; public static string GetBadMD5Hash(string usedString) { byte[] bytes = System.Text.Encoding.UTF8.GetBytes(usedString + secretKey); return GetBadMD5Hash(bytes); } public static string GetBadMD5Hash(byte[] bytes) { System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); byte[] hash = md5.ComputeHash(bytes); System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int i = 0; i < hash.Length; i++) { sb.Append(hash[i].ToString("x2")); } return sb.ToString(); } public static string GetBadMD5HashFromFile(string filePath) { if (File.Exists(filePath) == false) return null; string data = File.ReadAllText(filePath); return GetBadMD5Hash(data + secretKey); } public static string SanitizePath(string path, bool allowLeadingSlash = true) { if (path.Contains("\\\\")) path = path.Replace("\\\\", "\\"); if (path.Contains("//")) path = path.Replace("//", "/"); if (allowLeadingSlash == false) { if (path[0] == '/' || path[0] == '\\') path = path.Substring(1); } return path; } public static System.Type FindType(string typeName) { var type = System.Type.GetType(typeName); if (type != null) return type; foreach (var a in System.AppDomain.CurrentDomain.GetAssemblies()) { type = a.GetType(typeName); if (type != null) return type; } return null; } [System.Serializable] public struct RigidTransform { public Vector3 pos; public Quaternion rot; public static RigidTransform identity { get { return new RigidTransform(Vector3.zero, Quaternion.identity); } } public static RigidTransform FromLocal(Transform t) { return new RigidTransform(t.localPosition, t.localRotation); } public RigidTransform(Vector3 pos, Quaternion rot) { this.pos = pos; this.rot = rot; } public RigidTransform(Transform t) { this.pos = t.position; this.rot = t.rotation; } public RigidTransform(Transform from, Transform to) { var inv = Quaternion.Inverse(from.rotation); rot = inv * to.rotation; pos = inv * (to.position - from.position); } public RigidTransform(HmdMatrix34_t pose) { var m = Matrix4x4.identity; m[0, 0] = pose.m0; m[0, 1] = pose.m1; m[0, 2] = -pose.m2; m[0, 3] = pose.m3; m[1, 0] = pose.m4; m[1, 1] = pose.m5; m[1, 2] = -pose.m6; m[1, 3] = pose.m7; m[2, 0] = -pose.m8; m[2, 1] = -pose.m9; m[2, 2] = pose.m10; m[2, 3] = -pose.m11; this.pos = m.GetPosition(); this.rot = m.GetRotation(); } public RigidTransform(HmdMatrix44_t pose) { var m = Matrix4x4.identity; m[0, 0] = pose.m0; m[0, 1] = pose.m1; m[0, 2] = -pose.m2; m[0, 3] = pose.m3; m[1, 0] = pose.m4; m[1, 1] = pose.m5; m[1, 2] = -pose.m6; m[1, 3] = pose.m7; m[2, 0] = -pose.m8; m[2, 1] = -pose.m9; m[2, 2] = pose.m10; m[2, 3] = -pose.m11; m[3, 0] = pose.m12; m[3, 1] = pose.m13; m[3, 2] = -pose.m14; m[3, 3] = pose.m15; this.pos = m.GetPosition(); this.rot = m.GetRotation(); } public HmdMatrix44_t ToHmdMatrix44() { var m = Matrix4x4.TRS(pos, rot, Vector3.one); var pose = new HmdMatrix44_t(); pose.m0 = m[0, 0]; pose.m1 = m[0, 1]; pose.m2 = -m[0, 2]; pose.m3 = m[0, 3]; pose.m4 = m[1, 0]; pose.m5 = m[1, 1]; pose.m6 = -m[1, 2]; pose.m7 = m[1, 3]; pose.m8 = -m[2, 0]; pose.m9 = -m[2, 1]; pose.m10 = m[2, 2]; pose.m11 = -m[2, 3]; pose.m12 = m[3, 0]; pose.m13 = m[3, 1]; pose.m14 = -m[3, 2]; pose.m15 = m[3, 3]; return pose; } public HmdMatrix34_t ToHmdMatrix34() { var m = Matrix4x4.TRS(pos, rot, Vector3.one); var pose = new HmdMatrix34_t(); pose.m0 = m[0, 0]; pose.m1 = m[0, 1]; pose.m2 = -m[0, 2]; pose.m3 = m[0, 3]; pose.m4 = m[1, 0]; pose.m5 = m[1, 1]; pose.m6 = -m[1, 2]; pose.m7 = m[1, 3]; pose.m8 = -m[2, 0]; pose.m9 = -m[2, 1]; pose.m10 = m[2, 2]; pose.m11 = -m[2, 3]; return pose; } public override bool Equals(object o) { if (o is RigidTransform) { RigidTransform t = (RigidTransform)o; return pos == t.pos && rot == t.rot; } return false; } public override int GetHashCode() { return pos.GetHashCode() ^ rot.GetHashCode(); } public static bool operator ==(RigidTransform a, RigidTransform b) { return a.pos == b.pos && a.rot == b.rot; } public static bool operator !=(RigidTransform a, RigidTransform b) { return a.pos != b.pos || a.rot != b.rot; } public static RigidTransform operator *(RigidTransform a, RigidTransform b) { return new RigidTransform { rot = a.rot * b.rot, pos = a.pos + a.rot * b.pos }; } public void Inverse() { rot = Quaternion.Inverse(rot); pos = -(rot * pos); } public RigidTransform GetInverse() { var t = new RigidTransform(pos, rot); t.Inverse(); return t; } public void Multiply(RigidTransform a, RigidTransform b) { rot = a.rot * b.rot; pos = a.pos + a.rot * b.pos; } public Vector3 InverseTransformPoint(Vector3 point) { return Quaternion.Inverse(rot) * (point - pos); } public Vector3 TransformPoint(Vector3 point) { return pos + (rot * point); } public static Vector3 operator *(RigidTransform t, Vector3 v) { return t.TransformPoint(v); } public static RigidTransform Interpolate(RigidTransform a, RigidTransform b, float t) { return new RigidTransform(Vector3.Lerp(a.pos, b.pos, t), Quaternion.Slerp(a.rot, b.rot, t)); } public void Interpolate(RigidTransform to, float t) { pos = Utils.Lerp(pos, to.pos, t); rot = Utils.Slerp(rot, to.rot, t); } } } public struct HmdMatrix44_t { public float m0; public float m1; public float m2; public float m3; public float m4; public float m5; public float m6; public float m7; public float m8; public float m9; public float m10; public float m11; public float m12; public float m13; public float m14; public float m15; } public struct HmdMatrix34_t { public float m0; public float m1; public float m2; public float m3; public float m4; public float m5; public float m6; public float m7; public float m8; public float m9; public float m10; public float m11; public Vector3 GetPosition() { return new Vector3(m3, m7, 0f - m11); } public bool IsRotationValid() { if (m2 != 0f || m6 != 0f || m10 != 0f) { if (m1 == 0f && m5 == 0f) { return m9 != 0f; } return true; } return false; } public Quaternion GetRotation() { if (IsRotationValid()) { float w = Mathf.Sqrt(Mathf.Max(0f, 1f + m0 + m5 + m10)) / 2f; float sizeval = Mathf.Sqrt(Mathf.Max(0f, 1f + m0 - m5 - m10)) / 2f; float sizeval2 = Mathf.Sqrt(Mathf.Max(0f, 1f - m0 + m5 - m10)) / 2f; float sizeval3 = Mathf.Sqrt(Mathf.Max(0f, 1f - m0 - m5 + m10)) / 2f; _copysign(ref sizeval, 0f - m9 - (0f - m6)); _copysign(ref sizeval2, 0f - m2 - (0f - m8)); _copysign(ref sizeval3, m4 - m1); return new Quaternion(sizeval, sizeval2, sizeval3, w); } return Quaternion.identity; } private static void _copysign(ref float sizeval, float signval) { if (signval > 0f != sizeval > 0f) { sizeval = 0f - sizeval; } } } }