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
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.
41 changes: 41 additions & 0 deletions WinUIGallery/ControlPages/ContentIslandPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?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:local="using:WinUIGallery.ControlPages"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<StackPanel Grid.Row="0">
<TextBlock>Here's an island in a ScrollViewer. Notice now the content scrolls and clips correctly.</TextBlock>
<Button Click="Button_Click">Load Helmet</Button>
</StackPanel>
<StackPanel Grid.Row="1" HorizontalAlignment="Center">
<Grid x:Name="_rectanglePanel" HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="0" Margin="10" Fill="LightBlue" Width="450" Height="450" />
<Rectangle Grid.Column="1" Margin="10" Fill="LightCyan" Width="450" Height="450" />
<Rectangle Grid.Row="1" Grid.Column="0" Margin="10" Fill="LightCyan" Width="450" Height="450"/>
<Rectangle Grid.Row="1" Grid.Column="1" Margin="10" Fill="LightBlue" Width="450" Height="450" />
<Rectangle Grid.Row="2" Grid.Column="0" Margin="10" Fill="LightBlue" Width="450" Height="450"/>
<Rectangle Grid.Row="2" Grid.Column="1" Margin="10" Fill="LightCyan" Width="450" Height="450" />
</Grid>
</StackPanel>
</Grid>
</Page>
76 changes: 76 additions & 0 deletions WinUIGallery/ControlPages/ContentIslandPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using Microsoft.UI.Composition;
using Microsoft.UI.Content;
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 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 WinUIGallery.ControlPages
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class ContentIslandPage : Page
{
public ContentIslandPage()
{
this.InitializeComponent();
}

int idx = 0;

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

return null;
}

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

Microsoft.UI.Xaml.Shapes.Rectangle rect = GetNextHostElement();
if (rect == null)
{
return;
}

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

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

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

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

childSiteLink.Connect(helmetIsland);
}

private void Button_Click(object sender, RoutedEventArgs e)
{
SetupHelmet();
}

}
}
19 changes: 19 additions & 0 deletions WinUIGallery/DataModel/ControlInfoData.json
Original file line number Diff line number Diff line change
Expand Up @@ -3617,6 +3617,25 @@
"Clipboard"
]
},
{
"UniqueId": "ContentIsland",
"Title": "ContentIsland",
"ApiNamespace": "Microsoft.UI.Content",
"Subtitle": "Create ContentIslands to host other frameworks in your app.",
"ImagePath": "ms-appx:///Assets/ControlImages/PlaceHolder.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/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.content.contentisland"
}
],
"RelatedControls": [
"Clipboard"
]
},
{
"UniqueId": "ScratchPad",
"Title": "Scratch Pad",
Expand Down
160 changes: 160 additions & 0 deletions WinUIGallery/SceneNode/HelmetScenario.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.InteropServices;

using Windows.Foundation;
using Windows.Graphics;
using Windows.Storage;
using Windows.Storage.Streams;

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;
using System.Threading.Tasks;

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