public void MergeLeft(Heightmap leftTile, int transitionWidth)
        {
            if (leftTile == null)
            {
                throw new ArgumentNullException("leftTile");
            }
            if (leftTile.Width != Width || leftTile.Depth != Depth)
            {
                throw new ArgumentException("Tiles must have equal widths and depths", "leftTile");
            }

            if (transitionWidth >= Width)
            {
                throw new ArgumentException("Transition width must be less than tile width", "transitionWidth");
            }

            for (int x = 0; x < transitionWidth; x++)
            {
                for (int z = 0; z < Depth; z++)
                {
                    float leftEdgeHeight = leftTile.GetHeightValue(leftTile.Width - 1, z);
                    float originalHeight = GetHeightValue(x, z);
                    float newHeight      = MathHelper.Lerp(leftEdgeHeight, originalHeight, (float)x / (transitionWidth - 1));
                    SetHeightValue(x, z, newHeight);
                }
            }
        }
//        /// <summary>
//        /// Build a terrain patch.
//        /// </summary>
//        /// <param name="game"></param>
//        /// <param name="heightmap"></param>
//        /// <param name="worldMatrix"></param>
//        /// <param name="width"></param>
//        /// <param name="depth"></param>
//        /// <param name="offsetX"></param>
//        /// <param name="offsetZ"></param>
//        public static void BuildPatch(Game game, Heightmap heightmap, Matrix worldMatrix, int width, int depth, int offsetX, int offsetZ)
//        {
//
//        }

        /// <summary>
        /// Build the vertex buffer as well as the bounding box.
        /// </summary>
        /// <param name="heightmap"></param>
        private void BuildVertexBuffer(Heightmap heightmap)
        {
            int index = 0;

            _boundingBox.Min.Y = float.MaxValue;

            _boundingBox.Max.Y = float.MinValue;

            Geometry = new VertexPositionNormalTexture[Width * Depth];

            for (int z = _offsetZ; z < _offsetZ + Depth; ++z)
            {
                for (int x = _offsetX; x < _offsetX + Width; ++x)
                {
                    // We need to connect the patches by increasing each patch width and depth by 1,
                    // but this means the patches along some of the edges will run out of
                    // heightmap data, so make sure we cap the index at the edge
                    int cappedX = Math.Min(x, heightmap.Width - 1);
                    int cappedZ = Math.Min(z, heightmap.Depth - 1);

                    float height = heightmap.GetHeightValue(cappedX, cappedZ);

                    if (height < _boundingBox.Min.Y)
                    {
                        _boundingBox.Min.Y = height;
                    }

                    if (height > _boundingBox.Max.Y)
                    {
                        _boundingBox.Max.Y = height;
                    }

                    var position = new Vector3(x, height, z);

                    Vector3 normal;
                    ComputeVertexNormal(heightmap, cappedX, cappedZ, out normal);

                    Geometry[index] = new VertexPositionNormalTexture(position, normal, new Vector2(x, z));

                    ++index;
                }
            }
        }
        /// <summary>
        /// Add two heightmaps together.
        /// </summary>
        /// <param name="heightmap"></param>
        public void AddHeightmap(Heightmap heightmap)
        {
            // Reject the heightmap if it doesn't fit.
            if ((_width != heightmap.Width) ||
                (_depth != heightmap.Depth) ||
                (_minimumHeight != heightmap.MinimumHeight) ||
                (_maximumHeight != heightmap.MaximumHeight))
            {
                return;
            }

            // Add the heightmaps together.
            for (int x = 0; x < _width; ++x)
            {
                for (int z = 0; z < _depth; ++z)
                {
                    _heightValues[x + z * _width] = _heightValues[x + z * _width] + heightmap.GetHeightValue(x, z);
                }
            }
        }
        /// <summary>
        /// Combine the heightmap with the passed heightmap.
        /// The amount variable is the ratio of the heightmap passed as a parameter.
        /// </summary>
        /// <param name="heightmap"></param>
        /// <param name="amount"></param>
        public void CombineHeightmap(Heightmap heightmap, float amount)
        {
            // Reject the heightmap if it doesn't fit.
            if ((_width != heightmap.Width) ||
                (_depth != heightmap.Depth) ||
                (_minimumHeight != heightmap.MinimumHeight) ||
                (_maximumHeight != heightmap.MaximumHeight))
            {
                return;
            }

            // Combine the heightmaps.
            // H1 = H1 * (1.0f - amount) + H2 * amount
            for (int x = 0; x < _width; ++x)
            {
                for (int z = 0; z < _depth; ++z)
                {
                    _heightValues[x + z * _width] = _heightValues[x + z * _width] * (1.0f - amount) +
                                                    heightmap.GetHeightValue(x, z) * amount;
                }
            }
        }
        /// <summary>
        /// Combine the heightmap with the passed heightmap.
        /// The amount variable is the ratio of the heightmap passed as a parameter.
        /// </summary>
        /// <param name="heightmap"></param>
        /// <param name="amount"></param>
        public void CombineHeightmap(Heightmap heightmap, float amount)
        {
            // Reject the heightmap if it doesn't fit.
            if ((_width != heightmap.Width) ||
                (_depth != heightmap.Depth) ||
                (_minimumHeight != heightmap.MinimumHeight) ||
                (_maximumHeight != heightmap.MaximumHeight))
            {
                return;
            }

            // Combine the heightmaps.
            // H1 = H1 * (1.0f - amount) + H2 * amount
            for (int x = 0; x < _width; ++x)
            {
                for (int z = 0; z < _depth; ++z)
                {
                    _heightValues[x + z*_width] = _heightValues[x + z*_width]*(1.0f - amount) +
                                                  heightmap.GetHeightValue(x, z)*amount;
                }
            }
        }
        /// <summary>
        /// Add two heightmaps together.
        /// </summary>
        /// <param name="heightmap"></param>
        public void AddHeightmap(Heightmap heightmap)
        {
            // Reject the heightmap if it doesn't fit.
            if ((_width != heightmap.Width) ||
                (_depth != heightmap.Depth) ||
                (_minimumHeight != heightmap.MinimumHeight) ||
                (_maximumHeight != heightmap.MaximumHeight))
            {
                return;
            }

            // Add the heightmaps together.
            for (int x = 0; x < _width; ++x)
            {
                for (int z = 0; z < _depth; ++z)
                {
                    _heightValues[x + z*_width] = _heightValues[x + z*_width] + heightmap.GetHeightValue(x, z);
                }
            }
        }
        public void MergeLeft(Heightmap leftTile, int transitionWidth)
        {
            if (leftTile == null) throw new ArgumentNullException("leftTile");
            if (leftTile.Width != Width || leftTile.Depth != Depth)
                throw new ArgumentException("Tiles must have equal widths and depths", "leftTile");

            if (transitionWidth >= Width)
                throw new ArgumentException("Transition width must be less than tile width", "transitionWidth");

            for (int x = 0; x < transitionWidth; x++)
            {
                for (int z = 0; z < Depth; z++)
                {
                    float leftEdgeHeight = leftTile.GetHeightValue(leftTile.Width - 1, z);
                    float originalHeight = GetHeightValue(x, z);
                    float newHeight = MathHelper.Lerp(leftEdgeHeight, originalHeight, (float) x/(transitionWidth - 1));
                    SetHeightValue(x, z, newHeight);
                }
            }
        }
        /// <summary>
        /// Compute vertex normal at the given x,z coordinate.
        /// </summary>
        /// <param name="heightmap"></param>
        /// <param name="x"></param>
        /// <param name="z"></param>
        /// <param name="normal"></param>
        private static void ComputeVertexNormal(Heightmap heightmap, int x, int z, out Vector3 normal)
        {
            int width = heightmap.Width;
            int depth = heightmap.Depth;

            Vector3 p1;
            Vector3 p2;
            Vector3 avgNormal = Vector3.Zero;

            int avgCount = 0;

            bool spaceAbove = false;
            bool spaceBelow = false;
            bool spaceLeft  = false;
            bool spaceRight = false;

            Vector3 tmpNormal;
            Vector3 v1;
            Vector3 v2;

            var center = new Vector3(x, heightmap.GetHeightValue(x, z), z);

            if (x > 0)
            {
                spaceLeft = true;
            }

            if (x < width - 1)
            {
                spaceRight = true;
            }

            if (z > 0)
            {
                spaceAbove = true;
            }

            if (z < depth - 1)
            {
                spaceBelow = true;
            }

            if (spaceAbove && spaceLeft)
            {
                p1 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z), z);
                p2 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z - 1), z - 1);

                v1 = p1 - center;
                v2 = p2 - p1;

                tmpNormal  = Vector3.Cross(v1, v2);
                avgNormal += tmpNormal;

                ++avgCount;
            }

            if (spaceAbove && spaceRight)
            {
                p1 = new Vector3(x, heightmap.GetHeightValue(x, z - 1), z - 1);
                p2 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z - 1), z - 1);

                v1 = p1 - center;
                v2 = p2 - p1;

                tmpNormal  = Vector3.Cross(v1, v2);
                avgNormal += tmpNormal;

                ++avgCount;
            }

            if (spaceBelow && spaceRight)
            {
                p1 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z), z);
                p2 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z + 1), z + 1);

                v1 = p1 - center;
                v2 = p2 - p1;

                tmpNormal  = Vector3.Cross(v1, v2);
                avgNormal += tmpNormal;

                ++avgCount;
            }

            if (spaceBelow && spaceLeft)
            {
                p1 = new Vector3(x, heightmap.GetHeightValue(x, z + 1), z + 1);
                p2 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z + 1), z + 1);

                v1 = p1 - center;
                v2 = p2 - p1;

                tmpNormal  = Vector3.Cross(v1, v2);
                avgNormal += tmpNormal;

                ++avgCount;
            }

            normal = avgNormal / avgCount;
        }
        //        /// <summary>
        //        /// Build a terrain patch.
        //        /// </summary>
        //        /// <param name="game"></param>
        //        /// <param name="heightmap"></param>
        //        /// <param name="worldMatrix"></param>
        //        /// <param name="width"></param>
        //        /// <param name="depth"></param>
        //        /// <param name="offsetX"></param>
        //        /// <param name="offsetZ"></param>
        //        public static void BuildPatch(Game game, Heightmap heightmap, Matrix worldMatrix, int width, int depth, int offsetX, int offsetZ)
        //        {
        //            
        //        }
        /// <summary>
        /// Build the vertex buffer as well as the bounding box.
        /// </summary>
        /// <param name="heightmap"></param>
        private void BuildVertexBuffer(Heightmap heightmap)
        {
            int index = 0;

            _boundingBox.Min.Y = float.MaxValue;

            _boundingBox.Max.Y = float.MinValue;

            Geometry = new VertexPositionNormalTexture[Width*Depth];

            for (int z = _offsetZ; z < _offsetZ + Depth; ++z)
            {
                for (int x = _offsetX; x < _offsetX + Width; ++x)
                {
                    // We need to connect the patches by increasing each patch width and depth by 1,
                    // but this means the patches along some of the edges will run out of
                    // heightmap data, so make sure we cap the index at the edge
                    int cappedX = Math.Min(x, heightmap.Width - 1);
                    int cappedZ = Math.Min(z, heightmap.Depth - 1);

                    float height = heightmap.GetHeightValue(cappedX, cappedZ);

                    if (height < _boundingBox.Min.Y)
                    {
                        _boundingBox.Min.Y = height;
                    }

                    if (height > _boundingBox.Max.Y)
                    {
                        _boundingBox.Max.Y = height;
                    }

                    var position = new Vector3(x, height, z);

                    Vector3 normal;
                    ComputeVertexNormal(heightmap, cappedX, cappedZ, out normal);

                    Geometry[index] = new VertexPositionNormalTexture(position, normal, new Vector2(x, z));

                    ++index;
                }
            }
        }
        /// <summary>
        /// Compute vertex normal at the given x,z coordinate.
        /// </summary>
        /// <param name="heightmap"></param>
        /// <param name="x"></param>
        /// <param name="z"></param>
        /// <param name="normal"></param>
        private static void ComputeVertexNormal(Heightmap heightmap, int x, int z, out Vector3 normal)
        {
            int width = heightmap.Width;
            int depth = heightmap.Depth;

            Vector3 p1;
            Vector3 p2;
            Vector3 avgNormal = Vector3.Zero;

            int avgCount = 0;

            bool spaceAbove = false;
            bool spaceBelow = false;
            bool spaceLeft = false;
            bool spaceRight = false;

            Vector3 tmpNormal;
            Vector3 v1;
            Vector3 v2;

            var center = new Vector3(x, heightmap.GetHeightValue(x, z), z);

            if (x > 0)
            {
                spaceLeft = true;
            }

            if (x < width - 1)
            {
                spaceRight = true;
            }

            if (z > 0)
            {
                spaceAbove = true;
            }

            if (z < depth - 1)
            {
                spaceBelow = true;
            }

            if (spaceAbove && spaceLeft)
            {
                p1 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z), z);
                p2 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z - 1), z - 1);

                v1 = p1 - center;
                v2 = p2 - p1;

                tmpNormal = Vector3.Cross(v1, v2);
                avgNormal += tmpNormal;

                ++avgCount;
            }

            if (spaceAbove && spaceRight)
            {
                p1 = new Vector3(x, heightmap.GetHeightValue(x, z - 1), z - 1);
                p2 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z - 1), z - 1);

                v1 = p1 - center;
                v2 = p2 - p1;

                tmpNormal = Vector3.Cross(v1, v2);
                avgNormal += tmpNormal;

                ++avgCount;
            }

            if (spaceBelow && spaceRight)
            {
                p1 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z), z);
                p2 = new Vector3(x + 1, heightmap.GetHeightValue(x + 1, z + 1), z + 1);

                v1 = p1 - center;
                v2 = p2 - p1;

                tmpNormal = Vector3.Cross(v1, v2);
                avgNormal += tmpNormal;

                ++avgCount;
            }

            if (spaceBelow && spaceLeft)
            {
                p1 = new Vector3(x, heightmap.GetHeightValue(x, z + 1), z + 1);
                p2 = new Vector3(x - 1, heightmap.GetHeightValue(x - 1, z + 1), z + 1);

                v1 = p1 - center;
                v2 = p2 - p1;

                tmpNormal = Vector3.Cross(v1, v2);
                avgNormal += tmpNormal;

                ++avgCount;
            }

            normal = avgNormal/avgCount;
        }