using System; using UltimateWater.Internal; using UnityEngine; namespace UltimateWater { public sealed class WaterSample { public enum DisplacementMode { Height = 0, Displacement = 1, HeightAndForces = 2 } public enum ComputationsMode { Normal = 0, ForceCompletion = 2 } private readonly Water _Water; private float _X; private float _Z; private float _Time; private Vector3 _Displaced; private Vector3 _PreviousResult; private Vector3 _Forces; private Vector3 _PreviousForces; private bool _Finished; private bool _Enqueued; private readonly DisplacementMode _DisplacementMode; public bool Finished { get { return _Finished; } } public Vector2 Position { get { return new Vector2(_X, _Z); } } public WaterSample(Water water, DisplacementMode displacementMode = DisplacementMode.Height, float precision = 1f) { if (water == null) { throw new ArgumentException("Argument 'water' is null."); } if (precision <= 0f || precision > 1f) { throw new ArgumentException("Precision has to be between 0.0 and 1.0."); } _Water = water; _DisplacementMode = displacementMode; _PreviousResult.x = float.NaN; } public void Start(Vector3 origin) { _Finished = true; _PreviousResult = (_Displaced = origin); _PreviousForces = (_Forces = default(Vector3)); GetAndReset(origin.x, origin.z); } public void Start(float x, float z) { _Finished = true; _PreviousResult = (_Displaced = new Vector3(x, _Water.transform.position.y, z)); _PreviousForces = (_Forces = default(Vector3)); GetAndReset(x, z); } public Vector3 GetAndReset(Vector3 origin, ComputationsMode mode = ComputationsMode.Normal) { return GetAndReset(origin.x, origin.z, mode); } public Vector3 GetAndReset(float x, float z, ComputationsMode mode = ComputationsMode.Normal) { Vector3 forces; return GetAndReset(x, z, mode, out forces); } public Vector3 GetAndReset(float x, float z, ComputationsMode mode, out Vector3 forces) { switch (mode) { case ComputationsMode.ForceCompletion: if (!_Finished) { _Finished = true; ComputationStep(true); } break; case ComputationsMode.Normal: if (!_Finished && !float.IsNaN(_PreviousResult.x)) { forces = _PreviousForces; return _PreviousResult; } _PreviousResult = _Displaced; _PreviousForces = _Forces; break; } _Finished = true; if (!_Enqueued) { WaterAsynchronousTasks.Instance.AddWaterSampleComputations(this); _Enqueued = true; _Water.OnSamplingStarted(); } Vector3 displaced = _Displaced; displaced.y += _Water.transform.position.y; forces = _Forces; _X = x; _Z = z; _Displaced.x = x; _Displaced.y = 0f; _Displaced.z = z; _Forces.x = 0f; _Forces.y = 0f; _Forces.z = 0f; _Time = _Water.Time; _Finished = false; return displaced; } public void GetAndResetFast(float x, float z, float time, out Vector3 result, out Vector3 forces) { if (!_Finished) { forces = _PreviousForces; result = _PreviousResult; return; } _PreviousResult = _Displaced; _PreviousForces = _Forces; result = _Displaced; result.y += _Water.transform.position.y; forces = _Forces; _X = x; _Z = z; _Displaced.x = x; _Displaced.y = 0f; _Displaced.z = z; _Forces.x = 0f; _Forces.y = 0f; _Forces.z = 0f; _Time = time; _Finished = false; } public void GetAndResetFast(float x, float z, float time, out float result, out Vector3 forces) { if (!_Finished) { forces = _PreviousForces; result = _PreviousResult.y; return; } _PreviousResult = _Displaced; _PreviousForces = _Forces; result = _Displaced.y + _Water.transform.position.y; forces = _Forces; _X = x; _Z = z; _Displaced.x = x; _Displaced.y = 0f; _Displaced.z = z; _Forces.x = 0f; _Forces.y = 0f; _Forces.z = 0f; _Time = time; _Finished = false; } public Vector3 Stop() { if (_Enqueued) { if (WaterAsynchronousTasks.HasInstance) { WaterAsynchronousTasks.Instance.RemoveWaterSampleComputations(this); } _Enqueued = false; if (_Water != null) { _Water.OnSamplingStopped(); } } return _Displaced; } internal void ComputationStep(bool ignoreFinishedFlag = false) { if (_Finished && !ignoreFinishedFlag) { return; } if (_DisplacementMode == DisplacementMode.Height || _DisplacementMode == DisplacementMode.HeightAndForces) { _Water.CompensateHorizontalDisplacement(ref _X, ref _Z, _Time); if (_DisplacementMode == DisplacementMode.Height) { float uncompensatedHeightAt = _Water.GetUncompensatedHeightAt(_X, _Z, _Time); _Displaced.y += uncompensatedHeightAt; } else { Vector4 uncompensatedHeightAndForcesAt = _Water.GetUncompensatedHeightAndForcesAt(_X, _Z, _Time); _Displaced.y += uncompensatedHeightAndForcesAt.w; _Forces.x += uncompensatedHeightAndForcesAt.x; _Forces.y += uncompensatedHeightAndForcesAt.y; _Forces.z += uncompensatedHeightAndForcesAt.z; } } else { Vector3 vector = ((_Water.WaterId == -1) ? default(Vector3) : _Water.GetUncompensatedDisplacementAt(_X, _Z, _Time)); _Displaced += vector; } _Finished = true; } } }