Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ContentIsland page with Helmet demo (requires WinAppSDK 1.7 APIs) #1743

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added WinUIGallery/Assets/SceneNode/DamagedHelmet1.bmp
Binary file not shown.
Binary file added WinUIGallery/Assets/SceneNode/DamagedHelmet2.bmp
Binary file not shown.
Binary file added WinUIGallery/Assets/SceneNode/DamagedHelmet3.bmp
Binary file not shown.
Binary file added WinUIGallery/Assets/SceneNode/DamagedHelmet4.bmp
Binary file not shown.
Binary file added WinUIGallery/Assets/SceneNode/DamagedHelmet5.bmp
Binary file not shown.
Binary file added WinUIGallery/Assets/SceneNode/DamagedHelmet6.bin
Binary file not shown.
Binary file added WinUIGallery/Assets/SceneNode/DamagedHelmet7.bin
Binary file not shown.
Binary file added WinUIGallery/Assets/SceneNode/DamagedHelmet8.bin
Binary file not shown.
Binary file added WinUIGallery/Assets/SceneNode/DamagedHelmet9.bin
Binary file not shown.
77 changes: 77 additions & 0 deletions WinUIGallery/Samples/ControlPages/ContentIslandPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8" ?>
<Page
x:Class="WinUIGallery.ControlPages.ContentIslandPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:layouts="using:WinUIGallery.Layouts"
xmlns:local="using:WinUIGallery.ControlPages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<StackPanel Spacing="8">
<TextBlock Text="Here's an ContentIsland in a ScrollViewer. Notice now the content scrolls and clips correctly." />
<Button
Click="LoadModel_Click"
Content="Load model"
Style="{StaticResource AccentButtonStyle}" />
</StackPanel>
<layouts:WrapPanel
x:Name="_rectanglePanel"
Grid.Row="1"
HorizontalAlignment="Left">
<!--<WrapPanel.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</WrapPanel.RowDefinitions>
<WrapPanel.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</WrapPanel.ColumnDefinitions>-->
<Rectangle
Width="450"
Height="450"
Margin="8"
Fill="LightBlue" />
<Rectangle
Grid.Column="1"
Width="450"
Height="450"
Margin="8"
Fill="LightCyan" />
<Rectangle
Grid.Row="1"
Width="450"
Height="450"
Margin="8"
Fill="LightCyan" />
<Rectangle
Grid.Row="1"
Grid.Column="1"
Width="450"
Height="450"
Margin="8"
Fill="LightBlue" />
<Rectangle
Grid.Row="2"
Width="450"
Height="450"
Margin="8"
Fill="LightBlue" />
<Rectangle
Grid.Row="2"
Grid.Column="1"
Width="450"
Height="450"
Margin="8"
Fill="LightCyan" />
</layouts:WrapPanel>
</Grid>
</Page>
74 changes: 74 additions & 0 deletions WinUIGallery/Samples/ControlPages/ContentIslandPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Numerics;
using Microsoft.UI.Composition;
using Microsoft.UI.Content;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Hosting;
using Microsoft.UI.Xaml.Shapes;

namespace WinUIGallery.ControlPages;

public sealed partial class ContentIslandPage : Page
{
public ContentIslandPage()
{
this.InitializeComponent();
}

int idx = 0;

Rectangle GetNextHostElement()
{
if (idx < _rectanglePanel.Children.Count)
{
return ((Rectangle)_rectanglePanel.Children[idx++]);
}

return null;
}

public async void LoadModel()
{
ContentIsland parentIsland = this.XamlRoot.TryGetContentIsland();

Rectangle rect = GetNextHostElement();
if (rect == null)
{
return;
}

ContainerVisual placementVisual = (ContainerVisual)ElementCompositionPreview.GetElementVisual(rect);
Vector2 size = rect.ActualSize;

ChildSiteLink childSiteLink = ChildSiteLink.Create(parentIsland, placementVisual);

// We also need to keep the offset of the ChildContentLink within the parent ContentIsland in sync
// with that of the placementElement for UIA to work correctly.
var layoutUpdatedEventHandler = new EventHandler<object>((s, e) =>
{
// NOTE: Do as little work in here as possible because it gets called for every
// xaml layout change on this thread!
var transform = rect.TransformToVisual(null);
var point = transform.TransformPoint(new Windows.Foundation.Point(0, 0));
childSiteLink.LocalToParentTransformMatrix = System.Numerics.Matrix4x4.CreateTranslation(
(float)(point.X),
(float)(point.Y),
0);
});
rect.LayoutUpdated += layoutUpdatedEventHandler;
layoutUpdatedEventHandler.Invoke(null, null);

placementVisual.Size = size;
childSiteLink.ActualSize = size;

ContentIsland helmetIsland = await HelmetScenario.CreateIsland(placementVisual.Compositor);

childSiteLink.Connect(helmetIsland);
}

private void LoadModel_Click(object sender, RoutedEventArgs e)
{
LoadModel();
}
}
19 changes: 19 additions & 0 deletions WinUIGallery/Samples/Data/ControlInfoData.json
Original file line number Diff line number Diff line change
Expand Up @@ -3685,6 +3685,25 @@
"RelatedControls": [
"Clipboard"
]
},
{
"UniqueId": "ContentIsland",
"Title": "ContentIsland",
"ApiNamespace": "Microsoft.UI.Content",
"Subtitle": "Create ContentIslands to host other frameworks in your app.",
"ImagePath": "ms-appx:///Assets/ControlImages/ContentIsland.png",
"Description": "Create ContentIslands to host other frameworks in your app.",
"Content": "<p>Look at the <i>ContentIslandPage.xaml</i> file in Visual Studio to see the full code for this page.</p>",
"IsNew": true,
"Docs": [
{
"Title": "ContentIsland - API",
"Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.content.contentisland"
}
],
"RelatedControls": [
"Clipboard"
]
}
]
}
Expand Down
152 changes: 152 additions & 0 deletions WinUIGallery/Samples/SampleHelpers/SceneNode/HelmetScenario.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Numerics;
using System.Threading.Tasks;
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.UI.Composition;
using Microsoft.Graphics.DirectX;
using Microsoft.UI.Composition;
using Microsoft.UI.Composition.Scenes;
using Microsoft.UI.Content;

class HelmetScenario
{
public static async Task<ContentIsland> CreateIsland(Compositor compositor)
{
var visual = await LoadScene_DamagedHelmet(compositor);

var island = ContentIsland.Create(visual);
return island;
}

private static async Task<Visual> LoadScene_DamagedHelmet(Compositor compositor)
{
// Initialize Win2D, used for loading bitmaps.

var canvasDevice = new CanvasDevice();
var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(
compositor, canvasDevice);

// Create the Visuals and SceneNode structure, along with default rotation animations.

var sceneVisual = SceneVisual.Create(compositor);
sceneVisual.RelativeOffsetAdjustment = new Vector3(0.5f, 0.5f, 0.0f);

var worldNode = SceneNode.Create(compositor);
sceneVisual.Root = worldNode;

var rotateAngleAnimation = compositor.CreateScalarKeyFrameAnimation();
rotateAngleAnimation.InsertKeyFrame(0.0f, 0.0f);
rotateAngleAnimation.InsertKeyFrame(0.5f, 360.0f);
rotateAngleAnimation.InsertKeyFrame(1.0f, 0.0f);
rotateAngleAnimation.Duration = TimeSpan.FromSeconds(15);
rotateAngleAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
worldNode.Transform.RotationAxis = new Vector3(0, 1, 0);
worldNode.Transform.StartAnimation("RotationAngleInDegrees", rotateAngleAnimation);

var sceneNode0 = SceneNode.Create(compositor);
sceneNode0.Transform.Scale = new Vector3(170);
sceneNode0.Transform.Orientation = new Quaternion(0.70710683f, 0.0f, 0.0f, 0.70710683f);
worldNode.Children.Add(sceneNode0);

var sceneNodeForTheGLTFMesh0 = SceneNode.Create(compositor);
sceneNode0.Children.Add(sceneNodeForTheGLTFMesh0);

// Load all file data in parallel:
// - Although Scene Graph objects prefer a UI thread, Win2D can load and create the bitmaps
// on parallel background threads.

var vertexData = SceneNodeCommon.LoadMemoryBufferFromUriAsync(
"Assets/SceneNode/DamagedHelmet6.bin");

var normalData = SceneNodeCommon.LoadMemoryBufferFromUriAsync(
"Assets/SceneNode/DamagedHelmet7.bin");

var texCoordData = SceneNodeCommon.LoadMemoryBufferFromUriAsync(
"Assets/SceneNode/DamagedHelmet8.bin");

var indexData = SceneNodeCommon.LoadMemoryBufferFromUriAsync(
"Assets/SceneNode/DamagedHelmet9.bin");

var canvasBitmap0 = SceneNodeCommon.LoadIntoCanvasBitmap(
canvasDevice, "Assets/SceneNode/DamagedHelmet1.bmp");

var canvasBitmap1 = SceneNodeCommon.LoadIntoCanvasBitmap(
canvasDevice, "Assets/SceneNode/DamagedHelmet2.bmp");

var canvasBitmap2 = SceneNodeCommon.LoadIntoCanvasBitmap(
canvasDevice, "Assets/SceneNode/DamagedHelmet3.bmp");

var canvasBitmap3 = SceneNodeCommon.LoadIntoCanvasBitmap(
canvasDevice, "Assets/SceneNode/DamagedHelmet4.bmp");

var canvasBitmap4 = SceneNodeCommon.LoadIntoCanvasBitmap(
canvasDevice, "Assets/SceneNode/DamagedHelmet5.bmp");

await vertexData;
await normalData;
await texCoordData;
await indexData;
await canvasBitmap0;
await canvasBitmap1;
await canvasBitmap2;
await canvasBitmap3;
await canvasBitmap4;


// Generate mipmaps from the bitmaps, which are needed for 3D rendering.

var materialInput0 = SceneNodeCommon.LoadMipmapFromBitmap(graphicsDevice, canvasBitmap0.Result);
var materialInput1 = SceneNodeCommon.LoadMipmapFromBitmap(graphicsDevice, canvasBitmap1.Result);
var materialInput2 = SceneNodeCommon.LoadMipmapFromBitmap(graphicsDevice, canvasBitmap2.Result);
var materialInput3 = SceneNodeCommon.LoadMipmapFromBitmap(graphicsDevice, canvasBitmap3.Result);
var materialInput4 = SceneNodeCommon.LoadMipmapFromBitmap(graphicsDevice, canvasBitmap4.Result);


// Copy loaded binary data into mesh: verticies, normals, ...

var mesh0 = SceneMesh.Create(compositor);
mesh0.PrimitiveTopology = DirectXPrimitiveTopology.TriangleList;
mesh0.FillMeshAttribute(SceneAttributeSemantic.Vertex, DirectXPixelFormat.R32G32B32Float, vertexData.Result);
mesh0.FillMeshAttribute(SceneAttributeSemantic.Normal, DirectXPixelFormat.R32G32B32Float, normalData.Result);
mesh0.FillMeshAttribute(SceneAttributeSemantic.TexCoord0, DirectXPixelFormat.R32G32Float, texCoordData.Result);
mesh0.FillMeshAttribute(SceneAttributeSemantic.Index, DirectXPixelFormat.R16UInt, indexData.Result);


// Initialize the material with different texture inputs (color, roughness, normals, ...)

var sceneMaterial0 = SceneMetallicRoughnessMaterial.Create(compositor);

var renderComponent0 = SceneMeshRendererComponent.Create(compositor);
renderComponent0.Mesh = mesh0;
renderComponent0.Material = sceneMaterial0;
sceneNodeForTheGLTFMesh0.Components.Add(renderComponent0);

sceneMaterial0.BaseColorFactor = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);
sceneMaterial0.BaseColorInput = SceneNodeCommon.CreateMaterial(
compositor, materialInput0, renderComponent0, "BaseColorInput"); ;

sceneMaterial0.RoughnessFactor = 1.0f;
sceneMaterial0.MetallicFactor = 1.0f;
sceneMaterial0.MetallicRoughnessInput = SceneNodeCommon.CreateMaterial(
compositor, materialInput1, renderComponent0, "MetallicRoughnessInput");

sceneMaterial0.NormalScale = 1.0f;
sceneMaterial0.NormalInput = SceneNodeCommon.CreateMaterial(
compositor, materialInput2, renderComponent0, "NormalInput");

sceneMaterial0.OcclusionStrength = 1.0f;
sceneMaterial0.OcclusionInput = SceneNodeCommon.CreateMaterial(
compositor, materialInput3, renderComponent0, "OcclusionInput");

sceneMaterial0.AlphaMode = SceneAlphaMode.Opaque;
sceneMaterial0.IsDoubleSided = false;
sceneMaterial0.EmissiveFactor = new Vector3(1.0f, 1.0f, 1.0f);
sceneMaterial0.EmissiveInput = SceneNodeCommon.CreateMaterial(
compositor, materialInput4, renderComponent0, "EmissiveInput");

return sceneVisual;
}
}
Loading