diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/App.xaml b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/App.xaml
new file mode 100644
index 000000000..49a2ff313
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/App.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/App.xaml.cs b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/App.xaml.cs
new file mode 100644
index 000000000..99a5cacba
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/App.xaml.cs
@@ -0,0 +1,65 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+using Microsoft.UI.Xaml.Shapes;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.ApplicationModel;
+using Windows.ApplicationModel.Activation;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace DepthDemo
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ public partial class App : Application
+ {
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ }
+
+ ///
+ /// Invoked when the application is launched normally by the end user. Other entry points
+ /// will be used such as when the application is launched to open a specific file.
+ ///
+ /// Details about the launch request and process.
+ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
+ {
+ m_window = new MainWindow();
+ m_window.Activate();
+ }
+
+ private Window m_window;
+ }
+}
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/DepthDemoApp.csproj b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/DepthDemoApp.csproj
new file mode 100644
index 000000000..afbcb0e75
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/DepthDemoApp.csproj
@@ -0,0 +1,24 @@
+
+
+ WinExe
+ net8.0-windows10.0.19041.0
+ 10.0.17763.0
+ DepthDemo
+ app.manifest
+ x86;x64;arm64
+ win-x86;win-x64;win-arm64
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/DepthTreatmentConfigurations.cs b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/DepthTreatmentConfigurations.cs
new file mode 100644
index 000000000..7af395983
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/DepthTreatmentConfigurations.cs
@@ -0,0 +1,133 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI;
+using Microsoft.UI.Composition;
+using System;
+using System.Numerics;
+using Windows.UI;
+
+namespace DepthDemo
+{
+ ///
+ /// Configuration for constant values that are consistent across all scenarios
+ ///
+ class ConfigurationConstants
+ {
+ public ConfigurationConstants() { }
+
+ public static int ZOffsetSpacingIncrement = 20;
+
+ public static Color ShadowColor = Colors.DarkSlateGray;
+
+ public static TimeSpan FocusAnimationDuration = TimeSpan.FromSeconds(0.5);
+ public static TimeSpan NavAnimationDuration = TimeSpan.FromSeconds(0.25);
+
+ public static float ShadowOpacity = 0.7f;
+
+ public static float BlurFocusFloat = 10.0f;
+ }
+
+
+ public class DepthTreatmentConfigurations
+ {
+ private Layer _associatedLayer;
+
+ public Vector3 ChildScale { get; set; }
+
+ public ShadowTreatment ShadowTreatment { get; set; }
+
+ // Focus treatment increase for top layer objects
+ private float _focusScaleIncreaseFactor;
+
+ public DepthTreatmentConfigurations(Layer associatedLayer, Vector3 childScale, float focusScaleIncreaseFactor, ShadowTreatment shadowTreatment = null)
+ {
+ _associatedLayer = associatedLayer;
+ _focusScaleIncreaseFactor = focusScaleIncreaseFactor;
+ ChildScale = childScale;
+ ShadowTreatment = shadowTreatment;
+ }
+
+ public CompositionAnimationGroup GetVisualFocusAnimations(Compositor compositor, Layer layer)
+ {
+ var oldscale = ChildScale;
+ var newScale = new Vector3(oldscale.X * _focusScaleIncreaseFactor, oldscale.Y * _focusScaleIncreaseFactor, oldscale.Z);
+
+ // Create AnimationGroup
+ CompositionAnimationGroup animationGroup = compositor.CreateAnimationGroup();
+
+ // Scale
+ Vector3KeyFrameAnimation scaleAnimation = compositor.CreateVector3KeyFrameAnimation();
+ scaleAnimation.InsertKeyFrame(0.0f, oldscale);
+ scaleAnimation.InsertKeyFrame(1.0f, newScale);
+ scaleAnimation.Duration = ConfigurationConstants.FocusAnimationDuration;
+ scaleAnimation.Target = "Scale";
+ animationGroup.Add(scaleAnimation);
+
+ return animationGroup;
+ }
+ }
+
+
+ public class ShadowTreatment
+ {
+ public Color ShadowColor { get { return ConfigurationConstants.ShadowColor; } }
+ public int BlurRadius { get; set; }
+ public Vector3 Offset { get; set; }
+
+ private int _focusShadowBlurRadiusIncreaseAmount;
+ private int _focusShadowOffsetIncreaseAmount;
+
+ public ShadowTreatment(int blurRadius, Vector3 offset, int focusShadowBlurRadiusIncrease,
+ int focusShadowOffsetIncrease)
+ {
+ BlurRadius = blurRadius;
+ Offset = offset;
+
+ _focusShadowBlurRadiusIncreaseAmount = focusShadowBlurRadiusIncrease;
+ _focusShadowOffsetIncreaseAmount = focusShadowOffsetIncrease;
+ }
+
+ public CompositionAnimationGroup GetShadowFocusAnimations(Compositor compositor, Layer layer)
+ {
+ var newShadowBlurRadius = BlurRadius + _focusShadowBlurRadiusIncreaseAmount;
+ var oldShadowOffset = Offset;
+ var additionalShadowOffsetAmount = _focusShadowOffsetIncreaseAmount;
+ var newShadowOffset = new Vector3(oldShadowOffset.X + additionalShadowOffsetAmount, oldShadowOffset.Y +
+ additionalShadowOffsetAmount, oldShadowOffset.Z + additionalShadowOffsetAmount);
+
+
+ // Create AnimationGroup
+ CompositionAnimationGroup animationGroup = compositor.CreateAnimationGroup();
+
+ // Blur Radius
+ ScalarKeyFrameAnimation shadowBlurAnimation = compositor.CreateScalarKeyFrameAnimation();
+ shadowBlurAnimation.InsertKeyFrame(0.0f, BlurRadius);
+ shadowBlurAnimation.InsertKeyFrame(1.0f, newShadowBlurRadius);
+ shadowBlurAnimation.Duration = ConfigurationConstants.FocusAnimationDuration;
+ shadowBlurAnimation.Target = "BlurRadius";
+ animationGroup.Add(shadowBlurAnimation);
+
+ // Offset
+ Vector3KeyFrameAnimation shadowOffsetAnimation = compositor.CreateVector3KeyFrameAnimation();
+ shadowOffsetAnimation.InsertKeyFrame(0.0f, Offset);
+ shadowOffsetAnimation.InsertKeyFrame(1.0f, newShadowOffset);
+ shadowOffsetAnimation.Duration = ConfigurationConstants.FocusAnimationDuration;
+ shadowOffsetAnimation.Target = "Offset";
+ animationGroup.Add(shadowOffsetAnimation);
+
+ return animationGroup;
+ }
+ }
+}
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Layer.cs b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Layer.cs
new file mode 100644
index 000000000..f2f96eafa
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Layer.cs
@@ -0,0 +1,199 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Composition;
+using System.Collections.Generic;
+using System.Numerics;
+
+namespace DepthDemo
+{
+ public class Layer
+ {
+ private Compositor _compositor;
+ private SpriteVisual _backingVisual;
+ private CompositionAnimationGroup _shadowAnimationGroup;
+ private CompositionAnimationGroup _visualAnimationGroup;
+ private CompositionAnimationGroup _reversedShadowAnimationGroup;
+ private CompositionAnimationGroup _reversedVisualAnimationGroup;
+
+
+ public int Identifier { get; set; }
+ public Vector3 Offset { get; set; }
+ public CompositionColorBrush LayerColor;
+ public DepthTreatmentConfigurations DepthTreatment { get; set; }
+ public List FocusedVisuals { get; set; }
+ public List ElevatedVisuals { get; set; }
+ public SpriteVisual LayerBackingVisual
+ {
+ get { return _backingVisual; }
+ set { _backingVisual = LayerBackingVisual; }
+ }
+
+
+ public Layer(Compositor compositor, int identifier, Vector3 offset, Vector2 size,
+ ContainerVisual parent, CompositionColorBrush layerColor)
+ {
+ _compositor = compositor;
+ LayerColor = layerColor;
+ FocusedVisuals = new List();
+ ElevatedVisuals = new List();
+
+ SpriteVisual x = _compositor.CreateSpriteVisual();
+ x.Size = new Vector2(size.X, size.Y);
+ x.Offset = Offset = offset;
+ Identifier = identifier;
+ x.Comment = Identifier.ToString();
+
+ _backingVisual = x;
+ parent.Children.InsertAtTop(x);
+ }
+
+ public void SetDepthTreatments(DepthTreatmentConfigurations depthTreatmentConfig)
+ {
+ DepthTreatment = depthTreatmentConfig;
+ RefreshApplyDepthTreatments();
+
+ // Shadow Focus Animation
+ _shadowAnimationGroup = DepthTreatment.ShadowTreatment.GetShadowFocusAnimations(_compositor, this);
+ // Additional Focus Animations
+ _visualAnimationGroup = DepthTreatment.GetVisualFocusAnimations(_compositor, this);
+
+ // Create reversed animation groups to run on unfocus
+ _reversedShadowAnimationGroup = _compositor.CreateAnimationGroup();
+ _reversedVisualAnimationGroup = _compositor.CreateAnimationGroup();
+ foreach (KeyFrameAnimation animation in _shadowAnimationGroup)
+ {
+ animation.Direction = AnimationDirection.Reverse;
+ _reversedShadowAnimationGroup.Add(animation);
+ }
+ foreach (KeyFrameAnimation animation in _visualAnimationGroup)
+ {
+ animation.Direction = AnimationDirection.Reverse;
+ _reversedVisualAnimationGroup.Add(animation);
+ }
+ }
+
+ public void RefreshApplyDepthTreatments()
+ {
+ // Apply treatments to all children in layer
+ var children = _backingVisual.Children;
+ foreach (Visual child in children)
+ {
+ if (DepthTreatment.ShadowTreatment != null && child.GetType() == typeof(SpriteVisual))
+ {
+ var shadowTreatment = DepthTreatment.ShadowTreatment;
+
+ DropShadow shadow = _compositor.CreateDropShadow();
+ shadow.BlurRadius = shadowTreatment.BlurRadius;
+ shadow.Offset = shadowTreatment.Offset;
+ shadow.Color = shadowTreatment.ShadowColor;
+ shadow.Opacity = ConfigurationConstants.ShadowOpacity;
+
+ ((SpriteVisual)child).Shadow = shadow;
+ }
+ }
+ }
+
+ public void AnimateFocusTreatment(SpriteVisual target)
+ {
+ FocusedVisuals.Add(target);
+
+ target.Shadow.StartAnimationGroup(_shadowAnimationGroup);
+ target.StartAnimationGroup(_visualAnimationGroup);
+ }
+
+ public void AnimationUnfocusTreatment(SpriteVisual target)
+ {
+ if (FocusedVisuals.Contains(target))
+ {
+ if (target.Shadow != null && _reversedShadowAnimationGroup != null)
+ {
+ target.Shadow.StartAnimationGroup(_reversedShadowAnimationGroup);
+ }
+ if (_reversedVisualAnimationGroup != null)
+ {
+ target.StartAnimationGroup(_reversedVisualAnimationGroup);
+ }
+
+ FocusedVisuals.Remove(target);
+ }
+ }
+
+ public void AnimateAddedVisual(SpriteVisual target)
+ {
+ float currShadowBlurRadius = 0f;
+ Vector3 currShadowOffset = new Vector3();
+
+ if (target.Shadow != null)
+ {
+ currShadowBlurRadius = ((DropShadow)(target.Shadow)).BlurRadius;
+ currShadowOffset = ((DropShadow)(target.Shadow)).Offset;
+ }
+ else
+ {
+ DropShadow shadow = _compositor.CreateDropShadow();
+ shadow.Color = ConfigurationConstants.ShadowColor;
+ shadow.Opacity = ConfigurationConstants.ShadowOpacity;
+ target.Shadow = shadow;
+ }
+
+ // Create AnimationGroup for shadow change animation
+ CompositionAnimationGroup animationGroup = _compositor.CreateAnimationGroup();
+
+ // Animate shadow blur radius change
+ ScalarKeyFrameAnimation shadowBlurAnimation = _compositor.CreateScalarKeyFrameAnimation();
+ shadowBlurAnimation.InsertKeyFrame(0.0f, currShadowBlurRadius);
+ shadowBlurAnimation.InsertKeyFrame(1.0f, DepthTreatment.ShadowTreatment.BlurRadius);
+ shadowBlurAnimation.Duration = ConfigurationConstants.FocusAnimationDuration;
+ shadowBlurAnimation.Target = "BlurRadius";
+ animationGroup.Add(shadowBlurAnimation);
+
+ // Animate shadow offset change
+ Vector3KeyFrameAnimation shadowOffsetAnimation = _compositor.CreateVector3KeyFrameAnimation();
+ shadowOffsetAnimation.InsertKeyFrame(0.0f, currShadowOffset);
+ shadowOffsetAnimation.InsertKeyFrame(1.0f, DepthTreatment.ShadowTreatment.Offset);
+ shadowOffsetAnimation.Duration = ConfigurationConstants.FocusAnimationDuration;
+ shadowOffsetAnimation.Target = "Offset";
+ animationGroup.Add(shadowOffsetAnimation);
+
+ target.Shadow.StartAnimationGroup(animationGroup);
+
+ AnimateToLayerHelper(target);
+ }
+
+ private void AnimateToLayerHelper(SpriteVisual target)
+ {
+ // Create AnimationGroup for target visual propery animation
+ CompositionAnimationGroup animationGroup = _compositor.CreateAnimationGroup();
+
+ // Scale
+ Vector3KeyFrameAnimation scaleAnimation = _compositor.CreateVector3KeyFrameAnimation();
+ scaleAnimation.InsertKeyFrame(0.0f, target.Scale);
+ scaleAnimation.InsertKeyFrame(1.0f, this.DepthTreatment.ChildScale);
+ scaleAnimation.Duration = ConfigurationConstants.FocusAnimationDuration;
+ scaleAnimation.Target = "Scale";
+ animationGroup.Add(scaleAnimation);
+
+ target.StartAnimationGroup(animationGroup);
+
+
+ // Update item color to match items in new layer. Preserve content if any.
+ var brushType = target.Brush.GetType();
+ if (brushType != typeof(CompositionSurfaceBrush) && brushType != typeof(CompositionEffectBrush))
+ {
+ target.Brush = LayerColor;
+ }
+ }
+ }
+}
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainPage.xaml b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainPage.xaml
new file mode 100644
index 000000000..5a29df68f
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainPage.xaml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainPage.xaml.cs b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainPage.xaml.cs
new file mode 100644
index 000000000..962dc7b59
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainPage.xaml.cs
@@ -0,0 +1,490 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using DepthDemo.Scenarios;
+using ExpressionBuilder;
+using Microsoft.UI;
+using Microsoft.UI.Composition;
+using Microsoft.UI.Composition.Interactions;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Hosting;
+using Microsoft.UI.Xaml.Media;
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+using Windows.Foundation;
+using Windows.UI;
+using Windows.UI.Popups;
+
+using EF = ExpressionBuilder.ExpressionFunctions;
+
+namespace DepthDemo
+{
+
+ public sealed partial class MainPage : Page, IInteractionTrackerOwner
+ {
+ #region vars
+ private Compositor _compositor;
+ private ContainerVisual _mainContainer;
+ private InteractionTracker _tracker;
+ private VisualInteractionSource _interactionSource;
+ private List _scenarios;
+ private Scenario _currentScenario;
+ private Dictionary _scenarioContainersMapping;
+ private SpriteVisual _activeScenarioVisualIndicator;
+ private NestedScenario _nestedScenario;
+ private BasicElementsScenario _basicScenario;
+ #endregion
+ public MainPage()
+ {
+ this.InitializeComponent();
+
+ _scenarioContainersMapping = new Dictionary();
+ _scenarios = new List();
+ }
+
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ _compositor = ElementCompositionPreview.GetElementVisual(MainGrid).Compositor;
+
+ _activeScenarioVisualIndicator = _compositor.CreateSpriteVisual();
+ _activeScenarioVisualIndicator.Brush = _compositor.CreateColorBrush(Color.FromArgb(255, 0, 153, 153));
+ ElementCompositionPreview.SetElementChildVisual(ProgressIndicatorStackPanel, _activeScenarioVisualIndicator);
+
+ // Create and add container for layers
+ _mainContainer = _compositor.CreateContainerVisual();
+ ElementCompositionPreview.SetElementChildVisual(MainCanvas, _mainContainer);
+
+ InitializeScenarios();
+
+ ConfigureInteractionTracker();
+ }
+
+ private void InitializeScenarios()
+ {
+ _nestedScenario = new NestedScenario(0, _compositor, MainCanvas);
+ _scenarios.Add(_nestedScenario);
+ _basicScenario = new BasicElementsScenario(1, _compositor, MainCanvas);
+ _scenarios.Add(_basicScenario);
+
+ // For each scenario, allocate a spritevisual scenario container the size of maincanvas
+ // and add the scenario container to the maincontainer
+ var nextOffset = new Vector3(0, 0, 0);
+ for (int i = 0; i < _scenarios.Count; i++)
+ {
+ var scenarioContainer = _compositor.CreateSpriteVisual();
+ scenarioContainer.Size = new Vector2((float)MainCanvas.ActualWidth, (float)MainCanvas.ActualHeight);
+ scenarioContainer.Offset = nextOffset;
+ _mainContainer.Children.InsertAtTop(scenarioContainer);
+
+ _scenarioContainersMapping.Add(_scenarios[i], scenarioContainer);
+
+ nextOffset = new Vector3(nextOffset.X + scenarioContainer.Size.X, 0, 0);
+ }
+
+ _currentScenario = _scenarios[0];
+ _currentScenario.IsActive = true;
+
+ InitializeContent();
+
+ // For each scenario, add a button navigation/progress indicator
+ foreach (Scenario scenario in _scenarios)
+ {
+ Button bt = new Button();
+ bt.Click += ProgressIndicatorButton_Click;
+ bt.Name = scenario.Identifier.ToString();
+ bt.Content = "Scenario " + scenario.Identifier;
+ bt.Background = new SolidColorBrush(Colors.Transparent);
+
+ ProgressIndicatorStackPanel.Children.Add(bt);
+ }
+ }
+
+ private void InitializeContent()
+ {
+ foreach (Scenario scenario in _scenarios)
+ {
+ scenario.ImplementScenario(_compositor, _scenarioContainersMapping[scenario]);
+ }
+ }
+
+ public void ConfigureInteractionTracker()
+ {
+ var backgroundVisual = ElementCompositionPreview.GetElementVisual(MainGrid);
+ backgroundVisual.Size = new Vector2((float)MainGrid.ActualWidth, (float)MainGrid.ActualHeight);
+
+ // Configure interaction tracker
+ _tracker = InteractionTracker.CreateWithOwner(_compositor, this);
+ _tracker.MaxPosition = new Vector3((float)backgroundVisual.Size.X * _scenarios.Count, backgroundVisual.Size.Y, 0);
+ _tracker.MinPosition = new Vector3();
+
+ // Configure interaction source
+ _interactionSource = VisualInteractionSource.Create(backgroundVisual);
+ _interactionSource.PositionXSourceMode = InteractionSourceMode.EnabledWithInertia;
+ _tracker.InteractionSources.Add(_interactionSource);
+
+ // Bind interaction tracker output to animation for now
+ var positionExpression = -_tracker.GetReference().Position.X;
+ _mainContainer.StartAnimation("Offset.X", positionExpression);
+
+ ConfigureRestingPoints();
+
+ var nestedVisuals = _nestedScenario.GetVisuals();
+ var exp = _compositor.CreateExpressionAnimation();
+ for (int i = 0; i < nestedVisuals.Count; i++)
+ {
+ ConfigureParallax(i, nestedVisuals[i]);
+ }
+ }
+ private void ConfigureParallax(int index, Visual visual)
+ {
+ var parallaxExpression = _compositor.CreateExpressionAnimation(
+ "this.startingvalue + " +
+ "tracker.PositionVelocityInPixelsPerSecond.X *" +
+ "index / 100");
+ parallaxExpression.SetReferenceParameter("tracker", _tracker);
+ parallaxExpression.SetScalarParameter("index", index);
+
+ var parallaxExpression2 = ExpressionValues.StartingValue.CreateScalarStartingValue() +
+ _tracker.GetReference().PositionVelocityInPixelsPerSecond.X *
+ index / 50;
+
+ visual.StartAnimation("Offset.X", parallaxExpression2);
+ }
+ private void ConfigureRestingPoints()
+ {
+ var size = (_tracker.MaxPosition.X - _tracker.MinPosition.X);
+ var props = _compositor.CreatePropertySet();
+ props.InsertScalar("size", (_tracker.MaxPosition.X - _tracker.MinPosition.X));
+ props.InsertScalar("numScenarios", (_scenarios.Count));
+
+ var endpoint1 = InteractionTrackerInertiaRestingValue.Create(_compositor);
+
+ var endpoint1ExpressionAnimation = _tracker.GetReference().NaturalRestingPosition.X < (size / _scenarios.Count);
+ endpoint1.SetCondition(endpoint1ExpressionAnimation);
+
+ endpoint1.RestingValue = _compositor.CreateExpressionAnimation("this.target.MinPosition.x");
+
+ // Update endpoints for number of scenarios
+ InteractionTrackerInertiaModifier[] endpoints = new InteractionTrackerInertiaModifier[_scenarios.Count];
+ endpoints[0] = endpoint1;
+ for (int i = 1; i < _scenarios.Count - 1; i++)
+ {
+ var endpoint = InteractionTrackerInertiaRestingValue.Create(_compositor);
+
+ var endpointExpressionAnimation = _tracker.GetReference().NaturalRestingPosition.X > (size / _scenarios.Count) * i &
+ _tracker.GetReference().NaturalRestingPosition.X <= (i + 1) * size / _scenarios.Count;
+ endpoint.SetCondition(endpointExpressionAnimation);
+
+ var restingValueExpressionAnimation = i * _tracker.GetReference().MaxPosition.X / _scenarios.Count;
+ endpoint.SetRestingValue(restingValueExpressionAnimation);
+
+
+ endpoints[i] = endpoint;
+ }
+
+ var finalEndpoint = InteractionTrackerInertiaRestingValue.Create(_compositor);
+
+ var finalEndpointExpressionAnimation = _tracker.GetReference().NaturalRestingPosition.X > (_scenarios.Count - 1) * size / _scenarios.Count;
+ finalEndpoint.SetCondition(finalEndpointExpressionAnimation);
+
+ var finalRestingValueExpressionAnimation = (_scenarios.Count - 1) * _tracker.GetReference().MaxPosition.X / _scenarios.Count;
+ finalEndpoint.SetRestingValue(finalRestingValueExpressionAnimation);
+
+ endpoints[_scenarios.Count - 1] = finalEndpoint;
+
+ _tracker.ConfigurePositionXInertiaModifiers(endpoints);
+ }
+
+ #region PointerHandlers
+ private void MainGrid_PointerPressed(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
+ {
+ if (e.Pointer.PointerDeviceType == Microsoft.UI.Input.PointerDeviceType.Touch)
+ {
+ try
+ {
+ _interactionSource.TryRedirectForManipulation(e.GetCurrentPoint(MainGrid));
+ }
+ catch (UnauthorizedAccessException)
+ {
+ // Ignoring the failed redirect to prevent app crashing
+ }
+ }
+ }
+
+ private void MainCanvas_PointerPressed(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
+ {
+ // Pass event on to the scenario that's in view
+ foreach (Scenario scenario in _scenarios)
+ {
+ if (_scenarioContainersMapping[scenario].Offset.X == _tracker.Position.X)
+ {
+ scenario.CanvasPointerPressed(sender, e, MainCanvas);
+ }
+ }
+ }
+
+ private void MainCanvas_PointerMoved(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
+ {
+ // Pass event on to the scenario that's in view
+ foreach (Scenario scenario in _scenarios)
+ {
+ if (_scenarioContainersMapping[scenario].Offset.X == _tracker.Position.X)
+ {
+ scenario.CanvasPointerMoved(sender, e, MainCanvas);
+ }
+ }
+ }
+
+ private void MainCanvas_DoubleTapped(object sender, Microsoft.UI.Xaml.Input.DoubleTappedRoutedEventArgs e)
+ {
+ // Pass event on to the scenario that's in view
+ foreach (Scenario scenario in _scenarios)
+ {
+ if (_scenarioContainersMapping[scenario].Offset.X == _tracker.Position.X)
+ {
+ scenario.CanvasDoubleTapped(sender, e, MainCanvas);
+ }
+ }
+ }
+
+ private void MainGrid_SizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ if (_scenarios.Count > 0)
+ {
+ // Resize the container for each scenario
+ ContainerVisual previousScenarioContainer = null;
+ for (int i = 0; i < _scenarios.Count; i++)
+ {
+ var scenarioContainer = _scenarioContainersMapping[_scenarios[i]];
+ scenarioContainer.Size = new Vector2((float)MainCanvas.ActualWidth, (float)MainCanvas.ActualHeight);
+
+ // Update offset when applicable
+ if (previousScenarioContainer != null)
+ {
+ scenarioContainer.Offset = new Vector3(previousScenarioContainer.Offset.X + previousScenarioContainer.Size.X, 0, 0);
+ }
+
+ // Update content on a per-scenario basis
+ _scenarios[i].SizeChanged();
+
+ previousScenarioContainer = scenarioContainer;
+ }
+
+ // Update tracker position
+ var newOffset = _scenarioContainersMapping[_currentScenario].Offset;
+ _tracker.TryUpdatePosition(newOffset);
+
+ // Update resting points
+ var backgroundVisual = ElementCompositionPreview.GetElementVisual(MainGrid);
+ backgroundVisual.Size = new Vector2((float)MainGrid.ActualWidth, (float)MainGrid.ActualHeight);
+ _tracker.MaxPosition = new Vector3((float)backgroundVisual.Size.X * _scenarios.Count, backgroundVisual.Size.Y, 0);
+ ConfigureRestingPoints();
+ }
+ }
+
+ private void ProgressIndicatorButton_Click(object sender, RoutedEventArgs e)
+ {
+ TryNavigateToScenario(int.Parse((sender as Button).Name));
+ }
+
+ private async void InfoButton_Click(object sender, RoutedEventArgs e)
+ {
+ // Pull up scenario help popup
+ string helpTextInfo = _currentScenario.HelpTextInstructions;
+
+ var messageDialog = new MessageDialog(helpTextInfo);
+ WinRT.Interop.InitializeWithWindow.Initialize(messageDialog, WinRT.Interop.WindowNative.GetWindowHandle(MainWindow.CurrentWindow));
+ await messageDialog.ShowAsync();
+ }
+ #endregion
+
+ #region Navigation
+ private void TryNavigateToScenario(int num)
+ {
+ foreach (Scenario scenario in _scenarios)
+ {
+ if (scenario.Identifier == num && _currentScenario != scenario)
+ {
+ var oldScenario = _currentScenario;
+ _currentScenario = scenario;
+
+ var newOffset = _scenarioContainersMapping[scenario].Offset;
+ var currOffset = _tracker.Position;
+
+ // Offset animation
+ Vector3KeyFrameAnimation offsetAnimation = _compositor.CreateVector3KeyFrameAnimation();
+ offsetAnimation.InsertKeyFrame(0.0f, currOffset);
+ offsetAnimation.InsertKeyFrame(1.0f, newOffset);
+ offsetAnimation.Duration = ConfigurationConstants.FocusAnimationDuration;
+ offsetAnimation.Target = "Position";
+
+ _tracker.TryUpdatePositionWithAnimation(offsetAnimation);
+
+ UpdateActiveScenarioIndicator(oldScenario);
+
+ break;
+ }
+ }
+ }
+
+ private Scenario GetActiveScenarioByTrackerPosition(Vector3 trackerPosition)
+ {
+ foreach (Scenario scenario in _scenarios)
+ {
+ if (_scenarioContainersMapping[scenario].Offset == trackerPosition)
+ {
+ return scenario;
+ }
+ }
+ return null;
+ }
+
+ private void UpdateActiveScenarioIndicator(Scenario oldScenario)
+ {
+ oldScenario.IsActive = false;
+ _currentScenario.IsActive = true;
+
+ var activeScenarioNum = _scenarios.IndexOf(_currentScenario);
+
+ // Update nav active scenario indicator
+ // Get offset/size of new active scenario button
+ var buttonWidth = (float)ProgressIndicatorStackPanel.Children[activeScenarioNum].RenderSize.Width;
+ var buttonOffset = ProgressIndicatorStackPanel.Children[activeScenarioNum].GetOffset(ProgressIndicatorStackPanel);
+ var offsetDeltaX = Math.Abs(buttonOffset.X - _activeScenarioVisualIndicator.Offset.X);
+
+ // Scoped batch for first half of the animation
+ var batch = _compositor.CreateScopedBatch(CompositionBatchTypes.Animation);
+ batch.Completed += Batch_Completed;
+
+ CompositionAnimationGroup animationGroup = _compositor.CreateAnimationGroup();
+
+ // Animate line size
+ ScalarKeyFrameAnimation sizeGrowAnimation = _compositor.CreateScalarKeyFrameAnimation();
+ sizeGrowAnimation.Duration = ConfigurationConstants.NavAnimationDuration;
+ sizeGrowAnimation.InsertKeyFrame(0.0f, _activeScenarioVisualIndicator.Size.X);
+ sizeGrowAnimation.InsertKeyFrame(1.0f, offsetDeltaX + _activeScenarioVisualIndicator.Size.X);
+ sizeGrowAnimation.Target = "Size.X";
+ if (buttonOffset.X < _activeScenarioVisualIndicator.Offset.X)
+ {
+ // Add offset animation to size change, to make the line appear to move to the left
+ ScalarKeyFrameAnimation offsetAnimation = _compositor.CreateScalarKeyFrameAnimation();
+ offsetAnimation.InsertKeyFrame(0.0f, _activeScenarioVisualIndicator.Offset.X);
+ offsetAnimation.InsertKeyFrame(1.0f, buttonOffset.X);
+ offsetAnimation.Duration = ConfigurationConstants.NavAnimationDuration;
+ offsetAnimation.Target = "Offset.X";
+ animationGroup.Add(offsetAnimation);
+ }
+
+ animationGroup.Add(sizeGrowAnimation);
+
+ _activeScenarioVisualIndicator.StartAnimationGroup(animationGroup);
+
+ batch.End();
+ }
+
+ private void Batch_Completed(object sender, CompositionBatchCompletedEventArgs args)
+ {
+ // Start the second part of the animations
+
+ // Get offset/size of new active scenario button
+ var activeScenarioNum = _scenarios.IndexOf(_currentScenario);
+ var buttonWidth = (float)ProgressIndicatorStackPanel.Children[activeScenarioNum].RenderSize.Width;
+ var buttonOffset = ProgressIndicatorStackPanel.Children[activeScenarioNum].GetOffset(ProgressIndicatorStackPanel);
+ var offsetDeltaX = Math.Abs(buttonOffset.X - _activeScenarioVisualIndicator.Offset.X);
+
+ CompositionAnimationGroup animationGroup = _compositor.CreateAnimationGroup();
+
+ // Animate line size
+ ScalarKeyFrameAnimation sizeShrinkAnimation = _compositor.CreateScalarKeyFrameAnimation();
+ sizeShrinkAnimation.Duration = ConfigurationConstants.NavAnimationDuration;
+ sizeShrinkAnimation.InsertKeyFrame(0.0f, _activeScenarioVisualIndicator.Size.X);
+ sizeShrinkAnimation.InsertKeyFrame(1.0f, buttonWidth);
+ sizeShrinkAnimation.Target = "Size.X";
+ animationGroup.Add(sizeShrinkAnimation);
+
+ if (buttonOffset.X > _activeScenarioVisualIndicator.Offset.X)
+ {
+ // Animate line to new offset
+ ScalarKeyFrameAnimation offsetAnimation = _compositor.CreateScalarKeyFrameAnimation();
+ offsetAnimation.InsertKeyFrame(0.0f, _activeScenarioVisualIndicator.Offset.X);
+ offsetAnimation.InsertKeyFrame(1.0f, buttonOffset.X);
+ offsetAnimation.Duration = ConfigurationConstants.NavAnimationDuration;
+ offsetAnimation.Target = "Offset.X";
+ animationGroup.Add(offsetAnimation);
+ }
+
+ _activeScenarioVisualIndicator.StartAnimationGroup(animationGroup);
+ }
+
+ private void ProgressIndicatorStackPanel_SizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ var x = ProgressIndicatorStackPanel;
+ var y = ProgressIndicatorStackPanel.Children[0];
+
+ if (ProgressIndicatorStackPanel.Children.Count > 0)
+ {
+ var buttonHeight = (float)ProgressIndicatorStackPanel.Children[0].RenderSize.Height;
+ var buttonOffset = ProgressIndicatorStackPanel.Children[0].GetOffset(ProgressIndicatorStackPanel);
+
+ _activeScenarioVisualIndicator.Offset = new Vector3(0, buttonHeight + buttonOffset.Y, 0);
+ _activeScenarioVisualIndicator.Size = new Vector2((float)ProgressIndicatorStackPanel.ActualWidth / _scenarios.Count, 3);
+ }
+ }
+ #endregion
+
+ #region Callbacks
+
+ public void CustomAnimationStateEntered(InteractionTracker sender, InteractionTrackerCustomAnimationStateEnteredArgs args) { }
+
+ public void IdleStateEntered(InteractionTracker sender, InteractionTrackerIdleStateEnteredArgs args)
+ {
+ // Check offset for scenario and update progress indicator
+ var newScenario = GetActiveScenarioByTrackerPosition(sender.Position);
+ if (_currentScenario != newScenario && newScenario != null)
+ {
+ var oldScenario = _currentScenario;
+ _currentScenario = newScenario;
+
+ UpdateActiveScenarioIndicator(oldScenario);
+ }
+ }
+
+ public void InertiaStateEntered(InteractionTracker sender, InteractionTrackerInertiaStateEnteredArgs args) { }
+
+ public void InteractingStateEntered(InteractionTracker sender, InteractionTrackerInteractingStateEnteredArgs args) { }
+
+ public void RequestIgnored(InteractionTracker sender, InteractionTrackerRequestIgnoredArgs args) { }
+
+ public void ValuesChanged(InteractionTracker sender, InteractionTrackerValuesChangedArgs args) { }
+
+ #endregion Callbacks
+
+ }
+
+
+ public static class UIElementExtensions
+ {
+ public static Vector3 GetOffset(this UIElement element, UIElement relativeTo = null)
+ {
+ var transform = element.TransformToVisual(relativeTo ?? Window.Current.Content);
+ var point = transform.TransformPoint(new Point(0, 0));
+ Vector3 offset = new Vector3((float)point.X, (float)point.Y, 0);
+
+ return offset;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainWindow.xaml b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainWindow.xaml
new file mode 100644
index 000000000..75f6a92af
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainWindow.xaml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainWindow.xaml.cs b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainWindow.xaml.cs
new file mode 100644
index 000000000..74da2b184
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/MainWindow.xaml.cs
@@ -0,0 +1,49 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace DepthDemo
+{
+ ///
+ /// An empty window that can be used on its own or navigated to within a Frame.
+ ///
+ public sealed partial class MainWindow : Window
+ {
+ public static MainWindow CurrentWindow { get; private set; }
+
+ public MainWindow()
+ {
+ this.InitializeComponent();
+ this.Title = "Depth Demo - Windows App SDK";
+ CurrentWindow = this;
+ }
+ }
+}
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Properties/PublishProfiles/win-arm64.pubxml b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Properties/PublishProfiles/win-arm64.pubxml
new file mode 100644
index 000000000..08b5300d8
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Properties/PublishProfiles/win-arm64.pubxml
@@ -0,0 +1,19 @@
+
+
+
+
+ FileSystem
+ arm64
+ win-arm64
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Properties/PublishProfiles/win-x64.pubxml b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Properties/PublishProfiles/win-x64.pubxml
new file mode 100644
index 000000000..dcdbaed60
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Properties/PublishProfiles/win-x64.pubxml
@@ -0,0 +1,19 @@
+
+
+
+
+ FileSystem
+ x64
+ win-x64
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Properties/PublishProfiles/win-x86.pubxml b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Properties/PublishProfiles/win-x86.pubxml
new file mode 100644
index 000000000..cf7e029c0
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Properties/PublishProfiles/win-x86.pubxml
@@ -0,0 +1,19 @@
+
+
+
+
+ FileSystem
+ x86
+ win-x86
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Scenario.cs b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Scenario.cs
new file mode 100644
index 000000000..de09cba5e
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Scenario.cs
@@ -0,0 +1,216 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Composition;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Input;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using Windows.Foundation;
+using Windows.UI;
+
+namespace DepthDemo
+{
+ public abstract class Scenario
+ {
+ public Scenario(int identifier)
+ {
+ Identifier = identifier;
+ IsActive = false;
+ }
+
+ public struct LayerConfig
+ {
+ public int ID;
+ public Color Color;
+ public Vector3 Scale;
+ public int ShadowBlurRadius;
+ public Vector3 ShadowOffset;
+
+ public LayerConfig(int id, Color color, Vector3 scale, int shadowBlurRadius, Vector3 shadowOffset)
+ {
+ ID = id;
+ Color = color;
+ Scale = scale;
+ ShadowBlurRadius = shadowBlurRadius;
+ ShadowOffset = shadowOffset;
+ }
+ }
+
+ ///
+ /// String describing how to interact with the scenario
+ ///
+ public string HelpTextInstructions { get; set; }
+
+ ///
+ /// Boolean indicating whether the scenario is active or not. 'Active' indicates
+ /// the end user can see the scenario in the app.
+ ///
+ public bool IsActive { get; set; }
+
+ ///
+ /// Identifier for the scenario
+ ///
+ public int Identifier { get; set; }
+
+ ///
+ /// Used to define new behavior when animating a visual from one conceptual layer to another,
+ /// on a per scenario basis.
+ ///
+ public virtual void AnimateVisualToLayer(Layer oldLayer, Layer newLayer, SpriteVisual targetVisual, bool overrideProjectedShadows = false)
+ {
+ if (oldLayer.LayerBackingVisual.Children.Contains(targetVisual))
+ {
+ // Remove visual from current layer
+ oldLayer.LayerBackingVisual.Children.Remove(targetVisual);
+
+ // Add to new layer
+ newLayer.LayerBackingVisual.Children.InsertAtTop(targetVisual);
+
+ // Trigger animation to new values
+ newLayer.AnimateAddedVisual(targetVisual);
+ }
+ }
+
+ public Visual GetHittestVisual(Point pointerPosition, List visuals, List layers, List excludedVisuals)
+ {
+ return GetHittestVisualHelper(pointerPosition, visuals, layers, excludedVisuals);
+ }
+
+ public Visual GetHittestVisual(Point pointerPosition, List visuals, List layers, List excludedVisuals)
+ {
+ List visualsList = new List();
+ foreach (Visual visual in visuals)
+ {
+ visualsList.Add((Visual)visual);
+ }
+
+ return GetHittestVisualHelper(pointerPosition, visualsList, layers, excludedVisuals);
+ }
+
+ public Visual GetHittestVisual(Point pointerPosition, VisualCollection visuals, List layers, List excludedVisuals)
+ {
+ List visualsList = new List();
+ foreach (Visual visual in visuals)
+ {
+ visualsList.Add(visual);
+ }
+
+ return GetHittestVisualHelper(pointerPosition, visualsList, layers, excludedVisuals);
+ }
+
+ private Visual GetHittestVisualHelper(Point pointerPosition, List visuals, List layers, List excludedVisuals)
+ {
+ if (excludedVisuals == null) { excludedVisuals = new List(); }
+ List hitVisuals = new List();
+ foreach (Visual visual in visuals)
+ {
+ if (!excludedVisuals.Contains(visual))
+ {
+ var visualXLowerBound = visual.Offset.X;
+ var visualXUpperBound = visual.Offset.X + visual.Size.X;
+ var visualYLowerBound = visual.Offset.Y;
+ var visualYUpperBound = visual.Offset.Y + visual.Size.Y;
+
+ // Check if clicked
+ if (pointerPosition.X >= visualXLowerBound && pointerPosition.X <= visualXUpperBound &&
+ pointerPosition.Y >= visualYLowerBound && pointerPosition.Y <= visualYUpperBound)
+ {
+ hitVisuals.Add(visual);
+ }
+ }
+ }
+
+ if (hitVisuals.Count >= 1)
+ {
+ if (hitVisuals.Count == 1)
+ {
+ return hitVisuals.First();
+ }
+ else
+ {
+ // Go through each layer starting at the end (highest) and get the topmost hit visual
+ for (int i = layers.Count - 1; i >= 0; i--)
+ {
+ foreach (Visual v in hitVisuals)
+ {
+ if (layers[i].LayerBackingVisual.Children.Contains(v))
+ {
+ // Convert back to SV or CV
+ if (v.GetType().Name.Equals("SpriteVisual"))
+ {
+ return (SpriteVisual)v;
+ }
+ else if (v.GetType().Name.Equals("ContainerVisual"))
+ {
+ return (ContainerVisual)v;
+ }
+ return v;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Given a visual, get it's parent Layer object
+ ///
+ public Layer GetParentLayer(List layers, Visual visual)
+ {
+ foreach (Layer layer in layers)
+ {
+ if (layer.LayerBackingVisual.Children.Contains(visual))
+ {
+ return layer;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Create conceptual layers for the scenario, in order to define layer-specific behavior
+ ///
+ abstract public void CreateLayers();
+
+ ///
+ /// Size changed listener helper method
+ ///
+ abstract public void SizeChanged();
+
+ ///
+ /// Used to actually create the components of the scenario. Separated from the constructor
+ /// in order to provide greater control over scenarios.
+ ///
+ abstract public void ImplementScenario(Compositor compositor, SpriteVisual scenarioContainer);
+
+ ///
+ /// Scenario-specific behavior for canvas pointer moved input
+ ///
+ virtual public void CanvasPointerMoved(object sender, PointerRoutedEventArgs e, Canvas canvasReference) { }
+
+ ///
+ /// Scenario-specific behavior for canvas pointer pressed input
+ ///
+ virtual public void CanvasPointerPressed(object sender, PointerRoutedEventArgs e, Canvas canvasReference) { }
+
+ ///
+ /// Scenario-specific behavior for canvas double tapped input
+ ///
+ virtual public void CanvasDoubleTapped(object sender, DoubleTappedRoutedEventArgs e, Canvas canvasReference) { }
+
+ }
+}
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Scenarios/BasicElementsScenario.cs b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Scenarios/BasicElementsScenario.cs
new file mode 100644
index 000000000..97c5a9e11
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Scenarios/BasicElementsScenario.cs
@@ -0,0 +1,229 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Composition;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Input;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using Windows.UI;
+
+namespace DepthDemo.Scenarios
+{
+ class BasicElementsScenario : Scenario
+ {
+ private Compositor _compositor;
+ private List _visuals;
+ private List _layers;
+ private SpriteVisual _scenarioContainer;
+ private Canvas _canvasReference;
+ private Layer _primaryHostLayer;
+ private SpriteVisual _bottomLargeVisual;
+
+ private int _numTopVisuals = 6;
+
+ // Focus treatment increase for top layer objects
+ public static float _focusScaleIncreaseFactor = 1.1f;
+ // Shadow specific
+ public static int _focusShadowBlurRadiusIncreaseAmount = 15;
+ public static int _focusShadowOffsetIncreaseAmount = 15;
+
+ private static List s_layers = new List
+ {
+ new LayerConfig(0, Color.FromArgb(255,0,153,153), new Vector3(1, 1, 1), 30, new Vector3(0, 0, -20)),
+ new LayerConfig(1, Color.FromArgb(255,0,204,204), new Vector3(1.3f,1.3f, 1.3f), 60, new Vector3(0, 0, -30))
+ };
+
+ public BasicElementsScenario(int identifier, Compositor compositor, Canvas canvasReference) : base(identifier)
+ {
+ _visuals = new List();
+ _layers = new List();
+
+ _compositor = compositor;
+ _canvasReference = canvasReference;
+
+ HelpTextInstructions = "1. Click a visual in the upper portion of the screen to animate it forward with depth. " + System.Environment.NewLine +
+ "Click again to send it back to the original position.";
+ }
+
+ public override void CreateLayers()
+ {
+ // Create layers
+ for (int i = 0; i < s_layers.Count; i++)
+ {
+ var offset = new Vector3(0, 0, (ConfigurationConstants.ZOffsetSpacingIncrement * s_layers[i].ID));
+ var size = new Vector2((float)_canvasReference.ActualWidth, (float)_canvasReference.ActualHeight);
+
+ Layer l = new Layer(_compositor, s_layers[i].ID, offset, size, _scenarioContainer, _compositor.CreateColorBrush(s_layers[i].Color));
+ _layers.Add(l);
+
+ // Set depth treatment
+ ShadowTreatment shadowTreatment = new ShadowTreatment(s_layers[i].ShadowBlurRadius, s_layers[i].ShadowOffset, _focusShadowBlurRadiusIncreaseAmount, _focusShadowOffsetIncreaseAmount);
+ DepthTreatmentConfigurations depthTreatment = new DepthTreatmentConfigurations(_layers[i], s_layers[i].Scale, _focusScaleIncreaseFactor, shadowTreatment);
+ _layers[i].SetDepthTreatments(depthTreatment);
+ }
+ }
+
+ public override void ImplementScenario(Compositor compositor, SpriteVisual scenarioContainer)
+ {
+ _scenarioContainer = scenarioContainer;
+
+ CreateLayers();
+
+ // Get layer 0
+ foreach (Layer layer in _layers)
+ {
+ if (layer.Identifier == 0)
+ {
+ _primaryHostLayer = layer;
+ }
+ }
+
+ // Create larger visual on bottom
+ _bottomLargeVisual = compositor.CreateSpriteVisual();
+ _bottomLargeVisual.Brush = compositor.CreateColorBrush(s_layers[0].Color);
+ _bottomLargeVisual.Opacity = 1.0f;
+ _visuals.Add(_bottomLargeVisual);
+ _primaryHostLayer.LayerBackingVisual.Children.InsertAtTop(_bottomLargeVisual);
+
+ // Create basic sprite visuals, all on layer of id 0
+ for (int i = 0; i < _numTopVisuals; i++)
+ {
+ SpriteVisual v = compositor.CreateSpriteVisual();
+ v.Brush = compositor.CreateColorBrush(s_layers[0].Color);
+ v.Opacity = 1.0f;
+ _visuals.Add(v);
+ _primaryHostLayer.LayerBackingVisual.Children.InsertAtTop(v);
+ }
+
+ UpdateSizeAndLayout();
+
+ foreach (Layer l in _layers)
+ {
+ l.RefreshApplyDepthTreatments();
+ }
+ }
+
+ public override void CanvasPointerPressed(object sender, PointerRoutedEventArgs e, Canvas canvasReference)
+ {
+ List excludedVisuals = new List() { _bottomLargeVisual };
+ var hitVisual = (SpriteVisual)GetHittestVisual(e.GetCurrentPoint(canvasReference).Position, _visuals, _layers, excludedVisuals);
+
+ // Get parent layer
+ Layer parentLayer = GetParentLayer(_layers, hitVisual);
+
+ if (hitVisual != null)
+ {
+ // Check if the hittested visual was elevated from a previous layer. If it wasn't, elevate. Else move back.
+ if (!parentLayer.ElevatedVisuals.Contains(hitVisual))
+ {
+ RemoveElevatedVisuals();
+
+ // Elevate hit tested visual
+ // Get new layer owner
+ var newLayerIndex2 = _layers.IndexOf(parentLayer) + 1;
+ if (newLayerIndex2 >= _layers.Count)
+ {
+ newLayerIndex2 = _layers.Count - 1;
+ }
+ var newLayer = _layers[newLayerIndex2];
+
+ AnimateVisualToLayer(parentLayer, newLayer, hitVisual);
+ newLayer.ElevatedVisuals.Add(hitVisual);
+ }
+ else
+ {
+ // Animate back to non-elevated state
+ var newLayerIndex = _layers.IndexOf(parentLayer) - 1;
+ if (newLayerIndex < 0)
+ {
+ newLayerIndex = 0;
+ }
+ var newLayer = _layers[newLayerIndex];
+
+ AnimateVisualToLayer(parentLayer, newLayer, hitVisual);
+ parentLayer.ElevatedVisuals.Remove(hitVisual);
+ }
+ }
+ else
+ {
+ RemoveElevatedVisuals();
+ }
+ }
+
+ private void RemoveElevatedVisuals(bool overrideProjectedShadows = false)
+ {
+ foreach (Layer layer in _layers)
+ {
+ if (layer.ElevatedVisuals.Count > 0)
+ {
+ foreach (SpriteVisual currentlyElevatedVisual in layer.ElevatedVisuals.ToList())
+ {
+ var newLayerIndex = _layers.IndexOf(layer) - 1;
+ if (newLayerIndex < 0)
+ {
+ newLayerIndex = 0;
+ }
+
+ AnimateVisualToLayer(layer, _layers[newLayerIndex], currentlyElevatedVisual, overrideProjectedShadows);
+ layer.ElevatedVisuals.Remove(currentlyElevatedVisual);
+ }
+ }
+ }
+ }
+
+ public override void AnimateVisualToLayer(Layer oldLayer, Layer newLayer, SpriteVisual targetVisual, bool overrideProjectedShadows = false)
+ {
+ if (oldLayer.LayerBackingVisual.Children.Contains(targetVisual))
+ {
+ // Remove visual from current layer
+ oldLayer.LayerBackingVisual.Children.Remove(targetVisual);
+
+ // Add to new layer
+ newLayer.LayerBackingVisual.Children.InsertAtTop(targetVisual);
+
+ // Trigger animation to new values
+ newLayer.AnimateAddedVisual(targetVisual);
+ }
+ }
+
+ public override void SizeChanged()
+ {
+ UpdateSizeAndLayout();
+ }
+
+ private void UpdateSizeAndLayout()
+ {
+ var previousOffset = new Vector3(20, 20, 0);
+ foreach (SpriteVisual child in _primaryHostLayer.LayerBackingVisual.Children)
+ {
+ if (child == _bottomLargeVisual)
+ {
+ child.Size = new Vector2((float)_scenarioContainer.Size.X - 40, (float)_scenarioContainer.Size.Y - 20);
+ child.Offset = new Vector3(20, _scenarioContainer.Size.Y / 4, 0);
+ child.CenterPoint = new Vector3(child.Size.X / 2, child.Size.Y / 2, 0);
+ }
+ else
+ {
+ child.Size = new Vector2((_bottomLargeVisual.Size.X - 20 * (_numTopVisuals - 1)) / _numTopVisuals, _bottomLargeVisual.Offset.Y - 40);
+ child.Offset = previousOffset;
+ child.CenterPoint = new Vector3(child.Size.X / 2, child.Size.Y / 2, 0); // to center scaling
+ previousOffset = new Vector3(previousOffset.X + child.Size.X + 20, previousOffset.Y, 0);
+ }
+ }
+ }
+ }
+}
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Scenarios/NestedScenario.cs b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Scenarios/NestedScenario.cs
new file mode 100644
index 000000000..8c7f22283
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/Scenarios/NestedScenario.cs
@@ -0,0 +1,131 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Composition;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Input;
+using System.Collections.Generic;
+using System.Numerics;
+using Windows.UI;
+
+namespace DepthDemo.Scenarios
+{
+ class NestedScenario : Scenario
+ {
+ private Compositor _compositor;
+ private List _visuals;
+ private List _layers;
+ private SpriteVisual _scenarioContainer;
+ private Canvas _canvasReference;
+
+ // Focus treatment increase for top layer objects
+ public static float _focusScaleIncreaseFactor = 1.2f;
+ // Shadow specific
+ public static int _focusShadowBlurRadiusIncreaseAmount = 5;
+ public static int _focusShadowOffsetIncreaseAmount = 10;
+
+ private static List s_layers = new List
+ {
+ new LayerConfig(-2, Color.FromArgb(255,0,153,153), new Vector3(1, 1, 1), 0, new Vector3(0, 0, 0)),
+ new LayerConfig(-1, Color.FromArgb(255,0,204,204), new Vector3(1, 1, 1), 5, new Vector3(5,5,-5)),
+ new LayerConfig(0, Color.FromArgb(255,0,255,255), new Vector3(1, 1, 1), 9, new Vector3(10,10,-10)),
+ new LayerConfig(1, Color.FromArgb(255,102,255,255), new Vector3(1, 1, 1), 15, new Vector3(15,15,-15)),
+ new LayerConfig(2, Color.FromArgb(255,204,255,255), new Vector3(1, 1, 1), 30, new Vector3(20,20,-20))
+ };
+
+ public NestedScenario(int identifier, Compositor compositor, Canvas canvasReference) : base(identifier)
+ {
+ _visuals = new List();
+ _layers = new List();
+
+ _compositor = compositor;
+ _canvasReference = canvasReference;
+
+ HelpTextInstructions = "1. Move your finger L/R across the screen as if panning, to trigger the parallax behavior in the nested visuals.";
+ }
+
+ public override void CreateLayers()
+ {
+ // Create layers
+ for (int i = 0; i < s_layers.Count; i++)
+ {
+ var offset = new Vector3(0, 0, (ConfigurationConstants.ZOffsetSpacingIncrement * s_layers[i].ID));
+ var size = new Vector2((float)_canvasReference.ActualWidth, (float)_canvasReference.ActualHeight);
+
+ Layer l = new Layer(_compositor, s_layers[i].ID, offset, size, _scenarioContainer, _compositor.CreateColorBrush(s_layers[i].Color));
+ _layers.Add(l);
+
+ // Set depth treatment
+ ShadowTreatment shadowTreatment = new ShadowTreatment(s_layers[i].ShadowBlurRadius, s_layers[i].ShadowOffset, _focusShadowBlurRadiusIncreaseAmount, _focusShadowOffsetIncreaseAmount);
+ DepthTreatmentConfigurations depthTreatment = new DepthTreatmentConfigurations(_layers[i], s_layers[i].Scale, _focusScaleIncreaseFactor, shadowTreatment);
+ _layers[i].SetDepthTreatments(depthTreatment);
+ }
+ }
+
+ public override void ImplementScenario(Compositor compositor, SpriteVisual scenarioContainer)
+ {
+ _scenarioContainer = scenarioContainer;
+
+ CreateLayers();
+
+ // Create basic sprite visual to add to each layer, with random colors
+ for (int i = 0; i < _layers.Count; i++)
+ {
+ SpriteVisual v = compositor.CreateSpriteVisual();
+ v.Brush = compositor.CreateColorBrush(s_layers[i].Color);
+ v.Opacity = 1.0f;
+
+ _visuals.Add(v);
+ _layers[i].LayerBackingVisual.Children.InsertAtTop(v);
+ }
+
+ UpdateSizeAndLayout();
+
+ foreach (Layer l in _layers)
+ {
+ l.RefreshApplyDepthTreatments();
+ }
+ }
+
+ public List GetVisuals()
+ {
+ return _visuals;
+ }
+
+ public override void SizeChanged()
+ {
+ UpdateSizeAndLayout();
+ }
+
+ private void UpdateSizeAndLayout()
+ {
+ // Incremental offset and size starting values
+ var previousOffset = new Vector3(10, 10, 0);
+ var previousSize = new Vector2((float)_scenarioContainer.Size.X - 200, (float)_scenarioContainer.Size.Y - 200);
+
+ for (int i = 0; i < _layers.Count; i++)
+ {
+ foreach (SpriteVisual child in _layers[i].LayerBackingVisual.Children)
+ {
+ child.Size = previousSize;
+ child.Offset = previousOffset;
+ child.CenterPoint = new Vector3(previousSize.X / 2, previousSize.Y / 2, 0); // to center scaling
+
+ previousOffset = new Vector3(previousOffset.X + 50, previousOffset.Y + 50, 0);
+ previousSize = new Vector2(previousSize.X - 100, previousSize.Y - 100);
+ }
+ }
+ }
+ }
+}
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/app.manifest b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/app.manifest
new file mode 100644
index 000000000..2e0eca2ad
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoApp/app.manifest
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+
+
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/DepthDemoPackage.wapproj b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/DepthDemoPackage.wapproj
new file mode 100644
index 000000000..f02bf066e
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/DepthDemoPackage.wapproj
@@ -0,0 +1,62 @@
+
+
+
+ 15.0
+
+
+
+ Debug
+ x86
+
+
+ Release
+ x86
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ arm64
+
+
+ Release
+ arm64
+
+
+
+ $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\
+
+
+ 479855a2-c397-46d6-a034-ecb60fd91780
+ 10.0.19041.0
+ 10.0.17763.0
+ en-US
+ false
+ ..\DepthDemoApp\DepthDemoApp.csproj
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/LockScreenLogo.scale-200.png b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/LockScreenLogo.scale-200.png
new file mode 100644
index 000000000..7440f0d4b
Binary files /dev/null and b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/LockScreenLogo.scale-200.png differ
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/SplashScreen.scale-200.png b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/SplashScreen.scale-200.png
new file mode 100644
index 000000000..32f486a86
Binary files /dev/null and b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/SplashScreen.scale-200.png differ
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Square150x150Logo.scale-200.png b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Square150x150Logo.scale-200.png
new file mode 100644
index 000000000..53ee3777e
Binary files /dev/null and b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Square150x150Logo.scale-200.png differ
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Square44x44Logo.scale-200.png b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Square44x44Logo.scale-200.png
new file mode 100644
index 000000000..f713bba67
Binary files /dev/null and b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Square44x44Logo.scale-200.png differ
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Square44x44Logo.targetsize-24_altform-unplated.png b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 000000000..dc9f5bea0
Binary files /dev/null and b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/StoreLogo.png b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/StoreLogo.png
new file mode 100644
index 000000000..a4586f26b
Binary files /dev/null and b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/StoreLogo.png differ
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Wide310x150Logo.scale-200.png b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Wide310x150Logo.scale-200.png
new file mode 100644
index 000000000..8b4a5d0dd
Binary files /dev/null and b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Images/Wide310x150Logo.scale-200.png differ
diff --git a/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Package.appxmanifest b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Package.appxmanifest
new file mode 100644
index 000000000..f98b95947
--- /dev/null
+++ b/Samples/SceneGraph/Demos/DepthDemo/DepthDemoPackage/Package.appxmanifest
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+ DepthDemoPackage
+ getrou
+ Images\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/App.xaml b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/App.xaml
new file mode 100644
index 000000000..e8dfe9cd7
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/App.xaml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/App.xaml.cs b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/App.xaml.cs
new file mode 100644
index 000000000..1cc0aa472
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/App.xaml.cs
@@ -0,0 +1,65 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+using Microsoft.UI.Xaml.Shapes;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.ApplicationModel;
+using Windows.ApplicationModel.Activation;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace EffectEditor
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ public partial class App : Application
+ {
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ }
+
+ ///
+ /// Invoked when the application is launched normally by the end user. Other entry points
+ /// will be used such as when the application is launched to open a specific file.
+ ///
+ /// Details about the launch request and process.
+ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
+ {
+ m_window = new MainWindow();
+ m_window.Activate();
+ }
+
+ private Window m_window;
+ }
+}
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/Bruno'sFamily2015 (13)-X2.jpg b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/Bruno'sFamily2015 (13)-X2.jpg
new file mode 100644
index 000000000..55d9ce799
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/Bruno'sFamily2015 (13)-X2.jpg differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/Checkerboard_100x100.png b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/Checkerboard_100x100.png
new file mode 100644
index 000000000..f5e97147e
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/Checkerboard_100x100.png differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/CircleMask.png b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/CircleMask.png
new file mode 100644
index 000000000..4f64b1f1b
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/CircleMask.png differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/_P2A8041.jpg b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/_P2A8041.jpg
new file mode 100644
index 000000000..ab29117d8
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Assets/_P2A8041.jpg differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/EffectEditorApp.csproj b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/EffectEditorApp.csproj
new file mode 100644
index 000000000..4be186ba1
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/EffectEditorApp.csproj
@@ -0,0 +1,53 @@
+
+
+ WinExe
+ net8.0-windows10.0.19041.0
+ 10.0.17763.0
+ EffectEditor
+ app.manifest
+ x86;x64;arm64
+ win-x86;win-x64;win-arm64
+ true
+
+
+ 1701;1702;CA1416
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+ MSBuild:Compile
+
+
+
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainPage.xaml b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainPage.xaml
new file mode 100644
index 000000000..b926a5d8c
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainPage.xaml
@@ -0,0 +1,246 @@
+
+
+
+
+
+ No Effect
+ Alpha Mask
+ Arithmetic
+ Blend
+ Color Source
+ Contrast
+ Exposure
+ Gamma Transfer
+ Grayscale
+ Hue Rotation
+ Invert
+ Saturation
+ Sepia
+ Temperature and Tint
+ Transform 2D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Red
+ Green
+ Blue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Premultiplied
+ Straight
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainPage.xaml.cs b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainPage.xaml.cs
new file mode 100644
index 000000000..45f12b854
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainPage.xaml.cs
@@ -0,0 +1,886 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+//
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Composition;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Hosting;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Numerics;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Xml;
+using Microsoft.Graphics.Canvas;
+using Microsoft.Graphics.Canvas.Effects;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.Graphics.Imaging;
+using Windows.Storage;
+using Windows.UI;
+using SamplesCommon;
+using static SamplesCommon.ImageLoader;
+
+// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
+
+namespace EffectEditor
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+ public sealed partial class MainPage : Page
+ {
+ public enum EffectType
+ {
+ NoEffect,
+ AlphaMask,
+ Arithmetic,
+ Blend,
+ ColorSource,
+ Contrast,
+ Exposure,
+ GammaTransfer,
+ Grayscale,
+ HueRotation,
+ Invert,
+ Saturation,
+ Sepia,
+ TemperatureAndTint,
+ Transform2D,
+
+ NumEffectTypes
+ }
+
+ public MainPage()
+ {
+ this.InitializeComponent();
+
+ DataContext = this;
+ }
+
+
+ void InitializeValues()
+ {
+ EffectSelector.SelectedIndex = 0;
+ ArithmeticMultiply.Value = 0.5f;
+ ArithmeticSource1.Value = 0.5f;
+ ArithmeticSource2.Value = 0.5f;
+ ArithmeticOffset.Value = 0.0f;
+ BlendModeSelector.SelectedIndex = 0;
+ ColorSourceRed.Value = 1.0f;
+ ColorSourceGreen.Value = 1.0f;
+ ColorSourceBlue.Value = 1.0f;
+ ColorSourceAlpha.Value = 1.0f;
+ Contrast.Value = 0.5f;
+ Exposure.Value = 0.5f;
+ GammaTransferChannelSelector.SelectedIndex = 0;
+ GammaAmplitude.Value = 1.0f;
+ GammaExponent.Value = 1.0f;
+ GammaOffset.Value = 0.0f;
+ HueRotation.Value = 0.5f;
+ Saturation.Value = 0.5f;
+ SepiaAlphaModeSelector.SelectedIndex = 0;
+ Sepia.Value = 0.5f;
+ Temperature.Value = 0.5f;
+ Tint.Value = 0.5f;
+ }
+
+ private CompositionSurfaceBrush CreateBrushFromAsset(string name, out Size size)
+ {
+ CompositionDrawingSurface surface = ImageLoader.Instance.LoadFromUri(new Uri("ms-appx:///Assets/" + name)).Surface;
+ size = surface.Size;
+ return m_compositor.CreateSurfaceBrush(surface);
+ }
+
+ private CompositionSurfaceBrush CreateBrushFromAsset(string name)
+ {
+ Size size;
+ return CreateBrushFromAsset(name, out size);
+ }
+
+ private void MainGridLoaded(object sender, RoutedEventArgs e)
+ {
+ m_compositor = ElementCompositionPreview.GetElementVisual(MainGrid).Compositor;
+ m_root = m_compositor.CreateContainerVisual();
+ ElementCompositionPreview.SetElementChildVisual(MainGrid, m_root);
+
+ ImageLoader.Initialize(m_compositor);
+
+ Size imageSize;
+ m_noEffectBrush = CreateBrushFromAsset(
+ "Bruno'sFamily2015 (13)-X2.jpg",
+ out imageSize);
+ m_imageAspectRatio = (imageSize.Width == 0 && imageSize.Height == 0) ? 1 : imageSize.Width / imageSize.Height;
+
+ m_sprite = m_compositor.CreateSpriteVisual();
+ ResizeImage(new Size(MainGrid.ActualWidth, MainGrid.ActualHeight));
+ m_root.Children.InsertAtTop(m_sprite);
+
+ // Image with alpha channel as an mask.
+ var alphaMaskEffectDesc = new CompositeEffect
+ {
+ Mode = CanvasComposite.DestinationIn,
+ Sources =
+ {
+ new CompositionEffectSourceParameter("Image"),
+ new Transform2DEffect
+ {
+ Name = "MaskTransform",
+ Source = new CompositionEffectSourceParameter("Mask")
+ }
+ }
+ };
+ m_alphaMaskEffectBrush = m_compositor.CreateEffectFactory(
+ alphaMaskEffectDesc,
+ new[] { "MaskTransform.TransformMatrix" }
+ ).CreateBrush();
+ m_alphaMaskEffectBrush.SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+ m_alphaMaskEffectBrush.SetSourceParameter(
+ "Mask",
+ CreateBrushFromAsset("CircleMask.png"));
+
+ // Arithmetic operations between two images.
+ var arithmeticEffectDesc = new ArithmeticCompositeEffect
+ {
+ Name = "effect",
+ ClampOutput = false,
+ Source1 = new CompositionEffectSourceParameter("Source1"),
+ Source2 = new CompositionEffectSourceParameter("Source2")
+ };
+ m_arithmeticEffectBrush = m_compositor.CreateEffectFactory(
+ arithmeticEffectDesc,
+ new[]
+ {
+ "effect.MultiplyAmount",
+ "effect.Source1Amount",
+ "effect.Source2Amount",
+ "effect.Offset"
+ }
+ ).CreateBrush();
+ m_arithmeticEffectBrush.SetSourceParameter(
+ "Source1",
+ m_noEffectBrush);
+ m_arithmeticEffectBrush.SetSourceParameter(
+ "Source2",
+ CreateBrushFromAsset("_P2A8041.jpg"));
+
+ // Creates a blend effect that combines two images.
+ var foregroundBrush = CreateBrushFromAsset("Checkerboard_100x100.png");
+ m_blendEffectBrushes = new CompositionEffectBrush[m_supportedBlendModes.Length];
+ for (int i = 0; i < m_supportedBlendModes.Length; i++)
+ {
+ var blendEffectDesc = new BlendEffect
+ {
+ Mode = m_supportedBlendModes[i],
+ Background = new CompositionEffectSourceParameter("Background"),
+ Foreground = new CompositionEffectSourceParameter("Foreground")
+ };
+ m_blendEffectBrushes[i] = m_compositor.CreateEffectFactory(
+ blendEffectDesc
+ ).CreateBrush();
+ m_blendEffectBrushes[i].SetSourceParameter(
+ "Background",
+ m_noEffectBrush);
+ m_blendEffectBrushes[i].SetSourceParameter(
+ "Foreground",
+ foregroundBrush);
+ }
+
+ // Generates an image containing a solid color.
+ var colorSourceEffectDesc = new ColorSourceEffect // FloodEffect
+ {
+ Name = "effect"
+ };
+ m_colorSourceEffectBrush = m_compositor.CreateEffectFactory(
+ colorSourceEffectDesc,
+ new[] { "effect.Color" }
+ ).CreateBrush();
+
+ // Changes the contrast of an image.
+ var contrastEffectDesc = new ContrastEffect
+ {
+ Name = "effect",
+ Source = new CompositionEffectSourceParameter("Image")
+ };
+ m_contrastEffectBrush = m_compositor.CreateEffectFactory(
+ contrastEffectDesc,
+ new[] { "effect.Contrast" }
+ ).CreateBrush();
+ m_contrastEffectBrush.SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+
+ // Changes the exposure of an image.
+ var exposureEffectDesc = new ExposureEffect
+ {
+ Name = "effect",
+ Source = new CompositionEffectSourceParameter("Image")
+ };
+ m_exposureEffectBrush = m_compositor.CreateEffectFactory(
+ exposureEffectDesc,
+ new[] { "effect.Exposure" }
+ ).CreateBrush();
+ m_exposureEffectBrush.SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+
+ // Alters the colors of an image by applying a per-channel gamma transfer function.
+ var gammaTransferEffectDesc = new GammaTransferEffect
+ {
+ Name = "effect",
+ RedDisable = false,
+ GreenDisable = false,
+ BlueDisable = false,
+ AlphaDisable = false,
+ Source = new CompositionEffectSourceParameter("Image")
+ };
+ m_gammaTransferEffectBrush = m_compositor.CreateEffectFactory(
+ gammaTransferEffectDesc,
+ new[]
+ {
+ "effect.RedAmplitude",
+ "effect.RedExponent",
+ "effect.RedOffset",
+ "effect.GreenAmplitude",
+ "effect.GreenExponent",
+ "effect.GreenOffset",
+ "effect.BlueAmplitude",
+ "effect.BlueExponent",
+ "effect.BlueOffset"
+ }
+ ).CreateBrush();
+ m_gammaTransferEffectBrush.SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+
+ // Converts an image to monochromatic gray.
+ var grayscaleEffectDesc = new GrayscaleEffect
+ {
+ Name = "effect",
+ Source = new CompositionEffectSourceParameter("Image")
+ };
+ m_grayscaleEffectBrush = m_compositor.CreateEffectFactory(
+ grayscaleEffectDesc
+ ).CreateBrush();
+ m_grayscaleEffectBrush.SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+
+ // Alters the color of an image by rotating its hue values.
+ var hueRotationEffectDesc = new HueRotationEffect
+ {
+ Name = "effect",
+ Source = new CompositionEffectSourceParameter("Image")
+ };
+ m_hueRotationEffectBrush = m_compositor.CreateEffectFactory(
+ hueRotationEffectDesc,
+ new[] { "effect.Angle" }
+ ).CreateBrush();
+ m_hueRotationEffectBrush.SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+
+ // Inverts the colors of an image.
+ var invertEffectDesc = new InvertEffect
+ {
+ Name = "effect",
+ Source = new CompositionEffectSourceParameter("Image")
+ };
+ m_invertEffectBrush = m_compositor.CreateEffectFactory(
+ invertEffectDesc
+ ).CreateBrush();
+ m_invertEffectBrush.SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+
+ // Alters the saturation of an image.
+ var saturationEffectDesc = new SaturationEffect
+ {
+ Name = "effect",
+ Source = new CompositionEffectSourceParameter("Image")
+ };
+ m_saturateEffectBrush = m_compositor.CreateEffectFactory(
+ saturationEffectDesc,
+ new[] { "effect.Saturation" }
+ ).CreateBrush();
+ m_saturateEffectBrush.SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+
+ // Converts an image to sepia tones.
+ var supportedAlphaModes = new[]
+ {
+ CanvasAlphaMode.Premultiplied,
+ CanvasAlphaMode.Straight
+ };
+ m_sepiaEffectBrushes = new CompositionEffectBrush[supportedAlphaModes.Length];
+ for (int i = 0; i < supportedAlphaModes.Length; i++)
+ {
+ var sepiaEffectDesc = new SepiaEffect
+ {
+ Name = "effect",
+ AlphaMode = supportedAlphaModes[i],
+ Source = new CompositionEffectSourceParameter("Image")
+ };
+ m_sepiaEffectBrushes[i] = m_compositor.CreateEffectFactory(
+ sepiaEffectDesc,
+ new[] { "effect.Intensity" }
+ ).CreateBrush();
+ m_sepiaEffectBrushes[i].SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+ }
+
+ // Adjusts the temperature and/or tint of an image.
+ var temperatureAndTintEffectDesc = new TemperatureAndTintEffect
+ {
+ Name = "effect",
+ Source = new CompositionEffectSourceParameter("Image")
+ };
+ m_temperatureAndTintEffectBrush = m_compositor.CreateEffectFactory(
+ temperatureAndTintEffectDesc,
+ new[]
+ {
+ "effect.Temperature",
+ "effect.Tint"
+ }
+ ).CreateBrush();
+ m_temperatureAndTintEffectBrush.SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+
+ // Applies a 2D affine transform matrix to an image.
+ var transform2DEffectDesc = new Transform2DEffect
+ {
+ TransformMatrix = new Matrix3x2(
+ -1, 0,
+ 0, 1,
+ m_sprite.Size.X, 0),
+ Source = new CompositionEffectSourceParameter("Image")
+ };
+ m_transform2DEffectBrush = m_compositor.CreateEffectFactory(
+ transform2DEffectDesc
+ ).CreateBrush();
+ m_transform2DEffectBrush.SetSourceParameter(
+ "Image",
+ m_noEffectBrush);
+
+ // For simplying UI states switch, put effect parameter grids in an array
+ m_effectParamsGrids = new Grid[(int)EffectType.NumEffectTypes];
+ m_effectParamsGrids[(int)EffectType.NoEffect] = null;
+ m_effectParamsGrids[(int)EffectType.AlphaMask] = AlphaMaskParams;
+ m_effectParamsGrids[(int)EffectType.Arithmetic] = ArithmeticParams;
+ m_effectParamsGrids[(int)EffectType.Blend] = BlendParams;
+ m_effectParamsGrids[(int)EffectType.ColorSource] = ColorSourceParams;
+ m_effectParamsGrids[(int)EffectType.Contrast] = ContrastParams;
+ m_effectParamsGrids[(int)EffectType.Exposure] = ExposureParams;
+ m_effectParamsGrids[(int)EffectType.GammaTransfer] = GammaTransferParams;
+ m_effectParamsGrids[(int)EffectType.Grayscale] = null;
+ m_effectParamsGrids[(int)EffectType.HueRotation] = HueRotationParams;
+ m_effectParamsGrids[(int)EffectType.Invert] = null;
+ m_effectParamsGrids[(int)EffectType.Saturation] = SaturationParams;
+ m_effectParamsGrids[(int)EffectType.Sepia] = SepiaParams;
+ m_effectParamsGrids[(int)EffectType.TemperatureAndTint] = TemperatureAndTintParams;
+ m_effectParamsGrids[(int)EffectType.Transform2D] = null;
+
+ // Same as grids
+ m_effectBrushes = new CompositionBrush[(int)EffectType.NumEffectTypes];
+ m_effectBrushes[(int)EffectType.NoEffect] = m_noEffectBrush;
+ m_effectBrushes[(int)EffectType.AlphaMask] = m_alphaMaskEffectBrush;
+ m_effectBrushes[(int)EffectType.Arithmetic] = m_arithmeticEffectBrush;
+ m_effectBrushes[(int)EffectType.Blend] = m_blendEffectBrushes[m_activeBlendMode];
+ m_effectBrushes[(int)EffectType.ColorSource] = m_colorSourceEffectBrush;
+ m_effectBrushes[(int)EffectType.Contrast] = m_contrastEffectBrush;
+ m_effectBrushes[(int)EffectType.Exposure] = m_exposureEffectBrush;
+ m_effectBrushes[(int)EffectType.GammaTransfer] = m_gammaTransferEffectBrush;
+ m_effectBrushes[(int)EffectType.Grayscale] = m_grayscaleEffectBrush;
+ m_effectBrushes[(int)EffectType.HueRotation] = m_hueRotationEffectBrush;
+ m_effectBrushes[(int)EffectType.Invert] = m_invertEffectBrush;
+ m_effectBrushes[(int)EffectType.Saturation] = m_saturateEffectBrush;
+ m_effectBrushes[(int)EffectType.Sepia] = m_sepiaEffectBrushes[m_activeSepiaAlphaMode];
+ m_effectBrushes[(int)EffectType.TemperatureAndTint] = m_temperatureAndTintEffectBrush;
+ m_effectBrushes[(int)EffectType.Transform2D] = m_transform2DEffectBrush;
+
+ this.InitializeValues();
+ }
+
+ private void MainGridSizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ if (m_sprite != null)
+ {
+ ResizeImage(e.NewSize);
+ }
+ }
+
+ private void ResizeImage(Size windowSize)
+ {
+ double visibleWidth = windowSize.Width - EffectControls.Width;
+ double visibleHeight = windowSize.Height;
+ double newWidth = visibleWidth;
+ double newHeight = visibleHeight;
+
+ newWidth = newHeight * m_imageAspectRatio;
+ if (newWidth > visibleWidth)
+ {
+ newWidth = visibleWidth;
+ newHeight = newWidth / m_imageAspectRatio;
+ }
+
+ m_sprite.Offset = new Vector3(
+ (float)(EffectControls.Width + (visibleWidth - newWidth) / 2),
+ (float)((visibleHeight - newHeight) / 2),
+ 0.0f);
+ m_sprite.Size = new Vector2(
+ (float)newWidth,
+ (float)newHeight);
+ }
+
+ string ChannelName(int index)
+ {
+ string channel;
+ switch (index)
+ {
+ case 0:
+ channel = "Red";
+ break;
+ case 1:
+ channel = "Green";
+ break;
+ case 2:
+ channel = "Blue";
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ return channel;
+ }
+
+ public EffectType ActiveEffectType
+ {
+ get
+ {
+ return m_activeEffectType;
+ }
+ set
+ {
+ m_activeEffectType = value;
+
+ foreach (Grid paramsGrid in m_effectParamsGrids)
+ {
+ if (paramsGrid != null)
+ {
+ paramsGrid.Visibility = Visibility.Collapsed;
+ }
+ }
+
+ Grid selectedParamsGrid = m_effectParamsGrids[(int)m_activeEffectType];
+ if (selectedParamsGrid != null)
+ {
+ selectedParamsGrid.Visibility = Visibility.Visible;
+ }
+
+ m_sprite.Brush = m_effectBrushes[(int)m_activeEffectType];
+
+ EffectControls.UpdateLayout();
+ }
+ }
+
+ public int ActiveBlendMode
+ {
+ get
+ {
+ return m_activeBlendMode;
+ }
+ set
+ {
+ m_activeBlendMode = value;
+ m_sprite.Brush = m_effectBrushes[(int)EffectType.Blend]
+ = m_blendEffectBrushes[m_activeBlendMode];
+ }
+ }
+
+ public int ActiveSepiaAlphaMode
+ {
+ get
+ {
+ return m_activeSepiaAlphaMode;
+ }
+ set
+ {
+ m_activeSepiaAlphaMode = value;
+ m_sprite.Brush = m_effectBrushes[(int)EffectType.Sepia]
+ = m_sepiaEffectBrushes[m_activeSepiaAlphaMode];
+ }
+ }
+
+ public IReadOnlyList SupportedBlendModes
+ {
+ get
+ {
+ return m_supportedBlendModes;
+ }
+ }
+
+ private void OnArithmeticMultiplyValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_arithmeticEffectBrush.Properties.InsertScalar(
+ "effect.MultiplyAmount",
+ (float)(e.NewValue));
+ }
+
+ private void OnArithmeticSource1ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_arithmeticEffectBrush.Properties.InsertScalar(
+ "effect.Source1Amount",
+ (float)(e.NewValue));
+ }
+
+ private void OnArithmeticSource2ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_arithmeticEffectBrush.Properties.InsertScalar(
+ "effect.Source2Amount",
+ (float)(e.NewValue));
+ }
+
+ private void OnArithmeticOffsetValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_arithmeticEffectBrush.Properties.InsertScalar(
+ "effect.Offset",
+ (float)(e.NewValue));
+ }
+
+ private void OnColorSourceRedValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_colorSource.R = (byte)(e.NewValue * 255);
+ m_colorSourceEffectBrush.Properties.InsertColor(
+ "effect.Color",
+ m_colorSource);
+ }
+
+ private void OnColorSourceGreenValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_colorSource.G = (byte)(e.NewValue * 255);
+ m_colorSourceEffectBrush.Properties.InsertColor(
+ "effect.Color",
+ m_colorSource);
+ }
+
+ private void OnColorSourceBlueValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_colorSource.B = (byte)(e.NewValue * 255);
+ m_colorSourceEffectBrush.Properties.InsertColor(
+ "effect.Color",
+ m_colorSource);
+ }
+
+ private void OnColorSourceAlphaValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_colorSource.A = (byte)(e.NewValue * 255);
+ m_colorSourceEffectBrush.Properties.InsertColor(
+ "effect.Color",
+ m_colorSource);
+ }
+
+ private void OnContrastValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_contrastEffectBrush.Properties.InsertScalar(
+ "effect.Contrast",
+ (float)e.NewValue);
+ }
+
+ private void OnExposureValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_exposureEffectBrush.Properties.InsertScalar(
+ "effect.Exposure",
+ (float)e.NewValue);
+ }
+
+ private void OnGammaTransferChannelSelectorSelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (m_activeEffectType == EffectType.GammaTransfer)
+ {
+ m_sprite.Brush = m_gammaTransferEffectBrush;
+ }
+ }
+
+ private void OnGammaAmplitudeValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_gammaTransferEffectBrush.Properties.InsertScalar(
+ "effect." + ChannelName(GammaTransferChannelSelector.SelectedIndex) + "Amplitude",
+ (float)(e.NewValue));
+ }
+
+ private void OnGammaExponentValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_gammaTransferEffectBrush.Properties.InsertScalar(
+ "effect." + ChannelName(GammaTransferChannelSelector.SelectedIndex) + "Exponent",
+ (float)(e.NewValue));
+ }
+
+ private void OnGammaOffsetValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_gammaTransferEffectBrush.Properties.InsertScalar(
+ "effect." + ChannelName(GammaTransferChannelSelector.SelectedIndex) + "Offset",
+ (float)(e.NewValue));
+ }
+
+ private void OnHueRotationValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_hueRotationEffectBrush.Properties.InsertScalar(
+ "effect.Angle",
+ (float)(e.NewValue * Math.PI * 2));
+ }
+
+ private void OnSaturationValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_saturateEffectBrush.Properties.InsertScalar(
+ "effect.Saturation",
+ (float)e.NewValue);
+ }
+
+ private void OnSepiaValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_sepiaEffectBrushes[m_activeSepiaAlphaMode].Properties.InsertScalar(
+ "effect.Intensity",
+ (float)e.NewValue);
+ }
+
+ private void OnTemperatureValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_temperatureAndTintEffectBrush.Properties.InsertScalar(
+ "effect.Temperature",
+ (float)e.NewValue);
+ }
+
+ private void OnTintValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ m_temperatureAndTintEffectBrush.Properties.InsertScalar(
+ "effect.Tint",
+ (float)e.NewValue);
+ }
+
+ private void OnAlphaMaskAnimationToggled(object sender, RoutedEventArgs e)
+ {
+ if (AlphaMaskAnimation.IsOn)
+ {
+ var propertySet = m_compositor.CreatePropertySet();
+ propertySet.InsertScalar("Size", 0.0f);
+
+ // An animation for scaling the mask
+
+ var scaleAnimation = m_compositor.CreateScalarKeyFrameAnimation();
+ var linearEasing = m_compositor.CreateLinearEasingFunction();
+ scaleAnimation.InsertKeyFrame(0.0f, 0.0f, linearEasing);
+ scaleAnimation.InsertKeyFrame(0.4f, 1.0f, linearEasing);
+ scaleAnimation.InsertKeyFrame(0.6f, 1.0f, linearEasing);
+ scaleAnimation.InsertKeyFrame(1.0f, 0.0f, linearEasing);
+ scaleAnimation.Duration = TimeSpan.FromMilliseconds(5000);
+ scaleAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
+ propertySet.StartAnimation("Size", scaleAnimation);
+
+ var transformExpression = m_compositor.CreateExpressionAnimation(
+ "Matrix3x2(Props.Size, 0, 0, Props.Size, 0, 0)");
+ transformExpression.SetReferenceParameter("Props", propertySet);
+ m_alphaMaskEffectBrush.StartAnimation("MaskTransform.TransformMatrix",
+ transformExpression);
+ }
+ else
+ {
+ m_alphaMaskEffectBrush.StopAnimation("MaskTransform.TransformMatrix");
+ }
+ }
+
+ private void OnContrastAnimationToggled(object sender, RoutedEventArgs e)
+ {
+ if (ContrastAnimation.IsOn)
+ {
+ Contrast.IsEnabled = false;
+
+ // Animates the contrast from 0 to 1 and back to 0
+
+ var animation = m_compositor.CreateScalarKeyFrameAnimation();
+ animation.InsertExpressionKeyFrame(0.0f, "0.0f");
+ animation.InsertExpressionKeyFrame(0.5f, "1.0f");
+ animation.InsertExpressionKeyFrame(1.0f, "0.0f");
+ animation.Duration = TimeSpan.FromMilliseconds(5000);
+ animation.IterationBehavior = AnimationIterationBehavior.Forever;
+ m_contrastEffectBrush.StartAnimation("effect.Contrast", animation);
+ }
+ else
+ {
+ m_contrastEffectBrush.StopAnimation("effect.Contrast");
+
+ Contrast.IsEnabled = true;
+ }
+ }
+
+ private void OnExposureAnimationToggled(object sender, RoutedEventArgs e)
+ {
+ if (ExposureAnimation.IsOn)
+ {
+ Exposure.IsEnabled = false;
+
+ var animation = m_compositor.CreateScalarKeyFrameAnimation();
+ animation.InsertExpressionKeyFrame(0.0f, "0.0f");
+ animation.InsertExpressionKeyFrame(0.5f, "1.0f");
+ animation.InsertExpressionKeyFrame(1.0f, "0.0f");
+ animation.Duration = TimeSpan.FromMilliseconds(5000);
+ animation.IterationBehavior = AnimationIterationBehavior.Forever;
+ m_exposureEffectBrush.StartAnimation("effect.Exposure", animation);
+ }
+ else
+ {
+ m_exposureEffectBrush.StopAnimation("effect.Exposure");
+
+ Exposure.IsEnabled = true;
+ }
+ }
+
+ private void OnHueRotationAnimationToggled(object sender, RoutedEventArgs e)
+ {
+ if (HueRotationAnimation.IsOn)
+ {
+ HueRotation.IsEnabled = false;
+
+ var animation = m_compositor.CreateScalarKeyFrameAnimation();
+ animation.InsertExpressionKeyFrame(0.0f, "0.0f");
+ animation.InsertExpressionKeyFrame(0.5f, "PI * 2");
+ animation.InsertExpressionKeyFrame(1.0f, "0.0f");
+ animation.Duration = TimeSpan.FromMilliseconds(5000);
+ animation.IterationBehavior = AnimationIterationBehavior.Forever;
+ m_hueRotationEffectBrush.StartAnimation("effect.Angle", animation);
+ }
+ else
+ {
+ m_hueRotationEffectBrush.StopAnimation("effect.Angle");
+
+ HueRotation.IsEnabled = true;
+ }
+ }
+
+ private void OnSepiaAnimationToggled(object sender, RoutedEventArgs e)
+ {
+ if (SepiaAnimation.IsOn)
+ {
+ Sepia.IsEnabled = false;
+
+ var animation = m_compositor.CreateScalarKeyFrameAnimation();
+ animation.InsertExpressionKeyFrame(0.0f, "0.0f");
+ animation.InsertExpressionKeyFrame(0.5f, "1.0f");
+ animation.InsertExpressionKeyFrame(1.0f, "0.0f");
+ animation.Duration = TimeSpan.FromMilliseconds(5000);
+ animation.IterationBehavior = AnimationIterationBehavior.Forever;
+ m_sepiaEffectBrushes[m_activeSepiaAlphaMode].StartAnimation(
+ "effect.Intensity",
+ animation);
+ }
+ else
+ {
+ m_sepiaEffectBrushes[m_activeSepiaAlphaMode].StopAnimation("effect.Intensity");
+
+ Sepia.IsEnabled = true;
+ }
+ }
+
+ private void OnSaturationAnimationToggled(object sender, RoutedEventArgs e)
+ {
+ if (SaturationAnimation.IsOn)
+ {
+ Saturation.IsEnabled = false;
+
+ var animation = m_compositor.CreateScalarKeyFrameAnimation();
+ animation.InsertExpressionKeyFrame(0.0f, "0.0f");
+ animation.InsertExpressionKeyFrame(0.5f, "1.0f");
+ animation.InsertExpressionKeyFrame(1.0f, "0.0f");
+ animation.Duration = TimeSpan.FromMilliseconds(5000);
+ animation.IterationBehavior = AnimationIterationBehavior.Forever;
+ m_saturateEffectBrush.StartAnimation("effect.Saturation", animation);
+ }
+ else
+ {
+ m_saturateEffectBrush.StopAnimation("effect.Saturation");
+
+ Saturation.IsEnabled = true;
+ }
+ }
+
+ private Compositor m_compositor;
+ private ContainerVisual m_root;
+ private SpriteVisual m_sprite;
+
+ private CompositionSurfaceBrush m_noEffectBrush;
+ private CompositionEffectBrush m_alphaMaskEffectBrush;
+ private CompositionEffectBrush m_arithmeticEffectBrush;
+ private CompositionEffectBrush[] m_blendEffectBrushes;
+ private CompositionEffectBrush m_colorSourceEffectBrush;
+ private CompositionEffectBrush m_contrastEffectBrush;
+ private CompositionEffectBrush m_exposureEffectBrush;
+ private CompositionEffectBrush m_grayscaleEffectBrush;
+ private CompositionEffectBrush m_gammaTransferEffectBrush;
+ private CompositionEffectBrush m_hueRotationEffectBrush;
+ private CompositionEffectBrush m_invertEffectBrush;
+ private CompositionEffectBrush m_saturateEffectBrush;
+ private CompositionEffectBrush[] m_sepiaEffectBrushes;
+ private CompositionEffectBrush m_temperatureAndTintEffectBrush;
+ private CompositionEffectBrush m_transform2DEffectBrush;
+
+ private Color m_colorSource;
+
+ private BlendEffectMode[] m_supportedBlendModes = new[]
+ {
+ BlendEffectMode.Multiply,
+ BlendEffectMode.Screen,
+ BlendEffectMode.Darken,
+ BlendEffectMode.Lighten,
+ BlendEffectMode.ColorBurn,
+ BlendEffectMode.LinearBurn,
+ BlendEffectMode.DarkerColor,
+ BlendEffectMode.LighterColor,
+ BlendEffectMode.ColorDodge,
+ BlendEffectMode.LinearDodge,
+ BlendEffectMode.Overlay,
+ BlendEffectMode.SoftLight,
+ BlendEffectMode.HardLight,
+ BlendEffectMode.VividLight,
+ BlendEffectMode.LinearLight,
+ BlendEffectMode.PinLight,
+ BlendEffectMode.HardMix,
+ BlendEffectMode.Difference,
+ BlendEffectMode.Exclusion,
+ BlendEffectMode.Subtract,
+ BlendEffectMode.Division
+ };
+
+ private Grid[] m_effectParamsGrids;
+ private CompositionBrush[] m_effectBrushes;
+
+ private EffectType m_activeEffectType = EffectType.NoEffect;
+ private int m_activeBlendMode = 0;
+ private int m_activeSepiaAlphaMode = 0;
+
+ private double m_imageAspectRatio;
+ }
+}
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainWindow.xaml b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainWindow.xaml
new file mode 100644
index 000000000..e2bdd3e64
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainWindow.xaml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainWindow.xaml.cs b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainWindow.xaml.cs
new file mode 100644
index 000000000..ebfc55cb1
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/MainWindow.xaml.cs
@@ -0,0 +1,46 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace EffectEditor
+{
+ ///
+ /// An empty window that can be used on its own or navigated to within a Frame.
+ ///
+ public sealed partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ this.InitializeComponent();
+ this.Title = "Effect Editor - Windows App SDK";
+ }
+ }
+}
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Properties/PublishProfiles/win-arm64.pubxml b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Properties/PublishProfiles/win-arm64.pubxml
new file mode 100644
index 000000000..08b5300d8
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Properties/PublishProfiles/win-arm64.pubxml
@@ -0,0 +1,19 @@
+
+
+
+
+ FileSystem
+ arm64
+ win-arm64
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Properties/PublishProfiles/win-x64.pubxml b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Properties/PublishProfiles/win-x64.pubxml
new file mode 100644
index 000000000..dcdbaed60
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Properties/PublishProfiles/win-x64.pubxml
@@ -0,0 +1,19 @@
+
+
+
+
+ FileSystem
+ x64
+ win-x64
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Properties/PublishProfiles/win-x86.pubxml b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Properties/PublishProfiles/win-x86.pubxml
new file mode 100644
index 000000000..cf7e029c0
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/Properties/PublishProfiles/win-x86.pubxml
@@ -0,0 +1,19 @@
+
+
+
+
+ FileSystem
+ x86
+ win-x86
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/app.manifest b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/app.manifest
new file mode 100644
index 000000000..55cb58f36
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorApp/app.manifest
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+
+
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/EffectEditorPackage.wapproj b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/EffectEditorPackage.wapproj
new file mode 100644
index 000000000..046bb2981
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/EffectEditorPackage.wapproj
@@ -0,0 +1,62 @@
+
+
+
+ 15.0
+
+
+
+ Debug
+ x86
+
+
+ Release
+ x86
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ arm64
+
+
+ Release
+ arm64
+
+
+
+ $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\
+
+
+ 4e5e4821-d14b-451b-b4a0-9c0a872f4a25
+ 10.0.19041.0
+ 10.0.17763.0
+ en-US
+ false
+ ..\EffectEditorApp\EffectEditorApp.csproj
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/LockScreenLogo.scale-200.png b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/LockScreenLogo.scale-200.png
new file mode 100644
index 000000000..7440f0d4b
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/LockScreenLogo.scale-200.png differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/SplashScreen.scale-200.png b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/SplashScreen.scale-200.png
new file mode 100644
index 000000000..32f486a86
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/SplashScreen.scale-200.png differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Square150x150Logo.scale-200.png b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Square150x150Logo.scale-200.png
new file mode 100644
index 000000000..53ee3777e
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Square150x150Logo.scale-200.png differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Square44x44Logo.scale-200.png b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Square44x44Logo.scale-200.png
new file mode 100644
index 000000000..f713bba67
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Square44x44Logo.scale-200.png differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Square44x44Logo.targetsize-24_altform-unplated.png b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 000000000..dc9f5bea0
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/StoreLogo.png b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/StoreLogo.png
new file mode 100644
index 000000000..a4586f26b
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/StoreLogo.png differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Wide310x150Logo.scale-200.png b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Wide310x150Logo.scale-200.png
new file mode 100644
index 000000000..8b4a5d0dd
Binary files /dev/null and b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Images/Wide310x150Logo.scale-200.png differ
diff --git a/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Package.appxmanifest b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Package.appxmanifest
new file mode 100644
index 000000000..4d32101f8
--- /dev/null
+++ b/Samples/SceneGraph/Demos/EffectEditor/EffectEditorPackage/Package.appxmanifest
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+ EffectEditorPackage
+ getrou
+ Images\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/App.xaml b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/App.xaml
new file mode 100644
index 000000000..e98a5b37d
--- /dev/null
+++ b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/App.xaml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/App.xaml.cs b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/App.xaml.cs
new file mode 100644
index 000000000..325250ff6
--- /dev/null
+++ b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/App.xaml.cs
@@ -0,0 +1,65 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+using Microsoft.UI.Xaml.Shapes;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.ApplicationModel;
+using Windows.ApplicationModel.Activation;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace MaterialCreator
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ public partial class App : Application
+ {
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ }
+
+ ///
+ /// Invoked when the application is launched normally by the end user. Other entry points
+ /// will be used such as when the application is launched to open a specific file.
+ ///
+ /// Details about the launch request and process.
+ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
+ {
+ m_window = new MainWindow();
+ m_window.Activate();
+ }
+
+ private Window m_window;
+ }
+}
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/Aurora.jpg b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/Aurora.jpg
new file mode 100644
index 000000000..c97845eb7
Binary files /dev/null and b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/Aurora.jpg differ
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/City.jpg b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/City.jpg
new file mode 100644
index 000000000..a87cdf613
Binary files /dev/null and b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/City.jpg differ
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/Ferns.jpg b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/Ferns.jpg
new file mode 100644
index 000000000..0bf7e81f4
Binary files /dev/null and b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/Ferns.jpg differ
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/Lake.jpg b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/Lake.jpg
new file mode 100644
index 000000000..49668e35e
Binary files /dev/null and b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/Lake.jpg differ
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/MatMDL2.ttf b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/MatMDL2.ttf
new file mode 100644
index 000000000..6496b71a6
Binary files /dev/null and b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/MatMDL2.ttf differ
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/SwatchCheckerboard.png b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/SwatchCheckerboard.png
new file mode 100644
index 000000000..1f2e600ed
Binary files /dev/null and b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Assets/SwatchCheckerboard.png differ
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditEffectControl.xaml b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditEffectControl.xaml
new file mode 100644
index 000000000..6d32f4e71
--- /dev/null
+++ b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditEffectControl.xaml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditEffectControl.xaml.cs b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditEffectControl.xaml.cs
new file mode 100644
index 000000000..e7a1a7acf
--- /dev/null
+++ b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditEffectControl.xaml.cs
@@ -0,0 +1,73 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Xaml.Controls;
+using System;
+using System.Diagnostics;
+using System.Reflection;
+
+namespace MaterialCreator
+{
+ public sealed partial class EditEffectControl : UserControl
+ {
+ Effect _effect;
+
+ public EditEffectControl()
+ {
+ this.InitializeComponent();
+ }
+
+ public void Initialize(Effect effect)
+ {
+ Debug.Assert(effect != null);
+ _effect = effect;
+
+ ComboBoxItem item;
+ foreach (Type effectType in Effect.SupportedEffectTypes)
+ {
+ item = new ComboBoxItem();
+ item.Tag = effectType;
+ item.Content = effectType.Name.ToString();
+ item.IsSelected = effectType.Name == _effect.EffectType.Name;
+ EffectType.Items.Add(item);
+ }
+
+ UpdateEffectProperties();
+ }
+
+ void UpdateEffectProperties()
+ {
+ Type effectType = (Type)EffectType.SelectedValue;
+
+ EffectPropertyPanel.Children.Clear();
+
+ foreach (PropertyInfo info in effectType.GetProperties())
+ {
+ if (Helpers.SkipProperty(info.Name))
+ {
+ continue;
+ }
+
+ Helpers.AddPropertyToPanel(_effect.GraphicsEffect, _effect, EffectPropertyPanel, info);
+ }
+ }
+
+ private void EffectType_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ _effect.EffectType = (Type)EffectType.SelectedValue;
+
+ UpdateEffectProperties();
+ }
+ }
+}
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLayerControl.xaml b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLayerControl.xaml
new file mode 100644
index 000000000..17a7f6531
--- /dev/null
+++ b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLayerControl.xaml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLayerControl.xaml.cs b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLayerControl.xaml.cs
new file mode 100644
index 000000000..f995c22b4
--- /dev/null
+++ b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLayerControl.xaml.cs
@@ -0,0 +1,355 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using System;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using Windows.Storage;
+using Windows.Storage.Pickers;
+using Microsoft.UI.Composition.Effects;
+using Microsoft.UI.Xaml.Hosting;
+
+namespace MaterialCreator
+{
+ public sealed partial class EditLayerControl : UserControl
+ {
+ ObservableCollection _blendModes;
+
+ public EditLayerControl()
+ {
+ this.InitializeComponent();
+ }
+
+ public Layer Layer { get; set; }
+
+ public void Initialize(Layer layer)
+ {
+ Layer = layer;
+
+ // Create the blendmode collection
+ _blendModes = new ObservableCollection(Helpers.GetBlendModes());
+
+ // Create the layer types dropdown
+ ComboBoxItem item;
+ foreach (LayerType layerType in Enum.GetValues(typeof(LayerType)))
+ {
+ item = new ComboBoxItem();
+ item.Tag = layerType;
+ item.Content = layerType.ToString();
+
+ if ((Layer == null && layerType == LayerType.Color) ||
+ (Layer.LayerType == layerType))
+ {
+ item.IsSelected = true;
+ }
+ LayerTypeCombo.Items.Add(item);
+ }
+
+ foreach (EdgeMode edgeMode in Enum.GetValues(typeof(EdgeMode)))
+ {
+ item = new ComboBoxItem();
+ item.Tag = edgeMode;
+ item.Content = edgeMode.ToString();
+
+ if (Layer == null || Layer.LayerType != LayerType.Image ||
+ (Layer.LayerType == LayerType.Image && ((ImageLayer)Layer).EdgeMode == edgeMode))
+ {
+ item.IsSelected = true;
+ }
+
+ EdgeModeCombo.Items.Add(item);
+ }
+
+ UpdateUI();
+ }
+
+ private void OnColorPickerColorChanged(ColorPicker sender, ColorChangedEventArgs args)
+ {
+ if (Layer != null)
+ {
+ ((ColorLayer)Layer).Color = args.NewColor;
+ }
+ }
+
+ private void UpdateUI()
+ {
+ if (Layer.LayerType == LayerType.Color)
+ {
+ ColorPanel.Visibility = Visibility.Visible;
+ ColorPicker.Color = ((ColorLayer)Layer).Color;
+ }
+ else if (Layer.LayerType == LayerType.Image)
+ {
+ ImagePanel.Visibility = Visibility.Visible;
+ string file = System.IO.Path.GetFileName(((ImageLayer)Layer).FilePath);
+ if (file == null)
+ {
+ file = "";
+ }
+ Filename.Text = file;
+
+ ImageLayer layer = (ImageLayer)Layer;
+ EdgeModeCombo.SelectedValue = layer.EdgeMode.ToString();
+
+ ImagePropertyPanel.Children.Clear();
+ UpdateImageProperties(ImagePropertyPanel, layer);
+ EdgeModePanel.Children.Clear();
+ UpdateEdgeModeProperties(EdgeModePanel, layer);
+ }
+ else if (Layer.LayerType == LayerType.Lighting)
+ {
+ LightingPanel.Visibility = Visibility.Visible;
+
+ LightingLayer lightLayer = ((LightingLayer)Layer);
+
+ if (lightLayer.FilePath != null)
+ {
+ NormalMapFilename.Text = System.IO.Path.GetFileName(lightLayer.FilePath);
+
+ NormalMapPropertyPanel.Children.Clear();
+ UpdateImageProperties(NormalMapPropertyPanel, (ImageLayer)Layer);
+ UpdateEdgeModeProperties(NormalMapPropertyPanel, (ImageLayer)Layer);
+ }
+
+ UpdateLightingProperties(lightLayer);
+ }
+
+ LayerName.Text = Layer.Description;
+ BlendType.SelectedValue = Layer.BlendMode;
+ OpacitySlider.Value = (int)(Layer.Opacity * 100);
+ }
+
+ private void UpdateImageProperties(StackPanel panel, ImageLayer layer)
+ {
+ PropertyInfo info;
+
+ info = layer.Brush.GetType().GetProperties().FirstOrDefault(x => x.Name == "Offset");
+ Helpers.AddPropertyToPanel(layer.Brush, layer, panel, info);
+
+ info = layer.Brush.GetType().GetProperties().FirstOrDefault(x => x.Name == "Scale");
+ Helpers.AddPropertyToPanel(layer.Brush, layer, panel, info);
+
+ info = layer.Brush.GetType().GetProperties().FirstOrDefault(x => x.Name == "RotationAngleInDegrees");
+ Helpers.AddPropertyToPanel(layer.Brush, layer, panel, info);
+
+ info = layer.Brush.GetType().GetProperties().FirstOrDefault(x => x.Name == "AnchorPoint");
+ Helpers.AddPropertyToPanel(layer.Brush, layer, panel, info);
+
+ info = layer.Brush.GetType().GetProperties().FirstOrDefault(x => x.Name == "Stretch");
+ Helpers.AddPropertyToPanel(layer.Brush, layer, panel, info);
+
+ info = layer.Brush.GetType().GetProperties().FirstOrDefault(x => x.Name == "HorizontalAlignmentRatio");
+ Helpers.AddPropertyToPanel(layer.Brush, layer, panel, info);
+
+ }
+
+ private void UpdateLightingProperties(LightingLayer layer)
+ {
+ PropertyInfo info;
+
+ LightingPropertyPanel.Children.Clear();
+
+ SceneLightingEffect lighting = layer.LightingEffect;
+
+ info = lighting.GetType().GetProperties().FirstOrDefault(x => x.Name == "AmbientAmount");
+ Helpers.AddPropertyToPanel(lighting, layer, LightingPropertyPanel, info);
+
+ info = lighting.GetType().GetProperties().FirstOrDefault(x => x.Name == "DiffuseAmount");
+ Helpers.AddPropertyToPanel(lighting, layer, LightingPropertyPanel, info);
+
+ info = lighting.GetType().GetProperties().FirstOrDefault(x => x.Name == "SpecularAmount");
+ Helpers.AddPropertyToPanel(lighting, layer, LightingPropertyPanel, info);
+
+ info = lighting.GetType().GetProperties().FirstOrDefault(x => x.Name == "SpecularShine");
+ Helpers.AddPropertyToPanel(lighting, layer, LightingPropertyPanel, info);
+
+ info = lighting.GetType().GetProperties().FirstOrDefault(x => x.Name == "ReflectanceModel");
+ Helpers.AddPropertyToPanel(lighting, layer, LightingPropertyPanel, info);
+ }
+
+ private void UpdateEdgeModeProperties(StackPanel panel, ImageLayer layer)
+ {
+ PropertyInfo info;
+
+ if (layer.EdgeMode == EdgeMode.Ninegrid)
+ {
+ info = layer.NineGrid.GetType().GetProperties().FirstOrDefault(x => x.Name == "LeftInset");
+ Helpers.AddPropertyToPanel(layer.NineGrid, layer, panel, info);
+
+ info = layer.NineGrid.GetType().GetProperties().FirstOrDefault(x => x.Name == "TopInset");
+ Helpers.AddPropertyToPanel(layer.NineGrid, layer, panel, info);
+
+ info = layer.NineGrid.GetType().GetProperties().FirstOrDefault(x => x.Name == "RightInset");
+ Helpers.AddPropertyToPanel(layer.NineGrid, layer, panel, info);
+
+ info = layer.NineGrid.GetType().GetProperties().FirstOrDefault(x => x.Name == "BottomInset");
+ Helpers.AddPropertyToPanel(layer.NineGrid, layer, panel, info);
+
+ info = layer.NineGrid.GetType().GetProperties().FirstOrDefault(x => x.Name == "LeftInsetScale");
+ Helpers.AddPropertyToPanel(layer.NineGrid, layer, panel, info);
+
+ info = layer.NineGrid.GetType().GetProperties().FirstOrDefault(x => x.Name == "TopInsetScale");
+ Helpers.AddPropertyToPanel(layer.NineGrid, layer, panel, info);
+
+ info = layer.NineGrid.GetType().GetProperties().FirstOrDefault(x => x.Name == "RightInsetScale");
+ Helpers.AddPropertyToPanel(layer.NineGrid, layer, panel, info);
+
+ info = layer.NineGrid.GetType().GetProperties().FirstOrDefault(x => x.Name == "BottomInsetScale");
+ Helpers.AddPropertyToPanel(layer.NineGrid, layer, panel, info);
+
+ info = layer.NineGrid.GetType().GetProperties().FirstOrDefault(x => x.Name == "IsCenterHollow");
+ Helpers.AddPropertyToPanel(layer.NineGrid, layer, panel, info);
+ }
+ else
+ {
+ info = layer.BorderEffect.GetType().GetProperties().FirstOrDefault(x => x.Name == "ExtendX");
+ Helpers.AddPropertyToPanel(layer.BorderEffect, layer, panel, info);
+
+ info = layer.BorderEffect.GetType().GetProperties().FirstOrDefault(x => x.Name == "ExtendY");
+ Helpers.AddPropertyToPanel(layer.BorderEffect, layer, panel, info);
+ }
+ }
+
+ private async void Button_Click(object sender, RoutedEventArgs e)
+ {
+ FileOpenPicker openPicker = new FileOpenPicker();
+ openPicker.ViewMode = PickerViewMode.Thumbnail;
+ openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
+ openPicker.FileTypeFilter.Add(".jpg");
+ openPicker.FileTypeFilter.Add(".jpeg");
+ openPicker.FileTypeFilter.Add(".png");
+ WinRT.Interop.InitializeWithWindow.Initialize(openPicker, WinRT.Interop.WindowNative.GetWindowHandle(MainWindow.CurrentWindow));
+ StorageFile file = await openPicker.PickSingleFileAsync();
+
+ if (file != null)
+ {
+ Filename.Text = file.Name;
+ ((ImageLayer)Layer).File = file;
+ }
+ }
+
+ private void LayerType_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ ColorPanel.Visibility = Visibility.Collapsed;
+ ImagePanel.Visibility = Visibility.Collapsed;
+ LightingPanel.Visibility = Visibility.Collapsed;
+
+ ComboBoxItem item = LayerTypeCombo.SelectedItem as ComboBoxItem;
+ LayerType layerType = (LayerType)item.Tag;
+
+ if (Layer.LayerType != layerType)
+ {
+ Layer layer = null;
+ switch (layerType)
+ {
+ case LayerType.Backdrop:
+ {
+ layer = new BackdropLayer();
+ }
+ break;
+
+ //case LayerType.BackdropHost:
+ // {
+ // layer = new BackdropHostLayer();
+ // }
+ // break;
+
+ case LayerType.Color:
+ {
+ layer = new ColorLayer();
+ }
+ break;
+
+ case LayerType.Image:
+ {
+ layer = new ImageLayer();
+ }
+ break;
+
+ case LayerType.Lighting:
+ {
+ layer = new LightingLayer();
+ }
+ break;
+
+ case LayerType.Group:
+ {
+ layer = new GroupLayer();
+ }
+ break;
+
+ default:
+ Debug.Assert(false);
+ break;
+ }
+
+ // Set the new layer
+ Layer.GroupLayer.ReplaceLayer(Layer, layer);
+
+ Layer = layer;
+
+ // Update the edit control UI
+ UpdateUI();
+ }
+ }
+
+ private void OpacitySlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
+ {
+ if (Layer != null)
+ {
+ Layer.Opacity = ((float)OpacitySlider.Value) / 100;
+ }
+ }
+
+ private void LayerName_TextChanged(object sender, TextChangedEventArgs e)
+ {
+ if (Layer != null)
+ {
+ Layer.Description = LayerName.Text;
+ }
+ }
+
+ private void EdgeModeCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ string edgeMode = (string)EdgeModeCombo.SelectedValue;
+
+ if (Layer.LayerType == LayerType.Image)
+ {
+ ImageLayer layer = (ImageLayer)Layer;
+ layer.EdgeMode = (EdgeMode)Enum.Parse(typeof(EdgeMode), edgeMode);
+
+ UpdateUI();
+ }
+ }
+
+ private void DeleteNormalMap_Click(object sender, RoutedEventArgs e)
+ {
+ Debug.Assert(Layer.LayerType == LayerType.Lighting);
+
+ LightingLayer layer = (LightingLayer)Layer;
+
+ if (layer.FilePath != null)
+ {
+ ((LightingLayer)Layer).File = null;
+ NormalMapFilename.Text = "";
+ NormalMapPropertyPanel.Children.Clear();
+ }
+ }
+ }
+}
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLightControl.xaml b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLightControl.xaml
new file mode 100644
index 000000000..276f6a001
--- /dev/null
+++ b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLightControl.xaml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLightControl.xaml.cs b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLightControl.xaml.cs
new file mode 100644
index 000000000..11043871b
--- /dev/null
+++ b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EditLightControl.xaml.cs
@@ -0,0 +1,255 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI.Xaml.Controls;
+using System;
+using System.Diagnostics;
+using System.Numerics;
+using Windows.UI;
+
+
+namespace MaterialCreator
+{
+ public sealed partial class EditLightControl : UserControl
+ {
+ LightControl _light;
+
+ const float c_ConstantAttenMultiplier = .1f;
+ const float c_LinearAttenMultiplier = .03f;
+ const float c_QuadraticAttenMultiplier = .005f;
+
+ public EditLightControl(LightControl light)
+ {
+ this.InitializeComponent();
+
+ _light = light;
+
+ UpdateUI();
+
+ foreach (LightTypes lightType in Enum.GetValues(typeof(LightTypes)))
+ {
+ ComboBoxItem item = new ComboBoxItem();
+ item.Tag = lightType;
+ item.Content = lightType.ToString();
+ item.IsSelected = lightType == _light.Light.Type;
+ LightTypeSelection.Items.Add(item);
+ }
+ }
+
+ private void LightTypeSelection_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ ComboBoxItem item = LightTypeSelection.SelectedItem as ComboBoxItem;
+ LightTypes lightType = (LightTypes)item.Tag;
+
+ PointProperties.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
+ SpotProperties.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
+ DirectionProperties.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
+ DefaultProperties.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
+
+ switch (lightType)
+ {
+ case LightTypes.Point:
+ DefaultProperties.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
+ PointProperties.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
+ break;
+
+ case LightTypes.Spot:
+ DefaultProperties.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
+ SpotProperties.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
+ DirectionProperties.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
+ break;
+
+ case LightTypes.Distant:
+ PointProperties.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
+ DirectionProperties.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
+ break;
+
+ case LightTypes.Ambient:
+ PointProperties.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
+ break;
+
+ default:
+ break;
+ }
+
+ if (lightType != _light.Light.Type)
+ {
+ UpdateLight();
+ }
+ }
+
+ void UpdateUI()
+ {
+ switch (_light.Light.Type)
+ {
+ case LightTypes.Point:
+ {
+ Vector3 offset = _light.Light.Offset;
+ XOffset.Value = offset.X;
+ YOffset.Value = offset.Y;
+ ZOffset.Value = offset.Z;
+ ConstantAttenuation.Value = (float)_light.Light.GetProperty("ConstantAttenuation") / c_ConstantAttenMultiplier;
+ LinearAttenuation.Value = (float)_light.Light.GetProperty("LinearAttenuation") / c_LinearAttenMultiplier;
+ QuadraticAttenuation.Value = (float)_light.Light.GetProperty("QuadraticAttenuation") / c_QuadraticAttenMultiplier;
+ LightColor.Color = (Color)_light.Light.GetProperty("Color");
+ IntensitySlider.Value = (float)_light.Light.GetProperty("Intensity") * 100;
+ }
+ break;
+
+ case LightTypes.Spot:
+ {
+ Vector3 offset = _light.Light.Offset;
+ XOffset.Value = offset.X;
+ YOffset.Value = offset.Y;
+ ZOffset.Value = offset.Z;
+ ConstantAttenuation.Value = (float)_light.Light.GetProperty("ConstantAttenuation") / c_ConstantAttenMultiplier;
+ LinearAttenuation.Value = (float)_light.Light.GetProperty("LinearAttenuation") / c_LinearAttenMultiplier;
+ QuadraticAttenuation.Value = (float)_light.Light.GetProperty("QuadraticAttenuation") / c_QuadraticAttenMultiplier;
+ InnerCone.Value = (float)_light.Light.GetProperty("InnerConeAngleInDegrees");
+ InnerConeColor.Color = (Color)_light.Light.GetProperty("InnerConeColor");
+ InnerIntensitySlider.Value = (float)_light.Light.GetProperty("InnerConeIntensity") * 100;
+ OuterCone.Value = (float)_light.Light.GetProperty("OuterConeAngleInDegrees");
+ OuterConeColor.Color = (Color)_light.Light.GetProperty("OuterConeColor");
+ OuterIntensitySlider.Value = (float)_light.Light.GetProperty("OuterConeIntensity") * 100;
+
+ Vector3 direction = (Vector3)_light.Light.GetProperty("Direction");
+ float dot = Vector3.Dot(new Vector3(0, 0, 1), direction);
+ Vector3 a = (dot * 100) * direction;
+ DirectionX.Value = 300 - a.X;
+ DirectionY.Value = 300 - a.Y;
+ }
+ break;
+
+ case LightTypes.Distant:
+ {
+ LightColor.Color = (Color)_light.Light.GetProperty("Color");
+ IntensitySlider.Value = (float)_light.Light.GetProperty("Intensity") * 100;
+
+ Vector3 direction = (Vector3)_light.Light.GetProperty("Direction");
+ float dot = Vector3.Dot(new Vector3(0, 0, 1), direction);
+ Vector3 a = (dot * 100) * direction;
+ DirectionX.Value = 300 - a.X;
+ DirectionY.Value = 300 - a.Y;
+ }
+ break;
+
+ case LightTypes.Ambient:
+ {
+ LightColor.Color = (Color)_light.Light.GetProperty("Color");
+ IntensitySlider.Value = (float)_light.Light.GetProperty("Intensity") * 100;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ LightName.Text = _light.Light.Name;
+ }
+
+ private void UpdateLight()
+ {
+ if (LightTypeSelection.SelectedValue != null)
+ {
+ ComboBoxItem item = LightTypeSelection.SelectedItem as ComboBoxItem;
+ LightTypes lightType = (LightTypes)item.Tag;
+
+ _light.Light.Type = lightType;
+
+ switch (lightType)
+ {
+ case LightTypes.Point:
+ {
+ _light.Light.Offset = new Vector3((float)XOffset.Value, (float)YOffset.Value, (float)ZOffset.Value);
+ _light.Light.SetProperty("ConstantAttenuation", (float)ConstantAttenuation.Value * c_ConstantAttenMultiplier);
+ _light.Light.SetProperty("LinearAttenuation", (float)LinearAttenuation.Value * c_LinearAttenMultiplier);
+ _light.Light.SetProperty("QuadraticAttenuation", (float)QuadraticAttenuation.Value * c_QuadraticAttenMultiplier);
+ _light.Light.SetProperty("Color", LightColor.Color);
+ _light.Light.SetProperty("Intensity", (float)IntensitySlider.Value / 100f);
+ }
+ break;
+
+ case LightTypes.Spot:
+ {
+ _light.Light.Offset = new Vector3((float)XOffset.Value, (float)YOffset.Value, (float)ZOffset.Value);
+ _light.Light.SetProperty("ConstantAttenuation", (float)ConstantAttenuation.Value * c_ConstantAttenMultiplier);
+ _light.Light.SetProperty("LinearAttenuation", (float)LinearAttenuation.Value * c_LinearAttenMultiplier);
+ _light.Light.SetProperty("QuadraticAttenuation", (float)QuadraticAttenuation.Value * c_QuadraticAttenMultiplier);
+ _light.Light.SetProperty("InnerConeAngleInDegrees", (float)InnerCone.Value);
+ _light.Light.SetProperty("InnerConeColor", InnerConeColor.Color);
+ _light.Light.SetProperty("InnerConeIntensity", (float)InnerIntensitySlider.Value / 100f);
+ _light.Light.SetProperty("OuterConeAngleInDegrees", (float)OuterCone.Value);
+ _light.Light.SetProperty("OuterConeColor", OuterConeColor.Color);
+ _light.Light.SetProperty("OuterConeIntensity", (float)OuterIntensitySlider.Value / 100f);
+
+ Vector3 lookAt = new Vector3((float)DirectionX.Value, (float)DirectionY.Value, 0);
+ Vector3 offset = new Vector3(300, 300, 100);
+ _light.Light.SetProperty("Direction", Vector3.Normalize(lookAt - offset));
+ }
+ break;
+
+ case LightTypes.Distant:
+ {
+ _light.Light.SetProperty("Color", LightColor.Color);
+ _light.Light.SetProperty("Intensity", (float)IntensitySlider.Value / 100f);
+
+ Vector3 lookAt = new Vector3((float)DirectionX.Value, (float)DirectionY.Value, 0);
+ Vector3 offset = new Vector3(300, 300, 100);
+ _light.Light.SetProperty("Direction", Vector3.Normalize(lookAt - offset));
+ }
+ break;
+
+ case LightTypes.Ambient:
+ {
+ _light.Light.SetProperty("Color", LightColor.Color);
+ _light.Light.SetProperty("Intensity", (float)IntensitySlider.Value / 100f);
+ }
+ break;
+
+ default:
+ Debug.Assert(false, "Unexpected type");
+ break;
+ }
+ }
+ }
+
+ private void OnColorPickerColorChanged(ColorPicker sender, ColorChangedEventArgs args)
+ {
+ UpdateLight();
+ }
+
+ private void Slider_ValueChanged(object sender, Microsoft.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
+ {
+ if (InnerCone != null && OuterCone != null)
+ {
+ if (((Slider)sender).Name == "InnerCone")
+ {
+ OuterCone.Value = Math.Max(InnerCone.Value, OuterCone.Value);
+ }
+
+ if (((Slider)sender).Name == "OuterCone")
+ {
+ InnerCone.Value = Math.Min(InnerCone.Value, OuterCone.Value);
+ }
+ }
+
+ UpdateLight();
+ }
+
+ private void LightName_TextChanged(object sender, TextChangedEventArgs e)
+ {
+ _light.Light.Name = LightName.Text;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EffectControl.xaml b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EffectControl.xaml
new file mode 100644
index 000000000..bb66d466e
--- /dev/null
+++ b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EffectControl.xaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EffectControl.xaml.cs b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EffectControl.xaml.cs
new file mode 100644
index 000000000..481198d7b
--- /dev/null
+++ b/Samples/SceneGraph/Demos/MaterialCreator/MaterialCreatorApp/Controls/EffectControl.xaml.cs
@@ -0,0 +1,136 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//*********************************************************
+
+using Microsoft.UI;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using SamplesCommon;
+using System.ComponentModel;
+using Windows.UI;
+
+namespace MaterialCreator
+{
+ public sealed partial class EffectControl : UserControl, INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+ Effect _effect;
+
+ public EffectControl()
+ {
+ this.InitializeComponent();
+
+ this.DataContextChanged += OnDataContextChanged;
+ }
+
+ public Effect Effect
+ {
+ get { return _effect; }
+ set
+ {
+ if (_effect != value)
+ {
+ _effect = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Effect)));
+ }
+ }
+ }
+
+ private void OnDataContextChanged(FrameworkElement sender, DataContextChangedEventArgs e)
+ {
+ if (e.NewValue is Effect newEffect)
+ {
+ if (newEffect != null && Effect != newEffect)
+ {
+ Effect = newEffect;
+ Eyeball.Opacity = Effect.Enabled ? 1 : .2f;
+
+ if (!Effect.FirstLoadCompleted)
+ {
+ Effect.FirstLoadCompleted = true;
+ ShowEffectPropertyFlyout();
+ }
+ }
+ }
+ }
+
+ private void EffectVisible_Clicked(object sender, RoutedEventArgs e)
+ {
+ if (Effect.Enabled)
+ {
+ Effect.Enabled = false;
+ Eyeball.Opacity = .2f;
+ }
+ else
+ {
+ Effect.Enabled = true;
+ Eyeball.Opacity = 1;
+ }
+ }
+
+ private void RootGrid_Tapped(object sender, TappedRoutedEventArgs e)
+ {
+ Button ancestor = VisualTreeHelperExtensions.GetFirstAncestorOfType