/// <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); }
/// <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); }