/// <summary>Tessellates a Scene object into triangles.</summary>
        /// <param name="node">The root node of the hierarchy to tessellate</param>
        /// <param name="tessellationOptions">The tessellation options</param>
        /// <param name="nodeOpacities">If provided, the resulting node opacities</param>
        /// <returns>A list of tesselated geometry</returns>
        public static List <Geometry> TessellateScene(Scene scene, TessellationOptions tessellationOptions, Dictionary <SceneNode, float> nodeOpacities = null)
        {
            UnityEngine.Profiling.Profiler.BeginSample("TessellateVectorScene");

            VectorClip.ResetClip();
            var geoms = TessellateNodeHierarchyRecursive(scene.Root, tessellationOptions, scene.Root.Transform, 1.0f, nodeOpacities);

            UnityEngine.Profiling.Profiler.EndSample();

            return(geoms);
        }
        #pragma warning disable 612, 618 // Silence use of deprecated IDrawable
        private static List <Geometry> TessellateNodeHierarchyRecursive(SceneNode node, TessellationOptions tessellationOptions, Matrix2D worldTransform, float worldOpacity, Dictionary <SceneNode, float> nodeOpacities)
        {
            if (node.Clipper != null)
            {
                VectorClip.PushClip(TraceNodeHierarchyShapes(node.Clipper, tessellationOptions), worldTransform);
            }

            var geoms = new List <Geometry>();

            if (node.Shapes != null)
            {
                foreach (var shape in node.Shapes)
                {
                    bool isConvex = shape.IsConvex && shape.Contours.Length == 1;
                    TessellateShape(shape, geoms, tessellationOptions, isConvex);
                }
            }

            foreach (var g in geoms)
            {
                g.Color.a        *= worldOpacity;
                g.WorldTransform  = worldTransform;
                g.UnclippedBounds = Bounds(g.Vertices);

                VectorClip.ClipGeometry(g);
            }

            if (node.Children != null)
            {
                foreach (var child in node.Children)
                {
                    var childOpacity = 1.0f;
                    if (nodeOpacities == null || !nodeOpacities.TryGetValue(child, out childOpacity))
                    {
                        childOpacity = 1.0f;
                    }

                    var transform  = worldTransform * child.Transform;
                    var opacity    = worldOpacity * childOpacity;
                    var childGeoms = TessellateNodeHierarchyRecursive(child, tessellationOptions, transform, opacity, nodeOpacities);

                    geoms.AddRange(childGeoms);
                }
            }

            if (node.Clipper != null)
            {
                VectorClip.PopClip();
            }

            return(geoms);
        }
        #pragma warning disable 612, 618 // Silence use of deprecated IDrawable
        private static List <Geometry> TessellateNodeHierarchyRecursive(SceneNode node, TessellationOptions tessellationOptions, Matrix2D worldTransform, float worldOpacity, Dictionary <SceneNode, float> nodeOpacities)
        {
            if (node.Clipper != null)
            {
                VectorClip.PushClip(TraceNodeHierarchyShapes(node.Clipper, tessellationOptions), worldTransform);
            }

            var geoms = new List <Geometry>();

            if (node.Drawables != null)
            {
                // We process the drawables even though they are obsolete, until we remove the IDrawable interface entirely
                foreach (var drawable in node.Drawables)
                {
                    var vectorShape = drawable as Shape;
                    if (vectorShape != null)
                    {
                        bool isConvex = vectorShape.IsConvex && vectorShape.Contours.Length == 1;
                        TessellateShape(vectorShape, geoms, tessellationOptions, isConvex);
                        continue;
                    }

                    var vectorPath = drawable as Path;
                    if (vectorPath != null)
                    {
                        TessellatePath(vectorPath.Contour, vectorPath.PathProps, geoms, tessellationOptions);
                        continue;
                    }

                    var vectorRect = drawable as Rectangle;
                    if (vectorRect != null)
                    {
                        TessellateRectangle(vectorRect, geoms, tessellationOptions);
                        continue;
                    }
                }
            }

            if (node.Shapes != null)
            {
                foreach (var shape in node.Shapes)
                {
                    bool isConvex = shape.IsConvex && shape.Contours.Length == 1;
                    TessellateShape(shape, geoms, tessellationOptions, isConvex);
                }
            }

            foreach (var g in geoms)
            {
                g.Color.a        *= worldOpacity;
                g.WorldTransform  = worldTransform;
                g.UnclippedBounds = Bounds(g.Vertices);

                VectorClip.ClipGeometry(g);
            }

            if (node.Children != null)
            {
                foreach (var child in node.Children)
                {
                    var childOpacity = 1.0f;
                    if (nodeOpacities == null || !nodeOpacities.TryGetValue(child, out childOpacity))
                    {
                        childOpacity = 1.0f;
                    }

                    var transform  = worldTransform * child.Transform;
                    var opacity    = worldOpacity * childOpacity;
                    var childGeoms = TessellateNodeHierarchyRecursive(child, tessellationOptions, transform, opacity, nodeOpacities);

                    geoms.AddRange(childGeoms);
                }
            }

            if (node.Clipper != null)
            {
                VectorClip.PopClip();
            }

            return(geoms);
        }