├── .gitignore ├── Experimental └── CameraComponent │ ├── Animatable.cs │ ├── Camera.cs │ ├── CameraComponent.csproj │ ├── FirstPersonCamera.cs │ ├── ModelViewer.xaml │ ├── ModelViewer.xaml.cs │ ├── OrbitalCamera.cs │ ├── OrthographicProjection.cs │ ├── PerspectiveProjection.cs │ ├── Projection.cs │ ├── Properties │ └── AssemblyInfo.cs │ └── Viewport.cs ├── LICENSE.md ├── README.md ├── SceneLoader.sln ├── SceneLoader ├── Bounds3D.cpp ├── Bounds3D.h ├── GLTFVisitor.cpp ├── GLTFVisitor.h ├── GLTFVisitor_Camera.cpp ├── GLTFVisitor_Image.cpp ├── GLTFVisitor_Material.cpp ├── GLTFVisitor_Mesh.cpp ├── GLTFVisitor_MeshPrimitive.cpp ├── GLTFVisitor_Node.cpp ├── GLTFVisitor_Sampler.cpp ├── GLTFVisitor_Skin.cpp ├── GLTFVisitor_Texture.cpp ├── NugetPackager │ ├── SceneLoaderComponent.nuspec │ ├── SceneLoaderComponent.props │ └── SceneLoaderComponent.targets ├── SceneLoader.cpp ├── SceneLoader.h ├── SceneLoader.vcxproj ├── SceneLoader.vcxproj.filters ├── SceneLoaderComponent.def ├── SceneLoaderComponent.idl ├── SceneResourceSet.cpp ├── SceneResourceSet.h ├── UtilForIntermingledNamespaces.cpp ├── UtilForIntermingledNamespaces.h ├── packages.config ├── pch.cpp ├── pch.h └── readme.md ├── TestViewer ├── App.xaml ├── App.xaml.cs ├── Assets │ ├── DamagedHelmet.gltf │ ├── LockScreenLogo.scale-200.png │ ├── OrientationTest.gltf │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── StoreLogo.png │ └── Wide310x150Logo.scale-200.png ├── MainPage.xaml ├── MainPage.xaml.cs ├── Package.appxmanifest ├── Properties │ ├── AssemblyInfo.cs │ └── Default.rd.xml ├── TestViewer.csproj └── TestViewer_TemporaryKey.pfx ├── azure-pipelines.yml ├── build ├── Build.bat ├── Clean.bat ├── Find-WindowsSDKVersions.ps1 ├── Install-WindowsSDK.ps1 ├── Install-WindowsSdkISO.ps1 ├── Sign-Package.ps1 ├── SignClientSettings.json ├── StyleXaml.bat ├── UpdateHeaders.bat ├── build.cake ├── build.ps1 ├── header.txt └── nuget.png ├── settings.xamlstyler └── version.json /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | build/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | **/Properties/launchSettings.json 57 | 58 | # StyleCop 59 | StyleCopReport.xml 60 | 61 | # Files built by Visual Studio 62 | *_i.c 63 | *_p.c 64 | *_i.h 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.iobj 69 | *.pch 70 | *.pdb 71 | *.ipdb 72 | *.pgc 73 | *.pgd 74 | *.rsp 75 | *.sbr 76 | *.tlb 77 | *.tli 78 | *.tlh 79 | *.tmp 80 | *.tmp_proj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush 296 | .cr/ 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | 333 | # Nuget Packager 334 | */NugetPackager -------------------------------------------------------------------------------- /Experimental/CameraComponent/Animatable.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using Windows.UI.Composition; 6 | 7 | namespace CameraComponent 8 | { 9 | /// 10 | /// An interface that defines functions non-Composition objects can implement to become animatable. 11 | /// 12 | public interface Animatable 13 | { 14 | /// 15 | /// Returns an object's set of animatable properties. 16 | /// 17 | CompositionPropertySet GetPropertySet(); 18 | 19 | /// 20 | /// Starts a given animation on the specified property. 21 | /// 22 | /// The name of the property to be animated. 23 | /// The animation being applied. 24 | void StartAnimation(string propertyName, CompositionAnimation animation); 25 | 26 | /// 27 | /// Stops any animations on the specified property. 28 | /// 29 | /// The name of the property whose animations we are stopping. 30 | void StopAnimation(string propertyName); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/Camera.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Numerics; 6 | 7 | namespace CameraComponent 8 | { 9 | /// 10 | /// An interface that defines properties and functions that a Camera object must implement. 11 | /// 12 | public interface Camera : Animatable 13 | { 14 | /// 15 | /// A reference to a class that implements the Projection interace. 16 | /// 17 | Projection Projection { get; set; } 18 | 19 | /// 20 | /// Returns the matrix created using the Camera's position and rotation in world space. 21 | /// 22 | /// /// A Matrix4x4 that is the product of the matrices representing the camera's translation and rotation. 23 | Matrix4x4 GetViewMatrix(); 24 | 25 | /// 26 | /// Returns the matrix created using the Camera's view matrix and the Camera's Projection's matrix. 27 | /// 28 | /// A Matrix4x4 that is the the product of the matrices representing the camera's transformations in world space and 29 | /// the matrix created by the Camera's Projection property. 30 | Matrix4x4 GetModelViewProjectionMatrix(); 31 | } 32 | } -------------------------------------------------------------------------------- /Experimental/CameraComponent/CameraComponent.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D} 8 | winmdobj 9 | Properties 10 | CameraComponent 11 | CameraComponent 12 | en-US 13 | UAP 14 | 10.0.18362.0 15 | 10.0.18362.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | false 20 | 21 | 22 | AnyCPU 23 | true 24 | full 25 | false 26 | bin\Debug\ 27 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 28 | prompt 29 | 4 30 | 31 | 32 | AnyCPU 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE;NETFX_CORE;WINDOWS_UWP 37 | prompt 38 | 4 39 | 40 | 41 | x86 42 | true 43 | bin\x86\Debug\ 44 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 45 | ;2008 46 | full 47 | false 48 | prompt 49 | false 50 | 51 | 52 | 53 | 54 | x86 55 | bin\x86\Release\ 56 | TRACE;NETFX_CORE;WINDOWS_UWP 57 | true 58 | ;2008 59 | pdbonly 60 | false 61 | prompt 62 | 63 | 64 | ARM 65 | true 66 | bin\ARM\Debug\ 67 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 68 | ;2008 69 | full 70 | false 71 | prompt 72 | 73 | 74 | ARM 75 | bin\ARM\Release\ 76 | TRACE;NETFX_CORE;WINDOWS_UWP 77 | true 78 | ;2008 79 | pdbonly 80 | false 81 | prompt 82 | 83 | 84 | ARM64 85 | true 86 | bin\ARM64\Debug\ 87 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 88 | ;2008 89 | full 90 | false 91 | prompt 92 | 93 | 94 | ARM64 95 | bin\ARM64\Release\ 96 | TRACE;NETFX_CORE;WINDOWS_UWP 97 | true 98 | ;2008 99 | pdbonly 100 | false 101 | prompt 102 | 103 | 104 | x64 105 | true 106 | bin\x64\Debug\ 107 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 108 | ;2008 109 | full 110 | false 111 | prompt 112 | 113 | 114 | x64 115 | bin\x64\Release\ 116 | TRACE;NETFX_CORE;WINDOWS_UWP 117 | true 118 | ;2008 119 | pdbonly 120 | false 121 | prompt 122 | 123 | 124 | PackageReference 125 | 126 | 127 | 128 | 129 | 130 | 131 | ModelViewer.xaml 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 6.2.8 143 | 144 | 145 | 146 | 147 | Designer 148 | MSBuild:Compile 149 | 150 | 151 | 152 | 153 | {88c4d662-8669-433b-8a8b-47b3a17e3c6e} 154 | SceneLoaderComponent 155 | 156 | 157 | 158 | 14.0 159 | 160 | 161 | 162 | 163 | 164 | 171 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/FirstPersonCamera.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Numerics; 7 | using Windows.UI.Composition; 8 | 9 | namespace CameraComponent 10 | { 11 | /// 12 | /// A class that defines a FirstPersonCamera that has a position in 3D world space and rotates about the x,y, and z axes. 13 | /// Implements the Camera and Animatable interfaces. 14 | /// 15 | public sealed class FirstPersonCamera : Camera 16 | { 17 | private Compositor _compositor; 18 | private Projection _projection; 19 | private CompositionPropertySet _propertySet; 20 | 21 | /// 22 | /// Creates a FirstPersonCamera with default properties. 23 | /// Position = Vector3.Zero 24 | /// Yaw = 0 25 | /// Pitch = 0 26 | /// Roll = 0 27 | /// ModelViewProjectionMatrix = Matrix4x4.Identity 28 | /// 29 | /// 30 | /// Thrown when constructor is passed a null value. 31 | public FirstPersonCamera(Compositor compositor) 32 | { 33 | if (compositor == null) 34 | { 35 | throw new System.ArgumentException("Compositor cannot be null"); 36 | } 37 | 38 | _compositor = compositor; 39 | 40 | // Create the properties for the camera 41 | _propertySet = _compositor.CreatePropertySet(); 42 | _propertySet.InsertVector3("Position", Vector3.Zero); 43 | _propertySet.InsertScalar("Yaw", 0f); 44 | _propertySet.InsertScalar("Pitch", 0f); 45 | _propertySet.InsertScalar("Roll", 0f); 46 | _propertySet.InsertMatrix4x4("ModelViewProjectionMatrix", Matrix4x4.Identity); 47 | 48 | // Default is an orthographic projection 49 | Projection = new OrthographicProjection(_compositor); 50 | } 51 | 52 | /// 53 | /// Camera's rotation about the y-axis in radians. 54 | /// Rotates counterclockwise from 0 to 2Pi. 55 | /// 56 | public float Yaw 57 | { 58 | get 59 | { 60 | float curr; 61 | _propertySet.TryGetScalar("Yaw", out curr); 62 | return curr; 63 | } 64 | set 65 | { 66 | _propertySet.InsertScalar("Yaw", value); 67 | } 68 | } 69 | 70 | /// 71 | /// Camera's rotation about the x-axis in radians. 72 | /// Rotates counterclockwise from 0 to 2Pi. 73 | /// 74 | public float Pitch 75 | { 76 | get 77 | { 78 | float curr; 79 | _propertySet.TryGetScalar("Pitch", out curr); 80 | return curr; 81 | } 82 | set 83 | { 84 | _propertySet.InsertScalar("Pitch", value); 85 | } 86 | } 87 | 88 | /// 89 | /// Camera's rotation about the z-axis in radians. 90 | /// Rotates counterclockwise from 0 to 2Pi. 91 | /// 92 | public float Roll 93 | { 94 | get 95 | { 96 | float curr; 97 | _propertySet.TryGetScalar("Roll", out curr); 98 | return curr; 99 | } 100 | set 101 | { 102 | _propertySet.InsertScalar("Roll", value); 103 | } 104 | } 105 | 106 | /// 107 | /// Camera's position in 3D world space. 108 | /// 109 | public Vector3 Position 110 | { 111 | get 112 | { 113 | Vector3 curr; 114 | _propertySet.TryGetVector3("Position", out curr); 115 | return curr; 116 | } 117 | set 118 | { 119 | _propertySet.InsertVector3("Position", value); 120 | } 121 | } 122 | 123 | /// 124 | /// The camera's reference to an object that implements the Projection interace. 125 | /// When setting, this property starts animations on the camera's ModelViewProjectionMatrix property. 126 | /// 127 | /// When set to null, the ModelViewProjectionProperty is animated using an OrthographicProjection with the 128 | /// default values of: Height = 100, Width = 100, Near = 1, Far = 1000. 129 | public Projection Projection 130 | { 131 | get => _projection; 132 | set 133 | { 134 | _projection = value; 135 | 136 | // create view matrix based on the camera's rotation and position 137 | var matPos = "Matrix4x4.CreateTranslation(-FPCamera.Position)"; 138 | var matRoll = "Matrix4x4.CreateFromAxisAngle(Vector3(0, 0, 1), -FPCamera.Roll)"; 139 | var matPitch = "Matrix4x4.CreateFromAxisAngle(Vector3(1, 0, 0), -FPCamera.Pitch)"; 140 | var matYaw = "Matrix4x4.CreateFromAxisAngle(Vector3(0, 1, 0), -FPCamera.Yaw)"; 141 | var viewMat = matPos + "*" + matYaw + "*" + matPitch + "*" + matRoll; 142 | 143 | // create a matrix that is the product of the camera's view matrix and the projection's projection matrix 144 | var modelViewProjMatExpression = _compositor.CreateExpressionAnimation(); 145 | if (_projection == null) // if null then the default is an orthographic projection 146 | { 147 | OrthographicProjection defaultProj = new OrthographicProjection(_compositor); 148 | modelViewProjMatExpression.Expression = viewMat + "*" + "DefaultProjection.ProjectionMatrix"; 149 | modelViewProjMatExpression.SetReferenceParameter("FPCamera", _propertySet); 150 | modelViewProjMatExpression.SetReferenceParameter("DefaultProjection", Projection.GetPropertySet()); 151 | } 152 | else 153 | { 154 | modelViewProjMatExpression.Expression = viewMat + "*" + "Projection.ProjectionMatrix"; 155 | modelViewProjMatExpression.SetReferenceParameter("FPCamera", _propertySet); 156 | modelViewProjMatExpression.SetReferenceParameter("Projection", Projection.GetPropertySet()); 157 | } 158 | 159 | StartAnimation("ModelViewProjectionMatrix", modelViewProjMatExpression); 160 | } 161 | } 162 | 163 | /// 164 | /// Rotates the camera's yaw and pitch to look in the given direction. 165 | /// 166 | /// 167 | public void SetLookDirection(Vector3 direction) 168 | { 169 | if (direction != Vector3.Zero) 170 | { 171 | direction = Vector3.Normalize(direction); 172 | } 173 | 174 | direction.X *= -1; 175 | Yaw = (MathF.PI / 2f) + MathF.Atan2(direction.Z, direction.X); 176 | Pitch = MathF.Asin(direction.Y); 177 | } 178 | 179 | /// 180 | /// Returns the matrix created from the camera's translation and rotation transformations. 181 | /// 182 | /// A Matrix4x4 that is the product of the matrices created from the camera's position, yaw, pitch, and roll. 183 | public Matrix4x4 GetViewMatrix() 184 | { 185 | // create view matrix based on the camera's rotation and position 186 | Matrix4x4 matPos = Matrix4x4.CreateTranslation(-Position); 187 | Matrix4x4 matRoll = Matrix4x4.CreateFromAxisAngle(new Vector3(0, 0, 1), -Roll); 188 | Matrix4x4 matPitch = Matrix4x4.CreateFromAxisAngle(new Vector3(1, 0, 0), -Pitch); 189 | Matrix4x4 matYaw = Matrix4x4.CreateFromAxisAngle(new Vector3(0, 1, 0), -Yaw); 190 | 191 | return matPos * matYaw * matPitch * matRoll; 192 | } 193 | 194 | /// 195 | /// Returns that a matrix created from the camera's view matrix and it's Projection's projection matrix. 196 | /// 197 | /// A Matrix4x4 that is the product of matrices created from the Camera's position, yaw, pitch, and roll and its Projection's projection matrix. 198 | public Matrix4x4 GetModelViewProjectionMatrix() 199 | { 200 | return GetViewMatrix() * Projection.GetProjectionMatrix(); 201 | } 202 | 203 | /// 204 | /// Returns the camera's set of animatable properties. 205 | /// 206 | /// A CompositionPropertySet holding the camera's properties. 207 | public CompositionPropertySet GetPropertySet() 208 | { 209 | return _propertySet; 210 | } 211 | 212 | /// 213 | /// Starts a given animation on the specified property. 214 | /// 215 | /// The name of the property to be animated. 216 | /// The animation being applied. 217 | public void StartAnimation(string propertyName, CompositionAnimation animation) 218 | { 219 | _propertySet.StartAnimation(propertyName, animation); 220 | } 221 | 222 | /// 223 | /// Stops any animations on the specified property. 224 | /// 225 | /// The name of the property whose animations we are stopping. 226 | public void StopAnimation(string propertyName) 227 | { 228 | _propertySet.StopAnimation(propertyName); 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/ModelViewer.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/ModelViewer.xaml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using Windows.UI.Xaml; 7 | using Windows.UI.Xaml.Controls; 8 | using Windows.UI.Xaml.Input; 9 | using SceneLoaderComponent; 10 | using Windows.UI.Composition; 11 | using Windows.UI.Composition.Scenes; 12 | using System.Numerics; 13 | using Windows.UI.Xaml.Hosting; 14 | using Windows.Storage; 15 | using System.Threading.Tasks; 16 | 17 | // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 18 | 19 | namespace CameraComponent 20 | { 21 | public sealed partial class ModelViewer : UserControl 22 | { 23 | private Compositor _compositor; 24 | private SceneVisual _sceneVisual; 25 | private Viewport _viewport; 26 | private OrbitalCamera _camera; 27 | 28 | private bool _mouseDowned; 29 | private Vector2 _mouseDownLocation; 30 | 31 | public ModelViewer() 32 | { 33 | this.InitializeComponent(); 34 | 35 | // Create a camera and a ContainerVisual 36 | _compositor = Window.Current.Compositor; 37 | var root = _compositor.CreateContainerVisual(); 38 | root.Size = new Vector2(1000, 1000); 39 | ElementCompositionPreview.SetElementChildVisual(this, root); 40 | 41 | // create a SceneVisual and insert it into the visual tree 42 | _sceneVisual = SceneVisual.Create(_compositor); 43 | root.Children.InsertAtTop(_sceneVisual); 44 | 45 | // instantiate viewport and assign it "good" default values 46 | _viewport = new Viewport(_compositor); 47 | _viewport.AttachToVisual(_sceneVisual); 48 | _viewport.Size = Target.ActualSize; 49 | _viewport.Offset = new Vector3(_viewport.Size / 2f, 0f); 50 | 51 | // instantiate camera and assign it "good" default values 52 | _camera = new OrbitalCamera(_compositor); 53 | _camera.Target = new Vector3(0f, 0f, 0f); 54 | _camera.Radius = 600f; 55 | _camera.Theta = 0f; 56 | _camera.Phi = MathF.PI / 4; 57 | 58 | // instantiate projection and assign it "good" default values 59 | PerspectiveProjection projection = new PerspectiveProjection(_compositor); 60 | projection.Fov = MathF.PI / 2; 61 | 62 | _camera.Projection = projection; 63 | _viewport.Camera = _camera; 64 | 65 | // add event handler for chaning target size 66 | Target.SizeChanged += Target_SizeChanged; 67 | 68 | // event handlers for pointer events 69 | Target.PointerWheelChanged += Target_PointerWheelChanged; 70 | Target.PointerPressed += Target_PointerPressed; 71 | Target.PointerReleased += Target_PointerReleased; 72 | Target.PointerMoved += Target_PointerMoved; 73 | 74 | Window.Current.CoreWindow.PointerReleased += CoreWindow_PointerReleased; 75 | } 76 | 77 | private void CoreWindow_PointerReleased(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.PointerEventArgs args) 78 | { 79 | _mouseDowned = false; 80 | } 81 | 82 | private void Target_SizeChanged(object sender, SizeChangedEventArgs e) 83 | { 84 | _viewport.Size = e.NewSize.ToVector2(); 85 | } 86 | 87 | private void Target_PointerWheelChanged(object sender, PointerRoutedEventArgs e) 88 | { 89 | // positive if scroll away from the user, negative if scroll toward the user 90 | int scrollSign = Math.Sign(e.GetCurrentPoint(Target).Properties.MouseWheelDelta); 91 | 92 | // determines how much to increase or decrease camera's radius by with each scroll 93 | // smaller numbers correspond to greater changes in radius 94 | float sensitivity = 0.95f; 95 | 96 | // scroll away from you 97 | if (scrollSign > 0) 98 | { 99 | _camera.Radius *= sensitivity; 100 | } 101 | // scroll towards you 102 | else if (scrollSign < 0) 103 | { 104 | _camera.Radius *= 1 + (1 - sensitivity); 105 | } 106 | } 107 | 108 | private void Target_PointerPressed(object sender, PointerRoutedEventArgs e) 109 | { 110 | // use to determine how much to rotate camera by, based on size of change in pointer position 111 | _mouseDownLocation = e.GetCurrentPoint(Target).Position.ToVector2(); 112 | 113 | _mouseDowned = true; 114 | } 115 | 116 | private void Target_PointerReleased(object sender, PointerRoutedEventArgs e) 117 | { 118 | // prohibit mouse from changing rotation if the mouse button isn't pressed 119 | _mouseDowned = false; 120 | } 121 | 122 | private void Target_PointerMoved(object sender, PointerRoutedEventArgs e) 123 | { 124 | if (_mouseDowned) 125 | { 126 | // rotate proportionately to the size of the mouse movement 127 | Vector2 newPos = e.GetCurrentPoint(Target).Position.ToVector2(); 128 | float thetaDelta = newPos.X - _mouseDownLocation.X; 129 | float phiDelta = newPos.Y - _mouseDownLocation.Y; 130 | 131 | _mouseDownLocation = newPos; 132 | 133 | // higher number corresponds to faster rotation 134 | float sensitivity = 0.005f; 135 | 136 | // changes camera's phi and theta based on the sensitivity and size of the mouse movement 137 | _camera.Theta -= sensitivity * thetaDelta; 138 | _camera.Phi -= sensitivity * phiDelta; 139 | } 140 | } 141 | 142 | public string GltfFile 143 | { 144 | get { return (string)GetValue(GltfFileProperty); } 145 | set 146 | { 147 | SetValue(GltfFileProperty, value); 148 | LoadGltfFile(); 149 | } 150 | } 151 | 152 | private static readonly DependencyProperty GltfFileProperty = 153 | DependencyProperty.Register("GltfFile", typeof(string), typeof(ModelViewer), null); 154 | 155 | private async void LoadGltfFile() 156 | { 157 | _sceneVisual.Root = await LoadGLTF(new Uri(GltfFile)); 158 | } 159 | 160 | async Task LoadGLTF(Uri uri) 161 | { 162 | var storageFile = await StorageFile.GetFileFromApplicationUriAsync(uri); 163 | var buffer = await FileIO.ReadBufferAsync(storageFile); 164 | 165 | var loader = new SceneLoader(); 166 | return loader.Load(buffer, _compositor); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/OrbitalCamera.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Numerics; 7 | using Windows.UI.Composition; 8 | 9 | namespace CameraComponent 10 | { 11 | /// 12 | /// A class that defines an OrbitalCamera that orbits around a point in world space. 13 | /// Implements the Camera and Animatable interfaces. 14 | /// 15 | public sealed class OrbitalCamera : Camera 16 | { 17 | private Compositor _compositor; 18 | private FirstPersonCamera _fpCam; 19 | private CompositionPropertySet _propertySet; 20 | 21 | /// 22 | /// Creates an OrbitalCamera with default properties. 23 | /// Target = Vector3.Zero 24 | /// Phi = 0 25 | /// Theta = 0 26 | /// Radius = 300 27 | /// ModelViewProjectionMatrix = Matrix4x4.Identity 28 | /// 29 | /// 30 | /// Thrown when constructor is passed a null value. 31 | public OrbitalCamera(Compositor compositor) 32 | { 33 | if (compositor == null) 34 | { 35 | throw new System.ArgumentException("Compositor cannot be null"); 36 | } 37 | 38 | _compositor = compositor; 39 | _fpCam = new FirstPersonCamera(_compositor); 40 | _propertySet = _compositor.CreatePropertySet(); 41 | 42 | float epsilon = 0.0001f; 43 | 44 | // Create the properties for the camera 45 | _propertySet.InsertVector3("Target", Vector3.Zero); 46 | _propertySet.InsertScalar("Phi", epsilon); 47 | _propertySet.InsertScalar("Theta", 0f); 48 | _propertySet.InsertScalar("Radius", 300f); 49 | _propertySet.InsertMatrix4x4("ModelViewProjectionMatrix", Matrix4x4.Identity); 50 | 51 | // Connect orbital camera's properties to the _fpCam's properties 52 | StartAnimationsOnFPCamera(); 53 | } 54 | 55 | /// 56 | /// Point in 3D world space that the camera orbits about and centers it's view on. 57 | /// 58 | public Vector3 Target 59 | { 60 | get 61 | { 62 | Vector3 curr; 63 | _propertySet.TryGetVector3("Target", out curr); 64 | return curr; 65 | } 66 | set 67 | { 68 | _propertySet.InsertVector3("Target", value); 69 | } 70 | } 71 | 72 | /// 73 | /// Distance between the camera and its Target. 74 | /// 75 | public float Radius 76 | { 77 | get 78 | { 79 | float curr; 80 | _propertySet.TryGetScalar("Radius", out curr); 81 | return MathF.Max(200, curr); 82 | } 83 | set 84 | { 85 | _propertySet.InsertScalar("Radius", value); 86 | } 87 | } 88 | 89 | /// 90 | /// The camera's angle of separation from the positive y-axis in radians. 91 | /// From 0 to Pi. 92 | /// 93 | /// 94 | /// When Phi = 0 we are looking down on the "north pole" of the object we are orbiting 95 | /// When Phi = Pi / 2 we are looking at the equator of the object 96 | /// When Phi = Pi we are looking at the "south pole" of the object 97 | /// This mimics spherical coordinates a common spherical coordinate system with (radius, theta, phi) 98 | /// 99 | public float Phi 100 | { 101 | get 102 | { 103 | float epsilon = 0.0001f; 104 | float curr; 105 | 106 | _propertySet.TryGetScalar("Phi", out curr); 107 | return MathF.Min(MathF.PI - epsilon, MathF.Max(epsilon, curr)); 108 | } 109 | set 110 | { 111 | float epsilon = 0.0001f; 112 | _propertySet.InsertScalar("Phi", MathF.Min(MathF.PI - epsilon, MathF.Max(epsilon, value))); 113 | } 114 | } 115 | 116 | /// 117 | /// The camera's angle of separation from the positive y-axis in degrees 118 | /// From 0 to 180 119 | /// 120 | /// 121 | /// When PhiInDegrees = 0 we are looking down on the "north pole" of the object we are orbiting 122 | /// When PhiInDegrees = 90 we are looking at the equator of the object 123 | /// When PhiInDegrees = 180 we are looking at the "south pole" of the object 124 | /// This mimics spherical coordinates a common spherical coordinate system with (radius, theta, phi) 125 | /// 126 | public float PhiInDegrees { get => ConvertRadiansToDegrees(Phi); set => Phi = ConvertDegreesToRadians(value); } 127 | 128 | /// 129 | /// The angle of separation from the positive z-axis in radians. 130 | /// Rotates counterclockwise from 0 to 2Pi. 131 | /// 132 | /// 133 | /// When Theta = 0 we are looking at the front of the object we are orbiting 134 | /// When Theta = Pi we are looking at the back of the object 135 | /// When Theta = Pi/2 or 3*Pi/2 we are looking at either the object's left or right side 136 | /// 137 | public float Theta 138 | { 139 | get 140 | { 141 | float curr; 142 | _propertySet.TryGetScalar("Theta", out curr); 143 | return curr; 144 | } 145 | set 146 | { 147 | _propertySet.InsertScalar("Theta", value); 148 | } 149 | } 150 | 151 | /// 152 | /// The angle of separation from the positive z-axis in degrees. 153 | /// Rotates counterclockwise from 0 to 360. 154 | /// 155 | /// 156 | /// When ThetaInDegrees = 0 we are looking at the front of the object we are orbiting 157 | /// When ThetaInDegrees = 180 we are looking at the back of the object 158 | /// When ThetaInDegrees = 90 or 270 we are looking at either the object's left or right side 159 | /// 160 | public float ThetaInDegrees { get => ConvertRadiansToDegrees(Theta); set => Theta = ConvertDegreesToRadians(value); } 161 | 162 | // Helper function that converts radians to degrees 163 | private float ConvertRadiansToDegrees(float rads) 164 | { 165 | return (180 / MathF.PI) * rads; 166 | } 167 | 168 | // Helper function that converts radians to degrees 169 | private float ConvertDegreesToRadians(float degs) 170 | { 171 | return (MathF.PI / 180) * degs; 172 | } 173 | 174 | /// 175 | /// The camera's reference to an object that implements the Projection interace. 176 | /// When setting, this property starts animations on the camera's ModelViewProjectionMatrix property. 177 | /// 178 | /// When set to null, the ModelViewProjectionProperty is animated using an OrthographicProjection with the 179 | /// default values of: Height = 100, Width = 100, Near = 1, Far = 1000. 180 | public Projection Projection { get => _fpCam.Projection; set => _fpCam.Projection = value; } 181 | 182 | /// 183 | /// Returns the camera's position in 3D world space. 184 | /// 185 | /// A Vector3 that represents the camera's extrinsic position in 3D world space. 186 | public Vector3 GetAbsolutePosition() 187 | { 188 | float x = MathF.Sin(Phi) * MathF.Sin(Theta); 189 | float y = -MathF.Cos(Phi); 190 | float z = MathF.Sin(Phi) * MathF.Cos(Theta); 191 | 192 | return Target + (Radius * new Vector3(x, y, z)); 193 | } 194 | 195 | /// 196 | /// Returns the camera's position in 3D world space. 197 | /// 198 | /// 199 | public void SetAbsolutePosition(Vector3 value) 200 | { 201 | Radius = Vector3.Distance(Target, value); 202 | Theta = MathF.Atan2(value.X, value.Z); 203 | Phi = MathF.Atan2(value.Z, value.Y); 204 | } 205 | 206 | /// 207 | /// Returns the matrix created from the camera's translation and rotation transformations. 208 | /// 209 | /// A Matrix4x4 that is created from the camera's target, radius, phi, and theta. 210 | public Matrix4x4 GetViewMatrix() 211 | { 212 | Vector3 position = GetAbsolutePosition(); 213 | 214 | // use OrbitalCamera's properties to calculate rotaation in terms of yaw, pitch, and roll 215 | Matrix4x4 matPos = Matrix4x4.CreateTranslation(-position); 216 | Matrix4x4 matRoll = Matrix4x4.CreateFromAxisAngle(new Vector3(0, 0, 1), 0); 217 | Matrix4x4 matPitch = Matrix4x4.CreateFromAxisAngle(new Vector3(1, 0, 0), -MathF.Asin(Vector3.Normalize(Target - position).Y)); 218 | Matrix4x4 matYaw = Matrix4x4.CreateFromAxisAngle(new Vector3(0, 1, 0), -Theta); 219 | 220 | return matPos * matYaw * matPitch * matRoll; 221 | } 222 | 223 | /// 224 | /// Returns that a matrix created from the camera's view matrix and it's Projection's projection matrix. 225 | /// 226 | /// A Matrix4x4 that is the product of matrices created from the Camera's target, radius, phi, and theta and its Projection's projection matrix. 227 | public Matrix4x4 GetModelViewProjectionMatrix() 228 | { 229 | return GetViewMatrix() * Projection.GetProjectionMatrix(); 230 | } 231 | 232 | // Creates expression animations to drive an FPCamera's position and rotation through the OrbitalCamera's phi, theta, and radius 233 | private void StartAnimationsOnFPCamera() 234 | { 235 | CompositionPropertySet fpCamera = _fpCam.GetPropertySet(); 236 | 237 | // Drives FPCamera's position based on the following formula 238 | // FPCamera.Position = Radius*( Sin(Phi)*Sin(Theta), -Cos(Phi), Sin(Phi)*Cos(Theta) ) 239 | // Sums with Target in the case where Target is not the origin 240 | var positionExpression = _compositor.CreateExpressionAnimation(); 241 | positionExpression.Expression = 242 | "OrbitalCamera.Target + OrbitalCamera.Radius * " + 243 | "Vector3(" + 244 | "Sin(Clamp(OrbitalCamera.Phi, epsilon, Pi - epsilon)) * Sin(OrbitalCamera.Theta), " + 245 | "-Cos(Clamp(OrbitalCamera.Phi, epsilon, Pi - epsilon)), " + 246 | "Sin(Clamp(OrbitalCamera.Phi, epsilon, Pi - epsilon)) * Cos(OrbitalCamera.Theta))"; 247 | positionExpression.SetExpressionReferenceParameter("OrbitalCamera", _propertySet); 248 | positionExpression.SetScalarParameter("epsilon", 0.0001f); 249 | fpCamera.StartAnimation("Position", positionExpression); 250 | 251 | // Drives FPCamera's yaw by equating it with Theta 252 | var yawExpression = _compositor.CreateExpressionAnimation(); 253 | yawExpression.Expression = "OrbitalCamera.Theta"; 254 | yawExpression.SetExpressionReferenceParameter("OrbitalCamera", _propertySet); 255 | fpCamera.StartAnimation("Yaw", yawExpression); 256 | 257 | // Drives FPCamera's yaw using the vector eminating from the camera's position to its target 258 | var pitchExpression = _compositor.CreateExpressionAnimation(); 259 | pitchExpression.Expression = "Asin(Normalize(OrbitalCamera.Target - FPCamera.Position).Y)"; 260 | pitchExpression.SetExpressionReferenceParameter("OrbitalCamera", _propertySet); 261 | pitchExpression.SetExpressionReferenceParameter("FPCamera", fpCamera); 262 | fpCamera.StartAnimation("Pitch", pitchExpression); 263 | 264 | // Links OrbitalCamera's ModelViewProjectionMatrix to the ModelViewProjectionMatrix that's computed in FPCamera 265 | var modelViewProjExpression = _compositor.CreateExpressionAnimation(); 266 | modelViewProjExpression.Expression = "FPCamera.ModelViewProjectionMatrix"; 267 | modelViewProjExpression.SetReferenceParameter("FPCamera", fpCamera); 268 | _propertySet.StartAnimation("ModelViewProjectionMatrix", modelViewProjExpression); 269 | } 270 | 271 | /// 272 | /// Returns the camera's set of animatable properties. 273 | /// 274 | /// A CompositionPropertySet holding the camera's properties. 275 | public CompositionPropertySet GetPropertySet() 276 | { 277 | return _propertySet; 278 | } 279 | 280 | /// 281 | /// Starts a given animation on the specified property. 282 | /// 283 | /// The name of the property to be animated. 284 | /// The animation being applied. 285 | public void StartAnimation(string propertyName, CompositionAnimation animation) 286 | { 287 | _propertySet.StartAnimation(propertyName, animation); 288 | } 289 | 290 | /// 291 | /// Stops any animations on the specified property. 292 | /// 293 | /// The name of the property whose animations we are stopping. 294 | public void StopAnimation(string propertyName) 295 | { 296 | _propertySet.StopAnimation(propertyName); 297 | } 298 | } 299 | } -------------------------------------------------------------------------------- /Experimental/CameraComponent/OrthographicProjection.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Numerics; 7 | using Windows.UI.Composition; 8 | 9 | namespace CameraComponent 10 | { 11 | /// 12 | /// A class that defines an orthographic projection with a distance to the near and far planes and a size. 13 | /// Implements the Projection and Animatable interfaces. 14 | /// 15 | public sealed class OrthographicProjection : Projection 16 | { 17 | private CompositionPropertySet _propertySet; 18 | private Compositor _compositor; 19 | 20 | /// 21 | /// Creates a OrthographicProjection with default properties. 22 | /// Size = 100 23 | /// Near = 1 24 | /// Far = 1000 25 | /// 26 | /// 27 | /// Thrown when constructor is passed a null value. 28 | public OrthographicProjection(Compositor compositor) 29 | { 30 | if (compositor == null) 31 | { 32 | throw new System.ArgumentException("Compositor cannot be null"); 33 | } 34 | 35 | _compositor = compositor; 36 | _propertySet = _compositor.CreatePropertySet(); 37 | 38 | // Create the properties for the projection 39 | _propertySet.InsertScalar("Size", 100f); 40 | _propertySet.InsertScalar("Near", 1f); 41 | _propertySet.InsertScalar("Far", 1000f); 42 | _propertySet.InsertMatrix4x4("ProjectionMatrix", Matrix4x4.Identity); 43 | 44 | StartAnimationsOnProjectionMatrix(); 45 | } 46 | 47 | /// 48 | /// Size of the square plane that the image is projected onto. 49 | /// 50 | public float Size 51 | { 52 | get 53 | { 54 | float curr; 55 | _propertySet.TryGetScalar("Size", out curr); 56 | return curr; 57 | } 58 | set 59 | { 60 | float epsilon = 0.0001f; 61 | _propertySet.InsertScalar("Size", MathF.Max(epsilon, value)); 62 | } 63 | } 64 | 65 | /// 66 | /// Distance from the eye to the near plane. 67 | /// 68 | public float Near 69 | { 70 | get 71 | { 72 | float curr; 73 | _propertySet.TryGetScalar("Near", out curr); 74 | return curr; 75 | } 76 | set 77 | { 78 | float epsilon = 0.0001f; 79 | _propertySet.InsertScalar("Near", MathF.Max(epsilon, value)); 80 | } 81 | } 82 | 83 | /// 84 | /// Distance from the eye to the far plane. 85 | /// 86 | public float Far 87 | { 88 | get 89 | { 90 | float curr; 91 | _propertySet.TryGetScalar("Far", out curr); 92 | return curr; 93 | } 94 | set 95 | { 96 | _propertySet.InsertScalar("Far", value); 97 | } 98 | } 99 | 100 | /// 101 | /// Returns the matrix created from the projection's Near, Far, and Size. 102 | /// 103 | /// A Matrix4x4 that normalizes the scene in the range (-1, -1, -1) to (1, 1, 1). 104 | public Matrix4x4 GetProjectionMatrix() 105 | { 106 | Matrix4x4 matProj = Matrix4x4.Identity; 107 | matProj.M11 = 1 / Size; 108 | matProj.M22 = 1 / Size; 109 | matProj.M33 = 1 / (Far - Near); 110 | 111 | return matProj; 112 | } 113 | 114 | private void StartAnimationsOnProjectionMatrix() 115 | { 116 | var matProj = 117 | "Matrix4x4(" + 118 | "1 / Max(epsilon, OrthoProj.Size), 0, 0, 0, " + 119 | "0, 1 / Max(epsilon, OrthoProj.Size), 0, 0, " + 120 | "0, 0, 1 / (OrthoProj.Far - OrthoProj.Near), 0, " + 121 | "0, 0, 0, 1)"; 122 | 123 | var projExpression = _compositor.CreateExpressionAnimation(); 124 | projExpression.Expression = matProj; 125 | projExpression.SetScalarParameter("epsilon", 0.0001f); 126 | projExpression.SetReferenceParameter("OrthoProj", _propertySet); 127 | 128 | _propertySet.StartAnimation("ProjectionMatrix", projExpression); 129 | } 130 | 131 | /// 132 | /// Returns the projection's set of animatable properties. 133 | /// 134 | /// A CompositionPropertySet holding the projection's properties. 135 | public CompositionPropertySet GetPropertySet() 136 | { 137 | return _propertySet; 138 | } 139 | 140 | /// 141 | /// Starts a given animation on the specified property. 142 | /// 143 | /// The name of the property to be animated. 144 | /// The animation being applied. 145 | public void StartAnimation(string propertyName, CompositionAnimation animation) 146 | { 147 | _propertySet.StartAnimation(propertyName, animation); 148 | } 149 | 150 | /// 151 | /// Stops any animations on the specified property. 152 | /// 153 | /// The name of the property whose animations we are stopping. 154 | public void StopAnimation(string propertyName) 155 | { 156 | _propertySet.StopAnimation(propertyName); 157 | } 158 | } 159 | } -------------------------------------------------------------------------------- /Experimental/CameraComponent/PerspectiveProjection.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using System.Numerics; 7 | using Windows.UI.Composition; 8 | 9 | namespace CameraComponent 10 | { 11 | /// 12 | /// A class that defines a perspective projection with a distance to the near and far planes and a field of view. 13 | /// Implements the Projection and Animatable interfaces. 14 | /// 15 | public sealed class PerspectiveProjection : Projection 16 | { 17 | private Compositor _compositor; 18 | private CompositionPropertySet _propertySet; 19 | 20 | /// 21 | /// Creates a PerspectiveProjection with default properties. 22 | /// Fov = Pi / 2 23 | /// Near = 1 24 | /// Far = 1000 25 | /// 26 | /// 27 | /// Thrown when constructor is passed a null value. 28 | public PerspectiveProjection(Compositor compositor) 29 | { 30 | if (compositor == null) 31 | { 32 | throw new System.ArgumentException("Compositor cannot be null"); 33 | } 34 | 35 | _compositor = compositor; 36 | _propertySet = _compositor.CreatePropertySet(); 37 | 38 | // Create the properties for the projection 39 | _propertySet.InsertScalar("Fov", MathF.PI / 2); 40 | _propertySet.InsertScalar("Near", 1f); 41 | _propertySet.InsertScalar("Far", 1000f); 42 | _propertySet.InsertMatrix4x4("ProjectionMatrix", Matrix4x4.Identity); 43 | 44 | StartAnimationonProjectionMatrix(); 45 | } 46 | 47 | /// 48 | /// The field of view of the projection's frustum in radians. 49 | /// 50 | public float Fov 51 | { 52 | get 53 | { 54 | float curr; 55 | _propertySet.TryGetScalar("Fov", out curr); 56 | return curr; 57 | } 58 | set 59 | { 60 | float epsilon = 0.0001f; 61 | _propertySet.InsertScalar("Fov", MathF.Min(MathF.PI - epsilon, MathF.Max(epsilon, value))); 62 | } 63 | } 64 | 65 | /// 66 | /// The field of view of the projection's frustum in degrees. 67 | /// 68 | public float FovInDegrees { get => ConvertRadiansToDegrees(Fov); set => Fov = ConvertDegreesToRadians(value); } 69 | 70 | // Helper function that converts radians to degrees 71 | private float ConvertRadiansToDegrees(float rads) 72 | { 73 | return (180 / MathF.PI) * rads; 74 | } 75 | 76 | // Helper function that converts radians to degrees 77 | private float ConvertDegreesToRadians(float degs) 78 | { 79 | return (MathF.PI / 180) * degs; 80 | } 81 | 82 | /// 83 | /// Distance from the eye to the near plane. 84 | /// 85 | public float Near 86 | { 87 | get 88 | { 89 | float curr; 90 | _propertySet.TryGetScalar("Near", out curr); 91 | return curr; 92 | } 93 | set 94 | { 95 | float epsilon = 0.0001f; 96 | _propertySet.InsertScalar("Near", MathF.Max(epsilon, value)); 97 | } 98 | } 99 | 100 | /// 101 | /// Distance from the eye to the far plane. 102 | /// 103 | public float Far 104 | { 105 | get 106 | { 107 | float curr; 108 | _propertySet.TryGetScalar("Far", out curr); 109 | return curr; 110 | } 111 | set 112 | { 113 | _propertySet.InsertScalar("Far", value); 114 | } 115 | } 116 | 117 | /// 118 | /// Returns the matrix created from the projection's Near, Far, and Fov values. 119 | /// 120 | /// A Matrix4x4 that normalizes the scene in the range (-1, -1, -1) to (1, 1, 1). 121 | public Matrix4x4 GetProjectionMatrix() 122 | { 123 | Matrix4x4 matProj = Matrix4x4.Identity; 124 | matProj.M11 = 1 / MathF.Tan(Fov / 2); 125 | matProj.M22 = 1 / MathF.Tan(Fov / 2); 126 | matProj.M33 = (Far - Near) / -(Far + Near); 127 | matProj.M34 = -1; 128 | matProj.M43 = (-2 * Far * Near) / -(Far + Near); 129 | 130 | return matProj; 131 | } 132 | 133 | 134 | /// 135 | /// Returns the projection's set of animatable properties. 136 | /// 137 | /// A CompositionPropertySet holding the projection's properties. 138 | public CompositionPropertySet GetPropertySet() 139 | { 140 | return _propertySet; 141 | } 142 | 143 | private void StartAnimationonProjectionMatrix() 144 | { 145 | var matProj = 146 | "Matrix4x4(" + 147 | "1 / Tan(Clamp(PerspProj.Fov / 2, epsilon, Pi - epsilon)), 0, 0, 0, " + 148 | "0, 1 / Tan(Clamp(PerspProj.Fov / 2, epsilon, Pi - epsilon)), 0, 0, " + 149 | "0, 0, (PerspProj.Far - PerspProj.Near) / -(PerspProj.Far + PerspProj.Near), -1, " + 150 | "0, 0, (-2 * PerspProj.Far * PerspProj.Near) / -(PerspProj.Far + PerspProj.Near), 1)"; 151 | 152 | var projExpression = _compositor.CreateExpressionAnimation(); 153 | projExpression.Expression = matProj; 154 | projExpression.SetScalarParameter("epsilon", 0.0001f); 155 | projExpression.SetReferenceParameter("PerspProj", _propertySet); 156 | 157 | _propertySet.StartAnimation("ProjectionMatrix", projExpression); 158 | } 159 | 160 | /// 161 | /// Starts a given animation on the specified property. 162 | /// 163 | /// The name of the property to be animated. 164 | /// The animation being applied. 165 | public void StartAnimation(string propertyName, CompositionAnimation animation) 166 | { 167 | _propertySet.StartAnimation(propertyName, animation); 168 | } 169 | 170 | /// 171 | /// Stops any animations on the specified property. 172 | /// 173 | /// The name of the property whose animations we are stopping. 174 | public void StopAnimation(string propertyName) 175 | { 176 | _propertySet.StopAnimation(propertyName); 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/Projection.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Numerics; 6 | 7 | namespace CameraComponent 8 | { 9 | /// 10 | /// An interface that defines properties and functions that a Projection object must implement. 11 | /// 12 | public interface Projection : Animatable 13 | { 14 | /// 15 | /// Distance from the camera to the near plane. 16 | /// 17 | float Near { get; set; } 18 | 19 | /// 20 | /// Distance from the camera to the far plane. 21 | /// 22 | float Far { get; set; } 23 | 24 | /// 25 | /// Returns the matrix created by the near and far planes and other properties of the projection. 26 | /// 27 | /// A Matrix4x4 created from the specific type of projection's properties. 28 | Matrix4x4 GetProjectionMatrix(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Experimental/CameraComponent/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Reflection; 6 | using System.Runtime.CompilerServices; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("CameraComponent")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("CameraComponent")] 17 | [assembly: AssemblyCopyright("Copyright © 2019")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Version information for an assembly consists of the following four values: 22 | // 23 | // Major Version 24 | // Minor Version 25 | // Build Number 26 | // Revision 27 | // 28 | // You can specify all the values or you can default the Build and Revision Numbers 29 | // by using the '*' as shown below: 30 | // [assembly: AssemblyVersion("1.0.*")] 31 | [assembly: AssemblyVersion("1.0.0.0")] 32 | [assembly: AssemblyFileVersion("1.0.0.0")] 33 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Windows Community Toolkit 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | All rights reserved. 6 | 7 | # MIT License (MIT) 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | 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. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SceneLoader for Windows UI 2 | 3 | SceneLoader is a library for generating [Windows.UI.Composition.Scenes](https://docs.microsoft.com/uwp/api/windows.ui.composition.scenes) scene graphs from 3D file formats such as [glTF](https://www.khronos.org/gltf/). This project aims to simplify the design-to-code workflow for rendering 3D assets in your Windows applications. 4 | 5 | SceneLoader currently produces a [SceneNode](https://docs.microsoft.com/uwp/api/windows.ui.composition.scenes.scenenode), allowing you to programmatically construct your own [Visual](https://docs.microsoft.com/uwp/api/windows.ui.composition.scenes.scenevisual) tree. A [proposed companion Microsoft.UI.Xaml control](https://github.com/microsoft/microsoft-ui-xaml/issues/686) is expected to enable 3D assets to be loaded from markup without requiring explicit management of the Visual tree. 6 | 7 | ## Supported SDKs 8 | * May 2019 Update (18362) 9 | 10 | ## Getting Started 11 | * [Documentation](https://docs.microsoft.com/uwp/api/windows.ui.composition.scenes) 12 | * [Code Sample](https://github.com/windows-toolkit/SceneLoader/blob/master/TestViewer/MainPage.xaml.cs) 13 | 14 | ## Build Status 15 | | Target | Branch | Status | Recommended NuGet package | 16 | | ------ | ------ | ------ | ------ | 17 | | 0.0.1 | master | [![Build Status](https://dev.azure.com/dotnet/WindowsCommunityToolkit/_apis/build/status/windows-toolkit.SceneLoader?branchName=master)](https://dev.azure.com/dotnet/WindowsCommunityToolkit/_build/latest?definitionId=80&branchName=master) | ? | 18 | 19 | ## Feedback and Requests 20 | Please use [GitHub Issues](https://github.com/windows-toolkit/SceneLoader/issues) for bug reports and feature requests. 21 | 22 | ## Principles 23 | This project has adopted the code of conduct defined by the [Contributor Covenant](http://contributor-covenant.org/) 24 | to clarify expected behavior in our community. 25 | For more information see the [.NET Foundation Code of Conduct](http://dotnetfoundation.org/code-of-conduct). 26 | 27 | ## .NET Foundation 28 | This project is supported by the [.NET Foundation](http://dotnetfoundation.org). 29 | 30 | -------------------------------------------------------------------------------- /SceneLoader.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29123.88 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SceneLoaderComponent", "SceneLoader\SceneLoader.vcxproj", "{88C4D662-8669-433B-8A8B-47B3A17E3C6E}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestViewer", "TestViewer\TestViewer.csproj", "{5D504AFF-651A-4C27-BA19-550663227A85}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CameraComponent", "Experimental\CameraComponent\CameraComponent.csproj", "{239C87C3-1E17-4F01-8D93-9B21C1A53F3D}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|ARM = Debug|ARM 16 | Debug|ARM64 = Debug|ARM64 17 | Debug|x64 = Debug|x64 18 | Debug|x86 = Debug|x86 19 | Release|Any CPU = Release|Any CPU 20 | Release|ARM = Release|ARM 21 | Release|ARM64 = Release|ARM64 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|Any CPU.ActiveCfg = Debug|Win32 27 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|Any CPU.Build.0 = Debug|Win32 28 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|ARM.ActiveCfg = Debug|ARM 29 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|ARM.Build.0 = Debug|ARM 30 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|ARM64.ActiveCfg = Debug|ARM64 31 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|ARM64.Build.0 = Debug|ARM64 32 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|x64.ActiveCfg = Debug|x64 33 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|x64.Build.0 = Debug|x64 34 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|x86.ActiveCfg = Debug|Win32 35 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Debug|x86.Build.0 = Debug|Win32 36 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|Any CPU.ActiveCfg = Release|Win32 37 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|Any CPU.Build.0 = Release|Win32 38 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|ARM.ActiveCfg = Release|ARM 39 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|ARM.Build.0 = Release|ARM 40 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|ARM64.ActiveCfg = Release|ARM64 41 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|ARM64.Build.0 = Release|ARM64 42 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|x64.ActiveCfg = Release|x64 43 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|x64.Build.0 = Release|x64 44 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|x86.ActiveCfg = Release|Win32 45 | {88C4D662-8669-433B-8A8B-47B3A17E3C6E}.Release|x86.Build.0 = Release|Win32 46 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|Any CPU.ActiveCfg = Debug|x86 47 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|Any CPU.Build.0 = Debug|x86 48 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|Any CPU.Deploy.0 = Debug|x86 49 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM.ActiveCfg = Debug|ARM 50 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM.Build.0 = Debug|ARM 51 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM.Deploy.0 = Debug|ARM 52 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM64.ActiveCfg = Debug|ARM64 53 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM64.Build.0 = Debug|ARM64 54 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|ARM64.Deploy.0 = Debug|ARM64 55 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x64.ActiveCfg = Debug|x64 56 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x64.Build.0 = Debug|x64 57 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x64.Deploy.0 = Debug|x64 58 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x86.ActiveCfg = Debug|x86 59 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x86.Build.0 = Debug|x86 60 | {5D504AFF-651A-4C27-BA19-550663227A85}.Debug|x86.Deploy.0 = Debug|x86 61 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|Any CPU.ActiveCfg = Release|x86 62 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|Any CPU.Build.0 = Release|x86 63 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|Any CPU.Deploy.0 = Release|x86 64 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM.ActiveCfg = Release|ARM 65 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM.Build.0 = Release|ARM 66 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM.Deploy.0 = Release|ARM 67 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM64.ActiveCfg = Release|ARM64 68 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM64.Build.0 = Release|ARM64 69 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|ARM64.Deploy.0 = Release|ARM64 70 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x64.ActiveCfg = Release|x64 71 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x64.Build.0 = Release|x64 72 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x64.Deploy.0 = Release|x64 73 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x86.ActiveCfg = Release|x86 74 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x86.Build.0 = Release|x86 75 | {5D504AFF-651A-4C27-BA19-550663227A85}.Release|x86.Deploy.0 = Release|x86 76 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|Any CPU.ActiveCfg = Debug|x86 77 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|Any CPU.Build.0 = Debug|x86 78 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|ARM.ActiveCfg = Debug|ARM 79 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|ARM.Build.0 = Debug|ARM 80 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|ARM64.ActiveCfg = Debug|ARM64 81 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|ARM64.Build.0 = Debug|ARM64 82 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|x64.ActiveCfg = Debug|x64 83 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|x64.Build.0 = Debug|x64 84 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|x86.ActiveCfg = Debug|x86 85 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Debug|x86.Build.0 = Debug|x86 86 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|Any CPU.ActiveCfg = Release|x86 87 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|Any CPU.Build.0 = Release|x86 88 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|ARM.ActiveCfg = Release|ARM 89 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|ARM.Build.0 = Release|ARM 90 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|ARM64.ActiveCfg = Release|ARM64 91 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|ARM64.Build.0 = Release|ARM64 92 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|x64.ActiveCfg = Release|x64 93 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|x64.Build.0 = Release|x64 94 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|x86.ActiveCfg = Release|x86 95 | {239C87C3-1E17-4F01-8D93-9B21C1A53F3D}.Release|x86.Build.0 = Release|x86 96 | EndGlobalSection 97 | GlobalSection(SolutionProperties) = preSolution 98 | HideSolutionNode = FALSE 99 | EndGlobalSection 100 | GlobalSection(ExtensibilityGlobals) = postSolution 101 | SolutionGuid = {79558D4B-E776-4662-A741-BBDDC6C0556F} 102 | EndGlobalSection 103 | EndGlobal 104 | -------------------------------------------------------------------------------- /SceneLoader/Bounds3D.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "Bounds3D.h" 8 | 9 | using namespace std; 10 | 11 | namespace winrt { 12 | using namespace Windows::Foundation::Numerics; 13 | using namespace Windows::UI::Composition::Scenes; 14 | } 15 | using namespace winrt; 16 | 17 | namespace SceneLoader 18 | { 19 | Bounds3D::Bounds3D(SceneBoundingBox sceneBounds) 20 | { 21 | m_min = sceneBounds.Min(); 22 | m_max = sceneBounds.Max(); 23 | } 24 | 25 | Bounds3D::Bounds3D(float3 _min, float3 _max) 26 | { 27 | m_min = _min; 28 | m_max = _max; 29 | } 30 | 31 | Bounds3D 32 | Bounds3D::Union(const Bounds3D &lBounds, const Bounds3D &rBounds) 33 | { 34 | winrt::Windows::Foundation::Numerics::float3 newMin; 35 | winrt::Windows::Foundation::Numerics::float3 newMax; 36 | 37 | newMin.x = min(lBounds.Min().x, rBounds.Min().x); 38 | newMin.y = min(lBounds.Min().y, rBounds.Min().y); 39 | newMin.z = min(lBounds.Min().z, rBounds.Min().z); 40 | 41 | newMax.x = max(lBounds.Max().x, rBounds.Max().x); 42 | newMax.y = max(lBounds.Max().y, rBounds.Max().y); 43 | newMax.z = max(lBounds.Max().z, rBounds.Max().z); 44 | 45 | return Bounds3D(newMin, newMax); 46 | } 47 | 48 | Bounds3D 49 | Bounds3D::Transform(const Bounds3D &srcBounds, const winrt::Windows::Foundation::Numerics::float4x4 &srcToDestTransform) 50 | { 51 | float3 newMin(FLT_MAX, FLT_MAX, FLT_MAX); 52 | float3 newMax(-FLT_MAX, -FLT_MAX, -FLT_MAX); 53 | 54 | { 55 | float3 boxVertices[8]; 56 | 57 | // Setup a cube, first 4 verties will be min (z) plane, 2nd 4 vertices will be max (z) plane 58 | // First vertex in each plane will be at min (x,y) winding clockwise around to rest at (xMax, yMin) 59 | 60 | boxVertices[0] = srcBounds.Min(); 61 | boxVertices[6] = srcBounds.Max(); 62 | 63 | boxVertices[1] = boxVertices[0]; 64 | boxVertices[1].y = boxVertices[6].y; 65 | 66 | boxVertices[2] = boxVertices[1]; 67 | boxVertices[2].x = boxVertices[6].x; 68 | 69 | boxVertices[3] = boxVertices[2]; 70 | boxVertices[3].y = boxVertices[0].y; 71 | 72 | boxVertices[4] = boxVertices[0]; 73 | boxVertices[4].z = boxVertices[6].z; 74 | 75 | boxVertices[5] = boxVertices[4]; 76 | boxVertices[5].y = boxVertices[6].y; 77 | 78 | boxVertices[7] = boxVertices[6]; 79 | boxVertices[7].y = boxVertices[0].y; 80 | 81 | for (int i = 0; i < 8; i++) 82 | { 83 | boxVertices[i] = transform(boxVertices[i], srcToDestTransform); 84 | 85 | newMin.x = min(newMin.x, boxVertices[i].x); 86 | newMin.y = min(newMin.y, boxVertices[i].y); 87 | newMin.z = min(newMin.z, boxVertices[i].z); 88 | 89 | newMax.x = max(newMax.x, boxVertices[i].x); 90 | newMax.y = max(newMax.y, boxVertices[i].y); 91 | newMax.z = max(newMax.z, boxVertices[i].z); 92 | } 93 | } 94 | 95 | return Bounds3D(newMin, newMax); 96 | } 97 | 98 | 99 | float3 Bounds3D::Min() const 100 | { 101 | return m_min; 102 | } 103 | 104 | float3 Bounds3D::Max() const 105 | { 106 | return m_max; 107 | } 108 | 109 | 110 | Bounds3D ComputeTreeBounds(winrt::Windows::UI::Composition::Scenes::SceneNode root); 111 | 112 | void DecomposeMatrix( 113 | const std::array matrix, 114 | winrt::Windows::Foundation::Numerics::float3* pOutScale, 115 | winrt::Windows::Foundation::Numerics::quaternion* pOutRotation, 116 | winrt::Windows::Foundation::Numerics::float3* pOutTranslation 117 | ); 118 | 119 | Bounds3D ComputeTreeBounds( 120 | SceneNode root, 121 | float4x4 parentToWorldTransform 122 | ) 123 | { 124 | Bounds3D retBounds; 125 | 126 | float4x4 localToWorldTransform = parentToWorldTransform; 127 | 128 | localToWorldTransform *= make_float4x4_scale(root.Transform().Scale()); 129 | localToWorldTransform *= make_float4x4_from_quaternion(root.Transform().Orientation()); 130 | localToWorldTransform *= make_float4x4_translation(root.Transform().Translation()); 131 | 132 | // Check if we have a mesh attached 133 | auto firstComponent = root.Components().First(); 134 | 135 | if (firstComponent && firstComponent.HasCurrent()) 136 | { 137 | auto meshRenderer = firstComponent.Current().as(); 138 | 139 | if (meshRenderer) 140 | { 141 | auto mesh = meshRenderer.Mesh(); 142 | 143 | if (mesh) 144 | { 145 | Bounds3D localBounds = mesh.Bounds(); 146 | 147 | retBounds = Bounds3D::Transform(localBounds, localToWorldTransform); 148 | } 149 | } 150 | } 151 | 152 | for (UINT i = 0; i < root.Children().Size(); i++) 153 | { 154 | retBounds = Bounds3D::Union(retBounds, ComputeTreeBounds(root.Children().GetAt(i), localToWorldTransform)); 155 | } 156 | 157 | return retBounds; 158 | } 159 | 160 | void DecomposeMatrix( 161 | const std::array matrix, 162 | float3* pOutScale, 163 | quaternion* pOutRotation, 164 | float3* pOutTranslation) 165 | { 166 | float4x4 inputMatrix( 167 | matrix[0], matrix[1], matrix[2], matrix[3], 168 | matrix[4], matrix[5], matrix[6], matrix[7], 169 | matrix[8], matrix[9], matrix[10], matrix[11], 170 | matrix[12], matrix[13], matrix[14], matrix[15] 171 | ); 172 | 173 | bool fDecomposeResult = decompose( 174 | inputMatrix, 175 | pOutScale, 176 | pOutRotation, 177 | pOutTranslation); 178 | 179 | assert(fDecomposeResult); 180 | } 181 | } // namespace SceneLoader -------------------------------------------------------------------------------- /SceneLoader/Bounds3D.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | namespace SceneLoader { 8 | 9 | class Bounds3D 10 | { 11 | public: 12 | Bounds3D(winrt::Windows::UI::Composition::Scenes::SceneBoundingBox sceneBounds); 13 | 14 | Bounds3D(winrt::Windows::Foundation::Numerics::float3 _min = winrt::Windows::Foundation::Numerics::float3(FLT_MAX, FLT_MAX, FLT_MAX), 15 | winrt::Windows::Foundation::Numerics::float3 _max = winrt::Windows::Foundation::Numerics::float3(FLT_MIN, FLT_MIN, FLT_MIN)); 16 | 17 | static Bounds3D Union(const Bounds3D &lBounds, const Bounds3D &rBounds); 18 | static Bounds3D Transform(const Bounds3D &srcBounds, const winrt::Windows::Foundation::Numerics::float4x4 &transform); 19 | 20 | winrt::Windows::Foundation::Numerics::float3 Min() const; 21 | 22 | winrt::Windows::Foundation::Numerics::float3 Max() const; 23 | 24 | private: 25 | winrt::Windows::Foundation::Numerics::float3 m_min; 26 | winrt::Windows::Foundation::Numerics::float3 m_max; 27 | }; 28 | 29 | Bounds3D ComputeTreeBounds(winrt::Windows::UI::Composition::Scenes::SceneNode root, 30 | winrt::Windows::Foundation::Numerics::float4x4 parentTransform); 31 | 32 | void DecomposeMatrix( 33 | const std::array matrix, 34 | winrt::Windows::Foundation::Numerics::float3* pOutScale, 35 | winrt::Windows::Foundation::Numerics::quaternion* pOutRotation, 36 | winrt::Windows::Foundation::Numerics::float3* pOutTranslation 37 | ); 38 | } -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "UtilForIntermingledNamespaces.h" 8 | #include "GLTFVisitor.h" 9 | 10 | using namespace std; 11 | using namespace Microsoft::glTF; 12 | 13 | namespace winrt { 14 | using namespace Windows::UI::Composition; 15 | using namespace Windows::UI::Composition::Scenes; 16 | } 17 | using namespace winrt; 18 | 19 | extern std::wstringstream s_export; 20 | 21 | namespace SceneLoader 22 | { 23 | GLTFVisitor::GLTFVisitor(Compositor compositor, 24 | SceneNode rootSceneNode, 25 | shared_ptr resourceSet, 26 | shared_ptr gltfResourceReader, 27 | Document& gltfDocument, 28 | Scene& gltfScene) : 29 | m_compositor(compositor), 30 | m_rootSceneNode(rootSceneNode), 31 | m_sceneNodeMap(single_threaded_map()), 32 | m_resourceSet(resourceSet), 33 | m_gltfResourceReader(gltfResourceReader), 34 | m_gltfDocument(gltfDocument), 35 | m_gltfScene(gltfScene) 36 | { 37 | } 38 | 39 | HRESULT GLTFVisitor::EnsureGraphicsDevice() 40 | { 41 | HRESULT hr = S_OK; 42 | 43 | if (!m_graphicsDevice) 44 | { 45 | // Initialize DX 46 | winrt::com_ptr cpDevice; 47 | winrt::com_ptr cpContext; 48 | UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; 49 | D3D_FEATURE_LEVEL featureLevels[] = 50 | { 51 | D3D_FEATURE_LEVEL_11_1, 52 | D3D_FEATURE_LEVEL_11_0, 53 | D3D_FEATURE_LEVEL_10_1, 54 | D3D_FEATURE_LEVEL_10_0, 55 | D3D_FEATURE_LEVEL_9_3, 56 | D3D_FEATURE_LEVEL_9_2, 57 | D3D_FEATURE_LEVEL_9_1 58 | }; 59 | D3D_FEATURE_LEVEL usedFeatureLevel; 60 | 61 | hr = D3D11CreateDevice( 62 | nullptr, 63 | D3D_DRIVER_TYPE_HARDWARE, 64 | nullptr, 65 | creationFlags, 66 | featureLevels, 67 | ARRAYSIZE(featureLevels), 68 | D3D11_SDK_VERSION, 69 | cpDevice.put(), 70 | &usedFeatureLevel, 71 | cpContext.put()); 72 | 73 | winrt::com_ptr cpD2DFactory; 74 | winrt::com_ptr cpD2D1Device; 75 | winrt::com_ptr cpd3dDevice = cpDevice.as(); 76 | hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory1), cpD2DFactory.put_void()); 77 | winrt::com_ptr cpDxgiDevice = cpd3dDevice.as(); 78 | cpD2DFactory->CreateDevice(cpDxgiDevice.get(), cpD2D1Device.put()); 79 | 80 | winrt::com_ptr cpCompositorInterop = m_compositor.as< ABI::Windows::UI::Composition::ICompositorInterop>(); 81 | cpCompositorInterop->CreateGraphicsDevice(/*cpDevice*/cpD2D1Device.get(), m_graphicsDevice.put()); 82 | 83 | assert(m_graphicsDevice); 84 | } 85 | 86 | return hr; 87 | } 88 | 89 | winrt::Windows::UI::Composition::CompositionMipmapSurface 90 | GLTFVisitor::EnsureMipMapSurfaceId( 91 | const std::string id, 92 | winrt::Windows::Graphics::SizeInt32 sizePixels, 93 | winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat, 94 | winrt::Windows::Graphics::DirectX::DirectXAlphaMode alphaMode) 95 | { 96 | EnsureGraphicsDevice(); 97 | 98 | winrt::Windows::UI::Composition::ICompositionGraphicsDevice3 cpGraphicsDevice3 = m_graphicsDevice.as< winrt::Windows::UI::Composition::ICompositionGraphicsDevice3>(); 99 | 100 | return m_resourceSet->EnsureMipMapSurfaceId( 101 | id, 102 | sizePixels, 103 | pixelFormat, 104 | alphaMode, 105 | cpGraphicsDevice3 106 | ); 107 | } 108 | 109 | 110 | } // SceneLoader 111 | -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | #include "SceneResourceSet.h" 8 | 9 | namespace SceneLoader 10 | { 11 | struct GLTFVisitor 12 | { 13 | GLTFVisitor(winrt::Windows::UI::Composition::Compositor compositor, 14 | winrt::Windows::UI::Composition::Scenes::SceneNode rootSceneNode, 15 | std::shared_ptr resourceSet, 16 | std::shared_ptr gltfResourceReader, 17 | Microsoft::glTF::Document& gltfDocument, 18 | Microsoft::glTF::Scene& gltfScene); 19 | 20 | // Node 21 | void operator()(const Microsoft::glTF::Node& node, const Microsoft::glTF::Node* nodeParent); 22 | 23 | // Mesh 24 | void operator()(const Microsoft::glTF::Mesh& mesh, Microsoft::glTF::VisitState alreadyVisited); 25 | 26 | // MeshPrimitive 27 | void operator()(const Microsoft::glTF::MeshPrimitive&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 28 | 29 | // Material 30 | void operator()(const Microsoft::glTF::Material&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 31 | 32 | // Texture 33 | void operator()(const Microsoft::glTF::Texture&, Microsoft::glTF::TextureType, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 34 | 35 | // Image 36 | void operator()(const Microsoft::glTF::Image&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 37 | 38 | // Sampler 39 | void operator()(const Microsoft::glTF::Sampler&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 40 | 41 | // Skin 42 | void operator()(const Microsoft::glTF::Skin&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 43 | 44 | // Camera 45 | void operator()(const Microsoft::glTF::Camera&, Microsoft::glTF::VisitState, const Microsoft::glTF::VisitDefaultAction&); 46 | 47 | HRESULT EnsureGraphicsDevice(); 48 | 49 | 50 | winrt::Windows::UI::Composition::CompositionMipmapSurface EnsureMipMapSurfaceId( 51 | const std::string id, 52 | winrt::Windows::Graphics::SizeInt32 size, 53 | winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat, 54 | winrt::Windows::Graphics::DirectX::DirectXAlphaMode alphaMode); 55 | 56 | private: 57 | winrt::Windows::UI::Composition::Compositor m_compositor{ nullptr }; 58 | 59 | winrt::com_ptr m_graphicsDevice{ nullptr }; 60 | 61 | // The SceneNode connected to the SceneVisual 62 | winrt::Windows::UI::Composition::Scenes::SceneNode m_rootSceneNode{ nullptr }; 63 | 64 | // Only keeps track of the equivalent SceneNodes from the DOM into the Scenes API. 65 | winrt::Windows::Foundation::Collections::IMap m_sceneNodeMap{ nullptr }; 66 | 67 | // It keeps the equivalent SceneNodes from the DOM and the ones needed for adapting Mesh and MeshPrimitives into the Scenes API. 68 | winrt::Windows::UI::Composition::Scenes::SceneNode m_latestSceneNode{ nullptr }; 69 | 70 | Microsoft::glTF::Document& m_gltfDocument; 71 | 72 | Microsoft::glTF::Scene& m_gltfScene; 73 | 74 | std::shared_ptr m_gltfResourceReader; 75 | std::shared_ptr m_resourceSet; 76 | }; 77 | } // SceneLoader -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Camera.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | namespace winrt { 12 | using namespace Windows::UI::Composition; 13 | using namespace Windows::UI::Composition::Scenes; 14 | } 15 | using namespace winrt; 16 | 17 | namespace SceneLoader 18 | { 19 | // Camera 20 | void GLTFVisitor::operator()(const Camera& /*camera*/, VisitState /*alreadyVisited*/, const VisitDefaultAction&) 21 | { 22 | } 23 | } -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Image.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | #include "wincodec.h" 9 | 10 | using namespace std; 11 | using namespace Microsoft::glTF; 12 | 13 | namespace winrt { 14 | using namespace Windows::Graphics; 15 | using namespace Windows::Graphics::DirectX; 16 | using namespace Windows::UI::Composition; 17 | } 18 | using namespace winrt; 19 | 20 | namespace SceneLoader 21 | { 22 | // Image 23 | void GLTFVisitor::operator()(const Image& image, VisitState alreadyVisited, const VisitDefaultAction&) 24 | { 25 | if (alreadyVisited == VisitState::New) 26 | { 27 | std::vector imageData = m_gltfResourceReader->ReadBinaryData(m_gltfDocument, image); 28 | 29 | const void* pSource = static_cast(imageData.data()); 30 | 31 | // Create input stream for memory 32 | com_ptr cpWIC; 33 | winrt::check_hresult(CoCreateInstance( 34 | CLSID_WICImagingFactory, 35 | NULL, 36 | CLSCTX_INPROC_SERVER, 37 | __uuidof(cpWIC), 38 | (LPVOID*)&cpWIC)); 39 | 40 | com_ptr cpStream; 41 | winrt::check_hresult(cpWIC->CreateStream(cpStream.put())); 42 | winrt::check_hresult(cpStream->InitializeFromMemory(static_cast(const_cast(pSource)), 43 | static_cast(imageData.size()))); 44 | 45 | com_ptr cpDecoder; 46 | winrt::check_hresult(cpWIC->CreateDecoderFromStream(cpStream.get(), nullptr, WICDecodeMetadataCacheOnDemand, cpDecoder.put())); 47 | 48 | com_ptr cpSource; 49 | winrt::check_hresult(cpDecoder->GetFrame(0, cpSource.put())); 50 | 51 | UINT imageWidth = 0; 52 | UINT imageHeight = 0; 53 | winrt::check_hresult(cpSource->GetSize(&imageWidth, &imageHeight)); 54 | SizeInt32 size{ static_cast(imageWidth), static_cast(imageHeight) }; // FIXME: conversion from 'UINT' to 'int32_t' requires a narrowing conversion 55 | DirectXPixelFormat pixelFormat = DirectXPixelFormat::B8G8R8A8UIntNormalized; // Warning: SceneResourceSet::EnsureMipMapSurfaceId hard codes these values 56 | DirectXAlphaMode alphaMode = DirectXAlphaMode::Premultiplied; // Warning: SceneResourceSet::EnsureMipMapSurfaceId hard codes these values 57 | 58 | CompositionMipmapSurface mipmap = EnsureMipMapSurfaceId( 59 | image.id, 60 | size, 61 | pixelFormat, 62 | alphaMode 63 | ); 64 | 65 | com_ptr cpCurrentSourceBitmap; 66 | 67 | // Create highest resolution source bitmap 68 | { 69 | com_ptr cpD2DContext; 70 | 71 | // Create Scalar 72 | com_ptr cpScaler; 73 | winrt::check_hresult(cpWIC->CreateBitmapScaler(cpScaler.put())); 74 | 75 | winrt::check_hresult(cpScaler->Initialize( 76 | cpSource.get(), // Bitmap source to scale. 77 | imageWidth, // Scale width to half of original. 78 | imageHeight, // Scale height to half of original. 79 | WICBitmapInterpolationModeFant)); // Use Fant mode interpolation. 80 | 81 | com_ptr cpConverter; 82 | 83 | winrt::check_hresult(cpWIC->CreateFormatConverter(cpConverter.put())); 84 | winrt::check_hresult(cpConverter->Initialize( 85 | cpScaler.get(), 86 | /*WicPixelFormatFromDirectXPixelFormat(pixelFormat, alphaMode)*/GUID_WICPixelFormat32bppPBGRA, 87 | WICBitmapDitherTypeNone, 88 | nullptr, 89 | 0.0f, 90 | WICBitmapPaletteTypeMedianCut)); 91 | 92 | CompositionDrawingSurface cpDrawingSurface = mipmap.GetDrawingSurfaceForLevel(0); 93 | com_ptr cpDrawingSurfaceInterop = cpDrawingSurface.as(); 94 | 95 | POINT surfaceUpdateOffset; 96 | winrt::check_hresult(cpDrawingSurfaceInterop->BeginDraw( 97 | nullptr, 98 | IID_PPV_ARGS(cpD2DContext.put()), 99 | &surfaceUpdateOffset)); 100 | 101 | com_ptr cpCompatibleRenderTarget; 102 | winrt::check_hresult(cpD2DContext->CreateCompatibleRenderTarget(cpCompatibleRenderTarget.put())); 103 | 104 | winrt::check_hresult(cpCompatibleRenderTarget->CreateBitmapFromWicBitmap( 105 | cpConverter.get(), 106 | nullptr, 107 | cpCurrentSourceBitmap.put())); 108 | 109 | winrt::check_hresult(cpDrawingSurfaceInterop->EndDraw()); 110 | } 111 | 112 | float sourceBitmapDpiX, sourceBitmapDpiY; 113 | 114 | cpCurrentSourceBitmap->GetDpi(&sourceBitmapDpiX, &sourceBitmapDpiY); 115 | 116 | for (UINT i = 0; i < mipmap.LevelCount(); ++i) 117 | { 118 | CompositionDrawingSurface cpDrawingSurface = mipmap.GetDrawingSurfaceForLevel(i); 119 | com_ptr cpDrawingSurfaceInterop = cpDrawingSurface.as(); 120 | com_ptr cpD2DContext; 121 | 122 | #ifndef NDEBUG 123 | { 124 | D2D1_SIZE_U sourceSize2 = cpCurrentSourceBitmap->GetPixelSize(); 125 | 126 | assert(sourceSize2.width == imageWidth); 127 | assert(sourceSize2.height == imageHeight); 128 | } 129 | #endif 130 | 131 | POINT surfaceUpdateOffset; 132 | winrt::check_hresult(cpDrawingSurfaceInterop->BeginDraw( 133 | nullptr, 134 | IID_PPV_ARGS(cpD2DContext.put()), 135 | &surfaceUpdateOffset)); 136 | 137 | D2D1_RECT_F destRect; 138 | destRect.left = (float)surfaceUpdateOffset.x; 139 | destRect.top = (float)surfaceUpdateOffset.y; 140 | destRect.right = (float)(destRect.left + imageWidth); 141 | destRect.bottom = (float)(destRect.top + imageHeight); 142 | 143 | cpD2DContext->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY); 144 | 145 | cpD2DContext->DrawBitmap( 146 | cpCurrentSourceBitmap.get(), 147 | &destRect, 148 | 1.0f, 149 | D2D1_BITMAP_INTERPOLATION_MODE_LINEAR 150 | ); 151 | 152 | // For debugging, turn this on to clobber the contents with red 153 | #if 0 154 | com_ptr cpSolidColorBrush; 155 | winrt::check_hresult(cpD2DContext->CreateSolidColorBrush(D2D1::ColorF::ColorF(1.0f, 0.0f, 0.0f), cpSolidColorBrush.put())); 156 | 157 | cpD2DContext->FillRectangle( 158 | &destRect, 159 | cpSolidColorBrush.get() 160 | ); 161 | #endif 162 | 163 | winrt::check_hresult(cpD2DContext->Flush()); 164 | 165 | winrt::check_hresult(cpDrawingSurfaceInterop->EndDraw()); 166 | 167 | // Update image size 168 | #undef max 169 | imageWidth = std::max(imageWidth / 2, 1U); 170 | imageHeight = std::max(imageHeight / 2, 1U); 171 | 172 | // Now we need to generate the next level source bitmap that's going to be used for 173 | // the next imagewidth/height. Note that imageWidth/Height have already been divided 174 | // by 2. 175 | com_ptr cpNewD2DTarget; 176 | 177 | D2D1_SIZE_F newDesiredSizeF = D2D1::SizeF(static_cast(imageWidth) / sourceBitmapDpiX, static_cast(imageHeight) / sourceBitmapDpiY); 178 | 179 | // Compatible Target should match format 180 | winrt::check_hresult(cpD2DContext->CreateCompatibleRenderTarget( 181 | newDesiredSizeF, 182 | D2D1::SizeU(imageWidth, imageHeight), 183 | cpCurrentSourceBitmap->GetPixelFormat(), 184 | D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, 185 | cpNewD2DTarget.put() 186 | )); 187 | 188 | cpNewD2DTarget->BeginDraw(); 189 | 190 | cpNewD2DTarget->DrawBitmap( 191 | cpCurrentSourceBitmap.get(), 192 | D2D1::RectF(0.0f, 0.0f, newDesiredSizeF.width, newDesiredSizeF.height), 193 | 1.0f, 194 | D2D1_BITMAP_INTERPOLATION_MODE_LINEAR 195 | ); 196 | 197 | winrt::check_hresult(cpNewD2DTarget->Flush()); 198 | 199 | winrt::check_hresult(cpNewD2DTarget->EndDraw()); 200 | 201 | com_ptr cpNewBitmap; 202 | winrt::check_hresult(cpNewD2DTarget->GetBitmap(cpNewBitmap.put())); 203 | 204 | // Now that we've generated the next level of bitmap, replace our current one 205 | cpCurrentSourceBitmap = cpNewBitmap; 206 | } 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Material.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | namespace winrt { 12 | using namespace Windows::UI::Composition::Scenes; 13 | } 14 | using namespace winrt; 15 | 16 | namespace SceneLoader 17 | { 18 | // Material 19 | void GLTFVisitor::operator()(const Material& material, VisitState /*alreadyVisited*/, const VisitDefaultAction&) 20 | { 21 | auto curMaterial = m_resourceSet->EnsureMaterialById(material.id); 22 | 23 | if (!m_resourceSet->GetGLTFMaterialById(material.id, nullptr)) 24 | { 25 | m_resourceSet->StoreGLTFMaterialById(material.id, material); 26 | } 27 | else 28 | { 29 | Microsoft::glTF::Material storedMaterial; 30 | 31 | m_resourceSet->GetGLTFMaterialById(material.id, &storedMaterial); 32 | 33 | assert(storedMaterial == material); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Mesh.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | namespace winrt { 12 | using namespace Windows::UI::Composition::Scenes; 13 | } 14 | using namespace winrt; 15 | using namespace std; 16 | 17 | namespace SceneLoader 18 | { 19 | // Mesh 20 | void GLTFVisitor::operator()(const Mesh& mesh, VisitState state) 21 | { 22 | if (state == VisitState::New) 23 | { 24 | wstring meshID{ mesh.id.begin(), mesh.id.end() }; 25 | 26 | // We'll have a new SceneNode for each GLTF Mesh and another for each GLTF MeshComponent. 27 | auto sceneNodeForTheGLTFMesh = SceneNode::Create(m_compositor); 28 | sceneNodeForTheGLTFMesh.Comment(meshID); 29 | 30 | m_latestSceneNode.Children().Append(sceneNodeForTheGLTFMesh); 31 | 32 | m_latestSceneNode = sceneNodeForTheGLTFMesh; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_MeshPrimitive.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "UtilForIntermingledNamespaces.h" 8 | #include "GLTFVisitor.h" 9 | 10 | using namespace std; 11 | using namespace Microsoft::glTF; 12 | 13 | namespace winrt { 14 | using namespace Windows::Foundation::Numerics; 15 | using namespace Windows::Graphics::DirectX; 16 | using namespace Windows::UI::Composition::Scenes; 17 | } 18 | using namespace winrt; 19 | 20 | extern vector s_binExportVector; 21 | 22 | namespace SceneLoader 23 | { 24 | // Mesh Primitive 25 | void GLTFVisitor::operator()(const MeshPrimitive& meshPrimitive, VisitState state, const VisitDefaultAction&) // FIXME: It is creating necessary mesh primitives (engine.gltf) 26 | { 27 | if (state == VisitState::New) 28 | { 29 | static uint16_t sCounter = 0; 30 | 31 | auto sceneNodeForTheGLTFMeshPrimitive = SceneNode::Create(m_compositor); 32 | 33 | // m_latestSceneNode is sceneNodeForTheGLTFMesh 34 | m_latestSceneNode.Children().Append(sceneNodeForTheGLTFMeshPrimitive); 35 | 36 | 37 | // We want all MeshPrimitives of a Mesh to be siblings. 38 | // That's why we don't define m_latestSceneNode as sceneNodeForTheGLTFMeshPrimitive. 39 | 40 | auto curMaterial = m_resourceSet->EnsureMaterialById(meshPrimitive.materialId); 41 | 42 | auto mesh = SceneMesh::Create(m_compositor); 43 | 44 | if (meshPrimitive.mode == MESH_TRIANGLES) 45 | { 46 | mesh.PrimitiveTopology(DirectXPrimitiveTopology::TriangleList); 47 | } 48 | else 49 | { 50 | SceneResourceSet::UnimplementedFeatureFound(); 51 | } 52 | 53 | for (auto value : meshPrimitive.attributes) 54 | { 55 | if (value.first == ACCESSOR_POSITION) 56 | { 57 | auto accessorId = meshPrimitive.GetAttributeAccessorId(value.first); 58 | auto& accessor = m_gltfDocument.accessors[accessorId]; 59 | 60 | auto data = MeshPrimitiveUtils::GetPositions(m_gltfDocument, *m_gltfResourceReader, accessor); 61 | 62 | mesh.FillMeshAttribute( 63 | SceneAttributeSemantic::Vertex, 64 | DirectXPixelFormat::R32G32B32Float, 65 | CopyArrayOfBytesToMemoryBuffer((BYTE*)data.data(), data.size() * sizeof(float))); 66 | } 67 | else if (value.first == ACCESSOR_NORMAL) 68 | { 69 | auto accessorId = meshPrimitive.GetAttributeAccessorId(value.first); 70 | auto& accessor = m_gltfDocument.accessors[accessorId]; 71 | auto data = MeshPrimitiveUtils::GetNormals(m_gltfDocument, *m_gltfResourceReader, accessor); 72 | 73 | mesh.FillMeshAttribute( 74 | SceneAttributeSemantic::Normal, 75 | DirectXPixelFormat::R32G32B32Float, 76 | CopyArrayOfBytesToMemoryBuffer((BYTE*)data.data(), data.size() * sizeof(float))); 77 | } 78 | else if (value.first == ACCESSOR_TANGENT) 79 | { 80 | auto accessorId = meshPrimitive.GetAttributeAccessorId(value.first); 81 | auto& accessor = m_gltfDocument.accessors[accessorId]; 82 | auto data = MeshPrimitiveUtils::GetTangents(m_gltfDocument, *m_gltfResourceReader, accessor); 83 | 84 | mesh.FillMeshAttribute( 85 | SceneAttributeSemantic::Tangent, 86 | DirectXPixelFormat::R32G32B32A32Float, 87 | CopyArrayOfBytesToMemoryBuffer((BYTE*)data.data(), data.size() * sizeof(float))); 88 | } 89 | else if ((value.first == ACCESSOR_TEXCOORD_0) || (value.first == ACCESSOR_TEXCOORD_1)) 90 | { 91 | auto accessorId = meshPrimitive.GetAttributeAccessorId(value.first); 92 | auto& accessor = m_gltfDocument.accessors[accessorId]; 93 | auto data = MeshPrimitiveUtils::GetTexCoords(m_gltfDocument, *m_gltfResourceReader, accessor); 94 | 95 | mesh.FillMeshAttribute( 96 | (value.first == ACCESSOR_TEXCOORD_0) ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1, 97 | DirectXPixelFormat::R32G32Float, 98 | CopyArrayOfBytesToMemoryBuffer((BYTE*)data.data(), data.size() * sizeof(float))); 99 | } 100 | else if (value.first == ACCESSOR_COLOR_0) 101 | { 102 | auto accessorId = meshPrimitive.GetAttributeAccessorId(value.first); 103 | auto& accessor = m_gltfDocument.accessors[accessorId]; 104 | auto data = MeshPrimitiveUtils::GetColors(m_gltfDocument, *m_gltfResourceReader, accessor); 105 | 106 | mesh.FillMeshAttribute( 107 | SceneAttributeSemantic::Color, 108 | DirectXPixelFormat::R32UInt, 109 | CopyArrayOfBytesToMemoryBuffer((BYTE*)data.data(), data.size() * sizeof(uint32_t))); 110 | } 111 | } // for attributes 112 | 113 | auto indices = MeshPrimitiveUtils::GetTriangulatedIndices16(m_gltfDocument, *m_gltfResourceReader, meshPrimitive); 114 | 115 | mesh.FillMeshAttribute( 116 | SceneAttributeSemantic::Index, 117 | DirectXPixelFormat::R16UInt, 118 | CopyArrayOfBytesToMemoryBuffer((BYTE*)indices.data(), indices.size() * sizeof(uint16_t))); 119 | 120 | // 121 | // Creates SceneRendererComponent, attaches MeshRenderer and add as component of the SceneNode 122 | // 123 | auto renderComponent = SceneMeshRendererComponent::Create(m_compositor); 124 | 125 | renderComponent.Mesh(mesh); 126 | 127 | renderComponent.Material(curMaterial); 128 | 129 | sceneNodeForTheGLTFMeshPrimitive.Components().Append(renderComponent); 130 | 131 | sCounter++; 132 | m_resourceSet->SetLatestMeshRendererComponent(renderComponent); 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Node.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | #include "UtilForIntermingledNamespaces.h" 9 | #include "Bounds3D.h" 10 | 11 | using namespace Microsoft::glTF; 12 | 13 | namespace winrt { 14 | using namespace Windows::UI::Composition::Scenes; 15 | using namespace Windows::Foundation::Numerics; 16 | } 17 | using namespace winrt; 18 | 19 | using namespace std; 20 | 21 | namespace SceneLoader 22 | { 23 | // Node 24 | void GLTFVisitor::operator()(const Node& node, const Node* nodeParent) 25 | { 26 | wstring nodeID{ node.id.begin(), node.id.end() }; 27 | 28 | auto sceneNode = SceneNode::Create(m_compositor); 29 | sceneNode.Comment(nodeID); 30 | 31 | m_latestSceneNode = sceneNode; 32 | m_sceneNodeMap.Insert(GetHSTRINGFromStdString(node.id), sceneNode); 33 | 34 | if (!nodeParent) 35 | { 36 | m_rootSceneNode.Children().Append(sceneNode); 37 | } 38 | else 39 | { 40 | m_sceneNodeMap.Lookup(GetHSTRINGFromStdString(nodeParent->id)).Children().Append(sceneNode); 41 | } 42 | 43 | switch (node.GetTransformationType()) 44 | { 45 | case TRANSFORMATION_MATRIX: 46 | float3 scale; 47 | quaternion rotation; 48 | float3 translation; 49 | 50 | DecomposeMatrix( 51 | node.matrix.values, 52 | &scale, 53 | &rotation, 54 | &translation); 55 | 56 | sceneNode.Transform().Scale(scale); 57 | sceneNode.Transform().Translation(translation); 58 | sceneNode.Transform().Orientation(rotation); 59 | break; 60 | 61 | case TRANSFORMATION_TRS: 62 | sceneNode.Transform().Scale({ node.scale.x, node.scale.y, node.scale.z }); 63 | sceneNode.Transform().Orientation({ node.rotation.x, node.rotation.y, node.rotation.z, node.rotation.w }); 64 | sceneNode.Transform().Translation({ node.translation.x, node.translation.y, node.translation.z }); 65 | break; 66 | 67 | case TRANSFORMATION_IDENTITY: 68 | default: 69 | // Move along. Nothing to see here. 70 | break; 71 | } 72 | } 73 | } // SceneLoader 74 | -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Sampler.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | using namespace winrt; 12 | 13 | namespace SceneLoader 14 | { 15 | void GLTFVisitor::operator()(const Sampler& sampler, VisitState state, const VisitDefaultAction&) 16 | { 17 | if (state == VisitState::New) 18 | { 19 | if (!m_resourceSet->GetGLTFSamplerById(sampler.id, nullptr)) 20 | { 21 | m_resourceSet->StoreGLTFSamplerById(sampler.id, sampler); 22 | } 23 | else 24 | { 25 | Microsoft::glTF::Sampler storedSampler; 26 | 27 | m_resourceSet->GetGLTFSamplerById(sampler.id, &storedSampler); 28 | 29 | assert(storedSampler == sampler); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Skin.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | using namespace winrt; 12 | 13 | namespace SceneLoader 14 | { 15 | // Skin 16 | void GLTFVisitor::operator()(const Skin& /*skin*/, VisitState /*alreadyVisited*/, const VisitDefaultAction&) 17 | { 18 | } 19 | 20 | 21 | 22 | } -------------------------------------------------------------------------------- /SceneLoader/GLTFVisitor_Texture.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "GLTFVisitor.h" 8 | 9 | using namespace Microsoft::glTF; 10 | 11 | using namespace winrt; 12 | 13 | namespace SceneLoader 14 | { 15 | void GLTFVisitor::operator()(const Texture& texture, TextureType /*textureType*/, VisitState state, const VisitDefaultAction&) 16 | { 17 | if (state == VisitState::New) 18 | { 19 | if (!m_resourceSet->GetGLTFTextureById(texture.id, nullptr)) 20 | { 21 | m_resourceSet->StoreGLTFTextureById(texture.id, texture); 22 | } 23 | else 24 | { 25 | Microsoft::glTF::Texture storedTexture; 26 | 27 | m_resourceSet->GetGLTFTextureById(texture.id, &storedTexture); 28 | 29 | assert(storedTexture == texture); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /SceneLoader/NugetPackager/SceneLoaderComponent.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SceneLoaderComponent 5 | $version$ 6 | developer 7 | developer 8 | https://github.com/windows-toolkit/SceneLoader 9 | false 10 | Parses a GLTF file and produces a WUC SceneNode. 11 | 12 | Copyright 2019 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /SceneLoader/NugetPackager/SceneLoaderComponent.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /SceneLoader/NugetPackager/SceneLoaderComponent.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | $(MSBuildThisFileDirectory)$(Platform)\SceneLoaderComponent.winmd 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /SceneLoader/SceneLoader.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | #include "SceneLoader.h" 7 | 8 | #include "UtilForIntermingledNamespaces.h" 9 | #include "Bounds3D.h" 10 | #include "GLTFVisitor.h" 11 | 12 | using namespace std; 13 | using namespace Microsoft::glTF; 14 | using namespace SceneLoader; 15 | 16 | namespace winrt { 17 | using namespace Windows::ApplicationModel::Core; 18 | using namespace Windows::Foundation::Collections; 19 | using namespace Windows::UI::Core; 20 | using namespace Windows::UI::Composition; 21 | using namespace Windows::UI::Composition::Scenes; 22 | using namespace Windows::Storage; 23 | using namespace Windows::Storage::Streams; 24 | using namespace Windows::Storage::Pickers; 25 | using namespace Windows::Foundation::Numerics; 26 | using namespace Windows::Foundation; 27 | } 28 | using namespace winrt; 29 | 30 | namespace winrt::SceneLoaderComponent::implementation 31 | { 32 | struct MemBuf : std::streambuf 33 | { 34 | MemBuf(char* begin, char* end) { 35 | this->setg(begin, begin, end); 36 | } 37 | }; 38 | 39 | struct StreamReader : public IStreamReader 40 | { 41 | MemBuf m_membuf; 42 | 43 | StreamReader(BYTE* data, UINT32 capacity) : 44 | m_membuf((char*)data, (char*)(data + capacity)) 45 | { 46 | } 47 | 48 | virtual ~StreamReader() 49 | { 50 | 51 | } 52 | 53 | shared_ptr GetInputStream(const std::string&) const override 54 | { 55 | auto spIfStream = make_shared(const_cast(&m_membuf)); 56 | 57 | if (spIfStream->fail()) 58 | { 59 | throw exception("failed to open file"); 60 | } 61 | return spIfStream; 62 | } 63 | }; 64 | 65 | SceneNode SceneLoader::Load(IBuffer buffer, Compositor compositor) 66 | { 67 | auto memoryBuffer = winrt::Windows::Storage::Streams::Buffer::CreateMemoryBufferOverIBuffer(buffer); 68 | auto memoryBufferReference = memoryBuffer.CreateReference(); 69 | auto data = GetDataPointerFromMemoryBuffer(memoryBufferReference); 70 | 71 | SceneNode worldNode = SceneNode::Create(compositor); 72 | SceneNode rootNode = SceneNode::Create(compositor); 73 | worldNode.Children().Append(rootNode); 74 | 75 | // 76 | // Parses the GLTF file and creates the WUC Scenes objects 77 | // 78 | ParseGLTF(data.first, data.second, compositor, rootNode); 79 | 80 | Bounds3D bounds = ComputeTreeBounds( 81 | rootNode, 82 | float4x4::identity()); 83 | 84 | float lengthX = bounds.Max().x - bounds.Min().x; 85 | float lengthY = bounds.Max().y - bounds.Min().y; 86 | float lengthZ = bounds.Max().z - bounds.Min().z; 87 | 88 | float maxDimension = max(lengthX, max(lengthY, lengthZ)); 89 | 90 | if (maxDimension > 0.0f) 91 | { 92 | float scaleFactor = 300.0f / maxDimension; 93 | 94 | worldNode.Transform().Scale({ scaleFactor, scaleFactor, scaleFactor }); 95 | worldNode.Transform().Translation({ 0.0f, -(bounds.Min().y + bounds.Max().y) * scaleFactor / 2, 0.0f }); 96 | 97 | } 98 | 99 | return worldNode; 100 | } 101 | 102 | void SceneLoader::ParseGLTF(BYTE* data, UINT32 capacity, Compositor& compositor, SceneNode& rootNode) 103 | { 104 | auto streamReader = make_shared(data, capacity); 105 | auto spifstream = streamReader->GetInputStream(""); 106 | auto resourceReader = make_shared(streamReader); 107 | 108 | ////////////////////////////////////////////////////////////////////////////// 109 | // 110 | // Document 111 | // 112 | ////////////////////////////////////////////////////////////////////////////// 113 | Document gltfDoc = Deserialize(*spifstream); 114 | Validation::Validate(gltfDoc); 115 | 116 | DoIt(gltfDoc, resourceReader, compositor, rootNode); 117 | } 118 | 119 | void SceneLoader::DoIt(Document& gltfDoc, shared_ptr resourceReader, Compositor& compositor, SceneNode& rootNode) 120 | { 121 | ////////////////////////////////////////////////////////////////////////////// 122 | // 123 | // Scene 124 | // 125 | ////////////////////////////////////////////////////////////////////////////// 126 | auto scene = gltfDoc.GetDefaultScene(); 127 | 128 | shared_ptr resourceSet = make_shared(compositor); 129 | 130 | Visit(gltfDoc, DefaultSceneIndex, GLTFVisitor( 131 | compositor, 132 | rootNode, 133 | resourceSet, 134 | resourceReader, 135 | gltfDoc, 136 | scene)); 137 | 138 | resourceSet->CreateSceneMaterialObjects(); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /SceneLoader/SceneLoader.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | #include "SceneLoader.g.h" 8 | 9 | namespace winrt::SceneLoaderComponent::implementation 10 | { 11 | struct SceneLoader : SceneLoaderT 12 | { 13 | SceneLoader() = default; 14 | 15 | winrt::Windows::UI::Composition::Scenes::SceneNode Load(winrt::Windows::Storage::Streams::IBuffer buffer, winrt::Windows::UI::Composition::Compositor compositor); 16 | 17 | private: 18 | void ParseGLTF( 19 | BYTE * data, 20 | UINT32 capacity, 21 | winrt::Windows::UI::Composition::Compositor& compositor, 22 | winrt::Windows::UI::Composition::Scenes::SceneNode& rootNode); 23 | void DoIt( 24 | Microsoft::glTF::Document & gltfDoc, 25 | std::shared_ptr resourceReader, 26 | winrt::Windows::UI::Composition::Compositor& compositor, 27 | winrt::Windows::UI::Composition::Scenes::SceneNode& rootNode); 28 | }; 29 | } 30 | 31 | namespace winrt::SceneLoaderComponent::factory_implementation 32 | { 33 | struct SceneLoader : SceneLoaderT 34 | { 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /SceneLoader/SceneLoader.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 670a1d9e-70b7-4796-adc5-1817c10d6040 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /SceneLoader/SceneLoaderComponent.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE 3 | DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE 4 | -------------------------------------------------------------------------------- /SceneLoader/SceneLoaderComponent.idl: -------------------------------------------------------------------------------- 1 | namespace SceneLoaderComponent 2 | { 3 | [default_interface] 4 | runtimeclass SceneLoader 5 | { 6 | SceneLoader(); 7 | Windows.UI.Composition.Scenes.SceneNode Load(Windows.Storage.Streams.IBuffer buffer, Windows.UI.Composition.Compositor compositor); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /SceneLoader/SceneResourceSet.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "UtilForIntermingledNamespaces.h" 8 | #include "SceneResourceSet.h" 9 | 10 | using namespace std; 11 | using namespace Microsoft::glTF; 12 | 13 | namespace winrt { 14 | using namespace Windows::UI::Composition; 15 | using namespace Windows::UI::Composition::Scenes; 16 | } 17 | using namespace winrt; 18 | 19 | namespace SceneLoader 20 | { 21 | // If you want to assert when we hit a feature we don't support yet, change this to true. 22 | bool SceneResourceSet::s_assertOnUnimplementedFeature = false; 23 | 24 | SceneWrappingMode 25 | GLTFWrapModeToSceneWrapMode(Microsoft::glTF::WrapMode gltfWrapMode) 26 | { 27 | switch (gltfWrapMode) 28 | { 29 | case Microsoft::glTF::WrapMode::Wrap_CLAMP_TO_EDGE: 30 | return SceneWrappingMode::ClampToEdge; 31 | 32 | case Microsoft::glTF::WrapMode::Wrap_MIRRORED_REPEAT: 33 | return SceneWrappingMode::MirroredRepeat; 34 | 35 | case Microsoft::glTF::WrapMode::Wrap_REPEAT: 36 | default: 37 | return SceneWrappingMode::Repeat; 38 | } 39 | } 40 | 41 | 42 | SceneResourceSet::SceneResourceSet(winrt::Windows::UI::Composition::Compositor compositor) : 43 | m_compositor(compositor), 44 | m_sceneMaterialMap(single_threaded_map()), 45 | m_sceneSurfaceMaterialInputMap(single_threaded_map()), 46 | m_sceneMipMapSurfaceMap(single_threaded_map()) 47 | { 48 | 49 | } 50 | 51 | 52 | SceneMetallicRoughnessMaterial 53 | SceneResourceSet::EnsureMaterialById(const std::string id) 54 | { 55 | // Should we trust that the GLTF SDK is traversing correctly the DOM? 56 | if (!m_sceneMaterialMap.HasKey(GetHSTRINGFromStdString(id))) 57 | { 58 | auto sceneMaterial = SceneMetallicRoughnessMaterial::Create(m_compositor); 59 | sceneMaterial.Comment(wstring(id.begin(), id.end())); 60 | 61 | m_sceneMaterialMap.Insert(GetHSTRINGFromStdString(id), sceneMaterial); 62 | } 63 | 64 | return m_sceneMaterialMap.Lookup(GetHSTRINGFromStdString(id)); 65 | } 66 | 67 | 68 | CompositionMipmapSurface 69 | SceneResourceSet::EnsureMipMapSurfaceId( 70 | const std::string id, 71 | winrt::Windows::Graphics::SizeInt32 sizePixels, 72 | winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat, 73 | winrt::Windows::Graphics::DirectX::DirectXAlphaMode alphaMode, 74 | winrt::Windows::UI::Composition::ICompositionGraphicsDevice3 graphicsDevice) 75 | { 76 | // Should we trust that the GLTF SDK is traversing correctly the DOM? 77 | if (!m_sceneMipMapSurfaceMap.HasKey(GetHSTRINGFromStdString(id))) 78 | { 79 | auto mipmapSurface = graphicsDevice.CreateMipmapSurface( 80 | sizePixels, 81 | pixelFormat, 82 | alphaMode); 83 | wstring mipmapId{ id.begin(), id.end() }; 84 | mipmapSurface.Comment(mipmapId); 85 | 86 | m_sceneMipMapSurfaceMap.Insert(GetHSTRINGFromStdString(id), mipmapSurface); 87 | } 88 | 89 | return m_sceneMipMapSurfaceMap.Lookup(GetHSTRINGFromStdString(id)); 90 | } 91 | 92 | 93 | CompositionMipmapSurface 94 | SceneResourceSet::LookupMipMapSurfaceId(const std::string id) 95 | { 96 | return m_sceneMipMapSurfaceMap.Lookup(GetHSTRINGFromStdString(id)); 97 | } 98 | 99 | void 100 | SceneResourceSet::StoreGLTFSamplerById(const std::string id, Microsoft::glTF::Sampler sampler) 101 | { 102 | // Make sure we haven't stored this before 103 | assert(m_gltfSamplerMap.find(GetHSTRINGFromStdString(id)) == m_gltfSamplerMap.end()); 104 | 105 | m_gltfSamplerMap.insert(std::map::value_type(GetHSTRINGFromStdString(id), sampler)); 106 | } 107 | 108 | bool 109 | SceneResourceSet::GetGLTFSamplerById(const std::string id, Microsoft::glTF::Sampler* pSampler) 110 | { 111 | if (m_gltfSamplerMap.find(GetHSTRINGFromStdString(id)) == m_gltfSamplerMap.end()) 112 | { 113 | return false; 114 | } 115 | 116 | if (pSampler) 117 | { 118 | *pSampler = m_gltfSamplerMap.at(GetHSTRINGFromStdString(id)); 119 | } 120 | 121 | return true; 122 | } 123 | 124 | 125 | void 126 | SceneResourceSet::StoreGLTFMaterialById(const std::string id, Microsoft::glTF::Material material) 127 | { 128 | // Make sure we haven't stored this before 129 | assert(m_gltfMaterialMap.find(GetHSTRINGFromStdString(id)) == m_gltfMaterialMap.end()); 130 | 131 | m_gltfMaterialMap.insert(std::map::value_type(GetHSTRINGFromStdString(id), material)); 132 | } 133 | 134 | 135 | bool 136 | SceneResourceSet::GetGLTFMaterialById(const std::string id, Microsoft::glTF::Material* pMaterial) 137 | { 138 | if (m_gltfMaterialMap.find(GetHSTRINGFromStdString(id)) == m_gltfMaterialMap.end()) 139 | { 140 | return false; 141 | } 142 | 143 | if (pMaterial) 144 | { 145 | *pMaterial = m_gltfMaterialMap.at(GetHSTRINGFromStdString(id)); 146 | } 147 | 148 | return true; 149 | } 150 | 151 | 152 | void 153 | SceneResourceSet::StoreGLTFTextureById(const std::string id, Microsoft::glTF::Texture texture) 154 | { 155 | // Make sure we haven't stored this before 156 | assert(m_gltfTextureMap.find(GetHSTRINGFromStdString(id)) == m_gltfTextureMap.end()); 157 | 158 | m_gltfTextureMap.insert(std::map::value_type(GetHSTRINGFromStdString(id), texture)); 159 | } 160 | 161 | 162 | bool 163 | SceneResourceSet::GetGLTFTextureById(const std::string id, Microsoft::glTF::Texture* pTexture) 164 | { 165 | if (m_gltfTextureMap.find(GetHSTRINGFromStdString(id)) == m_gltfTextureMap.end()) 166 | { 167 | return false; 168 | } 169 | 170 | if (pTexture) 171 | { 172 | *pTexture = m_gltfTextureMap.at(GetHSTRINGFromStdString(id)); 173 | } 174 | 175 | return true; 176 | } 177 | 178 | 179 | void 180 | SceneResourceSet::CreateSceneMaterialObjects() 181 | { 182 | for (std::map::iterator materialIterator = m_gltfMaterialMap.begin(); materialIterator != m_gltfMaterialMap.end(); materialIterator++) 183 | { 184 | SceneMetallicRoughnessMaterial sceneMaterial = EnsureMaterialById(materialIterator->second.id); 185 | Microsoft::glTF::Material material = materialIterator->second; 186 | 187 | 188 | // BaseColor 189 | if (material.metallicRoughness.baseColorTexture.textureId != "") 190 | { 191 | auto materialInput = GetMaterialInputFromTextureId(material.metallicRoughness.baseColorTexture.textureId); 192 | sceneMaterial.BaseColorInput(materialInput); 193 | 194 | if (m_latestMeshRendererComponent) 195 | { 196 | m_latestMeshRendererComponent.UVMappings().Insert(L"BaseColorInput", 197 | material.metallicRoughness.baseColorTexture.texCoord == 0 ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1); 198 | } 199 | } 200 | 201 | sceneMaterial.BaseColorFactor({ material.metallicRoughness.baseColorFactor.r, material.metallicRoughness.baseColorFactor.g, material.metallicRoughness.baseColorFactor.b, material.metallicRoughness.baseColorFactor.a }); 202 | 203 | // MetallicRoughness 204 | if (material.metallicRoughness.metallicRoughnessTexture.textureId != "") 205 | { 206 | auto materialInput = GetMaterialInputFromTextureId(material.metallicRoughness.metallicRoughnessTexture.textureId); 207 | sceneMaterial.MetallicRoughnessInput(materialInput); 208 | 209 | if (m_latestMeshRendererComponent) 210 | { 211 | m_latestMeshRendererComponent.UVMappings().Insert(L"MetallicRoughnessInput", 212 | material.metallicRoughness.metallicRoughnessTexture.texCoord == 0 ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1); 213 | } 214 | } 215 | 216 | sceneMaterial.RoughnessFactor(material.metallicRoughness.roughnessFactor); 217 | 218 | sceneMaterial.MetallicFactor(material.metallicRoughness.metallicFactor); 219 | 220 | // Normal 221 | if (material.normalTexture.textureId != "") 222 | { 223 | auto materialInput = GetMaterialInputFromTextureId(material.normalTexture.textureId); 224 | sceneMaterial.NormalInput(materialInput); 225 | 226 | if (m_latestMeshRendererComponent) 227 | { 228 | m_latestMeshRendererComponent.UVMappings().Insert(L"NormalInput", 229 | material.normalTexture.texCoord == 0 ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1); 230 | } 231 | } 232 | 233 | sceneMaterial.NormalScale(material.normalTexture.scale); 234 | 235 | // Occlusion 236 | if (material.occlusionTexture.textureId != "") 237 | { 238 | auto materialInput = GetMaterialInputFromTextureId(material.occlusionTexture.textureId); 239 | sceneMaterial.OcclusionInput(materialInput); 240 | 241 | if (m_latestMeshRendererComponent) 242 | { 243 | m_latestMeshRendererComponent.UVMappings().Insert(L"OcclusionInput", 244 | material.occlusionTexture.texCoord == 0 ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1); 245 | } 246 | } 247 | 248 | sceneMaterial.OcclusionStrength(material.occlusionTexture.strength); 249 | 250 | // Emissive 251 | if (material.emissiveTexture.textureId != "") 252 | { 253 | auto materialInput = GetMaterialInputFromTextureId(material.emissiveTexture.textureId); 254 | sceneMaterial.EmissiveInput(materialInput); 255 | 256 | if (m_latestMeshRendererComponent) 257 | { 258 | m_latestMeshRendererComponent.UVMappings().Insert(L"EmissiveInput", 259 | material.emissiveTexture.texCoord == 0 ? SceneAttributeSemantic::TexCoord0 : SceneAttributeSemantic::TexCoord1); 260 | } 261 | } 262 | 263 | sceneMaterial.EmissiveFactor({ material.emissiveFactor.r, material.emissiveFactor.g, material.emissiveFactor.b }); 264 | 265 | switch (material.alphaMode) { 266 | case AlphaMode::ALPHA_OPAQUE: 267 | { 268 | sceneMaterial.AlphaMode(SceneAlphaMode::Opaque); 269 | break; 270 | } 271 | case AlphaMode::ALPHA_BLEND: 272 | { 273 | sceneMaterial.AlphaMode(SceneAlphaMode::Blend); 274 | break; 275 | } 276 | case AlphaMode::ALPHA_MASK: 277 | { 278 | sceneMaterial.AlphaMode(SceneAlphaMode::AlphaTest); 279 | break; 280 | } 281 | case AlphaMode::ALPHA_UNKNOWN: 282 | default: 283 | { 284 | UnimplementedFeatureFound(); 285 | } 286 | } 287 | 288 | sceneMaterial.AlphaCutoff(material.alphaCutoff); 289 | sceneMaterial.IsDoubleSided(material.doubleSided); 290 | } 291 | } 292 | 293 | 294 | SceneSurfaceMaterialInput 295 | SceneResourceSet::GetMaterialInputFromTextureId(const std::string textureId) 296 | { 297 | static uint16_t sCount = 0; 298 | Microsoft::glTF::Sampler sampler; 299 | Microsoft::glTF::Texture texture; 300 | 301 | bool resultFound; 302 | 303 | resultFound = GetGLTFTextureById(textureId, &texture); 304 | assert(resultFound); 305 | 306 | resultFound = GetGLTFSamplerById(texture.samplerId, &sampler); 307 | assert(resultFound); 308 | 309 | CompositionMipmapSurface mipMapSurface = LookupMipMapSurfaceId(texture.imageId); 310 | 311 | SceneSurfaceMaterialInput sceneSurfaceMaterialInput = SceneSurfaceMaterialInput::Create(m_compositor); 312 | wstringstream ssitoa; ssitoa << sCount; 313 | sceneSurfaceMaterialInput.Comment(ssitoa.str()); 314 | 315 | SetSceneSampler(sceneSurfaceMaterialInput, sampler); 316 | 317 | sceneSurfaceMaterialInput.Surface(mipMapSurface); 318 | 319 | ++sCount; 320 | 321 | return sceneSurfaceMaterialInput; 322 | } 323 | 324 | 325 | void 326 | SceneResourceSet::SetSceneSampler(winrt::Windows::UI::Composition::Scenes::SceneSurfaceMaterialInput sceneSurfaceMaterialInput, Microsoft::glTF::Sampler sampler) 327 | { 328 | sceneSurfaceMaterialInput.BitmapInterpolationMode(CompositionBitmapInterpolationMode::MagLinearMinLinearMipLinear); 329 | 330 | sceneSurfaceMaterialInput.WrappingUMode(GLTFWrapModeToSceneWrapMode(sampler.wrapS)); 331 | 332 | sceneSurfaceMaterialInput.WrappingVMode(GLTFWrapModeToSceneWrapMode(sampler.wrapT)); 333 | } 334 | 335 | void 336 | SceneResourceSet::SetLatestMeshRendererComponent(SceneMeshRendererComponent& meshRendererComponent) 337 | { 338 | m_latestMeshRendererComponent = meshRendererComponent; 339 | } 340 | 341 | void 342 | SceneResourceSet::UnimplementedFeatureFound() 343 | { 344 | if (s_assertOnUnimplementedFeature) 345 | { 346 | assert(false); 347 | } 348 | } 349 | 350 | } // namespace SceneLoader -------------------------------------------------------------------------------- /SceneLoader/SceneResourceSet.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | namespace SceneLoader 8 | { 9 | class SceneResourceSet 10 | { 11 | public: 12 | SceneResourceSet(winrt::Windows::UI::Composition::Compositor compositor); 13 | 14 | winrt::Windows::UI::Composition::Scenes::SceneMetallicRoughnessMaterial EnsureMaterialById(const std::string id); 15 | 16 | void StoreGLTFSamplerById(const std::string id, Microsoft::glTF::Sampler sampler); 17 | bool GetGLTFSamplerById(const std::string id, Microsoft::glTF::Sampler* pSampler); 18 | 19 | void StoreGLTFMaterialById(const std::string id, Microsoft::glTF::Material material); 20 | bool GetGLTFMaterialById(const std::string id, Microsoft::glTF::Material* pMaterial); 21 | 22 | void StoreGLTFTextureById(const std::string id, Microsoft::glTF::Texture texture); 23 | bool GetGLTFTextureById(const std::string id, Microsoft::glTF::Texture* pTexture); 24 | 25 | void CreateSceneMaterialObjects(); 26 | 27 | void SetSceneSampler(winrt::Windows::UI::Composition::Scenes::SceneSurfaceMaterialInput materialInput, Microsoft::glTF::Sampler sampler); 28 | 29 | winrt::Windows::UI::Composition::Scenes::SceneSurfaceMaterialInput GetMaterialInputFromTextureId(const std::string textureId); 30 | 31 | winrt::Windows::UI::Composition::CompositionMipmapSurface EnsureMipMapSurfaceId( 32 | const std::string id, 33 | winrt::Windows::Graphics::SizeInt32 size, 34 | winrt::Windows::Graphics::DirectX::DirectXPixelFormat pixelFormat, 35 | winrt::Windows::Graphics::DirectX::DirectXAlphaMode alphaMode, 36 | winrt::Windows::UI::Composition::ICompositionGraphicsDevice3 graphicsDevice); 37 | 38 | winrt::Windows::UI::Composition::CompositionMipmapSurface LookupMipMapSurfaceId(const std::string id); 39 | 40 | void SetLatestMeshRendererComponent(winrt::Windows::UI::Composition::Scenes::SceneMeshRendererComponent& meshRendererComponent); 41 | 42 | static void UnimplementedFeatureFound(); 43 | 44 | private: 45 | winrt::Windows::UI::Composition::Compositor m_compositor; 46 | 47 | // Only keeps track of the equivalent Mipmap from the DOM into the Scenes API. 48 | winrt::Windows::Foundation::Collections::IMap m_sceneSurfaceMaterialInputMap{ nullptr }; 49 | 50 | // Only keeps track of the equivalent Mipmap from the DOM into the Scenes API. 51 | winrt::Windows::Foundation::Collections::IMap m_sceneMipMapSurfaceMap{ nullptr }; 52 | 53 | // Only keeps track of the equivalent Materials from the DOM into the Scenes API. 54 | winrt::Windows::Foundation::Collections::IMap m_sceneMaterialMap{ nullptr }; 55 | 56 | // Only keeps track of the equivalent Materials from the DOM into the Scenes API. 57 | std::map m_gltfSamplerMap; 58 | std::map m_gltfMaterialMap; 59 | std::map m_gltfTextureMap; 60 | 61 | winrt::Windows::UI::Composition::Scenes::SceneMeshRendererComponent m_latestMeshRendererComponent{ nullptr }; 62 | 63 | static bool s_assertOnUnimplementedFeature; 64 | }; 65 | } // SceneLoader -------------------------------------------------------------------------------- /SceneLoader/UtilForIntermingledNamespaces.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | 7 | #include "UtilForIntermingledNamespaces.h" 8 | 9 | // WinRT 10 | #include 11 | 12 | // This class doesn't use any "using namespace XXX" because it mixes C++/WinRT 13 | // objects with WinRT ABI Objects (::Windows::Foundation::IMemoryBufferByteAccess). 14 | // The reason for that is that C++/WinRT doesn't expose ::Windows::Foundation::IMemoryBufferByteAccess 15 | // that is being declared into MemoryBuffer.h. 16 | // https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/interop-winrt-abi 17 | 18 | namespace SceneLoader 19 | { 20 | winrt::Windows::Foundation::MemoryBuffer 21 | CopyArrayOfBytesToMemoryBuffer(BYTE* data, size_t byteLength) 22 | { 23 | winrt::Windows::Foundation::MemoryBuffer mb{ winrt::Windows::Foundation::MemoryBuffer(static_cast(byteLength)) }; // FIXME: Check bounds sizeof(size_t) > sizeof(UINT32) on x64 24 | winrt::Windows::Foundation::IMemoryBufferReference mbr = mb.CreateReference(); 25 | winrt::com_ptr const mba{ mbr.as() }; 26 | 27 | { 28 | BYTE* bytes = nullptr; 29 | UINT32 capacity; 30 | mba->GetBuffer(&bytes, &capacity); 31 | for (UINT32 i = 0; i < capacity; ++i) 32 | { 33 | bytes[i] = data[i]; 34 | } 35 | } 36 | 37 | return mb; 38 | } 39 | 40 | // std::span is only available in C++20 :( 41 | std::pair 42 | GetDataPointerFromMemoryBuffer(winrt::Windows::Foundation::IMemoryBufferReference memoryBufferReference) 43 | { 44 | auto memoryBufferByteAccess = memoryBufferReference.as(); 45 | 46 | BYTE* data; 47 | UINT32 capacity; 48 | 49 | memoryBufferByteAccess->GetBuffer(&data, &capacity); 50 | 51 | return std::make_pair(data, capacity); 52 | } 53 | 54 | winrt::hstring 55 | GetHSTRINGFromStdString(const std::string& s) 56 | { 57 | size_t keyLenght = s.length() + 1; 58 | auto wcstring = std::make_unique(keyLenght); 59 | size_t convertedChars = 0; 60 | mbstowcs_s(&convertedChars, wcstring.get(), keyLenght, s.c_str(), _TRUNCATE); 61 | 62 | return wcstring.get(); 63 | } 64 | 65 | } // namespace SceneLoader 66 | -------------------------------------------------------------------------------- /SceneLoader/UtilForIntermingledNamespaces.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | namespace SceneLoader { 8 | winrt::Windows::Foundation::MemoryBuffer CopyArrayOfBytesToMemoryBuffer(BYTE* data, size_t byteLength); 9 | 10 | std::pair GetDataPointerFromMemoryBuffer(winrt::Windows::Foundation::IMemoryBufferReference); 11 | 12 | winrt::hstring GetHSTRINGFromStdString(const std::string& s); 13 | } -------------------------------------------------------------------------------- /SceneLoader/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /SceneLoader/pch.cpp: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #include "pch.h" 6 | -------------------------------------------------------------------------------- /SceneLoader/pch.h: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | #pragma once 6 | 7 | 8 | // rapidjson (a dependency of GLTF SDK) uses iterators in a way 9 | // that is deprecated on C++17. We can't got back to C++14 because 10 | // C++/WinRT requires C++17. The following line shuts off 11 | // the C++17 warning about the deprecated way of using iterators. 12 | #define _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING 13 | 14 | // std 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | // GLTF SDK 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | // Windows 43 | #include 44 | #include 45 | #include 46 | 47 | // C++/WinRT 48 | #include "winrt/Windows.ApplicationModel.Core.h" 49 | #include "winrt/Windows.Graphics.DirectX.h" 50 | #include "winrt/Windows.UI.Core.h" 51 | #include "winrt/Windows.UI.Composition.h" 52 | #include "winrt/Windows.UI.Composition.Scenes.h" 53 | #include "winrt/Windows.UI.Input.h" 54 | #include "winrt/Windows.UI.Xaml.h" 55 | #include "winrt/Windows.UI.Xaml.Controls.h" 56 | #include "winrt/Windows.Storage.Pickers.h" 57 | #include "winrt/Windows.Storage.Streams.h" 58 | #include "winrt/Windows.Foundation.h" 59 | #include "winrt/Windows.Foundation.Collections.h" 60 | #include "winrt/Windows.Foundation.Numerics.h" 61 | #include "winrt/Windows.Graphics.DirectX.Direct3D11.h" 62 | 63 | 64 | // FIXME: WinRT ABI headers should be moved to UtilForIntermingledNamespaces.h/cpp 65 | #include -------------------------------------------------------------------------------- /SceneLoader/readme.md: -------------------------------------------------------------------------------- 1 | Steps to run locally: 2 | 3 | 1. Clone the repo 4 | 2. Install Windows SDK 18362 5 | 3. cd ..\build 6 | 4. Run ./build.bat 7 | 8 | Outputs: 9 | The project create a nuget package located in ..\bin\nupkg -------------------------------------------------------------------------------- /TestViewer/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | -------------------------------------------------------------------------------- /TestViewer/App.xaml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System; 6 | using Windows.ApplicationModel; 7 | using Windows.ApplicationModel.Activation; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Controls; 10 | using Windows.UI.Xaml.Navigation; 11 | 12 | namespace TestViewer 13 | { 14 | /// 15 | /// Provides application-specific behavior to supplement the default Application class. 16 | /// 17 | sealed partial class App : Application 18 | { 19 | /// 20 | /// Initializes the singleton application object. This is the first line of authored code 21 | /// executed, and as such is the logical equivalent of main() or WinMain(). 22 | /// 23 | public App() 24 | { 25 | this.InitializeComponent(); 26 | this.Suspending += OnSuspending; 27 | } 28 | 29 | /// 30 | /// Invoked when the application is launched normally by the end user. Other entry points 31 | /// will be used such as when the application is launched to open a specific file. 32 | /// 33 | /// Details about the launch request and process. 34 | protected override void OnLaunched(LaunchActivatedEventArgs e) 35 | { 36 | Frame rootFrame = Window.Current.Content as Frame; 37 | 38 | // Do not repeat app initialization when the Window already has content, 39 | // just ensure that the window is active 40 | if (rootFrame == null) 41 | { 42 | // Create a Frame to act as the navigation context and navigate to the first page 43 | rootFrame = new Frame(); 44 | 45 | rootFrame.NavigationFailed += OnNavigationFailed; 46 | 47 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 48 | { 49 | //TODO: Load state from previously suspended application 50 | } 51 | 52 | // Place the frame in the current Window 53 | Window.Current.Content = rootFrame; 54 | } 55 | 56 | if (e.PrelaunchActivated == false) 57 | { 58 | if (rootFrame.Content == null) 59 | { 60 | // When the navigation stack isn't restored navigate to the first page, 61 | // configuring the new page by passing required information as a navigation 62 | // parameter 63 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 64 | } 65 | // Ensure the current window is active 66 | Window.Current.Activate(); 67 | } 68 | } 69 | 70 | /// 71 | /// Invoked when Navigation to a certain page fails 72 | /// 73 | /// The Frame which failed navigation 74 | /// Details about the navigation failure 75 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 76 | { 77 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 78 | } 79 | 80 | /// 81 | /// Invoked when application execution is being suspended. Application state is saved 82 | /// without knowing whether the application will be terminated or resumed with the contents 83 | /// of memory still intact. 84 | /// 85 | /// The source of the suspend request. 86 | /// Details about the suspend request. 87 | private void OnSuspending(object sender, SuspendingEventArgs e) 88 | { 89 | var deferral = e.SuspendingOperation.GetDeferral(); 90 | //TODO: Save application state and stop any background activity 91 | deferral.Complete(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /TestViewer/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/17151148934844231bc3aab6c0a3e8fcd32b7399/TestViewer/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /TestViewer/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/17151148934844231bc3aab6c0a3e8fcd32b7399/TestViewer/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /TestViewer/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/17151148934844231bc3aab6c0a3e8fcd32b7399/TestViewer/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /TestViewer/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/17151148934844231bc3aab6c0a3e8fcd32b7399/TestViewer/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /TestViewer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/17151148934844231bc3aab6c0a3e8fcd32b7399/TestViewer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /TestViewer/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/17151148934844231bc3aab6c0a3e8fcd32b7399/TestViewer/Assets/StoreLogo.png -------------------------------------------------------------------------------- /TestViewer/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/17151148934844231bc3aab6c0a3e8fcd32b7399/TestViewer/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /TestViewer/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /TestViewer/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using Windows.UI.Xaml.Controls; 6 | 7 | namespace TestViewer 8 | { 9 | /// 10 | /// A page that generates a gltf image using the SceneLoaderComponent. 11 | /// 12 | public sealed partial class MainPage : Page 13 | { 14 | public MainPage() 15 | { 16 | this.InitializeComponent(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TestViewer/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | TestViewer 18 | developer 19 | Assets\StoreLogo.png 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /TestViewer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | 5 | using System.Reflection; 6 | using System.Runtime.CompilerServices; 7 | using System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [assembly: AssemblyTitle("TestViewer")] 13 | [assembly: AssemblyDescription("")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("")] 16 | [assembly: AssemblyProduct("TestViewer")] 17 | [assembly: AssemblyCopyright("Copyright © 2019")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Version information for an assembly consists of the following four values: 22 | // 23 | // Major Version 24 | // Minor Version 25 | // Build Number 26 | // Revision 27 | // 28 | // You can specify all the values or you can default the Build and Revision Numbers 29 | // by using the '*' as shown below: 30 | // [assembly: AssemblyVersion("1.0.*")] 31 | [assembly: AssemblyVersion("1.0.0.0")] 32 | [assembly: AssemblyFileVersion("1.0.0.0")] 33 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /TestViewer/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /TestViewer/TestViewer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x86 7 | {5D504AFF-651A-4C27-BA19-550663227A85} 8 | AppContainerExe 9 | Properties 10 | TestViewer 11 | TestViewer 12 | en-US 13 | UAP 14 | 10.0.18362.0 15 | 10.0.18362.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | true 20 | TestViewer_TemporaryKey.pfx 21 | 22 | 23 | true 24 | bin\x86\Debug\ 25 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 26 | ;2008 27 | full 28 | x86 29 | false 30 | prompt 31 | true 32 | MixedMinimumRules.ruleset 33 | 34 | 35 | bin\x86\Release\ 36 | TRACE;NETFX_CORE;WINDOWS_UWP 37 | true 38 | ;2008 39 | pdbonly 40 | x86 41 | false 42 | prompt 43 | true 44 | true 45 | 46 | 47 | true 48 | bin\ARM\Debug\ 49 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 50 | ;2008 51 | full 52 | ARM 53 | false 54 | prompt 55 | true 56 | 57 | 58 | bin\ARM\Release\ 59 | TRACE;NETFX_CORE;WINDOWS_UWP 60 | true 61 | ;2008 62 | pdbonly 63 | ARM 64 | false 65 | prompt 66 | true 67 | true 68 | 69 | 70 | true 71 | bin\ARM64\Debug\ 72 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 73 | ;2008 74 | full 75 | ARM64 76 | false 77 | prompt 78 | true 79 | true 80 | 81 | 82 | bin\ARM64\Release\ 83 | TRACE;NETFX_CORE;WINDOWS_UWP 84 | true 85 | ;2008 86 | pdbonly 87 | ARM64 88 | false 89 | prompt 90 | true 91 | true 92 | 93 | 94 | true 95 | bin\x64\Debug\ 96 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 97 | ;2008 98 | full 99 | x64 100 | false 101 | prompt 102 | true 103 | 104 | 105 | bin\x64\Release\ 106 | TRACE;NETFX_CORE;WINDOWS_UWP 107 | true 108 | ;2008 109 | pdbonly 110 | x64 111 | false 112 | prompt 113 | true 114 | true 115 | 116 | 117 | PackageReference 118 | 119 | 120 | 121 | App.xaml 122 | 123 | 124 | MainPage.xaml 125 | 126 | 127 | 128 | 129 | 130 | Designer 131 | 132 | 133 | PreserveNewest 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | MSBuild:Compile 151 | Designer 152 | 153 | 154 | MSBuild:Compile 155 | Designer 156 | 157 | 158 | 159 | 160 | 6.2.8 161 | 162 | 163 | 164 | 165 | {239c87c3-1e17-4f01-8d93-9b21c1a53f3d} 166 | CameraComponent 167 | 168 | 169 | {88c4d662-8669-433b-8a8b-47b3a17e3c6e} 170 | SceneLoaderComponent 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 14.0 181 | 182 | 183 | 190 | -------------------------------------------------------------------------------- /TestViewer/TestViewer_TemporaryKey.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/17151148934844231bc3aab6c0a3e8fcd32b7399/TestViewer/TestViewer_TemporaryKey.pfx -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Control which branches get CI triggers (defaults to all branches if this parameter is not set) 2 | trigger: 3 | - master 4 | - rel/* 5 | 6 | # Specify the target branches for pull request builds 7 | pr: 8 | - master 9 | - rel/* 10 | 11 | # Microsoft-hosted agent pool for Visual Studio 2017 on Windows Server 2016 12 | pool: 13 | vmImage: vs2017-win2016 14 | 15 | # variables: 16 | # BuildConfiguration: SceneLoader 17 | 18 | steps: 19 | # Setup Environment Variables 20 | - task: BatchScript@1 21 | inputs: 22 | filename: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\Common7\\Tools\\VsDevCmd.bat" 23 | arguments: -no_logo 24 | modifyEnvironment: true 25 | displayName: Setup Environment Variables 26 | 27 | # Install Nuget Tool Installer 28 | - task: NuGetToolInstaller@0 29 | displayName: Use NuGet 4.7.0 30 | inputs: 31 | versionSpec: 4.7.0 32 | 33 | # Install NBGV Tool 34 | - task: DotNetCoreCLI@2 35 | inputs: 36 | command: custom 37 | custom: tool 38 | arguments: install --tool-path . nbgv 39 | displayName: Install NBGV tool 40 | 41 | # Set cloud build variables 42 | - script: nbgv cloud 43 | displayName: Set Version 44 | 45 | # Install Windows SDK 18362 (minimum compatible sdk) 46 | - powershell: .\build\Install-WindowsSdkISO.ps1 18362 47 | displayName: Insider SDK 48 | 49 | # Run cake build 50 | - powershell: .\build.ps1 -target=PackageNuget 51 | displayName: Build 52 | workingDirectory: .\build 53 | 54 | # Sign Nuget package 55 | - task: PowerShell@2 56 | displayName: Authenticode Sign Packages 57 | inputs: 58 | filePath: build/Sign-Package.ps1 59 | env: 60 | SignClientUser: $(SignClientUser) 61 | SignClientSecret: $(SignClientSecret) 62 | ArtifactDirectory: bin\nupkg 63 | condition: and(succeeded(), not(eq(variables['build.reason'], 'PullRequest')), not(eq(variables['SignClientSecret'], '')), not(eq(variables['SignClientUser'], ''))) 64 | 65 | # Publish nuget package 66 | - task: PublishBuildArtifacts@1 67 | displayName: Publish Package Artifacts 68 | inputs: 69 | pathToPublish: .\bin\nupkg 70 | artifactType: container 71 | artifactName: Packages -------------------------------------------------------------------------------- /build/Build.bat: -------------------------------------------------------------------------------- 1 | @pushd %~dp0 2 | @PowerShell.exe -file "%~dp0build.ps1" %* 3 | @popd 4 | @PAUSE -------------------------------------------------------------------------------- /build/Clean.bat: -------------------------------------------------------------------------------- 1 | @call "%~dp0build.bat" -t:Clean %* 2 | -------------------------------------------------------------------------------- /build/Find-WindowsSDKVersions.ps1: -------------------------------------------------------------------------------- 1 | ## Licensed to the .NET Foundation under one or more agreements. 2 | ## The .NET Foundation licenses this file to you under the MIT license. 3 | ## See the LICENSE file in the project root for more information. 4 | 5 | $script:ns = 'http://schemas.microsoft.com/developer/msbuild/2003' 6 | 7 | $ErrorActionPreference = 'Stop' 8 | 9 | # Unique set of Windows SDK versions referenced in files 10 | $versions = New-Object System.Collections.Generic.HashSet[System.String] 11 | 12 | function Get-Nodes 13 | { 14 | param( 15 | [parameter(ValueFromPipeline=$true)] 16 | [xml] $xml, 17 | [parameter(Mandatory=$true)] 18 | [string] $nodeName) 19 | 20 | # Try the old style csproj. Also format required for .targets and .props files 21 | $n = Select-Xml -Xml $xml.Project -Namespace @{d = $ns } -XPath "//d:$nodeName" 22 | 23 | # Try the SDK-style files 24 | if (!$n) { 25 | $r = Select-Xml -Xml $xml.Project -XPath "//$nodeName" 26 | } 27 | 28 | return $r 29 | } 30 | 31 | function Get-NodeValue 32 | { 33 | param( 34 | [parameter(ValueFromPipeline=$true)] 35 | [xml] $xml, 36 | [string] $nodeName) 37 | 38 | $node = get-nodes $xml $nodeName 39 | 40 | if ($node) { 41 | if ($node.Node) { 42 | return [string]$node.Node.'#text' 43 | } 44 | } 45 | 46 | return [string]"" 47 | } 48 | 49 | function Get-SdkVersion 50 | { 51 | param( 52 | [Parameter(ValueFromPipeline=$true)] $file) 53 | 54 | [xml] $xml = Get-Content $file 55 | 56 | # If you want a complete set of SDKs that are required, uncomment the following 57 | # $version = Get-NodeValue $xml 'PropertyGroup/TargetPlatformMinVersion' 58 | # $versions.Add($version) | Out-Null 59 | 60 | $version = Get-NodeValue $xml 'PropertyGroup/TargetPlatformVersion' 61 | $versions.Add($version) | Out-Null 62 | 63 | # Versions may also be specified without the 10.0.xxxxx.0 format in the 64 | # PropertyGroup/DefaultTargetPlatformVersion and PropertyGroup/DefaultTargetPlatformMinVersion 65 | 66 | # If you want a complete set of SDKs that are required, uncomment the following 67 | # $version = Get-NodeValue $xml 'PropertyGroup/DefaultTargetPlatformMinVersion' 68 | # $versions.Add("10.0." + $version + ".0") | Out-Null 69 | 70 | $version = Get-NodeValue $xml 'PropertyGroup/DefaultTargetPlatformVersion' 71 | $versions.Add("10.0." + $version + ".0") | Out-Null 72 | } 73 | 74 | function Test-RegistryPathAndValue 75 | { 76 | param ( 77 | [parameter(Mandatory=$true)] 78 | [ValidateNotNullOrEmpty()] 79 | [string] $path, 80 | [parameter(Mandatory=$true)] 81 | [ValidateNotNullOrEmpty()] 82 | [string] $value) 83 | 84 | try 85 | { 86 | if (Test-Path $path) 87 | { 88 | Get-ItemProperty -Path $path | Select-Object -ExpandProperty $value -ErrorAction Stop | Out-Null 89 | return $true 90 | } 91 | } 92 | catch 93 | { 94 | } 95 | 96 | return $false 97 | } 98 | 99 | function Test-InstallWindowsSdk([string] $WindowsSDKVersion) { 100 | $retval = $true 101 | 102 | $WindowsSDKRegPath = "HKLM:\Software\Microsoft\Windows Kits\Installed Roots" 103 | $WindowsSDKRegRootKey = "KitsRoot10" 104 | $WindowsSDKOptions = @("OptionId.UWPCpp") 105 | 106 | $WindowsSDKInstalledRegPath = "$WindowsSDKRegPath\$WindowsSDKVersion\Installed Options" 107 | 108 | if (Test-RegistryPathAndValue -Path $WindowsSDKRegPath -Value $WindowsSDKRegRootKey) 109 | { 110 | # A Windows SDK is installed 111 | # Is an SDK of our version installed with the options we need? 112 | if (Test-RegistryPathAndValue -Path $WindowsSDKInstalledRegPath -Value "$WindowsSDKOptions") 113 | { 114 | # It appears we have what we need. Double check the disk 115 | $sdkRoot = Get-ItemProperty -Path $WindowsSDKRegPath | Select-Object -ExpandProperty $WindowsSDKRegRootKey 116 | if ($sdkRoot) 117 | { 118 | if (Test-Path $sdkRoot) 119 | { 120 | $refPath = Join-Path $sdkRoot "References\$WindowsSDKVersion" 121 | if (Test-Path $refPath) 122 | { 123 | $umdPath = Join-Path $sdkRoot "UnionMetadata\$WindowsSDKVersion" 124 | if (Test-Path $umdPath) 125 | { 126 | # Pretty sure we have what we need 127 | $retval = $false 128 | } 129 | } 130 | } 131 | } 132 | } 133 | } 134 | 135 | return $retval 136 | } 137 | 138 | if(!$PSScriptRoot){ 139 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent 140 | } 141 | 142 | Write-Host -NoNewline "Locating referenced Windows SDK versions..." 143 | 144 | Get-ChildItem *.vcxproj -Recurse | ForEach-Object { get-sdkversion $_} 145 | Get-ChildItem *.targets -Recurse | ForEach-Object { get-sdkversion $_ } 146 | Get-ChildItem *.props -Recurse | ForEach-Object { get-sdkversion $_ } 147 | 148 | Write-Host "Done" 149 | Write-Host 150 | 151 | $anyInstallRequired = $false; 152 | 153 | foreach($version in $versions) { 154 | if ($version -match "10\.0\.\d{5}\.0") { 155 | $installRequired = Test-InstallWindowsSDK $version 156 | Write-Host "Windows SDK '$version' install required: $installRequired" 157 | if ($installRequired) { 158 | # Automatically invoke Install-WindowsSDKIso.ps1 ? 159 | $anyInstallRequired = $true 160 | } 161 | } 162 | } 163 | 164 | Write-Host 165 | if ($anyInstallRequired) { 166 | throw "At least one Windows SDK is missing from this machine" 167 | } else { 168 | Write-Host "All referenced Windows SDKs are installed!" 169 | } -------------------------------------------------------------------------------- /build/Install-WindowsSDK.ps1: -------------------------------------------------------------------------------- 1 | ## Licensed to the .NET Foundation under one or more agreements. 2 | ## The .NET Foundation licenses this file to you under the MIT license. 3 | ## See the LICENSE file in the project root for more information. 4 | 5 | mkdir c:\winsdktemp 6 | 7 | $client = new-object System.Net.WebClient 8 | $client.DownloadFile("https://go.microsoft.com/fwlink/p/?linkid=870807","c:\winsdktemp\winsdksetup.exe") 9 | 10 | Start-Process -Wait "c:\winsdktemp\winsdksetup.exe" "/features OptionId.UWPCpp /q" -------------------------------------------------------------------------------- /build/Install-WindowsSdkISO.ps1: -------------------------------------------------------------------------------- 1 | ## Licensed to the .NET Foundation under one or more agreements. 2 | ## The .NET Foundation licenses this file to you under the MIT license. 3 | ## See the LICENSE file in the project root for more information. 4 | 5 | [CmdletBinding()] 6 | param([Parameter(Mandatory=$true)] 7 | [string]$buildNumber) 8 | 9 | # Ensure the error action preference is set to the default for PowerShell3, 'Stop' 10 | $ErrorActionPreference = 'Stop' 11 | 12 | # Constants 13 | $WindowsSDKOptions = @("OptionId.UWPCpp") 14 | $WindowsSDKRegPath = "HKLM:\Software\Microsoft\Windows Kits\Installed Roots" 15 | $WindowsSDKRegRootKey = "KitsRoot10" 16 | $WindowsSDKVersion = "10.0.$buildNumber.0" 17 | $WindowsSDKInstalledRegPath = "$WindowsSDKRegPath\$WindowsSDKVersion\Installed Options" 18 | $StrongNameRegPath = "HKLM:\SOFTWARE\Microsoft\StrongName\Verification" 19 | $PublicKeyTokens = @("31bf3856ad364e35") 20 | 21 | function Download-File 22 | { 23 | param ([string] $outDir, 24 | [string] $downloadUrl, 25 | [string] $downloadName) 26 | 27 | $downloadPath = Join-Path $outDir "$downloadName.download" 28 | $downloadDest = Join-Path $outDir $downloadName 29 | $downloadDestTemp = Join-Path $outDir "$downloadName.tmp" 30 | 31 | Write-Host -NoNewline "Downloading $downloadName..." 32 | 33 | try 34 | { 35 | $webclient = new-object System.Net.WebClient 36 | $webclient.DownloadFile($downloadUrl, $downloadPath) 37 | } 38 | catch [System.Net.WebException] 39 | { 40 | Write-Host 41 | Write-Warning "Failed to fetch updated file from $downloadUrl" 42 | if (!(Test-Path $downloadDest)) 43 | { 44 | throw "$downloadName was not found at $downloadDest" 45 | } 46 | else 47 | { 48 | Write-Warning "$downloadName may be out of date" 49 | } 50 | } 51 | 52 | Unblock-File $downloadPath 53 | 54 | $downloadDestTemp = $downloadPath; 55 | 56 | # Delete and rename to final dest 57 | if (Test-Path -PathType Container $downloadDest) 58 | { 59 | [System.IO.Directory]::Delete($downloadDest, $true) 60 | } 61 | 62 | Move-Item -Force $downloadDestTemp $downloadDest 63 | Write-Host "Done" 64 | 65 | return $downloadDest 66 | } 67 | 68 | function Get-ISODriveLetter 69 | { 70 | param ([string] $isoPath) 71 | 72 | $diskImage = Get-DiskImage -ImagePath $isoPath 73 | if ($diskImage) 74 | { 75 | $volume = Get-Volume -DiskImage $diskImage 76 | 77 | if ($volume) 78 | { 79 | $driveLetter = $volume.DriveLetter 80 | if ($driveLetter) 81 | { 82 | $driveLetter += ":" 83 | return $driveLetter 84 | } 85 | } 86 | } 87 | 88 | return $null 89 | } 90 | 91 | function Mount-ISO 92 | { 93 | param ([string] $isoPath) 94 | 95 | # Check if image is already mounted 96 | $isoDrive = Get-ISODriveLetter $isoPath 97 | 98 | if (!$isoDrive) 99 | { 100 | Mount-DiskImage -ImagePath $isoPath -StorageType ISO | Out-Null 101 | } 102 | 103 | $isoDrive = Get-ISODriveLetter $isoPath 104 | Write-Verbose "$isoPath mounted to ${isoDrive}:" 105 | } 106 | 107 | function Dismount-ISO 108 | { 109 | param ([string] $isoPath) 110 | 111 | $isoDrive = (Get-DiskImage -ImagePath $isoPath | Get-Volume).DriveLetter 112 | 113 | if ($isoDrive) 114 | { 115 | Write-Verbose "$isoPath dismounted" 116 | Dismount-DiskImage -ImagePath $isoPath | Out-Null 117 | } 118 | } 119 | 120 | function Disable-StrongName 121 | { 122 | param ([string] $publicKeyToken = "*") 123 | 124 | reg ADD "HKLM\SOFTWARE\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null 125 | if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") 126 | { 127 | reg ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null 128 | } 129 | } 130 | 131 | function Test-Admin 132 | { 133 | $identity = [Security.Principal.WindowsIdentity]::GetCurrent() 134 | $principal = New-Object Security.Principal.WindowsPrincipal $identity 135 | $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) 136 | } 137 | 138 | function Test-RegistryPathAndValue 139 | { 140 | param ( 141 | [parameter(Mandatory=$true)] 142 | [ValidateNotNullOrEmpty()] 143 | [string] $path, 144 | [parameter(Mandatory=$true)] 145 | [ValidateNotNullOrEmpty()] 146 | [string] $value) 147 | 148 | try 149 | { 150 | if (Test-Path $path) 151 | { 152 | Get-ItemProperty -Path $path | Select-Object -ExpandProperty $value -ErrorAction Stop | Out-Null 153 | return $true 154 | } 155 | } 156 | catch 157 | { 158 | } 159 | 160 | return $false 161 | } 162 | 163 | function Test-InstallWindowsSDK 164 | { 165 | $retval = $true 166 | 167 | if (Test-RegistryPathAndValue -Path $WindowsSDKRegPath -Value $WindowsSDKRegRootKey) 168 | { 169 | # A Windows SDK is installed 170 | # Is an SDK of our version installed with the options we need? 171 | if (Test-RegistryPathAndValue -Path $WindowsSDKInstalledRegPath -Value "$WindowsSDKOptions") 172 | { 173 | # It appears we have what we need. Double check the disk 174 | $sdkRoot = Get-ItemProperty -Path $WindowsSDKRegPath | Select-Object -ExpandProperty $WindowsSDKRegRootKey 175 | if ($sdkRoot) 176 | { 177 | if (Test-Path $sdkRoot) 178 | { 179 | $refPath = Join-Path $sdkRoot "References\$WindowsSDKVersion" 180 | if (Test-Path $refPath) 181 | { 182 | $umdPath = Join-Path $sdkRoot "UnionMetadata\$WindowsSDKVersion" 183 | if (Test-Path $umdPath) 184 | { 185 | # Pretty sure we have what we need 186 | $retval = $false 187 | } 188 | } 189 | } 190 | } 191 | } 192 | } 193 | 194 | return $retval 195 | } 196 | 197 | function Test-InstallStrongNameHijack 198 | { 199 | foreach($publicKeyToken in $PublicKeyTokens) 200 | { 201 | $key = "$StrongNameRegPath\*,$publicKeyToken" 202 | if (!(Test-Path $key)) 203 | { 204 | return $true 205 | } 206 | } 207 | 208 | return $false 209 | } 210 | 211 | Write-Host -NoNewline "Checking for installed Windows SDK $WindowsSDKVersion..." 212 | $InstallWindowsSDK = Test-InstallWindowsSDK 213 | if ($InstallWindowsSDK) 214 | { 215 | Write-Host "Installation required" 216 | } 217 | else 218 | { 219 | Write-Host "INSTALLED" 220 | } 221 | 222 | $StrongNameHijack = Test-InstallStrongNameHijack 223 | Write-Host -NoNewline "Checking if StrongName bypass required..." 224 | 225 | if ($StrongNameHijack) 226 | { 227 | Write-Host "REQUIRED" 228 | } 229 | else 230 | { 231 | Write-Host "Done" 232 | } 233 | 234 | if ($StrongNameHijack -or $InstallWindowsSDK) 235 | { 236 | if (!(Test-Admin)) 237 | { 238 | Write-Host 239 | throw "ERROR: Elevation required" 240 | } 241 | } 242 | 243 | if ($InstallWindowsSDK) 244 | { 245 | # Static(ish) link for Windows SDK 246 | # Note: there is a delay from Windows SDK announcements to availability via the static link 247 | $uri = "https://go.microsoft.com/fwlink/?prd=11966&pver=1.0&plcid=0x409&clcid=0x409&ar=Flight&sar=Sdsurl&o1=$buildNumber" 248 | 249 | if ($env:TEMP -eq $null) 250 | { 251 | $env:TEMP = Join-Path $env:SystemDrive 'temp' 252 | } 253 | 254 | $winsdkTempDir = Join-Path $env:TEMP "WindowsSDK" 255 | 256 | if (![System.IO.Directory]::Exists($winsdkTempDir)) 257 | { 258 | [void][System.IO.Directory]::CreateDirectory($winsdkTempDir) 259 | } 260 | 261 | $file = "winsdk_$buildNumber.iso" 262 | 263 | Write-Verbose "Getting WinSDK from $uri" 264 | $downloadFile = Download-File $winsdkTempDir $uri $file 265 | 266 | # TODO Check if zip, exe, iso, etc. 267 | try 268 | { 269 | Write-Host -NoNewline "Mounting ISO $file..." 270 | Mount-ISO $downloadFile 271 | Write-Host "Done" 272 | 273 | $isoDrive = Get-ISODriveLetter $downloadFile 274 | 275 | if (Test-Path $isoDrive) 276 | { 277 | Write-Host -NoNewLine "Installing WinSDK..." 278 | 279 | $setupPath = Join-Path "$isoDrive" "WinSDKSetup.exe" 280 | Start-Process -Wait $setupPath "/features $WindowsSDKOptions /q" 281 | Write-Host "Done" 282 | } 283 | else 284 | { 285 | throw "Could not find mounted ISO at ${isoDrive}" 286 | } 287 | } 288 | finally 289 | { 290 | Write-Host -NoNewline "Dismounting ISO $file..." 291 | #Dismount-ISO $downloadFile 292 | Write-Host "Done" 293 | } 294 | } 295 | 296 | if ($StrongNameHijack) 297 | { 298 | Write-Host -NoNewline "Disabling StrongName for Windows SDK..." 299 | 300 | foreach($key in $PublicKeyTokens) 301 | { 302 | Disable-StrongName $key 303 | } 304 | 305 | Write-Host "Done" 306 | } -------------------------------------------------------------------------------- /build/Sign-Package.ps1: -------------------------------------------------------------------------------- 1 | ## Licensed to the .NET Foundation under one or more agreements. 2 | ## The .NET Foundation licenses this file to you under the MIT license. 3 | ## See the LICENSE file in the project root for more information. 4 | 5 | $currentDirectory = split-path $MyInvocation.MyCommand.Definition 6 | 7 | # See if we have the ClientSecret available 8 | if([string]::IsNullOrEmpty($Env:SignClientSecret)){ 9 | Write-Host "Client Secret not found, not signing packages" 10 | return; 11 | } 12 | 13 | dotnet tool install --tool-path . SignClient 14 | 15 | # Setup Variables we need to pass into the sign client tool 16 | 17 | $appSettings = "$currentDirectory\SignClientSettings.json" 18 | 19 | $nupkgs = gci $Env:ArtifactDirectory\*.nupkg -recurse | Select -ExpandProperty FullName 20 | 21 | foreach ($nupkg in $nupkgs){ 22 | Write-Host "Submitting $nupkg for signing" 23 | 24 | .\SignClient 'sign' -c $appSettings -i $nupkg -r $Env:SignClientUser -s $Env:SignClientSecret -n 'Windows Community Toolkit' -d 'Windows Community Toolkit' -u 'https://developer.microsoft.com/en-us/windows/uwp-community-toolkit' 25 | 26 | Write-Host "Finished signing $nupkg" 27 | } 28 | 29 | Write-Host "Sign-package complete" -------------------------------------------------------------------------------- /build/SignClientSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "SignClient": { 3 | "AzureAd": { 4 | "AADInstance": "https://login.microsoftonline.com/", 5 | "ClientId": "c248d68a-ba6f-4aa9-8a68-71fe872063f8", 6 | "TenantId": "16076fdc-fcc1-4a15-b1ca-32c9a255900e" 7 | }, 8 | "Service": { 9 | "Url": "https://codesign.dotnetfoundation.org/", 10 | "ResourceId": "https://SignService/3c30251f-36f3-490b-a955-520addb85001" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /build/StyleXaml.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | PowerShell.exe -file "%~dp0build.ps1" -target=StyleXaml 3 | PAUSE -------------------------------------------------------------------------------- /build/UpdateHeaders.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | PowerShell.exe -file "%~dp0build.ps1" -target=UpdateHeaders 3 | PAUSE -------------------------------------------------------------------------------- /build/build.cake: -------------------------------------------------------------------------------- 1 | #module "Cake.Longpath.Module" 2 | 3 | #addin "Cake.FileHelpers" 4 | #addin "Cake.Powershell" 5 | #addin nuget:?package=Cake.GitVersioning&version=2.3.38 6 | 7 | using System; 8 | using System.Linq; 9 | using System.Text.RegularExpressions; 10 | 11 | ////////////////////////////////////////////////////////////////////// 12 | // ARGUMENTS 13 | ////////////////////////////////////////////////////////////////////// 14 | 15 | var target = Argument("target", "Default"); 16 | var configuration = Argument("configuration", "Release"); 17 | 18 | ////////////////////////////////////////////////////////////////////// 19 | // VARIABLES 20 | ////////////////////////////////////////////////////////////////////// 21 | 22 | var baseDir = MakeAbsolute(Directory("../")).ToString(); 23 | var buildDir = $"{baseDir}/build"; 24 | var toolsDir = $"{buildDir}/tools"; 25 | 26 | var binDir = $"{baseDir}/bin"; 27 | var nupkgDir = $"{binDir}/nupkg"; 28 | var packageDir = $"{baseDir}/packages"; 29 | 30 | var nuspec = $"{baseDir}/SceneLoader/NugetPackager/SceneLoaderComponent.nuspec"; 31 | var sceneLoaderSln = $"{baseDir}/SceneLoader.sln"; 32 | 33 | var styler = $"{toolsDir}/XamlStyler.Console/tools/xstyler.exe"; 34 | var stylerFile = $"{baseDir}/settings.xamlstyler"; 35 | 36 | string Version = null; 37 | 38 | ////////////////////////////////////////////////////////////////////// 39 | // METHODS 40 | ////////////////////////////////////////////////////////////////////// 41 | 42 | // Builds the solution with the given target setting the given build properties. 43 | void MSBuildSolution( 44 | string target, 45 | params (string Name, string Value)[] properties) 46 | { 47 | MSBuildSettings SettingsWithTarget() => 48 | new MSBuildSettings 49 | { 50 | MaxCpuCount = 0, 51 | }.WithTarget(target); 52 | 53 | MSBuildSettings SetProperties(MSBuildSettings settings) 54 | { 55 | foreach(var property in properties) 56 | { 57 | settings = settings.WithProperty(property.Name, property.Value); 58 | } 59 | return settings; 60 | } 61 | 62 | var msBuildSettings = SetProperties(SettingsWithTarget().SetConfiguration(configuration)); 63 | 64 | foreach (var platformTarget in new [] 65 | { 66 | PlatformTarget.x86, 67 | PlatformTarget.x64, 68 | PlatformTarget.ARM, 69 | PlatformTarget.MSIL 70 | }) 71 | { 72 | msBuildSettings.PlatformTarget = platformTarget; 73 | MSBuild($"{baseDir}/SceneLoader.sln", msBuildSettings); 74 | } 75 | } 76 | 77 | // Returns true if the given file has a name that indicates it is 78 | // generated code. 79 | static bool IsAutoGenerated(FilePath path) 80 | { 81 | var fileName = path.GetFilename().ToString(); 82 | // Exclude these auto-generated files. 83 | return fileName.EndsWith(".g.cs") || 84 | fileName.EndsWith(".i.cs") || 85 | fileName.Contains("TemporaryGeneratedFile"); 86 | } 87 | 88 | static bool IsExcludedDirectory(FilePath path) 89 | { 90 | var segments = path.Segments; 91 | 92 | return 93 | segments.Contains("bin") || 94 | segments.Contains("internal") || 95 | segments.Contains("obj") || 96 | segments.Contains("Generated Files") || 97 | segments.Contains("tools") || 98 | segments.Contains("packages"); 99 | } 100 | 101 | // Returns true if the given file is source that the build system 102 | // should use directly i.e. it is not generated in the build and 103 | // is not being excluded for some reason. 104 | static bool IsBuildInput(FilePath path) 105 | { 106 | var filename = path.GetFilename().ToString(); 107 | return !IsExcludedDirectory(path) && !IsAutoGenerated(path) && 108 | (filename.EndsWith(".cs") || filename.EndsWith(".cpp") || 109 | filename.EndsWith(".h")); 110 | } 111 | 112 | void VerifyHeaders(bool updateHeaders) 113 | { 114 | var header = FileReadText("header.txt") + "\r\n"; 115 | bool hasMissing = false; 116 | 117 | // Source files need copyright headers 118 | var files = GetFiles($"{baseDir}/**/*").Where(IsBuildInput); 119 | 120 | Information($"\r\nChecking {files.Count()} file header(s)"); 121 | foreach(var file in files) 122 | { 123 | var oldContent = FileReadText(file); 124 | if(oldContent.Contains("// ")) 125 | { 126 | continue; 127 | } 128 | var rgx = new Regex("^(//.*\r?\n)*\r?\n"); 129 | var newContent = header + rgx.Replace(oldContent, ""); 130 | 131 | if(!newContent.Equals(oldContent, StringComparison.Ordinal)) 132 | { 133 | if(updateHeaders) 134 | { 135 | Information($"\r\nUpdating {file} header..."); 136 | FileWriteText(file, newContent); 137 | } 138 | else 139 | { 140 | Error($"\r\nWrong/missing header on {file}"); 141 | hasMissing = true; 142 | } 143 | } 144 | } 145 | 146 | if(!updateHeaders && hasMissing) 147 | { 148 | throw new Exception("Please run UpdateHeaders.bat or '.\\build.ps1 -target=UpdateHeaders' and commit the changes."); 149 | } 150 | } 151 | 152 | ////////////////////////////////////////////////////////////////////// 153 | // TASK TARGETS 154 | ////////////////////////////////////////////////////////////////////// 155 | 156 | Task("Clean") 157 | .Description("Clean the output folder and run the solution Clean target") 158 | .Does(() => 159 | { 160 | if(DirectoryExists(binDir)) 161 | { 162 | Information("\r\nCleaning Working Directory"); 163 | CleanDirectory(binDir); 164 | } 165 | else 166 | { 167 | CreateDirectory(binDir); 168 | } 169 | 170 | // Run the clean target on the solution. 171 | // MSBuildSolution("Clean"); 172 | }); 173 | 174 | Task("VerifyWindowsSDK") 175 | .Description("Run pre-build verifications") 176 | .Does(() => 177 | { 178 | // Verifies the correct Windows SDK is installed. 179 | StartPowershellFile("./Find-WindowsSDKVersions.ps1"); 180 | }); 181 | 182 | Task("VerifyHeaders") 183 | .Description("Verify that headers in source files are updated") 184 | .Does(() => 185 | { 186 | // Outputs warning message if any source files do not have necessary licensing. 187 | VerifyHeaders(false); 188 | }); 189 | 190 | Task("UpdateVersionInfo") 191 | .Description("Updates the version information in all Projects") 192 | .Does(() => 193 | { 194 | Information("\r\nRetrieving version..."); 195 | Version = GitVersioningGetVersion().NuGetPackageVersion; 196 | Information($"\r\nBuild Version: {Version}"); 197 | }); 198 | 199 | Task("RestoreNugetPackages") 200 | .Description("Restore all Nuget packages used by solution") 201 | .Does(() => 202 | { 203 | Information("\r\nRestoring Nuget Packages"); 204 | // Restore nuget packages for SceneLoader vcxproj 205 | var solution = new FilePath(@"..\SceneLoader\packages.config"); 206 | var nugetRestoreSettings = new NuGetRestoreSettings { 207 | PackagesDirectory = new DirectoryPath(packageDir), 208 | }; 209 | NuGetRestore(solution, nugetRestoreSettings); 210 | 211 | // Restore nuget packages for all csproj files 212 | var buildSettings = new MSBuildSettings 213 | { 214 | MaxCpuCount = 0 215 | } 216 | .SetConfiguration("Release") 217 | .WithTarget("Restore"); 218 | 219 | MSBuild(sceneLoaderSln, buildSettings); 220 | }); 221 | 222 | Task("BuildSolution") 223 | .Description("Build all projects and get the assemblies") 224 | .IsDependentOn("VerifyWindowsSDK") 225 | .IsDependentOn("Clean") 226 | .IsDependentOn("UpdateVersionInfo") 227 | .IsDependentOn("VerifyHeaders") 228 | .IsDependentOn("RestoreNugetPackages") 229 | .Does(() => 230 | { 231 | Information("\r\nBuilding Solution"); 232 | EnsureDirectoryExists(nupkgDir); 233 | 234 | MSBuildSolution("Build", ("GenerateLibraryLayout", "true")); 235 | }); 236 | 237 | Task("PackageNuget") 238 | .Description("Pack the NuPkg") 239 | .IsDependentOn("BuildSolution") 240 | .Does(() => 241 | { 242 | Information("\r\nCopy files needed for Nuget package into a directory and create the package"); 243 | MSBuildSolution("Pack", ("GenerateLibraryLayout", "true"), ("PackageOutputPath", nupkgDir)); 244 | var nuGetPackSettings = new NuGetPackSettings 245 | { 246 | OutputDirectory = nupkgDir, 247 | Version = Version 248 | }; 249 | NuGetPack(nuspec, nuGetPackSettings); 250 | }); 251 | 252 | Task("UpdateHeaders") 253 | .Description("Updates the headers in source files") 254 | .Does(() => 255 | { 256 | VerifyHeaders(true); 257 | }); 258 | 259 | Task("StyleXaml") 260 | .Description("Ensures XAML Formatting is clean") 261 | .Does(() => 262 | { 263 | Information("\r\nDownloading XamlStyler..."); 264 | var installSettings = new NuGetInstallSettings { 265 | ExcludeVersion = true, 266 | OutputDirectory = toolsDir 267 | }; 268 | 269 | NuGetInstall(new []{"xamlstyler.console"}, installSettings); 270 | 271 | var files = GetFiles($"{baseDir}/**/*.xaml").Where(IsBuildInput); 272 | Information($"\r\nChecking {files.Count()} file(s) for XAML Structure"); 273 | foreach(var file in files) 274 | { 275 | StartProcess(styler, $"-f \"{file}\" -c \"{stylerFile}\""); 276 | } 277 | }); 278 | 279 | Task("Default") 280 | .IsDependentOn("PackageNuget"); 281 | 282 | ////////////////////////////////////////////////////////////////////// 283 | // EXECUTION 284 | ////////////////////////////////////////////////////////////////////// 285 | 286 | RunTarget(target); 287 | -------------------------------------------------------------------------------- /build/build.ps1: -------------------------------------------------------------------------------- 1 | ## Licensed to the .NET Foundation under one or more agreements. 2 | ## The .NET Foundation licenses this file to you under the MIT license. 3 | ## See the LICENSE file in the project root for more information. 4 | 5 | ########################################################################## 6 | # This is the Cake bootstrapper script for PowerShell. 7 | # This file was downloaded from https://github.com/cake-build/resources 8 | # Feel free to change this file to fit your needs. 9 | ########################################################################## 10 | 11 | <# 12 | 13 | .SYNOPSIS 14 | This is a Powershell script to bootstrap a Cake build. 15 | 16 | .DESCRIPTION 17 | This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) 18 | and execute your Cake build script with the parameters you provide. 19 | 20 | .PARAMETER Script 21 | The build script to execute. 22 | .PARAMETER Target 23 | The build script target to run. 24 | .PARAMETER Configuration 25 | The build configuration to use. 26 | .PARAMETER Verbosity 27 | Specifies the amount of information to be displayed. 28 | .PARAMETER ShowDescription 29 | Shows description about tasks. 30 | .PARAMETER DryRun 31 | Performs a dry run. 32 | .PARAMETER SkipToolPackageRestore 33 | Skips restoring of packages. 34 | .PARAMETER ScriptArgs 35 | Remaining arguments are added here. 36 | 37 | .LINK 38 | https://cakebuild.net 39 | 40 | #> 41 | 42 | [CmdletBinding()] 43 | Param( 44 | [string]$Script = "build.cake", 45 | [string]$Target, 46 | [string]$Configuration, 47 | [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] 48 | [string]$Verbosity, 49 | [switch]$ShowDescription, 50 | [Alias("WhatIf", "Noop")] 51 | [switch]$DryRun, 52 | [switch]$SkipToolPackageRestore, 53 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] 54 | [string[]]$ScriptArgs 55 | ) 56 | 57 | # Attempt to set highest encryption available for SecurityProtocol. 58 | # PowerShell will not set this by default (until maybe .NET 4.6.x). This 59 | # will typically produce a message for PowerShell v2 (just an info 60 | # message though) 61 | try { 62 | # Set TLS 1.2 (3072), then TLS 1.1 (768), then TLS 1.0 (192), finally SSL 3.0 (48) 63 | # Use integers because the enumeration values for TLS 1.2 and TLS 1.1 won't 64 | # exist in .NET 4.0, even though they are addressable if .NET 4.5+ is 65 | # installed (.NET 4.5 is an in-place upgrade). 66 | [System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor 192 -bor 48 67 | } catch { 68 | Write-Output 'Unable to set PowerShell to use TLS 1.2 and TLS 1.1 due to old .NET Framework installed. If you see underlying connection closed or trust errors, you may need to upgrade to .NET Framework 4.5+ and PowerShell v3' 69 | } 70 | 71 | [Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null 72 | function MD5HashFile([string] $filePath) 73 | { 74 | if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) 75 | { 76 | return $null 77 | } 78 | 79 | [System.IO.Stream] $file = $null; 80 | [System.Security.Cryptography.MD5] $md5 = $null; 81 | try 82 | { 83 | $md5 = [System.Security.Cryptography.MD5]::Create() 84 | $file = [System.IO.File]::OpenRead($filePath) 85 | return [System.BitConverter]::ToString($md5.ComputeHash($file)) 86 | } 87 | finally 88 | { 89 | if ($file -ne $null) 90 | { 91 | $file.Dispose() 92 | } 93 | } 94 | } 95 | 96 | function GetProxyEnabledWebClient 97 | { 98 | $wc = New-Object System.Net.WebClient 99 | $proxy = [System.Net.WebRequest]::GetSystemWebProxy() 100 | $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials 101 | $wc.Proxy = $proxy 102 | return $wc 103 | } 104 | 105 | Write-Host "Preparing to run build script..." 106 | 107 | if(!$PSScriptRoot){ 108 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent 109 | } 110 | 111 | cd $PSScriptRoot 112 | 113 | $TOOLS_DIR = Join-Path $PSScriptRoot "tools" 114 | $ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" 115 | $MODULES_DIR = Join-Path $TOOLS_DIR "Modules" 116 | $NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" 117 | $CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" 118 | $NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" 119 | $PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" 120 | $PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" 121 | $ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config" 122 | $MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config" 123 | 124 | # Make sure tools folder exists 125 | if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { 126 | Write-Verbose -Message "Creating tools directory..." 127 | New-Item -Path $TOOLS_DIR -Type directory | out-null 128 | } 129 | 130 | # Make sure that packages.config exist. 131 | if (!(Test-Path $PACKAGES_CONFIG)) { 132 | Write-Verbose -Message "Downloading packages.config..." 133 | try { 134 | $wc = GetProxyEnabledWebClient 135 | $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) 136 | } catch { 137 | Throw "Could not download packages.config." 138 | } 139 | } 140 | 141 | # Try find NuGet.exe in path if not exists 142 | if (!(Test-Path $NUGET_EXE)) { 143 | Write-Verbose -Message "Trying to find nuget.exe in PATH..." 144 | $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) } 145 | $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 146 | if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { 147 | Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." 148 | $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName 149 | } 150 | } 151 | 152 | # Try download NuGet.exe if not exists 153 | if (!(Test-Path $NUGET_EXE)) { 154 | Write-Verbose -Message "Downloading NuGet.exe..." 155 | try { 156 | $wc = GetProxyEnabledWebClient 157 | $wc.DownloadFile($NUGET_URL, $NUGET_EXE) 158 | } catch { 159 | Throw "Could not download NuGet.exe." 160 | } 161 | } 162 | 163 | # Save nuget.exe path to environment to be available to child processed 164 | $ENV:NUGET_EXE = $NUGET_EXE 165 | 166 | # Restore tools from NuGet? 167 | if(-Not $SkipToolPackageRestore.IsPresent) { 168 | Push-Location 169 | Set-Location $TOOLS_DIR 170 | 171 | # Check for changes in packages.config and remove installed tools if true. 172 | [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) 173 | if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or 174 | ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { 175 | Write-Verbose -Message "Missing or changed package.config hash..." 176 | Get-ChildItem -Exclude packages.config,nuget.exe,Cake.Bakery | 177 | Remove-Item -Recurse 178 | } 179 | 180 | Write-Verbose -Message "Restoring tools from NuGet..." 181 | $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" 182 | 183 | if ($LASTEXITCODE -ne 0) { 184 | Throw "An error occurred while restoring NuGet tools." 185 | } 186 | else 187 | { 188 | $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" 189 | } 190 | Write-Verbose -Message ($NuGetOutput | out-string) 191 | 192 | Pop-Location 193 | } 194 | 195 | # Restore addins from NuGet 196 | if (Test-Path $ADDINS_PACKAGES_CONFIG) { 197 | Push-Location 198 | Set-Location $ADDINS_DIR 199 | 200 | Write-Verbose -Message "Restoring addins from NuGet..." 201 | $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`"" 202 | 203 | if ($LASTEXITCODE -ne 0) { 204 | Throw "An error occurred while restoring NuGet addins." 205 | } 206 | 207 | Write-Verbose -Message ($NuGetOutput | out-string) 208 | 209 | Pop-Location 210 | } 211 | 212 | # Restore modules from NuGet 213 | if (Test-Path $MODULES_PACKAGES_CONFIG) { 214 | Push-Location 215 | Set-Location $MODULES_DIR 216 | 217 | Write-Verbose -Message "Restoring modules from NuGet..." 218 | $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`"" 219 | 220 | if ($LASTEXITCODE -ne 0) { 221 | Throw "An error occurred while restoring NuGet modules." 222 | } 223 | 224 | Write-Verbose -Message ($NuGetOutput | out-string) 225 | 226 | Pop-Location 227 | } 228 | 229 | # Make sure that Cake has been installed. 230 | if (!(Test-Path $CAKE_EXE)) { 231 | Throw "Could not find Cake.exe at $CAKE_EXE" 232 | } 233 | 234 | # Build Cake arguments 235 | $cakeArguments = @("$Script"); 236 | if ($Target) { $cakeArguments += "-target=$Target" } 237 | if ($Configuration) { $cakeArguments += "-configuration=$Configuration" } 238 | if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" } 239 | if ($ShowDescription) { $cakeArguments += "-showdescription" } 240 | if ($DryRun) { $cakeArguments += "-dryrun" } 241 | $cakeArguments += $ScriptArgs 242 | 243 | # Start Cake 244 | Write-Host "Running build script..." 245 | &$CAKE_EXE $cakeArguments 246 | exit $LASTEXITCODE 247 | -------------------------------------------------------------------------------- /build/header.txt: -------------------------------------------------------------------------------- 1 | // Licensed to the .NET Foundation under one or more agreements. 2 | // The .NET Foundation licenses this file to you under the MIT license. 3 | // See the LICENSE file in the project root for more information. 4 | -------------------------------------------------------------------------------- /build/nuget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CommunityToolkit/SceneLoader/17151148934844231bc3aab6c0a3e8fcd32b7399/build/nuget.png -------------------------------------------------------------------------------- /settings.xamlstyler: -------------------------------------------------------------------------------- 1 | { 2 | "AttributesTolerance": 1, 3 | "KeepFirstAttributeOnSameLine": true, 4 | "MaxAttributeCharatersPerLine": 0, 5 | "MaxAttributesPerLine": 1, 6 | "NewlineExemptionElements": "RadialGradientBrush, GradientStop, LinearGradientBrush, ScaleTransfom, SkewTransform, RotateTransform, TranslateTransform, Trigger, Condition, Setter", 7 | "SeparateByGroups": false, 8 | "AttributeIndentation": 0, 9 | "AttributeIndentationStyle": 1, 10 | "RemoveDesignTimeReferences": false, 11 | "EnableAttributeReordering": true, 12 | "AttributeOrderingRuleGroups": [ 13 | "x:Class", 14 | "xmlns, xmlns:x", 15 | "xmlns:*", 16 | "x:Key, Key, x:Name, Name, x:Uid, Uid, Title", 17 | "Grid.Row, Grid.RowSpan, Grid.Column, Grid.ColumnSpan, Canvas.Left, Canvas.Top, Canvas.Right, Canvas.Bottom", 18 | "Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight", 19 | "Margin, Padding, HorizontalAlignment, VerticalAlignment, HorizontalContentAlignment, VerticalContentAlignment, Panel.ZIndex", 20 | "*:*, *", 21 | "PageSource, PageIndex, Offset, Color, TargetName, Property, Value, StartPoint, EndPoint", 22 | "mc:Ignorable, d:IsDataSource, d:LayoutOverrides, d:IsStaticText", 23 | "Storyboard.*, From, To, Duration" 24 | ], 25 | "FirstLineAttributes": "", 26 | "OrderAttributesByName": true, 27 | "PutEndingBracketOnNewLine": false, 28 | "RemoveEndingTagOfEmptyElement": true, 29 | "SpaceBeforeClosingSlash": true, 30 | "RootElementLineBreakRule": 0, 31 | "ReorderVSM": 2, 32 | "ReorderGridChildren": false, 33 | "ReorderCanvasChildren": false, 34 | "ReorderSetters": 0, 35 | "FormatMarkupExtension": true, 36 | "NoNewLineMarkupExtensions": "x:Bind, Binding", 37 | "ThicknessSeparator": 2, 38 | "ThicknessAttributes": "Margin, Padding, BorderThickness, ThumbnailClipMargin", 39 | "FormatOnSave": true, 40 | "CommentPadding": 2, 41 | "IndentSize": 4 42 | } 43 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-build.{height}", 3 | "publicReleaseRefSpec": [ 4 | "^refs/heads/master$", // we release out of master 5 | "^refs/heads/dev$", // we release out of dev 6 | "^refs/heads/rel/\\d+\\.\\d+\\.\\d+" // we also release branches starting with rel/N.N.N 7 | ], 8 | "nugetPackageVersion":{ 9 | "semVer": 2 10 | }, 11 | "cloudBuild": { 12 | "buildNumber": { 13 | "enabled": false 14 | } 15 | } 16 | } 17 | --------------------------------------------------------------------------------