/// <inheritdoc />
        public override IGameObject BuildWay(Tile tile, Rule rule, Way way)
        {
            if (way.Points.Count < 2)
            {
                Trace.Warn("model.barrier", Strings.InvalidPolyline);
                return(null);
            }

            if (tile.Registry.Contains(way.Id))
            {
                return(null);
            }

            tile.Registry.RegisterGlobal(way.Id);

            var gameObjectWrapper = GameObjectFactory.CreateNew(GetName(way));
            var maxWidth          = 4f;

            var points = ObjectPool.NewList <Vector2d>(way.Points.Count);

            PointUtils.SetPolygonPoints(tile.RelativeNullPoint, way.Points, points);

            var vertexCount = GetVertexCount(points, maxWidth);
            var meshIndex   = new MultiPlaneMeshIndex(points.Count - 1, vertexCount);
            var meshData    = new MeshData(meshIndex, vertexCount)
            {
                MaterialKey = rule.GetMaterialKey(),
                GameObject  = gameObjectWrapper,
            };

            meshData.Index = meshIndex;
            var context = new SegmentBuilderContext()
            {
                MeshData       = meshData,
                Gradient       = CustomizationService.GetGradient(rule.GetFillColor()),
                ColorNoiseFreq = rule.GetColorNoiseFreq(),
                Height         = rule.GetHeight(),
                MaxWidth       = maxWidth,
            };

            var index = 0;

            for (int i = 0; i < points.Count - 1; i++)
            {
                var p1 = points[i];
                var p2 = points[i + 1];

                var start = new Vector3((float)p1.X, ElevationProvider.GetElevation(p1), (float)p1.Y);
                var end   = new Vector3((float)p2.X, ElevationProvider.GetElevation(p2), (float)p2.Y);

                meshIndex.AddPlane(new Vector3((float)p1.X, 0, (float)p1.Y), start, end, meshData.NextIndex);

                BuildBarrierSegment(context, start, end, ref index);
            }
            ObjectPool.StoreList(points);
            BuildObject(tile.GameObject, meshData, rule, way);

            return(gameObjectWrapper);
        }
        private void BuildBarrierSegment(SegmentBuilderContext context, Vector3 start, Vector3 end,
                                         ref int startIndex)
        {
            var distance  = Vector3.Distance(start, end);
            var direction = (end - start).normalized;

            var stepCount = (int)Math.Ceiling(distance / context.MaxWidth);
            var width     = distance / stepCount;

            var startEle = ElevationProvider.GetElevation(start.x, start.z);

            // read context properties
            var gradient       = context.Gradient;
            var colorNoiseFreq = context.ColorNoiseFreq;
            var vertCount      = context.MeshData.Vertices.Length / 2;
            var vertices       = context.MeshData.Vertices;
            var triangles      = context.MeshData.Triangles;
            var colors         = context.MeshData.Colors;

            for (int z = 0; z < stepCount; z++)
            {
                // get next points
                end = start + direction * width;
                var   middle = start + direction * (0.5f * width);
                float endEle = ElevationProvider.GetElevation(end.x, end.z);

                var p0 = new Vector3(start.x, startEle, start.z);
                var p1 = new Vector3(end.x, endEle, end.z);
                var p2 = new Vector3(end.x, endEle + context.Height, end.z);
                var p3 = new Vector3(start.x, startEle + context.Height, start.z);
                var pc = new Vector3(middle.x, startEle + context.Height / 2, middle.z);

                var count = startIndex;

                #region Vertices
                vertices[count]             = p3;
                vertices[count + vertCount] = p3;
                vertices[++count]           = p0;
                vertices[count + vertCount] = p0;
                vertices[++count]           = pc;
                vertices[count + vertCount] = pc;

                vertices[++count]           = p0;
                vertices[count + vertCount] = p0;
                vertices[++count]           = p1;
                vertices[count + vertCount] = p1;
                vertices[++count]           = pc;
                vertices[count + vertCount] = pc;

                vertices[++count]           = p1;
                vertices[count + vertCount] = p1;
                vertices[++count]           = p2;
                vertices[count + vertCount] = p2;
                vertices[++count]           = pc;
                vertices[count + vertCount] = pc;

                vertices[++count]           = p2;
                vertices[count + vertCount] = p2;
                vertices[++count]           = p3;
                vertices[count + vertCount] = p3;
                vertices[++count]           = pc;
                vertices[count + vertCount] = pc;
                #endregion

                #region Triangles
                // triangles for outer part
                for (int i = startIndex; i < startIndex + 12; i++)
                {
                    triangles[i] = i;
                }

                var lastIndex = startIndex + vertCount + 12;
                for (int i = startIndex + vertCount; i < lastIndex; i++)
                {
                    var rest = i % 3;
                    triangles[i] = rest == 0 ? i : (rest == 1 ? i + 1 : i - 1);
                }
                #endregion

                #region Colors
                count = startIndex;
                var color = GetColor(gradient, colorNoiseFreq, p3);
                colors[count]             = color;
                colors[count + vertCount] = color;
                colors[++count]           = color;
                colors[count + vertCount] = color;
                colors[++count]           = color;
                colors[count + vertCount] = color;

                color                     = GetColor(gradient, colorNoiseFreq, p0);
                colors[++count]           = color;
                colors[count + vertCount] = color;
                colors[++count]           = color;
                colors[count + vertCount] = color;
                colors[++count]           = color;
                colors[count + vertCount] = color;

                color                     = GetColor(gradient, colorNoiseFreq, p1);
                colors[++count]           = color;
                colors[count + vertCount] = color;
                colors[++count]           = color;
                colors[count + vertCount] = color;
                colors[++count]           = color;
                colors[count + vertCount] = color;

                color                     = GetColor(gradient, colorNoiseFreq, p2);
                colors[++count]           = color;
                colors[count + vertCount] = color;
                colors[++count]           = color;
                colors[count + vertCount] = color;
                colors[++count]           = color;
                colors[count + vertCount] = color;
                #endregion

                // reuse last
                start       = end;
                startEle    = endEle;
                startIndex += 12;
            }
        }