예제 #1
0
        public static LayerTranslator CreatePreCompLayerTranslator(PreCompLayerContext context)
        {
            // TODO - the animations produced inside a PreComp need to be time-mapped.

            // Create the transform chain.
            if (!Transforms.TryCreateContainerVisualTransformChain(context, out var rootNode, out var contentsNode))
            {
                // The layer is never visible.
                return(null);
            }

            var result = context.ObjectFactory.CreateContainerVisual();

#if !NoClipping
            // PreComps must clip to their size.
            // Create another ContainerVisual to apply clipping to.
            var clippingNode = context.ObjectFactory.CreateContainerVisual();
            contentsNode.Children.Add(clippingNode);
            contentsNode      = clippingNode;
            contentsNode.Clip = context.ObjectFactory.CreateInsetClip();
            contentsNode.Size = context.ChildrenCompositionContext.Size;
#endif

            // Add the translations of each layer to the clipping node. This will recursively
            // add the tranlation of the layers in nested precomps.
            var contentsChildren = contentsNode.Children;
            foreach (var visual in Layers.TranslateLayersToVisuals(context.ChildrenCompositionContext))
            {
                contentsChildren.Add(visual);
            }

            // Add mask if the layer has masks.
            // This must be done after all children are added to the content node.
            bool layerHasMasks = false;
#if !NoClipping
            layerHasMasks = context.Layer.Masks.Any();
#endif
            if (layerHasMasks)
            {
                var compositedVisual = Masks.TranslateAndApplyMasksForLayer(context, rootNode);

                result.Children.Add(compositedVisual);
            }
            else
            {
                result.Children.Add(rootNode);
            }

            return(new LayerTranslator.FromVisual(result));
        }
예제 #2
0
 static LayerCollection GetLayerCollectionByAssetId(PreCompLayerContext context, string assetId)
 => ((LayerCollectionAsset)context.Translation.GetAssetById(context, assetId, Asset.AssetType.LayerCollection))?.Layers;
예제 #3
0
        static LayerVisual ApplyDropShadow(PreCompLayerContext context, Visual visual, DropShadowEffect dropShadowEffect)
        {
            Debug.Assert(dropShadowEffect.IsEnabled, "Precondition");

            // Create a LayerVisual so we can add a drop shadow.
            var result = context.ObjectFactory.CreateLayerVisual();

            result.Children.Add(visual);

            // TODO: Due to a Composition bug, LayerVisual currently must be given a size for the drop
            // shadow to show up correctly. And even then it is not reliable.
            result.Size = context.CompositionContext.Size;

            var shadow = context.ObjectFactory.CreateDropShadow();

            result.Shadow       = shadow;
            shadow.SourcePolicy = CompositionDropShadowSourcePolicy.InheritFromVisualContent;

            var isShadowOnly = Optimizer.TrimAnimatable(context, dropShadowEffect.IsShadowOnly);

            if (!isShadowOnly.IsAlways(true))
            {
                context.Issues.ShadowOnlyShadowEffect();
            }

            // TODO - it's not clear whether BlurRadius and Softness are equivalent. We may
            //        need to scale Softness to convert it to BlurRadius.
            var blurRadius = Optimizer.TrimAnimatable(context, dropShadowEffect.Softness);

            if (blurRadius.IsAnimated)
            {
                Animate.Scalar(context, blurRadius, shadow, nameof(shadow.BlurRadius));
            }
            else
            {
                shadow.BlurRadius = (float)blurRadius.InitialValue;
            }

            var color = Optimizer.TrimAnimatable(context, dropShadowEffect.Color);

            if (color.IsAnimated)
            {
                Animate.Color(context, color, shadow, nameof(shadow.Color));
            }
            else
            {
                shadow.Color = ConvertTo.Color(color.InitialValue);
            }

            var opacity = Optimizer.TrimAnimatable(context, dropShadowEffect.Opacity);

            if (opacity.IsAnimated)
            {
                Animate.Opacity(context, opacity, shadow, nameof(shadow.Opacity));
            }
            else
            {
                shadow.Opacity = (float)opacity.InitialValue.Value;
            }

            // Convert direction and distance to a Vector3.
            var direction = Optimizer.TrimAnimatable(context, dropShadowEffect.Direction);
            var distance  = Optimizer.TrimAnimatable(context, dropShadowEffect.Distance);

            if (direction.IsAnimated)
            {
                if (distance.IsAnimated)
                {
                    // Direction and distance are animated.
                    // NOTE: we could support this in some cases. The worst cases are
                    //       where the keyframes don't line up, and/or the easings are different
                    //       between distance and direction.
                    context.Issues.AnimatedLayerEffectParameters("drop shadow");
                }
                else
                {
                    // Only direction is animated.
                    var distanceValue = distance.InitialValue;
                    var keyFrames     = direction.KeyFrames.Select(
                        kf => new KeyFrame <Vector3>(kf.Frame, VectorFromRotationAndDistance(kf.Value, distanceValue), kf.Easing)).ToArray();
                    var directionAnimation = new TrimmedAnimatable <Vector3>(context, keyFrames[0].Value, keyFrames);
                    Animate.Vector3(context, directionAnimation, shadow, nameof(shadow.Offset));
                }
            }
            else if (distance.IsAnimated)
            {
                // Only distance is animated.
                var directionRadians = direction.InitialValue.Radians;
                var keyFrames        = distance.KeyFrames.Select(
                    kf => new KeyFrame <Vector3>(kf.Frame, VectorFromRotationAndDistance(directionRadians, kf.Value), kf.Easing)).ToArray();
                var distanceAnimation = new TrimmedAnimatable <Vector3>(context, keyFrames[0].Value, keyFrames);
                Animate.Vector3(context, distanceAnimation, shadow, nameof(shadow.Offset));
            }
            else
            {
                // Direction and distance are both not animated.
                var directionRadians = direction.InitialValue.Radians;
                var distanceValue    = distance.InitialValue;

                shadow.Offset = ConvertTo.Vector3(VectorFromRotationAndDistance(direction.InitialValue, distance.InitialValue));
            }

            return(result);
        }
예제 #4
0
        internal static ContainerVisual ApplyGaussianBlur(
            PreCompLayerContext context,
            ContainerVisual source,
            GaussianBlurEffect gaussianBlurEffect)
        {
            Debug.Assert(gaussianBlurEffect.IsEnabled, "Precondition");

            var factory = context.ObjectFactory;

            if (!factory.IsUapApiAvailable(nameof(CompositionVisualSurface), versionDependentFeatureDescription: "Gaussian blur"))
            {
                // The effect can't be displayed on the targeted version.
                return(source);
            }

            // Gaussian blur:
            // +--------------+
            // | SpriteVisual | -- Has the final composited result.
            // +--------------+
            //     ^
            //     |
            // +--------------+
            // | EffectBrush  | -- Composition effect brush allows the composite effect result to be used as a brush.
            // +--------------+
            //     ^
            //     |
            // +--------------------+
            // | GaussianBlurEffect |
            // +--------------------+
            //     ^ Source
            //     |
            // +--------------+
            // | SurfaceBrush | -- Surface brush that will paint with the output of the VisualSurface
            // +--------------+    that has the source visual assigned to it.
            //      ^ CompositionEffectSourceParameter("source")
            //      |
            // +---------------+
            // | VisualSurface | -- The visual surface captures the renderable contents of its source visual.
            // +---------------+
            //      ^
            //      |
            //  +--------+
            //  | Visual | -- The layer translated to a Visual.
            //  +--------+
            var size = ConvertTo.Vector2(context.Layer.Width, context.Layer.Height);

            // Build from the bottom up.
            var visualSurface = factory.CreateVisualSurface();

            visualSurface.SourceVisual = source;
            visualSurface.SourceSize   = size;

            var surfaceBrush = factory.CreateSurfaceBrush(visualSurface);

            var effect = new WinCompData.Mgce.GaussianBlurEffect();

            var blurriness = Optimizer.TrimAnimatable(context, gaussianBlurEffect.Blurriness);

            if (blurriness.IsAnimated)
            {
                context.Issues.AnimatedLayerEffectParameters("Gaussian blur");
            }

            effect.BlurAmount = ConvertTo.Float(blurriness.InitialValue / 10.0);

            // We only support HorizontalAndVertical blur dimension.
            var blurDimensions            = Optimizer.TrimAnimatable(context, gaussianBlurEffect.BlurDimensions);
            var unsupportedBlurDimensions = blurDimensions
                                            .KeyFrames
                                            .Select(kf => kf.Value)
                                            .Distinct()
                                            .Where(v => v.Value != BlurDimension.HorizontalAndVertical).ToArray();

            foreach (var value in unsupportedBlurDimensions)
            {
                context.Issues.UnsupportedLayerEffectParameter("gaussian blur", "blur dimension", value.Value.ToString());
            }

            effect.Source = new CompositionEffectSourceParameter("source");

            var effectBrush = factory.CreateEffectFactory(effect).CreateBrush();

            effectBrush.SetSourceParameter("source", surfaceBrush);

            var result = factory.CreateSpriteVisual();

            result.Brush = effectBrush;
            result.Size  = size;

            return(result);
        }