/// <summary>
        /// Parse one layer. Drill down recursively for groups.
        /// </summary>
        private static Layer ParseLayer(dynamic l)
        {
            if (l == null)
            {
                return(null);
            }

            Layer     layer;
            LayerType type = ParseEnum <LayerType>(l.Type);

            switch (type)
            {
            case LayerType.Group:
            {
                layer = new LayerGroup();
                LayerGroup lg = layer as LayerGroup;
                foreach (var c in l.Implementation.Children)
                {
                    Layer child = ParseLayer(c);
                    if (child != null)
                    {
                        lg.Children.Add(child);
                    }
                }

                break;
            }

            case LayerType.Paint:
            {
                layer = new LayerPaint();
                LayerPaint lp = layer as LayerPaint;

                lp.Framerate      = ParseInt(l.Implementation.Framerate, lp.Framerate);
                lp.MaxRepeatCount = ParseInt(l.Implementation.MaxRepeatCount, lp.MaxRepeatCount);

                if (l.Implementation.Drawings != null && l.Implementation.Frames != null)
                {
                    foreach (var d in l.Implementation.Drawings)
                    {
                        Drawing drawing = ParseDrawing(d);
                        if (drawing != null)
                        {
                            lp.Drawings.Add(drawing);
                        }
                    }
                    lp.Frames = l.Implementation.Frames.ToObject <List <int> >();
                }
                else if (l.Implementation.BoundingBox != null && l.Implementation.DataFileOffset != null)
                {
                    // Old format from Quill 1.3, circa 2017, before animations.
                    Drawing drawing = new Drawing();
                    drawing.BoundingBox = ParseBoundingBox(l.Implementation.BoundingBox);
                    long offset;
                    bool parsed = long.TryParse((string)l.Implementation.DataFileOffset.ToObject(typeof(string)), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out offset);
                    drawing.DataFileOffset = parsed ? offset : -1;
                    lp.Drawings.Add(drawing);
                    lp.Frames.Add(0);
                }
                break;
            }

            case LayerType.Viewpoint:
            {
                layer = new LayerViewpoint();
                LayerViewpoint lv = layer as LayerViewpoint;
                lv.Version           = l.Implementation.Version;
                lv.Color             = ParseColor(l.Implementation.Color);
                lv.Sphere            = ParseVector4(l.Implementation.Sphere);
                lv.AllowTranslationX = l.Implementation.AllowTranslationX;
                lv.AllowTranslationY = l.Implementation.AllowTranslationY;
                lv.AllowTranslationZ = l.Implementation.AllowTranslationZ;
                lv.Exporting         = l.Implementation.Exporting;
                lv.ShowingVolume     = l.Implementation.ShowingVolume;
                lv.TypeStr           = l.Implementation.TypeStr;
                break;
            }

            case LayerType.Camera:
            {
                layer = new LayerCamera();
                LayerCamera lc = layer as LayerCamera;
                lc.FOV = l.Implementation.FOV;
                break;
            }

            case LayerType.Model:
            case LayerType.Picture:
            case LayerType.Sound:
            case LayerType.Unknown:
            default:
                layer = null;
                break;
            }

            if (layer != null)
            {
                ParseLayerCommon(layer, l);
            }

            return(layer);
        }