using System; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Xml.Linq; using Microsoft.Xna.Framework; using System.IO.Compression; namespace Subsurface { static class ToolBox { public static Vector2 SmoothStep(Vector2 v1, Vector2 v2, float amount) { return new Vector2( MathHelper.SmoothStep(v1.X, v2.X, amount), MathHelper.SmoothStep(v1.Y, v2.Y, amount)); } public static float Round(float value, float div) { return (float)Math.Floor(value / div) * div; } public static float RandomFloat(float minimum, float maximum) { return (float)Game1.localRandom.NextDouble() * (maximum - minimum) + minimum; } public static int RandomInt(int minimum, int maximum) { return Game1.localRandom.Next(maximum - minimum) + minimum; } public static float VectorToAngle(Vector2 vector) { return (float)Math.Atan2(vector.Y, vector.X); } public static float CurveAngle(float from, float to, float step) { // Ensure that 0 <= angle < 2pi for both "from" and "to" while (from < 0) from += MathHelper.TwoPi; while (from >= MathHelper.TwoPi) from -= MathHelper.TwoPi; while (to < 0) to += MathHelper.TwoPi; while (to >= MathHelper.TwoPi) to -= MathHelper.TwoPi; if (Math.Abs(from - to) < MathHelper.Pi) { // The simple case - a straight lerp will do. return MathHelper.Lerp(from, to, step); } // If we get here we have the more complex case. // First, increment the lesser value to be greater. if (from < to) from += MathHelper.TwoPi; else to += MathHelper.TwoPi; float retVal = MathHelper.Lerp(from, to, step); // Now ensure the return value is between 0 and 2pi if (retVal >= MathHelper.TwoPi) retVal -= MathHelper.TwoPi; return retVal; } public static float WrapAngleTwoPi(float angle) { // Ensure that 0 <= angle < 2pi for both "from" and "to" while (angle < 0) angle += MathHelper.TwoPi; while (angle >= MathHelper.TwoPi) angle -= MathHelper.TwoPi; return angle; } public static float WrapAnglePi(float angle) { // Ensure that -pi <= angle < pi for both "from" and "to" while (angle < -MathHelper.Pi) angle += MathHelper.TwoPi; while (angle >= MathHelper.Pi) angle -= MathHelper.TwoPi; return angle; } public static float GetShortestAngle(float from, float to) { // Ensure that 0 <= angle < 2pi for both "from" and "to" from = WrapAngleTwoPi(from); to = WrapAngleTwoPi(to); if (Math.Abs(from - to) < MathHelper.Pi) { return to - from; } // If we get here we have the more complex case. // First, increment the lesser value to be greater. if (from < to) from += MathHelper.TwoPi; else to += MathHelper.TwoPi; return to - from; } /// /// solves the angle opposite to side a (parameters: lengths of each side) /// public static float SolveTriangleSSS(float a, float b, float c) { float A = (float)Math.Acos((b*b + c*c - a*a) / (2*b*c)); if (float.IsNaN(A)) A = 1.0f; return A; } public static void CompressStringToFile(string fileName, string value) { // A. // Write string to temporary file. string temp = Path.GetTempFileName(); File.WriteAllText(temp, value); // B. // Read file into byte array buffer. byte[] b; using (FileStream f = new FileStream(temp, FileMode.Open)) { b = new byte[f.Length]; f.Read(b, 0, (int)f.Length); } // C. // Use GZipStream to write compressed bytes to target file. using (FileStream f2 = new FileStream(fileName, FileMode.Create)) using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false)) { gz.Write(b, 0, b.Length); } } public static Stream DecompressFiletoStream(string fileName) { if (!File.Exists(fileName)) { DebugConsole.ThrowError("File ''"+fileName+" doesn't exist!"); return null; } using (FileStream originalFileStream = new FileStream(fileName, FileMode.Open)) { MemoryStream decompressedFileStream = new MemoryStream(); using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress)) { decompressionStream.CopyTo(decompressedFileStream); return decompressedFileStream; } } } public static XDocument TryLoadXml(string filePath) { XDocument doc; try { doc = XDocument.Load(filePath); } catch (Exception e) { DebugConsole.ThrowError("Couldn't load xml document ''"+filePath+"''!", e); return null; } if (doc.Root == null) return null; return doc; } public static object GetAttributeObject(XElement element, string name) { if (element.Attribute(name) == null) return null; return GetAttributeObject(element.Attribute(name)); } public static object GetAttributeObject(XAttribute attribute) { if (attribute == null) return null; return ParseToObject(attribute.Value.ToString()); } public static object ParseToObject(string value) { float floatVal; int intVal; if (value.ToString().Contains(".") && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out floatVal)) { return floatVal; } else if (int.TryParse(value, out intVal)) { return intVal; } else { string lowerTrimmedVal = value.ToLower().Trim(); if (lowerTrimmedVal == "true") { return true; } else if (lowerTrimmedVal == "false") { return false; } else { return value; } } } public static string GetAttributeString(XElement element, string name, string defaultValue) { if (element.Attribute(name) == null) return defaultValue; return GetAttributeString(element.Attribute(name), defaultValue); } public static string GetAttributeString(XAttribute attribute, string defaultValue) { string value = attribute.Value; if (String.IsNullOrEmpty(value)) return defaultValue; return value; } public static float GetAttributeFloat(XElement element, string name, float defaultValue) { if (element.Attribute(name) == null) return defaultValue; float val = defaultValue; try { if (!float.TryParse(element.Attribute(name).Value, NumberStyles.Float, CultureInfo.InvariantCulture, out val)) { return defaultValue; } } catch (Exception e) { DebugConsole.ThrowError("Error in "+element+"!", e); } return val; } public static float GetAttributeFloat(XAttribute attribute, float defaultValue) { if (attribute == null) return defaultValue; float val = defaultValue; try { val = float.Parse(attribute.Value, CultureInfo.InvariantCulture); } catch (Exception e) { DebugConsole.ThrowError("Error in " + attribute + "! ", e); } return val; } public static int GetAttributeInt(XElement element, string name, int defaultValue) { if (element.Attribute(name) == null) return defaultValue; int val = defaultValue; try { val = int.Parse(element.Attribute(name).Value); } catch (Exception e) { DebugConsole.ThrowError("Error in " + element + "! ", e); } return val; } public static bool GetAttributeBool(XElement element, string name, bool defaultValue) { if (element.Attribute(name) == null) return defaultValue; string val = element.Attribute(name).Value.ToLower().Trim(); if (val == "true") { return true; } else if (val == "false") { return false; } else { DebugConsole.ThrowError("Error in " + element + "! ''" + val + "'' is not a valid boolean value"); return false; } } public static Vector2 GetAttributeVector2(XElement element, string name, Vector2 defaultValue) { if (element.Attribute(name) == null) return defaultValue; string val = element.Attribute(name).Value; return ParseToVector2(val); } public static Vector4 GetAttributeVector4(XElement element, string name, Vector4 defaultValue) { if (element.Attribute(name) == null) return defaultValue; string val = element.Attribute(name).Value; return ParseToVector4(val); } public static Vector2 ParseToVector2(string stringVector2) { string[] components = stringVector2.Split(','); Vector2 vector = Vector2.Zero; if (components.Length!=2) { DebugConsole.ThrowError("Failed to parse the string "+stringVector2+" to Vector2"); return vector; } float.TryParse(components[0], NumberStyles.Float, CultureInfo.InvariantCulture, out vector.X); float.TryParse(components[1], NumberStyles.Float, CultureInfo.InvariantCulture, out vector.Y); return vector; } public static string Vector2ToString(Vector2 vector) { return vector.X.ToString("G", CultureInfo.InvariantCulture) + "," + vector.Y.ToString("G", CultureInfo.InvariantCulture); } public static Vector4 ParseToVector4(string stringVector4) { string[] components = stringVector4.Split(','); Vector4 vector = Vector4.Zero; if (components.Length < 3) { DebugConsole.ThrowError("Failed to parse the string " + stringVector4 + " to Vector4"); return vector; } float.TryParse(components[0], NumberStyles.Float, CultureInfo.InvariantCulture, out vector.X); float.TryParse(components[1], NumberStyles.Float, CultureInfo.InvariantCulture, out vector.Y); float.TryParse(components[2], NumberStyles.Float, CultureInfo.InvariantCulture, out vector.Z); if (components.Length>3) float.TryParse(components[3], NumberStyles.Float, CultureInfo.InvariantCulture, out vector.W); return vector; } public static string Vector4ToString(Vector4 vector) { return vector.X.ToString("G", CultureInfo.InvariantCulture) + "," + vector.Y.ToString("G", CultureInfo.InvariantCulture) + "," + vector.Z.ToString("G", CultureInfo.InvariantCulture) + "," + vector.W.ToString("G", CultureInfo.InvariantCulture); } public static float[] ParseArrayToFloat(string[] stringArray) { if (stringArray == null || stringArray.Length == 0) return null; float[] floatArray = new float[stringArray.Length]; for (int i = 0; i