using System; using System.Collections.Generic; using UnityEngine; using Debug = System.Diagnostics.Debug; namespace LibNoise.Operator { /// /// Provides a noise module that maps the output value from a source module onto a /// terrace-forming curve. [OPERATOR] /// public class Terrace : ModuleBase { #region Fields private readonly List _data = new List(); private bool _inverted; #endregion #region Constructors /// /// Initializes a new instance of Terrace. /// public Terrace() : base(1) { } /// /// Initializes a new instance of Terrace. /// /// The input module. public Terrace(ModuleBase input) : base(1) { Modules[0] = input; } /// /// Initializes a new instance of Terrace. /// /// Indicates whether the terrace curve is inverted. /// The input module. public Terrace(bool inverted, ModuleBase input) : base(1) { Modules[0] = input; IsInverted = inverted; } #endregion #region Properties /// /// Gets the number of control points. /// public int ControlPointCount { get { return _data.Count; } } /// /// Gets the list of control points. /// public List ControlPoints { get { return _data; } } /// /// Gets or sets a value whether the terrace curve is inverted. /// public bool IsInverted { get { return _inverted; } set { _inverted = value; } } #endregion #region Methods /// /// Adds a control point to the curve. /// /// The curves input value. public void Add(double input) { if (!_data.Contains(input)) { _data.Add(input); } _data.Sort(delegate(double lhs, double rhs) { return lhs.CompareTo(rhs); }); } /// /// Clears the control points. /// public void Clear() { _data.Clear(); } /// /// Auto-generates a terrace curve. /// /// The number of steps. public void Generate(int steps) { if (steps < 2) { throw new ArgumentException("Need at least two steps"); } Clear(); var ts = 2.0 / (steps - 1.0); var cv = -1.0; for (var i = 0; i < steps; i++) { Add(cv); cv += ts; } } #endregion #region ModuleBase Members /// /// Returns the output value for the given input coordinates. /// /// The input coordinate on the x-axis. /// The input coordinate on the y-axis. /// The input coordinate on the z-axis. /// The resulting output value. public override double GetValue(double x, double y, double z) { Debug.Assert(Modules[0] != null); Debug.Assert(ControlPointCount >= 2); var smv = Modules[0].GetValue(x, y, z); int ip; for (ip = 0; ip < _data.Count; ip++) { if (smv < _data[ip]) { break; } } var i0 = Mathf.Clamp(ip - 1, 0, _data.Count - 1); var i1 = Mathf.Clamp(ip, 0, _data.Count - 1); if (i0 == i1) { return _data[i1]; } var v0 = _data[i0]; var v1 = _data[i1]; var a = (smv - v0) / (v1 - v0); if (_inverted) { a = 1.0 - a; var t = v0; v0 = v1; v1 = t; } a *= a; return Utils.InterpolateLinear(v0, v1, a); } #endregion } }