/// <summary>
        /// Animates a point light and it's distance.
        /// </summary>
        /// <param name="animationSet">The animation set.</param>
        /// <param name="distance">The distance of the light.</param>
        /// <param name="duration">The duration in milliseconds.</param>
        /// <param name="delay">The delay. (ignored if duration == 0)</param>
        /// <seealso cref="IsLightingSupported" />
        /// <returns>
        /// An Animation Set.
        /// </returns>
        public static AnimationSet Light(
            this AnimationSet animationSet,
            double distance = 0d,
            double duration = 500d,
            double delay    = 0d)
        {
            if (!IsLightingSupported)
            {
                return(null);
            }

            if (animationSet == null)
            {
                return(null);
            }

            var visual           = animationSet.Visual;
            var associatedObject = animationSet.Element as FrameworkElement;

            if (associatedObject == null)
            {
                return(animationSet);
            }

            var compositor = visual?.Compositor;

            if (compositor == null)
            {
                return(null);
            }

            var task = new AnimationTask();

            task.AnimationSet = animationSet;

            task.Task = DispatcherHelper.ExecuteOnUIThreadAsync(
                () =>
            {
                const string sceneName = "PointLightScene";
                PointLight pointLight;
                CompositionDrawingSurface normalMap = null;

                if (!pointLights.ContainsKey(visual))
                {
                    SurfaceLoader.Initialize(compositor);
                    normalMap = SurfaceLoader.LoadText(string.Empty, new Windows.Foundation.Size(512, 512), new Graphics.Canvas.Text.CanvasTextFormat(), Colors.Transparent, Colors.Transparent);
                }

                if (pointLights.ContainsKey(visual))
                {
                    pointLight = pointLights[visual];
                }
                else
                {
                    pointLight = compositor.CreatePointLight();

                    var normalBrush     = compositor.CreateSurfaceBrush(normalMap);
                    normalBrush.Stretch = CompositionStretch.Fill;

                    // check to see if the visual already has a point light applied.
                    var spriteVisual = ElementCompositionPreview.GetElementChildVisual(associatedObject) as SpriteVisual;
                    var normalsBrush = spriteVisual?.Brush as CompositionEffectBrush;

                    if (normalsBrush == null || normalsBrush.Comment != sceneName)
                    {
                        var lightEffect = new CompositeEffect()
                        {
                            Mode    = CanvasComposite.Add,
                            Sources =
                            {
                                new CompositionEffectSourceParameter("ImageSource"),
                                new SceneLightingEffect()
                                {
                                    Name            = sceneName,
                                    AmbientAmount   = 0,
                                    DiffuseAmount   = 0.5f,
                                    SpecularAmount  = 0,
                                    NormalMapSource = new CompositionEffectSourceParameter("NormalMap"),
                                }
                            }
                        };

                        var effectFactory = compositor.CreateEffectFactory(lightEffect);
                        var brush         = effectFactory.CreateBrush();
                        brush.SetSourceParameter("NormalMap", normalBrush);

                        var sprite     = compositor.CreateSpriteVisual();
                        sprite.Size    = visual.Size;
                        sprite.Brush   = brush;
                        sprite.Comment = sceneName;

                        ElementCompositionPreview.SetElementChildVisual(task.AnimationSet.Element, sprite);

                        pointLight.CoordinateSpace = visual;
                        pointLight.Targets.Add(visual);
                    }
                }

                var delayTime    = task.Delay != null ? task.Delay.Value : TimeSpan.FromMilliseconds(delay);
                var durationTime = task.Duration != null ? task.Duration.Value : TimeSpan.FromMilliseconds(duration);

                if (durationTime.TotalMilliseconds <= 0)
                {
                    task.AnimationSet.AddEffectDirectPropertyChange(pointLight, (float)distance, nameof(pointLight.Offset));
                }
                else
                {
                    var diffuseAnimation = compositor.CreateVector3KeyFrameAnimation();
                    diffuseAnimation.InsertKeyFrame(1f, new System.Numerics.Vector3(visual.Size.X / 2, visual.Size.Y / 2, (float)distance));
                    diffuseAnimation.Duration  = durationTime;
                    diffuseAnimation.DelayTime = delayTime;

                    task.AnimationSet.AddCompositionEffectAnimation(pointLight, diffuseAnimation, nameof(pointLight.Offset));
                }

                pointLights[visual] = pointLight;
            }, Windows.UI.Core.CoreDispatcherPriority.Normal);

            animationSet.AddAnimationThroughTask(task);
            return(animationSet);
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Adds a <see cref="AnimationTask"/> to the AnimationSet that
 /// will run add an animation once completed. Usefull when an animation
 /// needs to do asyncronous initialization before running
 /// </summary>
 /// <param name="animationTask">The <see cref="AnimationTask"/> to be added</param>
 internal void AddAnimationThroughTask(AnimationTask animationTask)
 {
     _animationTasks.Add(animationTask);
 }