/// <summary>
    /// Executes the wave simulation step.
    /// </summary>
    /// <param name="speed">
    /// Overall simulation speed factor.
    /// </param>
    /// <param name="damping">
    /// The damping value (range 0-1).
    /// </param>
    public override void StepSimulation(float speed, float damping)
    {
        if (!_isDirty || !_isInitialized)
        {
            return;
        }

        _simulationSpeedNormalizationFactor = (_grid.x + _grid.y) / 128f;     // assume 64 grid as normal

        float dt = Mathf.Clamp(Time.deltaTime * speed * _simulationSpeedNormalizationFactor, 0f, LinearWaveEqueationSolver.MaxDt);
        float max;

#if !UNITY_FLASH
        bool useNative = DynamicWaterNativeLibrary.CanUseNative;
#else
        const bool useNative = false;
        #endif

        if (useNative)
        {
#if !UNITY_FLASH
            if (_switchField)
            {
                DynamicWaterNativeLibrary.SolveWaveEquationNative(_grid.x, _grid.y, dt, damping, out max, FieldSim, FieldSimNew, FieldSimSpeed, _fieldObstruction);
                _field = FieldSimNew;
            }
            else
            {
                DynamicWaterNativeLibrary.SolveWaveEquationNative(_grid.x, _grid.y, dt, damping, out max, FieldSimNew, FieldSim, FieldSimSpeed, _fieldObstruction);
                _field = FieldSim;
            }
#endif
        }
        else
        {
            if (_switchField)
            {
                LinearWaveEqueationSolver.Solve(FieldSim, FieldSimNew, FieldSimSpeed, _fieldObstruction, _grid, dt, damping, out max);
                _field = FieldSimNew;
            }
            else
            {
                LinearWaveEqueationSolver.Solve(FieldSimNew, FieldSim, FieldSimSpeed, _fieldObstruction, _grid, dt, damping, out max);
                _field = FieldSim;
            }
        }

        _switchField = !_switchField;

        _isDirty = max > DirtyThreshold;
    }
        /// <summary>
        /// Updates the mesh state using the simulation state field <paramref name="field"/>
        /// and (optional) the obstruction field.
        /// </summary>
        /// <param name="field">
        /// The simulation state field.
        /// </param>
        /// <param name="fieldObstruction">
        /// The array of <c>bool</c> indicating whether the water is obstructed by an object.
        /// </param>
        public void UpdateMesh(float[] field, byte[] fieldObstruction)
        {
            if (!_isDirty || !IsReady)
            {
                return;
            }

            #if !UNITY_FLASH
            bool useNative = DynamicWaterNativeLibrary.CanUseNative;
            #else
            const bool useNative = false;
            #endif

            // Caching some values to avoid expensive calls
            bool isFieldObstructionNull = fieldObstruction == null;
            bool calculateNormals       = _settings.CalculateNormals;
            bool useFastNormals         = _settings.UseFastNormals;

            if (useNative)
            {
                #if !UNITY_FLASH
                DynamicWaterNativeLibrary.UpdateMesh(calculateNormals, useFastNormals, _nodeSize, _grid.x, _grid.y, field, fieldObstruction, _meshStruct.Vertices, _meshStruct.Normals);
                #endif
            }
            else
            {
                // We can't run native, run C# then
                Vector3 up             = Vector3.up;
                Vector3 normal         = up;
                float   doubleNodeSize = 2f * _nodeSize;

                // Minimal node value to calculate normals for (in case of using approximate normals).
                const float normalThreshold = 0.0001f;

                // If not using fast normals, then all we need is to update the vertices
                if (!useFastNormals)
                {
                    for (int j = 0; j < _grid.y; j++)
                    {
                        int index = j * _grid.x;
                        for (int i = 0; i < _grid.x; i++)
                        {
                            _meshStruct.Vertices[index].y = field[index];

                            index++;
                        }
                    }
                }
                else
                {
                    // Otherwise, calculate the normals too
                    for (int j = 0; j < _grid.y; j++)
                    {
                        int index = j * _grid.x;
                        for (int i = 0; i < _grid.x; i++)
                        {
                            if ((i == 0 || j == 0 || i >= _grid.x - 1 || j >= _grid.y - 1) || (!isFieldObstructionNull && fieldObstruction[index] == byte.MinValue))
                            {
                                normal = up;
                            }
                            else
                            {
                                float valAbs;
                                if (field[index] > 0f)
                                {
                                    valAbs = field[index];
                                }
                                else
                                {
                                    valAbs = -field[index];
                                }

                                if (valAbs > normalThreshold)
                                {
                                    normal.x = field[index - 1] - field[index + 1];
                                    normal.z = field[index - _grid.x] - field[index + _grid.x];
                                    normal.y = doubleNodeSize;

                                    // Fast approximate Vector3 normalization
                                    // See also: LostPolygon.DynamicWaterSystem.FastFunctions.FastInvSqrt()
                                    float invLength = normal.x * normal.x + normal.y * normal.y + normal.z * normal.z;
                                    FastFunctions.FloatIntUnion u;
                                    u.i = 0;
                                    u.f = invLength;
                                    float xhalf = 0.5f * invLength;
                                    u.i       = 0x5f3759df - (u.i >> 1);
                                    invLength = u.f * (1.5f - xhalf * u.f * u.f);

                                    normal.x *= invLength;
                                    normal.y *= invLength;
                                    normal.z *= invLength;
                                }
                                else
                                {
                                    normal = up;
                                }
                            }

                            _meshStruct.Normals[index] = normal;

                            _meshStruct.Vertices[index].y = field[index];
                            index++;
                        }
                    }
                }
            }


            // Actually updating the mesh
            _mesh.vertices = _meshStruct.Vertices;
            if (calculateNormals)
            {
                if (useFastNormals)
                {
                    _mesh.normals = _meshStruct.Normals;
                }
                else
                {
                    _mesh.RecalculateNormals();
                }
            }

            _isDirty = false;
        }