[
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n**/Properties/launchSettings.json\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Typescript v1 declaration files\ntypings/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.\n"
  },
  {
    "path": "LICENSE",
    "content": "    MIT License\n\n    Copyright (c) Microsoft Corporation. All rights reserved.\n\n    Permission is hereby granted, free of charge, to any person obtaining a copy\n    of this software and associated documentation files (the \"Software\"), to deal\n    in the Software without restriction, including without limitation the rights\n    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n    copies of the Software, and to permit persons to whom the Software is\n    furnished to do so, subject to the following conditions:\n\n    The above copyright notice and this permission notice shall be included in all\n    copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n    SOFTWARE\n"
  },
  {
    "path": "README.md",
    "content": "# Microsoft glTF Toolkit\n\nThis project contains a collection of tools and libraries to modify and optimize glTF assets.\n\nAdditionally the repository includes a command line tool that uses these steps in sequence in order to convert a glTF 2.0 core asset for use in the Windows Mixed Reality home, following the published [documentation](https://developer.microsoft.com/en-us/windows/mixed-reality/creating_3d_models_for_use_in_the_windows_mixed_reality_home). The latest release of the Windows Mixed Reality Asset converter is available on the [releases tab](https://github.com/Microsoft/glTF-Toolkit/releases).\n\n[![Build status](https://ci.appveyor.com/api/projects/status/4n8m94mpc03dcuxt?svg=true)](https://ci.appveyor.com/project/robertos/gltf-toolkit)\n\n## Features\n\nThe current release includes code for:\n\n- Packing PBR material textures using [DirectXTex](http://github.com/Microsoft/DirectXTex) for use with the [MSFT_packing_occlusionRoughnessMetallic](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_occlusionRoughnessMetallic) and [MSFT_packing_normalRoughnessMetallic](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_normalRoughnessMetallic) extensions.\n- Compressing textures as BC3, BC5 or BC7 and generate mip maps using [DirectXTex](http://github.com/Microsoft/DirectXTex) for use with the [MSFT_texture_dds](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds) extension.\n- Removing [KHR_materials_pbrSpecularGlossiness](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness) by converting material prameters to metallic-roughness.\n- Mesh compression using [KHR_draco_mesh_compression](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression) extension; this can only be used on 1809 and later and should only be used for assets that are transmitted over the network as load time is increased with compression.\n- Merging multiple glTF assets into a asset with multiple levels of detail using the [MSFT_lod](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod) extension.\n- A command line tool that combines these components to create optimized glTF assets for the Windows Mixed Reality Home\n- A UWP compatible Windows Runtime component to perform conversions between GLTF and GLB, as well as optimize assets for Windows Mixed Reality at runtime\n\n## Dependencies\n\nThis project consumes the following projects through NuGet packages:\n\n- [Microsoft.glTF.CPP](https://www.nuget.org/packages/Microsoft.glTF.CPP), licensed under the MIT license\n- [DirectXTex](http://github.com/Microsoft/DirectXTex), licensed under the MIT license\n- [RapidJSON](https://github.com/Tencent/rapidjson/), licensed under the MIT license\n- [Draco](https://github.com/google/draco/), licensed under Apache License 2.0\n\n## Building\n\nThis project can be built using Visual Studio 2017 Update 4 on Windows 10 Fall Creators Update (16299.0).\n\n## Contributing\n\nThis project welcomes contributions and suggestions.  Most contributions require you to agree to a\nContributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us\nthe rights to use your contribution. For details, visit https://cla.microsoft.com.\n\nWhen you submit a pull request, a CLA-bot will automatically determine whether you need to provide\na CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions\nprovided by the bot. You will only need to do this once across all repos using our CLA.\n\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).\nFor more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or\ncontact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.\n\n## License\n\nCopyright (c) Microsoft Corporation. All rights reserved.\n\nLicensed under the [MIT License](LICENSE).\n"
  },
  {
    "path": "SECURITY.md",
    "content": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.8 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).\n\nIf you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.\n\n## Reporting Security Issues\n\n**Please do not report security vulnerabilities through public GitHub issues.**\n\nInstead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).\n\nIf you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).\n\nYou should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). \n\nPlease include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:\n\n  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)\n  * Full paths of source file(s) related to the manifestation of the issue\n  * The location of the affected source code (tag/branch/commit or direct URL)\n  * Any special configuration required to reproduce the issue\n  * Step-by-step instructions to reproduce the issue\n  * Proof-of-concept or exploit code (if possible)\n  * Impact of the issue, including how an attacker might exploit the issue\n\nThis information will help us triage your report more quickly.\n\nIf you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.\n\n## Preferred Languages\n\nWe prefer all communications to be in English.\n\n## Policy\n\nMicrosoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).\n\n<!-- END MICROSOFT SECURITY.MD BLOCK -->\n"
  },
  {
    "path": "WindowsMRAssetConverter/AssetType.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"stdafx.h\"\r\n#include \"AssetType.h\"\r\n\r\nconst wchar_t * EXTENSION_GLTF = L\".gltf\";\r\nconst wchar_t * EXTENSION_GLB = L\".glb\";\r\n\r\nAssetType AssetTypeUtils::AssetTypeFromFilePath(const std::wstring& assetPath)\r\n{\r\n    const wchar_t *inputExtensionRaw = nullptr;\r\n    if (FAILED(PathCchFindExtension(assetPath.c_str(), assetPath.length() + 1, &inputExtensionRaw)))\r\n    {\r\n        throw std::invalid_argument(\"Invalid input file extension.\");\r\n    }\r\n\r\n    if (_wcsicmp(inputExtensionRaw, EXTENSION_GLTF) == 0)\r\n    {\r\n        return AssetType::GLTF;\r\n    }\r\n    else if (_wcsicmp(inputExtensionRaw, EXTENSION_GLB) == 0)\r\n    {\r\n        return AssetType::GLB;\r\n    }\r\n    else\r\n    {\r\n        throw std::invalid_argument(\"Invalid file, please provide a GLTF or GLB.\");\r\n    }\r\n}"
  },
  {
    "path": "WindowsMRAssetConverter/AssetType.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\nextern const wchar_t * EXTENSION_GLTF;\r\nextern const wchar_t * EXTENSION_GLB;\r\n\r\nenum class AssetType\r\n{\r\n    GLTF,\r\n    GLB\r\n};\r\n\r\nnamespace AssetTypeUtils\r\n{\r\n    AssetType AssetTypeFromFilePath(const std::wstring& assetPath);\r\n}\r\n"
  },
  {
    "path": "WindowsMRAssetConverter/CommandLine.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"stdafx.h\"\r\n#include \"CommandLine.h\"\r\n#include \"FileSystem.h\"\r\n\r\n// Constants\r\nconst wchar_t * PARAM_OUTFILE = L\"-o\";\r\nconst wchar_t * PARAM_TMPDIR = L\"-temp-directory\";\r\nconst wchar_t * PARAM_LOD = L\"-lod\";\r\nconst wchar_t * PARAM_SCREENCOVERAGE = L\"-screen-coverage\";\r\nconst wchar_t * PARAM_MAXTEXTURESIZE = L\"-max-texture-size\";\r\nconst wchar_t * PARAM_SHARE_MATERIALS = L\"-share-materials\";\r\nconst wchar_t * PARAM_MIN_VERSION = L\"-min-version\";\r\nconst wchar_t * PARAM_PLATFORM = L\"-platform\";\r\nconst wchar_t * PARAM_REPLACE_TEXTURES = L\"-replace-textures\";\r\nconst wchar_t * PARAM_COMPRESS_MESHES = L\"-compress-meshes\";\r\nconst wchar_t * PARAM_VALUE_VERSION_1709 = L\"1709\";\r\nconst wchar_t * PARAM_VALUE_VERSION_1803 = L\"1803\";\r\nconst wchar_t * PARAM_VALUE_VERSION_1809 = L\"1809\";\r\nconst wchar_t * PARAM_VALUE_VERSION_RS3 = L\"rs3\";\r\nconst wchar_t * PARAM_VALUE_VERSION_RS4 = L\"rs4\";\r\nconst wchar_t * PARAM_VALUE_VERSION_RS5 = L\"rs5\";\r\nconst wchar_t * PARAM_VALUE_VERSION_LATEST = L\"latest\";\r\nconst wchar_t * PARAM_VALUE_HOLOGRAPHIC = L\"holographic\";\r\nconst wchar_t * PARAM_VALUE_HOLOLENS= L\"hololens\";\r\nconst wchar_t * PARAM_VALUE_DESKTOP = L\"desktop\";\r\nconst wchar_t * PARAM_VALUE_PC = L\"pc\";\r\nconst wchar_t * PARAM_VALUE_ALL = L\"all\";\r\nconst wchar_t * SUFFIX_CONVERTED = L\"_converted\";\r\nconst wchar_t * CLI_INDENT = L\"    \";\r\nconst size_t MAXTEXTURESIZE_DEFAULT = 512;\r\nconst size_t MAXTEXTURESIZE_MAX = 4096;\r\nconst CommandLine::Version MIN_VERSION_DEFAULT = CommandLine::Version::Version1709;\r\nconst CommandLine::Platform PLATFORM_DEFAULT = CommandLine::Platform::Desktop;\r\n\r\nenum class CommandLineParsingState\r\n{\r\n    Initial,\r\n    InputRead,\r\n    ReadOutFile,\r\n    ReadTmpDir,\r\n    ReadLods,\r\n    ReadScreenCoverage,\r\n    ReadMaxTextureSize,\r\n    ReadMinVersion,\r\n    ReadPlatform\r\n};\r\n\r\nvoid CommandLine::PrintHelp()\r\n{\r\n    auto indent = std::wstring(CLI_INDENT);\r\n    std::wcerr << std::endl\r\n        << L\"Windows Mixed Reality Asset Converter\" << std::endl\r\n        << L\"=====================================\" << std::endl\r\n        << std::endl\r\n        << L\"A command line tool to convert core GLTF 2.0 assets for use in \"\r\n        << L\"the Windows Mixed Reality home, with the proper texture packing, compression and merged LODs.\" << std::endl << std::endl\r\n        << L\"Usage: WindowsMRAssetConverter <path to GLTF/GLB>\" << std::endl\r\n        << std::endl\r\n        << L\"Optional arguments:\" << std::endl\r\n        << indent << \"[\" << std::wstring(PARAM_OUTFILE) << L\" <output file path>]\" << std::endl\r\n        << indent << \"[\" << std::wstring(PARAM_TMPDIR) << L\" <temporary folder>] - default is the system temp folder for the user\" << std::endl\r\n        << indent << \"[\" << std::wstring(PARAM_PLATFORM) << \" <\" << PARAM_VALUE_ALL << \" | \" << PARAM_VALUE_HOLOGRAPHIC << \" | \" << PARAM_VALUE_DESKTOP << \">] - defaults to \" << PARAM_VALUE_DESKTOP << std::endl\r\n        << indent << \"[\" << std::wstring(PARAM_MIN_VERSION) << \" <\" << PARAM_VALUE_VERSION_1709 << \" | \" << PARAM_VALUE_VERSION_1803 << \" | \" << PARAM_VALUE_VERSION_1809 << \" | \" << PARAM_VALUE_VERSION_LATEST << \">] - defaults to \" << PARAM_VALUE_VERSION_1709 << std::endl\r\n        << indent << \"[\" << std::wstring(PARAM_LOD) << \" <path to each lower LOD asset in descending order of quality>]\" << std::endl\r\n        << indent << \"[\" << std::wstring(PARAM_SCREENCOVERAGE) << \" <LOD screen coverage values>]\" << std::endl\r\n        << indent << \"[\" << std::wstring(PARAM_SHARE_MATERIALS) << \"] - disabled if not present\" << std::endl\r\n        << indent << \"[\" << std::wstring(PARAM_MAXTEXTURESIZE) << \" <Max texture size in pixels>] - defaults to 512\" << std::endl\r\n        << indent << \"[\" << std::wstring(PARAM_REPLACE_TEXTURES) << \"] - disabled if not present\" << std::endl\r\n        << indent << \"[\" << std::wstring(PARAM_COMPRESS_MESHES) << \"] - compress meshes with Draco\" << std::endl\r\n        << std::endl\r\n        << \"Example:\" << std::endl\r\n        << indent << \"WindowsMRAssetConverter FileToConvert.gltf \"\r\n        << std::wstring(PARAM_OUTFILE) << \" ConvertedFile.glb \"\r\n        << std::wstring(PARAM_LOD) << \" Lod1.gltf Lod2.gltf \"\r\n        << std::wstring(PARAM_SCREENCOVERAGE) << \" 0.5 0.2 0.01\" << std::endl\r\n        << std::endl\r\n        << \"The above will convert \\\"FileToConvert.gltf\\\" into \\\"ConvertedFile.glb\\\" in the \"\r\n        << \"current directory.\" << std::endl\r\n        << std::endl\r\n        << \"If the file is a GLB and the output name is not specified, defaults to the same name as input \"\r\n        << \"+ \\\"_converted.glb\\\".\" << std::endl\r\n        << std::endl;\r\n}\r\n\r\nvoid CommandLine::ParseCommandLineArguments(\r\n    int argc, wchar_t *argv[],\r\n    std::wstring& inputFilePath, AssetType& inputAssetType, std::wstring& outFilePath, std::wstring& tempDirectory,\r\n    std::vector<std::wstring>& lodFilePaths, std::vector<double>& screenCoveragePercentages, size_t& maxTextureSize,\r\n    bool& shareMaterials, Version& minVersion, Platform& targetPlatforms, bool& replaceTextures, bool& compressMeshes)\r\n{\r\n    CommandLineParsingState state = CommandLineParsingState::Initial;\r\n\r\n    inputFilePath = FileSystem::GetFullPath(std::wstring(argv[1]));\r\n\r\n    inputAssetType = AssetTypeUtils::AssetTypeFromFilePath(inputFilePath);\r\n\r\n    // Reset input parameters\r\n    outFilePath = L\"\";\r\n    tempDirectory = L\"\";\r\n    lodFilePaths.clear();\r\n    screenCoveragePercentages.clear();\r\n    maxTextureSize = MAXTEXTURESIZE_DEFAULT;\r\n    shareMaterials = false;\r\n    minVersion = MIN_VERSION_DEFAULT;\r\n    targetPlatforms = PLATFORM_DEFAULT;\r\n    replaceTextures = false;\r\n    compressMeshes = false;\r\n\r\n    state = CommandLineParsingState::InputRead;\r\n\r\n    std::wstring outFile;\r\n    std::wstring tmpDir;\r\n    for (int i = 2; i < argc; i++)\r\n    {\r\n        std::wstring param = argv[i];\r\n\r\n        if (param == PARAM_OUTFILE)\r\n        {\r\n            outFile = L\"\";\r\n            state = CommandLineParsingState::ReadOutFile;\r\n        }\r\n        else if (param == PARAM_TMPDIR)\r\n        {\r\n            tmpDir = L\"\";\r\n            state = CommandLineParsingState::ReadTmpDir;\r\n        }\r\n        else if (param == PARAM_LOD)\r\n        {\r\n            lodFilePaths.clear();\r\n            state = CommandLineParsingState::ReadLods;\r\n        }\r\n        else if (param == PARAM_SCREENCOVERAGE)\r\n        {\r\n            screenCoveragePercentages.clear();\r\n            state = CommandLineParsingState::ReadScreenCoverage;\r\n        }\r\n        else if (param == PARAM_MAXTEXTURESIZE)\r\n        {\r\n            maxTextureSize = MAXTEXTURESIZE_DEFAULT;\r\n            state = CommandLineParsingState::ReadMaxTextureSize;\r\n        }\r\n        else if (param == PARAM_SHARE_MATERIALS)\r\n        {\r\n            shareMaterials = true;\r\n            state = CommandLineParsingState::InputRead;\r\n        }\r\n        else if (param == PARAM_MIN_VERSION)\r\n        {\r\n            minVersion = MIN_VERSION_DEFAULT;\r\n            state = CommandLineParsingState::ReadMinVersion;\r\n        }\r\n        else if (param == PARAM_PLATFORM)\r\n        {\r\n            targetPlatforms = PLATFORM_DEFAULT;\r\n            state = CommandLineParsingState::ReadPlatform;\r\n        }\r\n        else if (param == PARAM_REPLACE_TEXTURES)\r\n        {\r\n            replaceTextures = true;\r\n            state = CommandLineParsingState::InputRead;\r\n        }\r\n        else if (param == PARAM_COMPRESS_MESHES)\r\n        {\r\n            if (minVersion >= CommandLine::Version::Version1809)\r\n            {\r\n                compressMeshes = true;\r\n            }\r\n            else\r\n            {\r\n                throw std::invalid_argument(\"Invalid min version specified with mesh compression; must be at least 1809.\");\r\n            }\r\n            state = CommandLineParsingState::InputRead;\r\n        }        \r\n        else\r\n        {\r\n            switch (state)\r\n            {\r\n            case CommandLineParsingState::ReadOutFile:\r\n                outFile = FileSystem::GetFullPath(param);\r\n                state = CommandLineParsingState::InputRead;\r\n                break;\r\n            case CommandLineParsingState::ReadTmpDir:\r\n                tmpDir = FileSystem::GetFullPath(param);\r\n                state = CommandLineParsingState::InputRead;\r\n                break;\r\n            case CommandLineParsingState::ReadLods:\r\n                lodFilePaths.push_back(FileSystem::GetFullPath(param));\r\n                break;\r\n            case CommandLineParsingState::ReadScreenCoverage:\r\n            {\r\n                auto paramA = std::string(param.begin(), param.end());\r\n                screenCoveragePercentages.push_back(std::atof(paramA.c_str()));\r\n                break;\r\n            }\r\n            case CommandLineParsingState::ReadMaxTextureSize:\r\n                maxTextureSize = std::min(static_cast<size_t>(std::stoul(param.c_str())), MAXTEXTURESIZE_MAX);\r\n                break;\r\n            case CommandLineParsingState::ReadMinVersion:\r\n                if (_wcsicmp(param.c_str(), PARAM_VALUE_VERSION_1709) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_VERSION_RS3) == 0)\r\n                {\r\n                    minVersion = Version::Version1709;\r\n                }\r\n                else if (_wcsicmp(param.c_str(), PARAM_VALUE_VERSION_1803) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_VERSION_RS4) == 0)\r\n                {\r\n                    minVersion = Version::Version1803;\r\n                }\r\n                else if (_wcsicmp(param.c_str(), PARAM_VALUE_VERSION_1809) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_VERSION_RS5) == 0)\r\n                {\r\n                    minVersion = Version::Version1809;\r\n                }\r\n                else if (_wcsicmp(param.c_str(), PARAM_VALUE_VERSION_LATEST) == 0)\r\n                {\r\n                    minVersion = Version::Latest;\r\n                }\r\n                else\r\n                {\r\n                    throw std::invalid_argument(\"Invalid min version specified. For help, try the command again without parameters.\");\r\n                }\r\n                state = CommandLineParsingState::InputRead;\r\n                break;\r\n            case CommandLineParsingState::ReadPlatform:\r\n                if (_wcsicmp(param.c_str(), PARAM_VALUE_ALL) == 0)\r\n                {\r\n                    targetPlatforms = (Platform) (Platform::Desktop | Platform::Holographic);\r\n                } \r\n                else if (_wcsicmp(param.c_str(), PARAM_VALUE_HOLOGRAPHIC) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_HOLOLENS) == 0)\r\n                {\r\n                    targetPlatforms = Platform::Holographic;\r\n                }\r\n                else if (_wcsicmp(param.c_str(), PARAM_VALUE_DESKTOP) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_PC) == 0)\r\n                {\r\n                    targetPlatforms = Platform::Desktop;\r\n                }\r\n                else\r\n                {\r\n                    throw std::invalid_argument(\"Invalid platform specified. For help, try the command again without parameters.\");\r\n                }\r\n                state = CommandLineParsingState::InputRead;\r\n                break;\r\n            case CommandLineParsingState::Initial:\r\n            case CommandLineParsingState::InputRead:\r\n            default:\r\n                // Invalid argument detected\r\n                throw std::invalid_argument(\"Invalid usage. For help, try the command again without parameters.\");\r\n            }\r\n        }\r\n    }\r\n\r\n    if (!std::experimental::filesystem::exists(inputFilePath))\r\n    {\r\n        throw std::invalid_argument(\"Input file not found.\");\r\n    }\r\n\r\n    for (auto& lodFilePath : lodFilePaths)\r\n    {\r\n        if (!std::experimental::filesystem::exists(lodFilePath))\r\n        {\r\n            throw  std::invalid_argument(\"Lod file not found.\");\r\n        }\r\n    }\r\n\r\n    if (outFile.empty())\r\n    {\r\n        std::wstring inputFilePathWithoutExtension = inputFilePath;\r\n        if (FAILED(PathCchRemoveExtension(&inputFilePathWithoutExtension[0], inputFilePathWithoutExtension.length() + 1)))\r\n        {\r\n            throw std::invalid_argument(\"Invalid input file extension.\");\r\n        }\r\n\r\n        outFile = std::wstring(&inputFilePathWithoutExtension[0]);\r\n\r\n        if (inputAssetType == AssetType::GLB)\r\n        {\r\n            outFile += SUFFIX_CONVERTED;\r\n        }\r\n\r\n        outFile += EXTENSION_GLB;\r\n    }\r\n\r\n    outFilePath = outFile;\r\n\r\n    if (tmpDir.empty())\r\n    {\r\n        tmpDir = FileSystem::CreateTempFolder();\r\n    }\r\n\r\n    tempDirectory = tmpDir;\r\n}\r\n"
  },
  {
    "path": "WindowsMRAssetConverter/CommandLine.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n#include <vector>\r\n#include \"AssetType.h\"\r\n\r\nnamespace CommandLine\r\n{\r\n    enum Platform\r\n    {\r\n        None = 0x0,\r\n        Holographic = 0x1,\r\n        Desktop = 0x2\r\n    };\r\n\r\n    enum class Version\r\n    {\r\n        Version1709, // Fall Creators Update (RS3)\r\n        Version1803,  // Spring Creators Update (RS4)\r\n        Version1809,  // Fall 2018 Update (RS5)\r\n        Latest = Version1809\r\n    };\r\n\r\n    void PrintHelp();\r\n\r\n    void ParseCommandLineArguments(\r\n        int argc, wchar_t *argv[],\r\n        std::wstring& inputFilePath, AssetType& inputAssetType, std::wstring& outFilePath, std::wstring& tempDirectory,\r\n        std::vector<std::wstring>& lodFilePaths, std::vector<double>& screenCoveragePercentages, size_t& maxTextureSize,\r\n        bool& sharedMaterials, Version& minVersion, Platform& targetPlatforms, bool& replaceTextures, bool& compressMeshes);\r\n};\r\n\r\n"
  },
  {
    "path": "WindowsMRAssetConverter/FileSystem.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"stdafx.h\"\r\n#include \"FileSystem.h\"\r\n\r\nstd::wstring FileSystem::GetRelativePathWithTrailingSeparator(std::wstring from, std::wstring to)\r\n{\r\n    // once c++17 filesystem is fully supported, this should become something like:\r\n    // return std::filesystem::relative(to, from) + std::filesystem::path::preferred_separator;\r\n\r\n    std::experimental::filesystem::path fromFS(std::experimental::filesystem::canonical(from));\r\n    std::experimental::filesystem::path toFS(std::experimental::filesystem::canonical(to));\r\n\r\n    std::experimental::filesystem::path result;\r\n    auto fromIter = fromFS.begin();\r\n    auto toIter = toFS.begin();\r\n\r\n    while (fromIter != fromFS.end() || toIter != toFS.end())\r\n    {\r\n        const auto& f = *fromIter;\r\n        const auto& t = *toIter;\r\n        if (f == t)\r\n        {\r\n            fromIter++;\r\n            toIter++;\r\n        }\r\n        else\r\n        {\r\n            while (fromIter != fromFS.end())\r\n            {\r\n                result /= \"..\";\r\n                fromIter++;\r\n            }\r\n\r\n            while (toIter != toFS.end())\r\n            {\r\n                result /= *toIter;\r\n                toIter++;\r\n            }\r\n\r\n            result += std::experimental::filesystem::path::preferred_separator;\r\n        }\r\n    }\r\n\r\n    return result;\r\n}\r\n\r\nstd::wstring FileSystem::GetBasePath(const std::wstring& path)\r\n{\r\n    std::wstring pathCopy(path);\r\n    wchar_t *basePath = &pathCopy[0];\r\n    if (FAILED(PathCchRemoveFileSpec(basePath, pathCopy.length() + 1)))\r\n    {\r\n        throw std::invalid_argument(\"Invalid input path.\");\r\n    }\r\n\r\n    return std::move(std::wstring(basePath));\r\n}\r\n\r\n\r\nstd::wstring FileSystem::GetFullPath(const std::wstring& path)\r\n{\r\n    wchar_t fullPath[MAX_PATH];\r\n    if (GetFullPathName(path.c_str(), ARRAYSIZE(fullPath), fullPath, NULL) == 0)\r\n    {\r\n        throw std::invalid_argument(\"Invalid input file path.\");\r\n    }\r\n    return std::move(std::wstring(fullPath));\r\n}\r\n\r\nstd::wstring FileSystem::CreateSubFolder(const std::wstring& parentPath, const std::wstring& subFolderName)\r\n{\r\n    std::wstring errorMessageW = L\"Could not create a sub-folder of \" + parentPath + L\".\";\r\n    std::string errorMessage(errorMessageW.begin(), errorMessageW.end());\r\n\r\n    wchar_t subFolderPath[MAX_PATH];\r\n    if (FAILED(PathCchCombine(subFolderPath, ARRAYSIZE(subFolderPath), parentPath.c_str(), (subFolderName + L\"\\\\\").c_str())))\r\n    {\r\n        throw std::runtime_error(errorMessage);\r\n    }\r\n\r\n    if (CreateDirectory(subFolderPath, NULL) == 0 && GetLastError() != ERROR_ALREADY_EXISTS)\r\n    {\r\n        throw std::runtime_error(errorMessage);\r\n    }\r\n\r\n    return std::move(std::wstring(subFolderPath));\r\n}\r\n\r\nstd::wstring FileSystem::CreateTempFolder()\r\n{\r\n    std::wstring errorMessageW = L\"Could not get a temporary folder. Try specifying one in the command line.\";\r\n    std::string errorMessage(errorMessageW.begin(), errorMessageW.end());\r\n\r\n    wchar_t tmpDirRaw[MAX_PATH];\r\n    auto returnValue = GetTempPath(MAX_PATH, tmpDirRaw);\r\n    if (returnValue > MAX_PATH || (returnValue == 0))\r\n    {\r\n        throw std::runtime_error(errorMessage);\r\n    }\r\n\r\n    // Get a random folder to drop the files\r\n    GUID guid = { 0 };\r\n    if (FAILED(CoCreateGuid(&guid)))\r\n    {\r\n        throw std::runtime_error(errorMessage);\r\n    }\r\n\r\n    wchar_t guidRaw[MAX_PATH];\r\n    if (StringFromGUID2(guid, guidRaw, ARRAYSIZE(guidRaw)) == 0)\r\n    {\r\n        throw std::runtime_error(errorMessage);\r\n    }\r\n\r\n    return std::move(CreateSubFolder(tmpDirRaw, guidRaw));\r\n}"
  },
  {
    "path": "WindowsMRAssetConverter/FileSystem.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n#include <filesystem>\r\n\r\nnamespace FileSystem\r\n{\r\n    std::wstring GetRelativePathWithTrailingSeparator(std::wstring from, std::wstring to);\r\n    std::wstring GetBasePath(const std::wstring& path);\r\n    std::wstring GetFullPath(const std::wstring& path);\r\n    std::wstring CreateSubFolder(const std::wstring& parentPath, const std::wstring& subFolderName);\r\n    std::wstring CreateTempFolder();\r\n};\r\n\r\n"
  },
  {
    "path": "WindowsMRAssetConverter/README.md",
    "content": "# Windows Mixed Reality Asset Converter\r\n\r\nA command line tool to convert core GLTF 2.0 for use in the Windows Mixed Reality home, following the published [documentation](https://developer.microsoft.com/en-us/windows/mixed-reality/creating_3d_models_for_use_in_the_windows_mixed_reality_home).\r\n\r\nNote that this tool does not enforce any limits specified in the documentation (polygon count, texture size, etc.), so you might still encounter issues placing models if you do not conform to those limits.\r\n\r\n## Usage\r\nWindowsMRAssetConverter _&lt;path to GLTF/GLB&gt;_\r\n\r\n## Optional arguments\r\n- `-o <output file path>`\r\n  - Specifies the output file name and directory for the output GLB.\r\n  - If the file is a GLB and the output name is not specified, the tool defaults to the same name as input + \"_converted.glb\".\r\n\r\n- `-platform <all | desktop | holographic>`\r\n  - **Default:** `desktop` \r\n  - `desktop`: optimizes assets for immersive PC-based headsets using the [MSFT_packing_occlusionRoughnessMetallic](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_occlusionRoughnessMetallic) extension.\r\n  - `holographic`: optimizes assets for HoloLens using the [MSFT_packing_normalRoughnessMetallic](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_normalRoughnessMetallic) extension.\r\n  - `all`: creates assets optimized for both holographic and desktop devices, but with a larger file size.\r\n\r\n- `-min-version <1709 | 1803 | latest>`\r\n  - **Default:** `1709`\r\n  - Specifies the minimum version of Windows 10 supported by this asset.\r\n  - The current options are `1709` (Fall Creators Update) and `1803` (Spring Creators Update), as well as `latest` which is currently the same as `1803`.\r\n  - Supporting Windows 10 version 1709 results in assets with a larger file size. If your app is compatible with Windows 10 1803+ only, it is recommended to set `-min-version 1803`.\r\n  - This setting does not have any effect on the Holographic platform.\r\n\r\n- `-lod <path to each lower LOD asset in descending order of quality>`\r\n  - Specifies a list of assets that represent levels of detail, from higher to lower, that should be merged with the main asset and used as alternates when the asset is displayed from a distance (with limited screen coverage).\r\n\r\n- `-screen-coverage <LOD screen coverage values>`\r\n  - Specifies the maximum screen coverage values for each of the levels of detail, according to the [MSFT_lod](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod) extension specification.\r\n\r\n- `-share-materials`\r\n  - If enabled, creates assets that share materials between different levels of detail. \r\n  - This assumes all LOD documents use the same indices for each material, and uses the textures from the most detailed level.\r\n\r\n- `-temp-directory <temporary folder>`\r\n  - **Default:** system temp folder for the user\r\n  - Allows overriding the temporary folder where intermediate files (packed/compressed textures, converted GLBs) will be placed.\r\n\r\n- `-max-texture-size <Max texture size in pixels>`\r\n  - **Default:** 512\r\n  - Allows overriding the maximum texture dimension (width/height) when compressing textures. The recommended maximum dimension in the [documentation](https://developer.microsoft.com/en-us/windows/mixed-reality/creating_3d_models_for_use_in_the_windows_mixed_reality_home#texture_resolutions_and_workflow) is 512, and the allowed maximum is 4096.\r\n\r\n- `-replace-textures`\r\n  - If enabled, replaces all textures with their DDS compressed equivalents during the compression step. \r\n  - This results in a smaller file size, but the resulting file will not be compatible with most glTF viewers.\r\n\r\n\r\n## Example\r\n`WindowsMRAssetConverter FileToConvert.gltf -o ConvertedFile.glb -platform all -lod Lod1.gltf Lod2.gltf -screen-coverage 0.5 0.2 0.01`\r\n\r\nThe above will convert _FileToConvert.gltf_ into _ConvertedFile.glb_ in the current directory.\r\n\r\n## Pipeline overview\r\n\r\nEach asset goes through the following steps when converting for compatibility with the Windows Mixed Reality home:\r\n\r\n1. **Conversion from GLB** - Any GLB files are converted to loose glTF + assets, to simplify the code for reading resources\r\n1. **Texture packing** - The textures that are relevant for the Windows MR home are packed according to the [documentation](https://developer.microsoft.com/en-us/windows/mixed-reality/creating_3d_models_for_use_in_the_windows_mixed_reality_home#materials) using the [MSFT\\_packing\\_occlusionRoughnessMetallic](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_occlusionRoughnessMetallic) and [MSFT\\_packing\\_normalRoughnessMetallic](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_normalRoughnessMetallic) extensions as necessary\r\n1. **Texture compression** - All textures that are used in the Windows MR home must be compressed as DDS BC5 or BC7 according to the [documentation](https://developer.microsoft.com/en-us/windows/mixed-reality/creating_3d_models_for_use_in_the_windows_mixed_reality_home#materials). This step also generates mip maps for the textures, and resizes them down if necessary\r\n1. **LOD merging** - All assets that represent levels of detail are merged into the main asset using the [MSFT_lod](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod) extension\r\n1. **GLB export** - The resulting assets are exported as a GLB with all resources. As part of this step, accessors are modified to conform to the [glTF implementation notes in the documentation](https://developer.microsoft.com/en-us/windows/mixed-reality/creating_3d_models_for_use_in_the_windows_mixed_reality_home#gltf_implementation_notes): component types are converted to types supported by the Windows MR home, and the min and max values are calculated before serializing the accessors to the GLB\r\n\r\n## Additional resources\r\n\r\n- [Creating 3D models for use in the Windows Mixed Reality home](https://developer.microsoft.com/en-us/windows/mixed-reality/creating_3d_models_for_use_in_the_windows_mixed_reality_home)\r\n- [Microsoft glTF LOD Extension Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)\r\n- [PC Mixed Reality Texture Packing Extensions Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_occlusionRoughnessMetallic)\r\n- [Holographic Mixed Reality Texture Packing Extensions Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_normalRoughnessMetallic)\r\n- [Microsoft DDS Textures glTF extensions specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds)\r\n- [Implementing 3D app launchers](https://developer.microsoft.com/en-us/windows/mixed-reality/implementing_3d_app_launchers)\r\n- [Implementing 3D deep links for your app in the Windows Mixed Reality home](https://developer.microsoft.com/en-us/windows/mixed-reality/implementing_3d_deep_links_for_your_app_in_the_windows_mixed_reality_home)\r\n- [Navigating the Windows Mixed Reality home](https://developer.microsoft.com/en-us/windows/mixed-reality/navigating_the_windows_mixed_reality_home)\r\n"
  },
  {
    "path": "WindowsMRAssetConverter/WindowsMRAssetConverter.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"stdafx.h\"\r\n\r\n#include <GLTFSDK/GLTF.h>\r\n#include <GLTFSDK/Deserialize.h>\r\n#include <GLTFSDK/IStreamWriter.h>\r\n#include <GLTFSDK/GLBResourceReader.h>\r\n#include <GLTFSDK/ExtensionsKHR.h>\r\n#include <GLTFTexturePackingUtils.h>\r\n#include <GLTFTextureCompressionUtils.h>\r\n#include <GLTFSpecularGlossinessUtils.h>\r\n#include <GLTFLODUtils.h>\r\n#include <SerializeBinary.h>\r\n#include <GLBtoGLTF.h>\r\n#include <GLTFMeshCompressionUtils.h>\r\n\r\n#include \"CommandLine.h\"\r\n#include \"FileSystem.h\"\r\n#include \"GLTFTextureUtils.h\"\r\n\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\nclass GLTFStreamReader : public IStreamReader\r\n{\r\npublic:\r\n    GLTFStreamReader(std::wstring uriBase) : m_uriBase(uriBase) {}\r\n\r\n    virtual ~GLTFStreamReader() override {}\r\n    virtual std::shared_ptr<std::istream> GetInputStream(const std::string& filename) const override\r\n    {\r\n        std::wstring filenameW = std::wstring(filename.begin(), filename.end());\r\n\r\n        wchar_t uriAbsoluteRaw[MAX_PATH];\r\n        // Note: PathCchCombine will return the last argument if it's an absolute path\r\n        if (FAILED(::PathCchCombine(uriAbsoluteRaw, ARRAYSIZE(uriAbsoluteRaw), m_uriBase.c_str(), filenameW.c_str())))\r\n        {\r\n            throw std::invalid_argument(\"Could not get the base path for the GLTF resources. Try specifying the full path.\");\r\n        }\r\n\r\n        return std::make_shared<std::ifstream>(uriAbsoluteRaw, std::ios::binary);\r\n    }\r\nprivate:\r\n    const std::wstring m_uriBase;\r\n};\r\n\r\nclass GLBStreamWriter : public Microsoft::glTF::IStreamWriter\r\n{\r\npublic:\r\n    GLBStreamWriter(const std::wstring& filename) :\r\n        m_stream(std::make_shared<std::ofstream>(filename, std::ios_base::binary | std::ios_base::out))\r\n    { }\r\n\r\n    std::shared_ptr<std::ostream> GetOutputStream(const std::string&) const override\r\n    {\r\n        return m_stream;\r\n    }\r\n\r\nprivate:\r\n    std::shared_ptr<std::ofstream> m_stream;\r\n};\r\n\r\nDocument ProcessTextures(\r\n    size_t maxTextureSize, \r\n    TexturePacking packing, \r\n    bool retainOriginalImages, \r\n    const std::wstring& tempDirectory,\r\n    const Document& document, \r\n    const std::shared_ptr<GLTFStreamReader>& streamReader)\r\n{\r\n    Document resultDocument(document);\r\n\r\n    std::string tempDirectoryA(tempDirectory.begin(), tempDirectory.end());\r\n\r\n    std::wcout << L\"Specular Glossiness conversion...\" << std::endl;\r\n\r\n    // 0. Specular Glossiness conversion\r\n    resultDocument = GLTFSpecularGlossinessUtils::ConvertMaterials(streamReader, resultDocument, tempDirectoryA);\r\n\r\n    std::wcout << L\"Removing redundant textures and images...\" << std::endl;\r\n\r\n    // 1. Remove redundant textures and images\r\n    resultDocument = GLTFTextureUtils::RemoveRedundantTexturesAndImages(resultDocument);\r\n\r\n    std::wcout << L\"Packing textures...\" << std::endl;\r\n\r\n    // 2. Texture Packing\r\n    resultDocument = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(streamReader, resultDocument, packing, tempDirectoryA);\r\n\r\n    std::wcout << L\"Compressing textures - this can take a few minutes...\" << std::endl;\r\n\r\n    // 3. Texture Compression\r\n    resultDocument = GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(streamReader, resultDocument, tempDirectoryA, maxTextureSize, retainOriginalImages);\r\n\r\n    return resultDocument;\r\n}\r\n\r\nDocument LoadAndConvertDocumentForWindowsMR(\r\n    std::wstring& inputFilePath,\r\n    AssetType inputAssetType,\r\n    const std::wstring& tempDirectory,\r\n    bool meshCompression)\r\n{\r\n    // Load the document\r\n    std::experimental::filesystem::path inputFilePathFS(inputFilePath);\r\n    std::wstring inputFileName = inputFilePathFS.filename();\r\n    std::wcout << L\"Loading input document: \" << inputFileName << L\"...\" << std::endl;\r\n\r\n    std::string tempDirectoryA(tempDirectory.begin(), tempDirectory.end());\r\n\r\n    if (inputAssetType == AssetType::GLB)\r\n    {\r\n        // Convert the GLB to GLTF in the temp directory\r\n\r\n        std::string inputFilePathA(inputFilePath.begin(), inputFilePath.end());\r\n\r\n        // inputGltfName is the path to the converted GLTF without extension\r\n        std::wstring inputGltfName = inputFilePathFS.stem();\r\n        std::string inputGltfNameA = std::string(inputGltfName.begin(), inputGltfName.end());\r\n\r\n        GLBToGLTF::UnpackGLB(inputFilePathA, tempDirectoryA, inputGltfNameA);\r\n\r\n        inputFilePath = tempDirectory + inputGltfName + EXTENSION_GLTF;\r\n    }\r\n\r\n    auto stream = std::make_shared<std::ifstream>(inputFilePath, std::ios::in);\r\n    Document document = Deserialize(*stream, KHR::GetKHRExtensionDeserializer());\r\n\r\n    // Get the base path from where to read all the assets\r\n\r\n    auto streamReader = std::make_shared<GLTFStreamReader>(FileSystem::GetBasePath(inputFilePath));\r\n\r\n    if (meshCompression)\r\n    {\r\n        std::wcout << L\"Compressing meshes - this can take a few minutes...\" << std::endl;\r\n\r\n        document = GLTFMeshCompressionUtils::CompressMeshes(streamReader, document, {}, tempDirectoryA);\r\n    }\r\n\r\n    return document;\r\n}\r\n\r\nint wmain(int argc, wchar_t *argv[])\r\n{\r\n    if (argc < 2)\r\n    {\r\n        CommandLine::PrintHelp();\r\n        return 0;\r\n    }\r\n\r\n    // Initialize COM\r\n    CoInitialize(NULL);\r\n\r\n    try\r\n    {\r\n        // Arguments\r\n        std::wstring inputFilePath;\r\n        AssetType inputAssetType;\r\n        std::wstring outFilePath;\r\n        std::wstring tempDirectory;\r\n        std::vector<std::wstring> lodFilePaths;\r\n        std::vector<double> screenCoveragePercentages;\r\n        size_t maxTextureSize;\r\n        bool shareMaterials;\r\n        CommandLine::Version minVersion;\r\n        CommandLine::Platform targetPlatforms;\r\n        bool replaceTextures;\r\n        bool meshCompression = false;\r\n\r\n        CommandLine::ParseCommandLineArguments(\r\n            argc, argv, inputFilePath, inputAssetType, outFilePath, tempDirectory, lodFilePaths, screenCoveragePercentages, \r\n            maxTextureSize, shareMaterials, minVersion, targetPlatforms, replaceTextures, meshCompression);\r\n\r\n        TexturePacking packing = TexturePacking::None;\r\n\r\n        std::wstring compatibleVersionsText;\r\n\r\n        if ((targetPlatforms & CommandLine::Platform::Holographic) > 0)\r\n        {\r\n            compatibleVersionsText += L\"HoloLens\";\r\n\r\n            // Holographic mode: NRM\r\n            packing = (TexturePacking)(packing | TexturePacking::NormalRoughnessMetallic);\r\n        }\r\n\r\n        if ((targetPlatforms & CommandLine::Platform::Desktop) > 0)\r\n        {\r\n            if (!compatibleVersionsText.empty())\r\n            {\r\n                compatibleVersionsText += L\" and \";\r\n            }\r\n\r\n            // Desktop 1803+ mode: ORM\r\n            packing = (TexturePacking)(packing | TexturePacking::OcclusionRoughnessMetallic);\r\n\r\n            if (minVersion == CommandLine::Version::Version1709)\r\n            {\r\n                // Desktop 1709 mode: RMO\r\n                packing = (TexturePacking)(packing | TexturePacking::RoughnessMetallicOcclusion);\r\n\r\n                compatibleVersionsText += L\"Desktop (version 1709+)\";\r\n            }\r\n            else if (minVersion == CommandLine::Version::Version1803)\r\n            {\r\n                compatibleVersionsText +=  L\"Desktop (version 1803+)\";\r\n            }\r\n            else\r\n            {\r\n                compatibleVersionsText += L\"Desktop (version 1809+)\";\r\n            }\r\n        }\r\n\r\n        std::wcout << L\"\\nThis will generate an asset compatible with \" << compatibleVersionsText << L\"\\n\" << std::endl;\r\n\r\n        // Load document, and perform steps:\r\n        // 1. Mesh Compression\r\n        auto document = LoadAndConvertDocumentForWindowsMR(inputFilePath, inputAssetType, tempDirectory, meshCompression);\r\n\r\n        // 2. LOD Merging\r\n        if (!lodFilePaths.empty())\r\n        {\r\n            std::wcout << L\"Merging LODs...\" << std::endl;\r\n\r\n            std::vector<Document> lodDocuments;\r\n            std::vector<std::wstring> lodDocumentRelativePaths;\r\n            lodDocuments.push_back(document);\r\n\r\n            for (size_t i = 0; i < lodFilePaths.size(); i++)\r\n            {\r\n                // Apply the same optimizations for each LOD\r\n                auto lod = lodFilePaths[i];\r\n                auto subFolder = FileSystem::CreateSubFolder(tempDirectory, L\"lod\" + std::to_wstring(i + 1));\r\n\r\n                lodDocuments.push_back(LoadAndConvertDocumentForWindowsMR(lod, AssetTypeUtils::AssetTypeFromFilePath(lod), subFolder, meshCompression));\r\n            \r\n                lodDocumentRelativePaths.push_back(FileSystem::GetRelativePathWithTrailingSeparator(FileSystem::GetBasePath(inputFilePath), FileSystem::GetBasePath(lod)));\r\n            }\r\n\r\n            document = GLTFLODUtils::MergeDocumentsAsLODs(lodDocuments, screenCoveragePercentages, lodDocumentRelativePaths, shareMaterials);\r\n        }\r\n\r\n        // 3. Texture Packing\r\n        // 4. Texture Compression\r\n        auto streamReader = std::make_shared<GLTFStreamReader>(FileSystem::GetBasePath(inputFilePath));\r\n        document = ProcessTextures(maxTextureSize, packing, !replaceTextures, tempDirectory, document, streamReader);\r\n\r\n        // 5. Make sure there's a default scene\r\n        if (!document.HasDefaultScene())\r\n        {\r\n            document.defaultSceneId = document.scenes.Elements()[0].id;\r\n        }\r\n\r\n        // 6. GLB Export\r\n        std::wcout << L\"Exporting as GLB...\" << std::endl;\r\n\r\n        // The Windows MR Fall Creators update has restrictions on the supported\r\n        // component types of accessors.\r\n        AccessorConversionStrategy accessorConversion = [](const Accessor& accessor)\r\n        {\r\n            if (accessor.type == AccessorType::TYPE_SCALAR)\r\n            {\r\n                switch (accessor.componentType)\r\n                {\r\n                case ComponentType::COMPONENT_BYTE:\r\n                case ComponentType::COMPONENT_UNSIGNED_BYTE:\r\n                case ComponentType::COMPONENT_SHORT:\r\n                    return ComponentType::COMPONENT_UNSIGNED_SHORT;\r\n                default:\r\n                    return accessor.componentType;\r\n                }\r\n            }\r\n            else if (accessor.type == AccessorType::TYPE_VEC2 || accessor.type == AccessorType::TYPE_VEC3)\r\n            {\r\n                return ComponentType::COMPONENT_FLOAT;\r\n            }\r\n\r\n            return accessor.componentType;\r\n        };\r\n\r\n        SerializeBinary(document, streamReader, std::make_shared<GLBStreamWriter>(outFilePath), accessorConversion);\r\n\r\n        std::wcout << L\"Done!\" << std::endl;\r\n        std::wcout << L\"Output file: \" << outFilePath << std::endl;\r\n    }\r\n    catch (std::exception ex)\r\n    {\r\n        std::cerr << ex.what() << std::endl;\r\n        return 1;\r\n    }\r\n\r\n    return 0;\r\n}"
  },
  {
    "path": "WindowsMRAssetConverter/WindowsMRAssetConverter.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <VCProjectVersion>15.0</VCProjectVersion>\r\n    <ProjectGuid>{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}</ProjectGuid>\r\n    <Keyword>Win32Proj</Keyword>\r\n    <RootNamespace>WindowsMRAssetConverter</RootNamespace>\r\n    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc</AdditionalIncludeDirectories>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <AdditionalOptions>/permissive- %(AdditionalOptions)</AdditionalOptions>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <AdditionalDependencies>d3d11.lib;dxgi.lib;pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc</AdditionalIncludeDirectories>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <AdditionalOptions>/permissive- %(AdditionalOptions)</AdditionalOptions>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <AdditionalDependencies>d3d11.lib;dxgi.lib;pathcch.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc</AdditionalIncludeDirectories>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <AdditionalOptions>/permissive- %(AdditionalOptions)</AdditionalOptions>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <AdditionalDependencies>d3d11.lib;dxgi.lib;pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc</AdditionalIncludeDirectories>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <AdditionalOptions>/permissive- %(AdditionalOptions)</AdditionalOptions>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <AdditionalDependencies>d3d11.lib;dxgi.lib;pathcch.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"AssetType.h\" />\r\n    <ClInclude Include=\"CommandLine.h\" />\r\n    <ClInclude Include=\"FileSystem.h\" />\r\n    <ClInclude Include=\"stdafx.h\" />\r\n    <ClInclude Include=\"targetver.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"CommandLine.cpp\" />\r\n    <ClCompile Include=\"FileSystem.cpp\" />\r\n    <ClCompile Include=\"AssetType.cpp\" />\r\n    <ClCompile Include=\"stdafx.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"WindowsMRAssetConverter.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\glTF-Toolkit\\glTF-Toolkit.vcxproj\">\r\n      <Project>{ff0275f1-58cb-4745-ba81-f6c1df66e206}</Project>\r\n      <UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>\r\n    </ProjectReference>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"README.md\" />\r\n    <None Include=\"packages.config\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n    <Import Project=\"$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets\" Condition=\"Exists('$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets')\" />\r\n  </ImportGroup>\r\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\r\n    <PropertyGroup>\r\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>\r\n    </PropertyGroup>\r\n    <Error Condition=\"!Exists('$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets'))\" />\r\n  </Target>\r\n</Project>"
  },
  {
    "path": "WindowsMRAssetConverter/WindowsMRAssetConverter.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Source Files\">\r\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Header Files\">\r\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Resource Files\">\r\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"stdafx.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"targetver.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"AssetType.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"CommandLine.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"FileSystem.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"stdafx.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"WindowsMRAssetConverter.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"CommandLine.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"FileSystem.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"AssetType.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"packages.config\" />\r\n    <None Include=\"README.md\" />\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "WindowsMRAssetConverter/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<packages>\r\n  <package id=\"directxtex_desktop_2015\" version=\"2018.8.5.1\" targetFramework=\"native\" />\r\n  <package id=\"draco.CPP\" version=\"1.3.3.1\" targetFramework=\"native\" />\r\n  <package id=\"Microsoft.glTF.CPP\" version=\"1.6.1.0\" targetFramework=\"native\" />\r\n  <package id=\"rapidjson.temprelease\" version=\"0.0.2.20\" targetFramework=\"native\" />\r\n</packages>"
  },
  {
    "path": "WindowsMRAssetConverter/stdafx.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"stdafx.h\""
  },
  {
    "path": "WindowsMRAssetConverter/stdafx.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n// Use the C++ standard templated min/max\r\n#define NOMINMAX\r\n\r\n// DirectX apps don't need GDI\r\n#define NODRAWTEXT\r\n#define NOGDI\r\n#define NOBITMAP\r\n\r\n// Include <mcx.h> if you need this\r\n#define NOMCX\r\n\r\n// Include <winsvc.h> if you need this\r\n#define NOSERVICE\r\n\r\n// WinHelp is deprecated\r\n#define NOHELP\r\n\r\n#define WIN32_LEAN_AND_MEAN\r\n#include <windows.h>\r\n#include <wincodec.h>\r\n#include <pathcch.h>\r\n#include <shlwapi.h>\r\n\r\n#include <wrl/client.h>\r\n\r\n#include <d3d11_1.h>\r\n#include <dxgi1_2.h>\r\n#include <DirectXMath.h>\r\n#include <DirectXColors.h>\r\n\r\n#include <algorithm>\r\n#include <exception>\r\n#include <memory>\r\n#include <stdexcept>\r\n#include <fstream>\r\n#include <iostream>\r\n#include <sstream>\r\n#include <set>\r\n\r\n#include <stdio.h>"
  },
  {
    "path": "WindowsMRAssetConverter/targetver.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n// Including SDKDDKVer.h defines the highest available Windows platform.\r\n\r\n// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and\r\n// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.\r\n\r\n#include <SDKDDKVer.h>\r\n"
  },
  {
    "path": "glTF-Toolkit/glTF-Toolkit.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|ARM\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>ARM</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|ARM\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>ARM</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug Static Runtime|ARM\">\r\n      <Configuration>Debug Static Runtime</Configuration>\r\n      <Platform>ARM</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug Static Runtime|Win32\">\r\n      <Configuration>Debug Static Runtime</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release Static Runtime|ARM\">\r\n      <Configuration>Release Static Runtime</Configuration>\r\n      <Platform>ARM</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release Static Runtime|Win32\">\r\n      <Configuration>Release Static Runtime</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug Static Runtime|x64\">\r\n      <Configuration>Debug Static Runtime</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release Static Runtime|x64\">\r\n      <Configuration>Release Static Runtime</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <VCProjectVersion>15.0</VCProjectVersion>\r\n    <ProjectGuid>{FF0275F1-58CB-4745-BA81-F6C1DF66E206}</ProjectGuid>\r\n    <Keyword>Win32Proj</Keyword>\r\n    <RootNamespace>glTFToolkit</RootNamespace>\r\n    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Label=\"Configuration\">\r\n    <ConfigurationType>StaticLibrary</ConfigurationType>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)'=='Debug' Or '$(Configuration)'=='Debug Static Runtime'\" Label=\"Configuration\">\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release' Or '$(Configuration)'=='Release Static Runtime'\" Label=\"Configuration\">\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Platform)'=='ARM'\" Label=\"Configuration\">\r\n    <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\" />\r\n  <ImportGroup Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release' Or '$(Configuration)'=='Release Static Runtime'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)'=='Debug' Or '$(Configuration)'=='Debug Static Runtime'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup>\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <AdditionalIncludeDirectories>inc;%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories>\r\n      <AdditionalOptions>/permissive- %(AdditionalOptions)</AdditionalOptions>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n      <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <RuntimeLibrary Condition=\"'$(Configuration)'=='Release Static Runtime'\">MultiThreaded</RuntimeLibrary>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)'=='Debug' Or '$(Configuration)'=='Debug Static Runtime'\">\r\n    <ClCompile>\r\n      <Optimization>Disabled</Optimization>\r\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <RuntimeLibrary Condition=\"'$(Configuration)'=='Debug Static Runtime'\">MultiThreadedDebug</RuntimeLibrary>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)'=='Release' Or '$(Configuration)'=='Release Static Runtime'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Platform)'=='x86'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <None Include=\"packages.config\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"inc\\AccessorUtils.h\" />\r\n    <ClInclude Include=\"inc\\DeviceResources.h\" />\r\n    <ClInclude Include=\"inc\\GLBtoGLTF.h\" />\r\n    <ClInclude Include=\"inc\\GLTFLODUtils.h\" />\r\n    <ClInclude Include=\"inc\\GLTFMeshCompressionUtils.h\" />\r\n    <ClInclude Include=\"inc\\GLTFSDK.h\" />\r\n    <ClInclude Include=\"inc\\GLTFSpecularGlossinessUtils.h\" />\r\n    <ClInclude Include=\"inc\\GLTFTextureCompressionUtils.h\" />\r\n    <ClInclude Include=\"inc\\GLTFTextureUtils.h\" />\r\n    <ClInclude Include=\"inc\\GLTFTexturePackingUtils.h\" />\r\n    <ClInclude Include=\"inc\\pch.h\" />\r\n    <ClInclude Include=\"inc\\SerializeBinary.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"src\\GLTFMeshCompressionUtils.cpp\" />\r\n    <ClCompile Include=\"src\\DeviceResources.cpp\" />\r\n    <ClCompile Include=\"src\\GLBtoGLTF.cpp\" />\r\n    <ClCompile Include=\"src\\GLTFLODUtils.cpp\" />\r\n    <ClCompile Include=\"src\\GLTFSpecularGlossinessUtils.cpp\" />\r\n    <ClCompile Include=\"src\\GLTFTextureCompressionUtils.cpp\" />\r\n    <ClCompile Include=\"src\\GLTFTextureUtils.cpp\" />\r\n    <ClCompile Include=\"src\\GLTFTexturePackingUtils.cpp\" />\r\n    <ClCompile Include=\"src\\pch.cpp\">\r\n      <PrecompiledHeader>Create</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\SerializeBinary.cpp\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n    <Import Project=\"$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets\" Condition=\"Exists('$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets')\" />\r\n  </ImportGroup>\r\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\r\n    <PropertyGroup>\r\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>\r\n    </PropertyGroup>\r\n    <Error Condition=\"!Exists('$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets'))\" />\r\n  </Target>\r\n</Project>"
  },
  {
    "path": "glTF-Toolkit/glTF-Toolkit.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <None Include=\"packages.config\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Filter Include=\"inc\">\r\n      <UniqueIdentifier>{2156fb82-8d5e-4cc3-b2ac-e13a18bc665f}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"src\">\r\n      <UniqueIdentifier>{620de9b6-9c44-44b6-9d93-99834c5efdf2}</UniqueIdentifier>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"inc\\DeviceResources.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\GLTFLODUtils.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\GLTFTextureCompressionUtils.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\GLTFTexturePackingUtils.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\SerializeBinary.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\pch.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\GLBtoGLTF.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\AccessorUtils.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\GLTFSDK.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\GLTFMeshCompressionUtils.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\GLTFSpecularGlossinessUtils.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"inc\\GLTFTextureUtils.h\">\r\n      <Filter>inc</Filter>\r\n    </ClInclude>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"src\\DeviceResources.cpp\">\r\n      <Filter>src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\GLTFLODUtils.cpp\">\r\n      <Filter>src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\GLTFTextureCompressionUtils.cpp\">\r\n      <Filter>src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\GLTFTexturePackingUtils.cpp\">\r\n      <Filter>src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\SerializeBinary.cpp\">\r\n      <Filter>src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\pch.cpp\">\r\n      <Filter>src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\GLBtoGLTF.cpp\">\r\n      <Filter>src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\GLTFMeshCompressionUtils.cpp\">\r\n      <Filter>src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\GLTFSpecularGlossinessUtils.cpp\">\r\n      <Filter>src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\GLTFTextureUtils.cpp\">\r\n      <Filter>src</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "glTF-Toolkit/inc/AccessorUtils.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See LICENSE in the project root for license information.\n\n#pragma once\n\n#include \"GLTFSDK.h\"\n#include <functional>\n#include <vector>\n\nnamespace Microsoft::glTF::Toolkit\n{\n    /// <summary>\n    /// Utilities to manipulate accessors in a glTF asset.\n    /// </summary>\n    class AccessorUtils\n    {\n    public:\n        // Note: XML Documentation cannot be applied to templated types per https://docs.microsoft.com/en-us/cpp/ide/xml-documentation-visual-cpp\n        // Calculates the min and max values for an accessor according to the glTF 2.0 specification.\n        // accessor is: The accessor definition for which the min and max values will be calculated.</param>\n        // accessorContents is: The raw data contained in the accessor.\n        // returns: A pair containing the min and max vectors for the accessor, in that order.\n        template <typename T>\n        static std::pair<std::vector<float>, std::vector<float>> CalculateMinMax(const Accessor& accessor, const std::vector<T>& accessorContents)\n        {\n            auto typeCount = Accessor::GetTypeCount(accessor.type);\n            auto min = std::vector<float>(typeCount);\n            auto max = std::vector<float>(typeCount);\n\n            if (accessorContents.size() < typeCount)\n            {\n                throw std::invalid_argument(\"The accessor must contain data in order to calculate min and max.\");\n            }\n\n            // Initialize min and max with the first elements of the array\n            for (size_t j = 0; j < typeCount; j++)\n            {\n                auto current = static_cast<float>(accessorContents[j]);\n                min[j] = current;\n                max[j] = current;\n            }\n\n            for (size_t i = 1; i < accessor.count; i++)\n            {\n                for (size_t j = 0; j < typeCount; j++)\n                {\n                    auto current = static_cast<float>(accessorContents[i * typeCount + j]);\n                    min[j] = std::min(min[j], current);\n                    max[j] = std::max(max[j], current);\n                }\n            }\n\n            return std::make_pair(min, max);\n        }\n    };\n}\n\n"
  },
  {
    "path": "glTF-Toolkit/inc/DeviceResources.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\nnamespace DX\r\n{\r\n    /// <summary>\r\n    /// Controls all the DirectX device resources.\r\n    /// </summary>\r\n    class DeviceResources\r\n    {\r\n    public:\r\n        DeviceResources(D3D_FEATURE_LEVEL minFeatureLevel = D3D_FEATURE_LEVEL_10_0);\r\n\r\n        void CreateDeviceResources();\r\n        void HandleDeviceLost();\r\n\r\n        // Direct3D Accessors.\r\n        ID3D11Device1*          GetD3DDevice() const                    { return m_d3dDevice.Get(); }\r\n        ID3D11DeviceContext1*   GetD3DDeviceContext() const             { return m_d3dContext.Get(); }\r\n        IDXGISwapChain1*        GetSwapChain() const                    { return m_swapChain.Get(); }\r\n        D3D_FEATURE_LEVEL       GetDeviceFeatureLevel() const           { return m_d3dFeatureLevel; }\r\n\r\n    private:\r\n        void GetHardwareAdapter(IDXGIAdapter1** ppAdapter);\r\n\r\n        // Direct3D objects.\r\n        Microsoft::WRL::ComPtr<ID3D11Device1>               m_d3dDevice;\r\n        Microsoft::WRL::ComPtr<ID3D11DeviceContext1>        m_d3dContext;\r\n        Microsoft::WRL::ComPtr<IDXGISwapChain1>             m_swapChain;\r\n        Microsoft::WRL::ComPtr<ID3DUserDefinedAnnotation>   m_d3dAnnotation;\r\n\r\n        // Direct3D properties.\r\n        D3D_FEATURE_LEVEL                               m_d3dMinFeatureLevel;\r\n\r\n        // Cached device properties.\r\n        D3D_FEATURE_LEVEL                               m_d3dFeatureLevel;\r\n    };\r\n\r\n    // Helper class for COM exceptions\r\n    class com_exception : public std::exception\r\n    {\r\n    public:\r\n        com_exception(HRESULT hr) : result(hr) {}\r\n\r\n        virtual const char* what() const override\r\n        {\r\n            static char s_str[64] = { 0 };\r\n            sprintf_s(s_str, \"Failure with HRESULT of %08X\", result);\r\n            return s_str;\r\n        }\r\n\r\n    private:\r\n        HRESULT result;\r\n    };\r\n\r\n    // Helper utility converts D3D API failures into exceptions.\r\n    inline void ThrowIfFailed(HRESULT hr)\r\n    {\r\n        if (FAILED(hr))\r\n        {\r\n            throw com_exception(hr);\r\n        }\r\n    }\r\n\r\n}"
  },
  {
    "path": "glTF-Toolkit/inc/GLBtoGLTF.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n#include \"GLTFSDK.h\"\r\n\r\nnamespace Microsoft::glTF::Toolkit\r\n{\r\n    /// <summary>\r\n    /// Utilities to convert glTF-Binary files (GLB) to\r\n    /// unpacked glTF assets.\r\n    /// </summary>\r\n    class GLBToGLTF\r\n    {\r\n    public:\r\n        /// <summary>\r\n        /// Unpacks a GLB asset into a GLTF manifest and its \r\n        /// resources (bin files and images).\r\n        /// </summary>\r\n        /// <param name=\"glbPath\">The path to the GLB file to unpack.</param>\r\n        /// <param name=\"outDirectory\">The directory to which the glTF manifest and resources will be unpacked.</param>\r\n        /// <param name=\"gltfName\">\r\n        /// The name of the output glTF manifest file, without the extension. \r\n        /// This name will be used as a prefix to all unpacked resources.\r\n        /// </param>\r\n        static void UnpackGLB(const std::string& glbPath, const std::string& outDirectory, const std::string& gltfName);\r\n\r\n        /// <summary>\r\n        /// Extracts the contents of all buffer views from a GLB file into a \r\n        /// byte vector that can be saves as a bin file to be used in a glTF file.\r\n        /// </summary>\r\n        /// <param name=\"in\">A stream pointing to the GLB file.</param>\r\n        /// <param name=\"glbDoc\">The manifest describing the GLB asset.</param>\r\n        /// <param name=\"bufferOffset\">The offset on the input file where the GLB buffer starts.</param>\r\n        /// <param name=\"newBufferLength\">The length of the new buffer (sum of all buffer view lengths).</param>\r\n        /// <returns>\r\n        /// The binary content of the buffer views as a vector.\r\n        /// </returns>\r\n        static std::vector<char> SaveBin(std::istream* in, const Microsoft::glTF::Document& glbDoc, const size_t bufferOffset, const size_t newBufferlength, std::unordered_set<std::string>& unpackedBufferViews);\r\n\r\n        /// <summary>\r\n        /// Loads all images in a glTF-Binary (GLB) asset into a map relating each image identifier to the contents of that image.\r\n        /// </summary>\r\n        /// <param name=\"in\">A stream pointing to the GLB file.</param>\r\n        /// <param name=\"glbDoc\">The manifest describing the GLB asset.</param>\r\n        /// <param name=\"name\">The name that should be used when creating the identifiers for the image files.</param>\r\n        /// <param name=\"bufferOffset\">The offset on the input file where the GLB buffer starts.</param>\r\n        /// <returns>\r\n        /// A map relating each image identifier to the contents of that image.\r\n        /// </returns>\r\n        static std::unordered_map<std::string, std::vector<char>> GetImagesData(std::istream* in, const Microsoft::glTF::Document& glbDoc, const std::string& name, const size_t bufferOffset);\r\n\r\n        /// <summary>\r\n        /// Creates the glTF manifest that represents a GLB file after unpacking.\r\n        /// </summary>\r\n        /// <param name=\"glbDoc\">The original manifest contained in the GLB file.</param>\r\n        /// <param name=\"name\">The name that should be used when creating the identifiers for the image and bin files when unpacking.</param>\r\n        /// <returns>\r\n        /// A new glTF manifest that represents the same file, but with images and resources referenced by URI instead of embedded ina GLB buffer.\r\n        /// </returns>\r\n        static Microsoft::glTF::Document CreateGLTFDocument(const Microsoft::glTF::Document& glbDoc, const std::string& name, std::unordered_set<std::string>& unpackedBufferViews);\r\n    };\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit/inc/GLTFLODUtils.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n#include \"GLTFSDK.h\"\r\n\r\nnamespace Microsoft::glTF::Toolkit\r\n{\r\n    extern const char* EXTENSION_MSFT_LOD;\r\n    extern const char* MSFT_LOD_IDS_KEY;\r\n    typedef std::unordered_map<std::string, std::shared_ptr<std::vector<std::string>>> LODMap;\r\n\r\n    /// <summary>\r\n    /// Utilities to load and merge levels of detail (LOD) in glTF assets using the MSFT_lod extension.\r\n    /// </summary>\r\n    class GLTFLODUtils\r\n    {\r\n    public:\r\n        /// <summary>\r\n        /// Parses the node LODs in a GLTF asset as a map that can be used to read LOD values for each node.\r\n        /// </summary>\r\n        /// <returns>A map that relates each node ID to a vector of its levels of detail node IDs.</returns>\r\n        /// <param name=\"doc\">The glTF document containing LODs to be parsed.</param>\r\n        static LODMap ParseDocumentNodeLODs(const Document& doc);\r\n\r\n        /// <summary>\r\n        /// Inserts each LOD Document as a node LOD (at the root level) of the specified primary GLTF asset.\r\n        /// Note: Animation is not currently supported.\r\n        /// </summary>\r\n        /// <returns>The primary GLTF Document with the inserted LOD node.</returns>\r\n        /// <param name=\"docs\">A vector of glTF documents to merge as LODs. The first element of the vector is assumed to be the primary LOD.</param>\r\n        /// <param name=\"relativePaths\">A vector of relative path prefixes to the non-LOD0 LOD gltf documents. Used for finding resources in those LODs.\r\n        /// If not specified, all resources are assumed to be in the same directory.</param>\r\n        static Document MergeDocumentsAsLODs(const std::vector<Document>& docs, const std::vector<std::wstring>& relativePaths = std::vector<std::wstring>(), const bool& sharedMaterials = false);\r\n\r\n        /// <summary>\r\n        /// Inserts each LOD Document as a node LOD (at the root level) of the specified primary GLTF asset.\r\n        /// Note: Animation is not currently supported.\r\n        /// </summary>\r\n        /// <returns>The primary GLTF Document with the inserted LOD node.</returns>\r\n        /// <param name=\"docs\">A vector of glTF documents to merge as LODs. The first element of the vector is assumed to be the primary LOD.</param>\r\n        /// <param name=\"screenCoveragePercentages\">A vector with the screen coverage percentages corresponding to each LOD. If the size of this \r\n        /// vector is larger than the size of <see name=\"docs\" />, lower coverage values will cause the asset to be invisible.</param>\r\n        /// <param name=\"relativePaths\">A vector of relative path prefixes to the non-LOD0 LOD gltf documents. Used for finding resources in those LODs.\r\n        /// If not specified, all resources are assumed to be in the same directory.</param>\r\n        static Document MergeDocumentsAsLODs(const std::vector<Document>& docs, const std::vector<double>& screenCoveragePercentages, const std::vector<std::wstring>& relativePaths = std::vector<std::wstring>(), const bool& sharedMaterials = false);\r\n\r\n        /// <summary>\r\n        /// Determines the highest number of Node LODs for a given glTF asset.\r\n        /// </summary>\r\n        /// <param name=\"doc\">The glTF asset for which to count the max number of node LODs.</param>\r\n        /// <param name=\"lods\">A map containing the parsed node LODs in the document.</param>\r\n        /// <returns>The highest number of Node LODs in the asset.</returns>\r\n        static uint32_t NumberOfNodeLODLevels(const Document& doc, const LODMap& lods);\r\n    };\r\n}\r\n\r\n"
  },
  {
    "path": "glTF-Toolkit/inc/GLTFMeshCompressionUtils.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See LICENSE in the project root for license information.\n\n#pragma once\n\n#include \"GLTFSDK.h\"\n#include \"GLTFSDK/BufferBuilder.h\"\n\nnamespace Microsoft::glTF::Toolkit\n{\n    /// <summary>Draco compression options.</summary>\n    struct CompressionOptions\n    {\n        int PositionQuantizationBits = 14;\n        int TexCoordQuantizationBits = 12;\n        int NormalQuantizationBits = 10;\n        int ColorQuantizationBits = 8;\n        int GenericQuantizationBits = 12;\n        int Speed = 3;\n    };\n\n    /// <summary>\n    /// Utilities to compress textures in a glTF asset.\n    /// </summary>\n    class GLTFMeshCompressionUtils\n    {\n    public:\n        /// <summary>\n        /// Applies <see cref=\"CompressMesh\" /> to every mesh in the document, following the same parameter structure as that function.\n        /// </summary>\n        /// <param name=\"streamReader\">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>\n        /// <param name=\"doc\">The document from which the mesh will be loaded.</param>\n        /// <param name=\"options\">The compression options that will be used.</param>\n        /// <param name=\"outputDirectory\">The output directory to which compressed data should be saved.</param>\n        /// <returns>\n        /// A new glTF manifest that uses the KHR_draco_mesh_compression extension to point to the compressed meshes.\n        /// </returns>\n        static Document CompressMeshes(\n            std::shared_ptr<IStreamReader> streamReader,\n            const Document & doc,\n            CompressionOptions options,\n            const std::string& outputDirectory);\n\n        /// <summary>\n        /// Applies Draco mesh compression to the supplied mesh and creates a new set of vertex buffers for all the primitive attributes.\n        /// </summary>\n        /// <param name=\"streamReader\">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>\n        /// <param name=\"doc\">The document from which the mesh will be loaded.</param>\n        /// <param name=\"mesh\">The mesh which the mesh will be compressed.</param>\n        /// <param name=\"options\">The compression options that will be used.</param>\n        /// <param name=\"builder\">The output buffer builder that handles bufferId generation for the return document.</param>\n        /// <param name=\"bufferViewsToRemove\">Out parameter of BufferView Ids that are no longer in use and should be removed.</param>\n        /// <returns>\n        /// A new glTF manifest that uses the KHR_draco_mesh_compression extension to point to the compressed meshes.\n        /// </returns>\n        static Document CompressMesh(\n            std::shared_ptr<IStreamReader> streamReader,\n            const Document & doc,\n            CompressionOptions options,\n            const Mesh & mesh,\n            BufferBuilder* builder,\n            std::unordered_set<std::string>& bufferViewsToRemove);\n    };\n}"
  },
  {
    "path": "glTF-Toolkit/inc/GLTFSDK.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See LICENSE in the project root for license information.\n\n#pragma once\n\n#pragma warning(push)\n#pragma warning(disable : 4634)\n#pragma warning(disable : 4996)\n\n#include <GLTFSDK/Document.h>\n#include <GLTFSDK/Deserialize.h>\n#include <GLTFSDK/Serialize.h>\n#include <GLTFSDK/GLTFResourceWriter.h>\n#include <GLTFSDK/GLBResourceReader.h>\n#include <GLTFSDK/GLTFResourceReader.h>\n#include <GLTFSDK/IStreamReader.h>\n#include <GLTFSDK/RapidJsonUtils.h>\n#include <GLTFSDK/GLTF.h>\n#include <GLTFSDK/Constants.h>\n\n#pragma warning(pop)"
  },
  {
    "path": "glTF-Toolkit/inc/GLTFSpecularGlossinessUtils.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See LICENSE in the project root for license information.\n\n#pragma once\n\n#include \"GLTFSDK.h\"\n\nnamespace Microsoft::glTF::Toolkit\n{\n    /// <summary>\n    /// Utilities to remove Specular Glossiness from a glTF asset.\n    /// </summary>\n    class GLTFSpecularGlossinessUtils\n    {\n    public:\n        /// <summary>\n        /// Applies <see cref=\"ConvertMaterial\" /> to every material in the document, following the same parameter structure as that function.\n        /// </summary>\n        /// <param name=\"streamReader\">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>\n        /// <param name=\"doc\">The document from which the mesh will be loaded.</param>\n        /// <param name=\"outputDirectory\">The output directory to which compressed data should be saved.</param>\n        /// <returns>\n        /// A new glTF manifest without the KHR_materials_pbrSpecularGlossiness extension.\n        /// </returns>\n        static Document ConvertMaterials(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const std::string& outputDirectory);\n\n        /// <summary>\n        /// Removes the KHR_materials_pbrSpecularGlossiness extension by converting the parameters to Metal Roughness.\n        /// </summary>\n        /// <param name=\"streamReader\">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>\n        /// <param name=\"doc\">The document from which the mesh will be loaded.</param>\n        /// <param name=\"material\">The material to be converted.</param>\n        /// <param name=\"outputDirectory\">The output directory to which compressed data should be saved.</param>\n        /// <returns>\n        /// A new glTF manifest without the KHR_materials_pbrSpecularGlossiness extension.\n        /// </returns>\n        static Document ConvertMaterial(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const Material & material, const std::string& outputDirectory);\n\n    };\n}"
  },
  {
    "path": "glTF-Toolkit/inc/GLTFTextureCompressionUtils.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n#include \"GLTFSDK.h\"\r\n\r\nnamespace DirectX\r\n{\r\n    class ScratchImage;\r\n}\r\n\r\nnamespace Microsoft::glTF::Toolkit\r\n{\r\n    extern const char* EXTENSION_MSFT_TEXTURE_DDS;\r\n\r\n    /// <summary>Supported compression algorithms for textures.</summary>\r\n    enum class TextureCompression\r\n    {\r\n        None,\r\n        BC3,\r\n        BC5,\r\n        BC7,\r\n        BC7_SRGB\r\n    };\r\n\r\n    /// <summary>\r\n    /// Utilities to compress textures in a glTF asset.\r\n    /// </summary>\r\n    class GLTFTextureCompressionUtils\r\n    {\r\n    public:\r\n        /// <summary>Compresses a texture in a glTF from a WIC-readable format (PNG, JPEG, BMP, GIF, TIFF, HD Photo, ICO) \r\n        /// into a DDS with the appropriate compression.\r\n        /// <para>If a dds extension already exists for this texture, do nothing.</para>\r\n        /// <param name=\"streamReader\">The stream reader that will be used to get streams to each image from its URI.</param>\r\n        /// <param name=\"doc\">Input glTF document.</param>\r\n        /// <param name=\"texture\">Texture object that is contained in input document. If texture does not exist in document, \r\n        /// throws exception.</param>\r\n        /// <param name=\"compression\">The desired block compression method (e.g. BC5, BC7).</param>\r\n        /// <param name=\"outputDirectory\">The output directory to which compressed files should be saved.</param>\r\n        /// <param name=\"maxTextureSize\">The maximum texture size to which textures should be resized before compression, in pixels.</param>\r\n        /// <param name=\"generateMipMaps\">If true, also generates mip maps when compressing.</param>\r\n        /// <param name=\"retainOriginalImage\">If true, retains the original image on the resulting glTF. If false, \r\n        /// replaces that image (making the glTF incompatible with most core glTF 2.0 viewers).</param>\r\n        /// <returns>Returns a new Document that contains a new reference to the compressed dds file added as part \r\n        /// of the MSFT_texture_dds extension.</returns>\r\n        /// <example>\r\n        /// Example Input:\r\n        /// <code>\r\n        /// \"textures\": [\r\n        ///    {\r\n        ///        \"source\": 0,\r\n        ///    }\r\n        /// ],\r\n        /// \"images\": [\r\n        /// {\r\n        ///    \"uri\": \"defaultTexture.png\"\r\n        /// }\r\n        /// ]\r\n        /// </code>\r\n        ///\r\n        /// Example Output (BC7 Compression, with retainOriginalImage == true):\r\n        /// <code>\r\n        /// \"textures\": \r\n        /// [\r\n        ///    {\r\n        ///        \"source\": 0,\r\n        ///        \"extensions\": {\r\n        ///            \"MSFT_texture_dds\": {\r\n        ///                \"source\": 1\r\n        ///            }\r\n        ///        }\r\n        ///    }\r\n        /// ],\r\n        /// \"images\": [\r\n        /// {\r\n        ///    \"uri\": \"defaultTexture.png\"\r\n        /// },\r\n        /// {\r\n        ///    \"uri\": \"defaultTexture-BC7.DDS\"\r\n        /// }\r\n        /// ]\r\n        /// </code>\r\n        /// </example>\r\n        /// </summary>\r\n        static Document CompressTextureAsDDS(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const Texture & texture, TextureCompression compression, const std::string& outputDirectory, size_t maxTextureSize = std::numeric_limits<size_t>::max(), bool generateMipMaps = true, bool retainOriginalImage = true, bool treatAsLinear = true);\r\n\r\n        /// <summary>\r\n        /// Applies <see cref=\"CompressTextureAsDDS\" /> to all textures in the document that are accessible via materials according to the \r\n        /// requirements of the Windows Mixed Reality home.\r\n        /// <para>Normal textures get compressed with BC5, while baseColorTexture, occlusion, metallicRoughness and emissive textures get compressed with BC7.</para>\r\n        /// <param name=\"streamReader\">The stream reader that will be used to get streams to each image from its URI.</param>\r\n        /// <param name=\"doc\">Input glTF document.</param>\r\n        /// <param name=\"outputDirectory\">The output directory to which compressed files should be saved.</param>\r\n        /// <param name=\"maxTextureSize\">The maximum texture size to which textures should be resized before compression, in pixels.</param>\r\n        /// <param name=\"generateMipMaps\">If true, also generates mip maps when compressing.</param>\r\n        /// <param name=\"retainOriginalImage\">If true, retains the original image on the resulting glTF. If false, \r\n        /// replaces that image (making the glTF incompatible with most core glTF 2.0 viewers).</param>\r\n        /// <returns>Returns a new Document that contains alternate textures for all applicable materials following the requirements of the Windows\r\n        /// Mixed Reality home using the MSFT_texture_dds extension.</returns>\r\n        /// </summary>\r\n        static Document CompressAllTexturesForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const std::string& outputDirectory, size_t maxTextureSize = std::numeric_limits<size_t>::max(), bool retainOriginalImages = true);\r\n\r\n        /// <summary>\r\n        /// Compresses a DirectX::ScratchImage in place using the specified compression.\r\n        /// </summary>\r\n        /// <param name=\"image\">The image to compress.</param>\r\n        /// <param name=\"compression\">The desired compression algorithm.</param>\r\n        static void CompressImage(DirectX::ScratchImage& image, TextureCompression compression);\r\n    };\r\n}"
  },
  {
    "path": "glTF-Toolkit/inc/GLTFTexturePackingUtils.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n#include \"GLTFSDK.h\"\r\n\r\nnamespace Microsoft::glTF::Toolkit\r\n{\r\n    extern const char* EXTENSION_MSFT_PACKING_ORM;\r\n    extern const char* EXTENSION_MSFT_PACKING_NRM;\r\n    extern const char* MSFT_PACKING_INDEX_KEY;\r\n    extern const char* MSFT_PACKING_ORM_ORMTEXTURE_KEY;\r\n    extern const char* MSFT_PACKING_ORM_RMOTEXTURE_KEY;\r\n    extern const char* MSFT_PACKING_ORM_NORMALTEXTURE_KEY;\r\n    extern const char* MSFT_PACKING_NRM_KEY;\r\n\r\n    /// <summary>Texture packing flags. May be combined to pack multiple formats at once.</summary>\r\n    enum TexturePacking\r\n    {\r\n        None = 0x0,\r\n        OcclusionRoughnessMetallic = 0x1,\r\n        RoughnessMetallicOcclusion = 0x2,\r\n        NormalRoughnessMetallic = 0x4\r\n    };\r\n\r\n    /// <summary>\r\n    /// Utilities to pack textures from glTF assets and refer to them from an asset\r\n    /// using the MSFT_packing_occlusionRoughnessMetallic extension.\r\n    /// </summary>\r\n    class GLTFTexturePackingUtils\r\n    {\r\n    public:\r\n        /// <summary>\r\n        /// Packs a single material's textures for Windows Mixed Reality for all the packing schemes selected, and adds the resulting texture(s) back to the material in the document.\r\n        /// </summary>\r\n        /// <param name=\"streamReader\">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>\r\n        /// <param name=\"doc\">The document from which the texture will be loaded.</param>\r\n        /// <param name=\"material\">The material to be packed.</param>\r\n        /// <param name=\"packing\">The packing scheme that will be used to pick the textures and choose their order.</param>\r\n        /// <param name=\"outputDirectory\">The output directory to which packed textures should be saved.</param>\r\n        /// <returns>\r\n        /// A new glTF manifest that uses the MSFT_packing_occlusionRoughnessMetallic extension to point to the packed textures.\r\n        /// </returns>\r\n        static Document PackMaterialForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const Material & material, TexturePacking packing, const std::string& outputDirectory);\r\n\r\n        /// <summary>\r\n        /// Applies <see cref=\"PackMaterialForWindowsMR\" /> to every material in the document, following the same parameter structure as that function.\r\n        /// </summary>\r\n        /// <param name=\"streamReader\">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>\r\n        /// <param name=\"doc\">The document from which the texture will be loaded.</param>\r\n        /// <param name=\"packing\">The packing scheme that will be used to pick the textures and choose their order.</param>\r\n        /// <param name=\"outputDirectory\">The output directory to which packed textures should be saved.</param>\r\n        /// <returns>\r\n        /// A new glTF manifest that uses the MSFT_packing_occlusionRoughnessMetallic extension to point to the packed textures.\r\n        /// </returns>\r\n        static Document PackAllMaterialsForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document & doc, TexturePacking packing, const std::string& outputDirectory);\r\n\r\n        static std::unordered_set<int> GetTextureIndicesFromMsftExtensions(const Material& material);\r\n    };\r\n}\r\n\r\n"
  },
  {
    "path": "glTF-Toolkit/inc/GLTFTextureUtils.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See LICENSE in the project root for license information.#pragma once\n\n#include \"GLTFSDK.h\"\n#include <DirectXTex.h>\n#include <GLTFSDK/Document.h>\n#include <wincodec.h>\n\nnamespace Microsoft::glTF::Toolkit\n{\n    enum Channel\n    {\n        Red = 0,\n        Green = 4,\n        Blue = 8,\n        Alpha = 12\n    };\n\n    /// <summary>\n    /// Utilities to load textures from glTF assets.\n    /// </summary>\n    class GLTFTextureUtils\n    {\n    public:\n        /// <summary>\n        /// Loads a texture into a scratch image in the DXGI_FORMAT_R32G32B32A32_FLOAT format for in-memory processing.\n        /// </summary>\n        /// <returns>A scratch image containing the loaded texture in the DXGI_FORMAT_R32G32B32A32_FLOAT format.</returns>\n        /// <param name=\"streamReader\">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>\n        /// <param name=\"doc\">The document from which the texture will be loaded.</param>\n        /// <param name=\"textureId\">The identifier of the texture to be loaded.</param>\n        static DirectX::ScratchImage LoadTexture(std::shared_ptr<const IStreamReader> streamReader, const Document& doc, const std::string& textureId, bool treatAsLinear = true);\n\n        /// <summary>\n        /// Gets the value of channel `channel` in pixel index `offset` in image `imageData`\n        /// assumed to be formatted as DXGI_FORMAT_R32G32B32A32_FLOAT\n        /// </summary>\n        static float* GetChannelValue(uint8_t * imageData, size_t offset, Channel channel);\n\n        static std::string SaveAsPng(DirectX::ScratchImage* image, const std::string& fileName, const std::string& directory, const GUID* targetFormat = &GUID_WICPixelFormat24bppBGR);\n\n        static std::string AddImageToDocument(Document& doc, const std::string& imageUri);\n        \n        static void ResizeToLargest(std::unique_ptr<DirectX::ScratchImage>& image1, std::unique_ptr<DirectX::ScratchImage>& image2);\n\n        static void ResizeIfNeeded(const std::unique_ptr<DirectX::ScratchImage>& image, size_t resizedWidth, size_t resizedHeight);\n\n        static Document RemoveRedundantTexturesAndImages(const Document& doc);\n    };\n}\n\n"
  },
  {
    "path": "glTF-Toolkit/inc/SerializeBinary.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.#pragma once\r\n\r\n#include \"GLTFSDK.h\"\r\n\r\n#include <functional>\r\n#include <memory>\r\n#include <vector>\r\n\r\n#include \"AccessorUtils.h\"\r\n\r\nnamespace Microsoft::glTF::Toolkit\r\n{\r\n    /// <summary>\r\n    /// A function that determines to which type an accessor should be converted,\r\n    /// based on the accessor metadata.\r\n    /// </summary>\r\n    typedef std::function<ComponentType(const Accessor&)> AccessorConversionStrategy;\r\n\r\n    /// <summary>\r\n    /// Serializes a glTF asset as a glTF binary (GLB) file.\r\n    /// </summary>\r\n    /// <param name=\"Document\">The glTF asset manifest to be serialized.</param>\r\n    /// <param name=\"inputStreamReader\">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>\r\n    /// <param name=\"outputStreamFactory\">A stream factory that is capable of creating an output stream where the GLB will be saved, and a temporary stream for\r\n    /// use during the serialization process.</param>\r\n    void SerializeBinary(const Document& document, std::shared_ptr<const IStreamReader> inputStreamReader, std::shared_ptr<const IStreamWriter> outputStreamWriter, const AccessorConversionStrategy& accessorConversion = nullptr);\r\n\r\n    /// <summary>\r\n    /// Serializes a glTF asset as a glTF binary (GLB) file.\r\n    /// </summary>\r\n    /// <param name=\"Document\">The glTF asset manifest to be serialized.</param>\r\n    /// <param name=\"resourceReader\">A resource reader that is capable of accessing the resources used in the document.</param>\r\n    /// <param name=\"outputStreamFactory\">A stream factory that is capable of creating an output stream where the GLB will be saved, and a temporary stream for\r\n    /// use during the serialization process.</param>\r\n    void SerializeBinary(const Document& document, const GLTFResourceReader& resourceReader, std::shared_ptr<const IStreamWriter> outputStreamWriter, const AccessorConversionStrategy& accessorConversion = nullptr);\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit/inc/pch.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n// Use the C++ standard templated min/max\r\n#define NOMINMAX\r\n\r\n// DirectX apps don't need GDI\r\n#define NODRAWTEXT\r\n#define NOGDI\r\n#define NOBITMAP\r\n\r\n// Include <mcx.h> if you need this\r\n#define NOMCX\r\n\r\n// Include <winsvc.h> if you need this\r\n#define NOSERVICE\r\n\r\n// WinHelp is deprecated\r\n#define NOHELP\r\n\r\n#define WIN32_LEAN_AND_MEAN\r\n#include <windows.h>\r\n#include <wincodec.h>\r\n#include <pathcch.h>\r\n\r\n#include <wrl/client.h>\r\n\r\n#include <d3d11_1.h>\r\n#include <dxgi1_2.h>\r\n#include <DirectXMath.h>\r\n#include <DirectXColors.h>\r\n\r\n// Silence C4996 for CodeCVT deprecations. CodeCVT is still used for UTF8 conversions in GLTFLODUtils.cpp\r\n// TODO: Remove\r\n#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING\r\n#include <string>\r\n#undef _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING\r\n\r\n#include <algorithm>\r\n#include <exception>\r\n#include <fstream>\r\n#include <iostream>\r\n#include <memory>\r\n#include <set>\r\n#include <sstream>\r\n#include <stdexcept>\r\n\r\n#include <stdio.h>"
  },
  {
    "path": "glTF-Toolkit/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<packages>\r\n  <package id=\"directxtex_desktop_2015\" version=\"2018.8.5.1\" targetFramework=\"native\" />\r\n  <package id=\"draco.CPP\" version=\"1.3.3.1\" targetFramework=\"native\" />\r\n  <package id=\"Microsoft.glTF.CPP\" version=\"1.6.1.0\" targetFramework=\"native\" />\r\n  <package id=\"rapidjson.temprelease\" version=\"0.0.2.20\" targetFramework=\"native\" />\r\n</packages>"
  },
  {
    "path": "glTF-Toolkit/src/DeviceResources.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n\r\n#include \"DeviceResources.h\"\r\n\r\nusing namespace DirectX;\r\nusing namespace DX;\r\n\r\nusing Microsoft::WRL::ComPtr;\r\n\r\nnamespace\r\n{\r\n#if defined(_DEBUG)\r\n    // Check for SDK Layer support.\r\n    inline bool SdkLayersAvailable()\r\n    {\r\n        HRESULT hr = D3D11CreateDevice(\r\n            nullptr,\r\n            D3D_DRIVER_TYPE_NULL,       // There is no need to create a real hardware device.\r\n            0,\r\n            D3D11_CREATE_DEVICE_DEBUG,  // Check for the SDK layers.\r\n            nullptr,                    // Any feature level will do.\r\n            0,\r\n            D3D11_SDK_VERSION,\r\n            nullptr,                    // No need to keep the D3D device reference.\r\n            nullptr,                    // No need to know the feature level.\r\n            nullptr                     // No need to keep the D3D device context reference.\r\n            );\r\n\r\n        return SUCCEEDED(hr);\r\n    }\r\n#endif\r\n};\r\n\r\n// Constructor for DeviceResources.\r\nDeviceResources::DeviceResources(D3D_FEATURE_LEVEL minFeatureLevel) :\r\n    m_d3dMinFeatureLevel(minFeatureLevel),\r\n    m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1)\r\n{\r\n}\r\n\r\n// Configures the Direct3D device, and stores handles to it and the device context.\r\nvoid DeviceResources::CreateDeviceResources() \r\n{\r\n    UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;\r\n\r\n#if defined(_DEBUG)\r\n    if (SdkLayersAvailable())\r\n    {\r\n        // If the project is in a debug build, enable debugging via SDK Layers with this flag.\r\n        creationFlags |= D3D11_CREATE_DEVICE_DEBUG;\r\n    }\r\n    else\r\n    {\r\n        OutputDebugStringA(\"WARNING: Direct3D Debug Device is not available\\n\");\r\n    }\r\n#endif\r\n\r\n    // Determine DirectX hardware feature levels this app will support.\r\n    static const D3D_FEATURE_LEVEL s_featureLevels[] =\r\n    {\r\n        D3D_FEATURE_LEVEL_11_1,\r\n        D3D_FEATURE_LEVEL_11_0,\r\n        D3D_FEATURE_LEVEL_10_1,\r\n        D3D_FEATURE_LEVEL_10_0,\r\n        D3D_FEATURE_LEVEL_9_3,\r\n        D3D_FEATURE_LEVEL_9_2,\r\n        D3D_FEATURE_LEVEL_9_1,\r\n    };\r\n\r\n    UINT featLevelCount = 0;\r\n    for (; featLevelCount < _countof(s_featureLevels); ++featLevelCount)\r\n    {\r\n        if (s_featureLevels[featLevelCount] < m_d3dMinFeatureLevel)\r\n            break;\r\n    }\r\n\r\n    if (!featLevelCount)\r\n    {\r\n        throw std::out_of_range(\"minFeatureLevel too high\");\r\n    }\r\n\r\n    ComPtr<IDXGIAdapter1> adapter;\r\n    GetHardwareAdapter(adapter.GetAddressOf());\r\n\r\n    // Create the Direct3D 11 API device object and a corresponding context.\r\n    ComPtr<ID3D11Device> device;\r\n    ComPtr<ID3D11DeviceContext> context;\r\n\r\n    HRESULT hr = E_FAIL;\r\n    if (adapter)\r\n    {\r\n        hr = D3D11CreateDevice(\r\n            adapter.Get(),\r\n            D3D_DRIVER_TYPE_UNKNOWN,\r\n            0,\r\n            creationFlags,\r\n            s_featureLevels,\r\n            featLevelCount,\r\n            D3D11_SDK_VERSION,\r\n            device.GetAddressOf(),      // Returns the Direct3D device created.\r\n            &m_d3dFeatureLevel,         // Returns feature level of device created.\r\n            context.GetAddressOf()      // Returns the device immediate context.\r\n            );\r\n    }\r\n#if defined(NDEBUG)\r\n    else\r\n    {\r\n        throw std::exception(\"No Direct3D hardware device found\");\r\n    }\r\n#else\r\n    if (FAILED(hr))\r\n    {\r\n        // If the initialization fails, fall back to the WARP device.\r\n        // For more information on WARP, see: \r\n        // http://go.microsoft.com/fwlink/?LinkId=286690\r\n        hr = D3D11CreateDevice(\r\n            nullptr,\r\n            D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device.\r\n            0,\r\n            creationFlags,\r\n            s_featureLevels,\r\n            featLevelCount,\r\n            D3D11_SDK_VERSION,\r\n            device.GetAddressOf(),\r\n            &m_d3dFeatureLevel,\r\n            context.GetAddressOf()\r\n            );\r\n\r\n        if (SUCCEEDED(hr))\r\n        {\r\n            OutputDebugStringA(\"Direct3D Adapter - WARP\\n\");\r\n        }\r\n    }\r\n#endif\r\n\r\n    ThrowIfFailed(hr);\r\n\r\n#ifndef NDEBUG\r\n    ComPtr<ID3D11Debug> d3dDebug;\r\n    if (SUCCEEDED(device.As(&d3dDebug)))\r\n    {\r\n        ComPtr<ID3D11InfoQueue> d3dInfoQueue;\r\n        if (SUCCEEDED(d3dDebug.As(&d3dInfoQueue)))\r\n        {\r\n#ifdef _DEBUG\r\n            d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);\r\n            d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);\r\n#endif\r\n            D3D11_MESSAGE_ID hide [] =\r\n            {\r\n                D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS,\r\n            };\r\n            D3D11_INFO_QUEUE_FILTER filter = {};\r\n            filter.DenyList.NumIDs = _countof(hide);\r\n            filter.DenyList.pIDList = hide;\r\n            d3dInfoQueue->AddStorageFilterEntries(&filter);\r\n        }\r\n    }\r\n#endif\r\n\r\n    ThrowIfFailed(device.As(&m_d3dDevice));\r\n    ThrowIfFailed(context.As(&m_d3dContext));\r\n    ThrowIfFailed(context.As(&m_d3dAnnotation));\r\n}\r\n\r\n// Recreate all device resources and set them back to the current state.\r\nvoid DeviceResources::HandleDeviceLost()\r\n{\r\n    m_swapChain.Reset();\r\n    m_d3dContext.Reset();\r\n    m_d3dAnnotation.Reset();\r\n\r\n#ifdef _DEBUG\r\n    {\r\n        ComPtr<ID3D11Debug> d3dDebug;\r\n        if (SUCCEEDED(m_d3dDevice.As(&d3dDebug)))\r\n        {\r\n            d3dDebug->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY);\r\n        }\r\n    }\r\n#endif\r\n\r\n    m_d3dDevice.Reset();\r\n\r\n    CreateDeviceResources();\r\n}\r\n\r\n// This method acquires the first available hardware adapter.\r\n// If no such adapter can be found, *ppAdapter will be set to nullptr.\r\nvoid DeviceResources::GetHardwareAdapter(IDXGIAdapter1** ppAdapter)\r\n{\r\n    *ppAdapter = nullptr;\r\n\r\n    ComPtr<IDXGIFactory1> dxgiFactory;\r\n    ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(dxgiFactory.GetAddressOf())));\r\n\r\n    ComPtr<IDXGIAdapter1> adapter;\r\n    for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != dxgiFactory->EnumAdapters1(adapterIndex, adapter.ReleaseAndGetAddressOf()); adapterIndex++)\r\n    {\r\n        DXGI_ADAPTER_DESC1 desc;\r\n        adapter->GetDesc1(&desc);\r\n\r\n        if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)\r\n        {\r\n            // Don't select the Basic Render Driver adapter.\r\n            continue;\r\n        }\r\n\r\n#ifdef _DEBUG\r\n        wchar_t buff[256] = {};\r\n        swprintf_s(buff, L\"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\\n\", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description);\r\n        OutputDebugStringW(buff);\r\n#endif\r\n\r\n        break;\r\n    }\r\n\r\n    *ppAdapter = adapter.Detach();\r\n}"
  },
  {
    "path": "glTF-Toolkit/src/GLBtoGLTF.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n#include \"GLBtoGLTF.h\"\r\n#include \"GLTFSDK/ExtensionsKHR.h\"\r\n\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\nstatic std::unordered_map<std::string, std::string> s_gltfMimeTypes = \r\n{\r\n    { MIMETYPE_PNG, FILE_EXT_PNG },\r\n    { MIMETYPE_JPEG, FILE_EXT_JPEG },\r\n    { \"image/vnd-ms.dds\", \"dds\" },\r\n    { \"text/plain\", \"glsl\" },\r\n    { \"audio/wav\", \"wav\" },\r\n};\r\n\r\nstd::string GuessFileExtension(const std::string& mimeType)\r\n{\r\n    auto itr = s_gltfMimeTypes.find(mimeType);\r\n    if (itr != s_gltfMimeTypes.end())\r\n    {\r\n        return itr->second;\r\n    }\r\n    return BUFFER_EXTENSION;\r\n}\r\n\r\nnamespace\r\n{\r\n    class StreamMock : public IStreamReader\r\n    {\r\n    public:\r\n        StreamMock() : m_stream(std::make_shared<std::stringstream>(std::ios_base::app | std::ios_base::binary | std::ios_base::in | std::ios_base::out))\r\n        {\r\n        }\r\n\r\n        std::shared_ptr<std::istream> GetInputStream(const std::string&) const override\r\n        {\r\n            return m_stream;\r\n        }\r\n\r\n    private:\r\n        std::shared_ptr<std::stringstream> m_stream;\r\n    };\r\n\r\n    size_t GetGLBBufferChunkOffset(std::ifstream* input)\r\n    {\r\n        // get offset from beginning of glb binary to beginning of buffer chunk\r\n        input->seekg(GLB2_HEADER_BYTE_SIZE, std::ios::beg);\r\n        uint32_t length = 0;\r\n        for (int i = 0; i < GLB_CHUNK_TYPE_SIZE*CHAR_BIT; i += CHAR_BIT)\r\n        {\r\n            uint8_t c = static_cast<uint8_t>(input->get());\r\n            length |= ((uint16_t)c << i);\r\n        }\r\n        // 28 is total length of non-json blocks from start of glb blob\r\n        // 28 = (GLB2_HEADER_BYTE_SIZE = 12bytes) + (uint32 = 4bytes) * 4\r\n        return length + GLB2_HEADER_BYTE_SIZE + GLB_CHUNK_TYPE_SIZE * 4;\r\n    }\r\n}\r\n\r\nstd::vector<char> GLBToGLTF::SaveBin(std::istream* input, const Document& glbDoc, const size_t bufferOffset, const size_t newBufferlength, std::unordered_set<std::string>& unpackedBufferViews)\r\n{\r\n    if (newBufferlength == 0)\r\n    {\r\n        return {};\r\n    }\r\n\r\n    const auto images = glbDoc.images.Elements();\r\n    const auto bufferViews = glbDoc.bufferViews.Elements();\r\n\r\n    // gather all non-image bufferViews in UsedBufferViews\r\n    std::vector<BufferView> usedBufferViews(bufferViews.size());\r\n    auto end = copy_if(bufferViews.begin(), bufferViews.end(), usedBufferViews.begin(), [unpackedBufferViews](const auto& a)\r\n    {\r\n        return unpackedBufferViews.count(a.id) == 0;\r\n    });\r\n    usedBufferViews.resize(distance(usedBufferViews.begin(), end));\r\n\r\n    // sort buffer views by offset\r\n    sort(usedBufferViews.begin(), usedBufferViews.end(), [](const BufferView& a, const BufferView& b)\r\n    {\r\n        return a.byteOffset < b.byteOffset;\r\n    });\r\n\r\n    std::vector<char> result(newBufferlength);\r\n    size_t vecpos = 0; // number of chunks read\r\n    size_t currOffset = bufferOffset; // offset into buffer\r\n    input->seekg(bufferOffset, std::ios::beg);\r\n\r\n    for (const auto& bufferView : usedBufferViews)\r\n    {\r\n        // traverse through original buffer while grabbing non-image buffer segments\r\n        size_t nextOffset = bufferOffset + bufferView.byteOffset;\r\n        if (currOffset < nextOffset)\r\n        {\r\n            // skip over buffer segments of no interest\r\n            size_t chunkLength = nextOffset - currOffset;\r\n            input->seekg(chunkLength, std::ios::cur);\r\n            currOffset += chunkLength;\r\n        }\r\n\r\n        if (vecpos % GLB_BUFFER_OFFSET_ALIGNMENT != 0)\r\n        {\r\n            // Alignment padding\r\n            // Accessor component sizes can be 1, 2, 4.\r\n            // Aligning to 4 will satisfy requirements but wastes space\r\n            vecpos += (GLB_BUFFER_OFFSET_ALIGNMENT - (vecpos % GLB_BUFFER_OFFSET_ALIGNMENT));\r\n        }\r\n\r\n        // read and increment vecpos + offset\r\n        input->read(&result[vecpos], bufferView.byteLength);\r\n        currOffset += bufferView.byteLength;\r\n        vecpos += bufferView.byteLength;\r\n    }\r\n\r\n    if (vecpos == 0)\r\n    {\r\n        return {};\r\n    }\r\n\r\n    return result;\r\n}\r\n\r\nstd::unordered_map<std::string, std::vector<char>> GLBToGLTF::GetImagesData(std::istream* input, const Document& glbDoc, const std::string& name, const size_t bufferOffset)\r\n{\r\n    input->seekg(0, std::ios::beg);\r\n    std::unordered_map<std::string, int> imageIDs;\r\n    std::vector<Image> images = std::vector<Image>(glbDoc.images.Elements());\r\n    if (images.size() == 0)\r\n    {\r\n        return {};\r\n    }\r\n\r\n    int imgId = 0;\r\n    for (const auto& img : images)\r\n    {\r\n        // save mapping of original image order\r\n        imageIDs[img.bufferViewId] = imgId;\r\n        imgId++;\r\n    }\r\n\r\n    // sort images by buffer offset so only traverse once\r\n    sort(images.begin(), images.end(), [glbDoc](const auto& a, const auto& b)\r\n    {\r\n        return glbDoc.bufferViews.Get(a.bufferViewId).byteOffset < glbDoc.bufferViews.Get(b.bufferViewId).byteOffset;\r\n    });\r\n\r\n    size_t currOffset = bufferOffset; // offset into buffer\r\n    input->seekg(bufferOffset, std::ios::beg);\r\n\r\n    std::unordered_map<std::string, std::vector<char>> imageStream;\r\n    for (const auto& img : images)\r\n    {\r\n        // traverse through buffer while saving images\r\n        auto bufferView = glbDoc.bufferViews.Get(img.bufferViewId);\r\n        size_t nextImageOffset = bufferOffset + bufferView.byteOffset;\r\n        if (currOffset < nextImageOffset)\r\n        {\r\n            // skip over non-image buffer segments\r\n            size_t chunkLength = nextImageOffset - currOffset;\r\n            input->seekg(chunkLength, std::ios::cur);\r\n            currOffset = nextImageOffset;\r\n        }\r\n        // read and increment offset\r\n        std::vector<char> result;\r\n        result.resize(bufferView.byteLength);\r\n        input->read(&result[0], bufferView.byteLength);\r\n        currOffset += bufferView.byteLength;\r\n\r\n        // write image file\r\n        std::string outname = name + \"_image\" + std::to_string(imageIDs[img.bufferViewId]) + \".\" + GuessFileExtension(img.mimeType);\r\n\r\n        imageStream[outname] = std::move(result);\r\n    }\r\n    return imageStream;\r\n}\r\n\r\nstd::unordered_map<std::string, std::vector<char>> GetExtensionsData(std::istream* input, const Document& glbDoc, const std::string& name, const size_t bufferOffset)\r\n{\r\n    std::unordered_map<std::string, std::vector<char>> extensionStreams;\r\n    // Collect anything in extensions that looks like it should be unpacked.\r\n    for (const auto& extension : glbDoc.extensions)\r\n    {\r\n        rapidjson::Document extensionJson;\r\n        extensionJson.Parse(extension.second.c_str());\r\n        if (!extensionJson.IsObject())\r\n        {\r\n            continue;\r\n        }\r\n        for (auto& member : extensionJson.GetObject())\r\n        {\r\n            if (!member.value.IsArray())\r\n            {\r\n                continue;\r\n            }\r\n            for (auto& possibleBuffer : member.value.GetArray())\r\n            {\r\n                if (!possibleBuffer.IsObject())\r\n                {\r\n                    continue;\r\n                }\r\n                std::string bufferViewId{};\r\n                std::string mimeType{};\r\n                if (possibleBuffer.HasMember(\"bufferView\"))\r\n                {\r\n                    bufferViewId = std::to_string(possibleBuffer[\"bufferView\"].GetUint());\r\n                    \r\n                }\r\n                else\r\n                {\r\n                    continue;\r\n                }\r\n                if (possibleBuffer.HasMember(\"mimeType\"))\r\n                {\r\n                    mimeType = possibleBuffer[\"mimeType\"].GetString();\r\n                }\r\n                try\r\n                {\r\n                    auto bufferView = glbDoc.bufferViews.Get(bufferViewId);\r\n                    auto filename = name + \"_\" + extension.first + \"_\" + member.name.GetString() + \"_\" + bufferViewId + \".\" + GuessFileExtension(mimeType);\r\n\r\n                    size_t offset = bufferOffset + bufferView.byteOffset;\r\n                    input->seekg(offset, std::ios::beg);\r\n                    std::vector<char> result;\r\n                    result.resize(bufferView.byteLength);\r\n                    input->read(&result[0], bufferView.byteLength);\r\n\r\n                    extensionStreams[filename] = std::move(result);\r\n                }\r\n                catch (...)\r\n                {\r\n                    // Didn't work out.\r\n                    continue;\r\n                }\r\n            }\r\n        }\r\n    }\r\n    return extensionStreams;\r\n}\r\n\r\n// Create modified gltf from original by removing image buffer segments and updating\r\n// images, bufferViews and accessors fields accordingly\r\nDocument GLBToGLTF::CreateGLTFDocument(const Document& glbDoc, const std::string& name, std::unordered_set<std::string>& unpackedBufferViews)\r\n{\r\n    Document gltfDoc(glbDoc);\r\n\r\n    gltfDoc.images.Clear();\r\n    gltfDoc.buffers.Clear();\r\n    gltfDoc.bufferViews.Clear();\r\n    gltfDoc.accessors.Clear();\r\n\r\n    const auto images = glbDoc.images.Elements();\r\n    const auto buffers = glbDoc.buffers.Elements();\r\n    const auto bufferViews = glbDoc.bufferViews.Elements();\r\n    const auto accessors = glbDoc.accessors.Elements();\r\n    std::unordered_map<std::string, std::string> bufferViewIndex;\r\n\r\n    size_t updatedBufferSize = 0;\r\n    int imgId = 0;\r\n    for (const auto& im : images)\r\n    {\r\n        // find which buffer segments correspond to images\r\n        unpackedBufferViews.insert(im.bufferViewId);\r\n\r\n        // update image fields with image names instead of buffer views\r\n        Image updatedImage;\r\n        updatedImage.id = std::to_string(imgId);\r\n        updatedImage.uri = name + \"_image\" + std::to_string(imgId) + \".\" + GuessFileExtension(im.mimeType);\r\n\r\n        gltfDoc.images.Append(std::move(updatedImage));\r\n        imgId++;\r\n    }\r\n\r\n    // Collect anything in extensions that looks like it should be unpacked.\r\n    for (auto& extension : gltfDoc.extensions)\r\n    {\r\n        rapidjson::Document extensionJson;\r\n        extensionJson.Parse(extension.second.c_str());\r\n        if (!extensionJson.IsObject())\r\n        {\r\n            continue;\r\n        }\r\n        for (auto& member : extensionJson.GetObject())\r\n        {\r\n            if (!member.value.IsArray())\r\n            {\r\n                continue;\r\n            }\r\n            for (auto& possibleBuffer : member.value.GetArray())\r\n            {\r\n                if (!possibleBuffer.IsObject())\r\n                {\r\n                    continue;\r\n                }\r\n                std::string bufferViewId{};\r\n                std::string mimeType{};\r\n                if (possibleBuffer.HasMember(\"bufferView\"))\r\n                {\r\n                    bufferViewId = std::to_string(possibleBuffer[\"bufferView\"].GetUint());\r\n                    unpackedBufferViews.insert(bufferViewId);\r\n                }\r\n                else\r\n                {\r\n                    continue;\r\n                }\r\n                if (possibleBuffer.HasMember(\"mimeType\"))\r\n                {\r\n                    mimeType = possibleBuffer[\"mimeType\"].GetString();\r\n                }\r\n                try\r\n                {\r\n                    possibleBuffer.RemoveMember(\"uri\");\r\n                    possibleBuffer.RemoveMember(\"mimeType\");\r\n                    possibleBuffer.RemoveMember(\"bufferView\");\r\n                    auto filename = name + \"_\" + extension.first + \"_\" + member.name.GetString() + \"_\" + bufferViewId + \".\" + GuessFileExtension(mimeType);\r\n                    possibleBuffer.AddMember(\"uri\", rapidjson::Value(filename.c_str(), extensionJson.GetAllocator()), extensionJson.GetAllocator());\r\n                }\r\n                catch (...)\r\n                {\r\n                    // Didn't work out.\r\n                    continue;\r\n                }\r\n            }\r\n        }\r\n\r\n        rapidjson::StringBuffer buffer;\r\n        rapidjson::Writer<rapidjson::StringBuffer> jsonWriter(buffer);\r\n        extensionJson.Accept(jsonWriter);\r\n\r\n        extension.second = buffer.GetString();\r\n    }\r\n\r\n    // gather all non-image bufferViews in UsedBufferViews\r\n    std::vector<BufferView> usedBufferViews(bufferViews.size());\r\n    auto end = copy_if(bufferViews.begin(), bufferViews.end(), usedBufferViews.begin(), [&unpackedBufferViews](const auto& a)\r\n    {\r\n        return unpackedBufferViews.count(a.id) == 0;\r\n    });\r\n\r\n    usedBufferViews.resize(distance(usedBufferViews.begin(), end));\r\n\r\n    // group buffer views by buffer, then sort them by byteOffset to calculate their new byteOffsets\r\n    sort(usedBufferViews.begin(), usedBufferViews.end(), [](const auto& a, const auto& b)\r\n    {\r\n        return a.byteOffset < b.byteOffset;\r\n    });\r\n\r\n    int updatedBufferViewId = 0;\r\n    size_t currentOffset = 0;\r\n    for (const auto& b : usedBufferViews)\r\n    {\r\n        // provide new byte ranges for bufferviews\r\n        size_t padding = 0;\r\n        auto updatedBufferView = b;\r\n        updatedBufferView.id = std::to_string(updatedBufferViewId);\r\n\r\n        if (currentOffset % GLB_BUFFER_OFFSET_ALIGNMENT != 0)\r\n        {\r\n            // alignment padding as in SaveBin\r\n            padding = (GLB_BUFFER_OFFSET_ALIGNMENT - (currentOffset % GLB_BUFFER_OFFSET_ALIGNMENT));\r\n            currentOffset += padding;\r\n        }\r\n\r\n        updatedBufferView.byteOffset = currentOffset;\r\n        currentOffset += b.byteLength;\r\n        gltfDoc.bufferViews.Append(std::move(updatedBufferView));\r\n        bufferViewIndex[b.id] = std::to_string(updatedBufferViewId);\r\n        updatedBufferSize += (b.byteLength + padding);\r\n        updatedBufferViewId++;\r\n    }\r\n\r\n    if (!buffers.empty())\r\n    {\r\n        auto updatedBuffer = buffers[0];\r\n        updatedBuffer.byteLength = updatedBufferSize;\r\n        updatedBuffer.uri = name + \".\" + BUFFER_EXTENSION;\r\n        gltfDoc.buffers.Append(std::move(updatedBuffer));\r\n    }\r\n\r\n    for (const auto& a : accessors)\r\n    {\r\n        if (unpackedBufferViews.find(a.bufferViewId) == unpackedBufferViews.end())\r\n        {\r\n            // update acessors with new bufferview IDs, the above check may not be needed\r\n            auto updatedAccessor = a;\r\n            updatedAccessor.bufferViewId = bufferViewIndex[a.bufferViewId];\r\n            gltfDoc.accessors.Append(std::move(updatedAccessor));\r\n        }\r\n    }\r\n\r\n    bool changes = false;\r\n    const auto meshes = glbDoc.meshes.Elements();\r\n    std::vector<Mesh> updatedMeshs;\r\n    for (auto updatedMesh : meshes)\r\n    {\r\n        for (auto& primitive : updatedMesh.primitives)\r\n        {\r\n            if (primitive.HasExtension<KHR::MeshPrimitives::DracoMeshCompression>())\r\n            {\r\n                auto& draco = primitive.GetExtension<KHR::MeshPrimitives::DracoMeshCompression>();\r\n                draco.bufferViewId = bufferViewIndex[draco.bufferViewId];\r\n                changes = true;\r\n            }\r\n        }\r\n        updatedMeshs.emplace_back(updatedMesh);\r\n    }\r\n\r\n    if (changes)\r\n    {\r\n        for (const auto& mesh : updatedMeshs)\r\n        {\r\n            gltfDoc.meshes.Replace(mesh);\r\n        }\r\n    }\r\n\r\n    return gltfDoc;\r\n}\r\n\r\nvoid GLBToGLTF::UnpackGLB(const std::string& glbPath, const std::string& outDirectory, const std::string& gltfName)\r\n{\r\n    // read glb file into json\r\n    auto glbStream = std::make_shared<std::ifstream>(glbPath, std::ios::binary);\r\n    auto streamReader = std::make_shared<StreamMock>();\r\n    GLBResourceReader reader(streamReader, glbStream);\r\n\r\n    // get original json\r\n    auto json = reader.GetJson();\r\n    auto doc = Deserialize(json, KHR::GetKHRExtensionDeserializer());\r\n\r\n    // create new modified json\r\n    std::unordered_set<std::string> unpackedBufferViews;\r\n    auto gltfDoc = GLBToGLTF::CreateGLTFDocument(doc, gltfName, unpackedBufferViews);\r\n\r\n    // serialize and write new gltf json\r\n    auto gltfJson = Serialize(gltfDoc, KHR::GetKHRExtensionSerializer());\r\n    std::ofstream outputStream(outDirectory + gltfName + \".\" + GLTF_EXTENSION);\r\n    outputStream << gltfJson;\r\n    outputStream.flush();\r\n\r\n    // write images\r\n    size_t bufferOffset = GetGLBBufferChunkOffset(glbStream.get());\r\n    for (auto image : GLBToGLTF::GetImagesData(glbStream.get(), doc, gltfName, bufferOffset))\r\n    {\r\n        std::ofstream out(outDirectory + image.first, std::ios::binary);\r\n        out.write(&image.second[0], image.second.size());\r\n    }\r\n\r\n    for (auto ext : GetExtensionsData(glbStream.get(), doc, gltfName, bufferOffset))\r\n    {\r\n        std::ofstream out(outDirectory + ext.first, std::ios::binary);\r\n        out.write(&ext.second[0], ext.second.size());\r\n    }\r\n\r\n    // get new buffer size and write new buffer\r\n    if (gltfDoc.buffers.Size() != 0)\r\n    {\r\n        size_t newBufferSize = gltfDoc.buffers[0].byteLength;\r\n        auto binFileData = GLBToGLTF::SaveBin(glbStream.get(), doc, bufferOffset, newBufferSize, unpackedBufferViews);\r\n        std::ofstream out(outDirectory + gltfName + \".\" + BUFFER_EXTENSION, std::ios::binary);\r\n        out.write(&binFileData[0], binFileData.size());\r\n    }\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit/src/GLTFLODUtils.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n\r\n#include \"GLTFTextureCompressionUtils.h\"\r\n#include \"GLTFTexturePackingUtils.h\"\r\n#include \"GLTFLODUtils.h\"\r\n\r\n#include \"GLTFSDK/GLTF.h\"\r\n#include \"GLTFSDK/Constants.h\"\r\n#include \"GLTFSDK/Deserialize.h\"\r\n#include \"GLTFSDK/RapidJsonUtils.h\"\r\n#include \"GLTFSDK/ExtensionsKHR.h\"\r\n\r\n#include <algorithm>\r\n#include <iostream>\r\n#include <set>\r\n#include <codecvt>\r\n#include <filesystem>\r\n\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\nconst char* Microsoft::glTF::Toolkit::EXTENSION_MSFT_LOD = \"MSFT_lod\";\r\nconst char* Microsoft::glTF::Toolkit::MSFT_LOD_IDS_KEY = \"ids\";\r\n\r\nnamespace\r\n{\r\n    inline void AddIndexOffset(std::string& id, size_t offset)\r\n    {\r\n        // an empty id string indicates that the id is not inuse and therefore should not be updated\r\n        id = (id.empty()) ? \"\" : std::to_string(std::stoi(id) + offset);\r\n    }\r\n\r\n    inline void AddIndexOffset(MeshPrimitive& primitive, const char* attributeName, size_t offset)\r\n    {\r\n        // an empty id string indicates that the id is not inuse and therefore should not be updated\r\n        auto attributeItr = primitive.attributes.find(attributeName);\r\n        if (attributeItr != primitive.attributes.end())\r\n        {\r\n            attributeItr->second = std::to_string(std::stoi(attributeItr->second) + offset);\r\n        }\r\n    }\r\n\r\n    inline void AddIndexOffsetPacked(rapidjson::Value& json, const char* textureId, size_t offset)\r\n    {\r\n        if (json.HasMember(textureId))\r\n        {\r\n            if (json[textureId].HasMember(MSFT_PACKING_INDEX_KEY))\r\n            {\r\n                auto index = json[textureId][MSFT_PACKING_INDEX_KEY].GetInt();\r\n                json[textureId][MSFT_PACKING_INDEX_KEY] = index + offset;\r\n            }\r\n        }\r\n    }\r\n\r\n    std::vector<std::string> ParseExtensionMSFTLod(const Node& node)\r\n    {\r\n        std::vector<std::string> lodIds;\r\n\r\n        auto lodExtension = node.extensions.find(Toolkit::EXTENSION_MSFT_LOD);\r\n        if (lodExtension != node.extensions.end())\r\n        {\r\n            auto json = RapidJsonUtils::CreateDocumentFromString(lodExtension->second);\r\n\r\n            auto idIt = json.FindMember(Toolkit::MSFT_LOD_IDS_KEY);\r\n            if (idIt != json.MemberEnd())\r\n            {\r\n                for (rapidjson::Value::ConstValueIterator ait = idIt->value.Begin(); ait != idIt->value.End(); ++ait)\r\n                {\r\n                    lodIds.push_back(std::to_string(ait->GetInt()));\r\n                }\r\n            }\r\n        }\r\n\r\n        return lodIds;\r\n    }\r\n\r\n    template <typename T>\r\n    std::string SerializeExtensionMSFTLod(const T&, const std::vector<std::string>& lods, const Document& document)\r\n    {\r\n        // Omit MSFT_lod entirely if no LODs are available\r\n        if (lods.empty())\r\n        {\r\n            return std::string();\r\n        }\r\n\r\n        rapidjson::Document doc(rapidjson::kObjectType);\r\n        rapidjson::Document::AllocatorType& a = doc.GetAllocator();\r\n\r\n        std::vector<size_t> lodIndices;\r\n        lodIndices.reserve(lods.size());\r\n\r\n        if (std::is_same<T, Material>())\r\n        {\r\n            for (const auto& lodId : lods)\r\n            {\r\n                lodIndices.push_back(ToKnownSizeType(document.materials.GetIndex(lodId)));\r\n            }\r\n        }\r\n        else if (std::is_same<T, Node>())\r\n        {\r\n            for (const auto& lodId : lods)\r\n            {\r\n                lodIndices.push_back(ToKnownSizeType(document.nodes.GetIndex(lodId)));\r\n            }\r\n        }\r\n        else\r\n        {\r\n            throw GLTFException(\"LODs can only be applied to materials or nodes.\");\r\n        }\r\n\r\n        doc.AddMember(RapidJsonUtils::ToStringValue(Toolkit::MSFT_LOD_IDS_KEY, a), RapidJsonUtils::ToJsonArray(lodIndices, a), a);\r\n\r\n        rapidjson::StringBuffer stringBuffer;\r\n        rapidjson::Writer<rapidjson::StringBuffer> writer(stringBuffer);\r\n        doc.Accept(writer);\r\n\r\n        return stringBuffer.GetString();\r\n    }\r\n\r\n    Document AddGLTFNodeLOD(const Document& primary, LODMap& primaryLods, const Document& lod, const std::wstring& relativePath = L\"\", bool sharedMaterials = false)\r\n    {\r\n        Microsoft::glTF::Document gltfLod(primary);\r\n\r\n        auto primaryScenes = primary.scenes.Elements();\r\n        auto lodScenes = lod.scenes.Elements();\r\n\r\n        size_t MaxLODLevel = 0;\r\n\r\n        // Both GLTF must have equivalent number and order of scenes and root nodes per scene otherwise merge will not be possible\r\n        bool sceneNodeMatch = false;\r\n        if (primaryScenes.size() == lodScenes.size())\r\n        {\r\n            for (size_t sceneIdx = 0; sceneIdx < primaryScenes.size(); sceneIdx++)\r\n            {\r\n\r\n                if ((primaryScenes[sceneIdx].nodes.size() == lodScenes[sceneIdx].nodes.size()) &&\r\n                    (lodScenes[sceneIdx].nodes.size() == 1 ||\r\n                        std::equal(primaryScenes[sceneIdx].nodes.begin(), primaryScenes[sceneIdx].nodes.end(), lodScenes[sceneIdx].nodes.begin()))\r\n                    )\r\n                {\r\n                    sceneNodeMatch = true;\r\n                    auto primaryRootNode = gltfLod.nodes.Get(primaryScenes[sceneIdx].nodes[0]);\r\n                    MaxLODLevel = std::max(MaxLODLevel, primaryLods.at(primaryRootNode.id)->size());\r\n                }\r\n                else\r\n                {\r\n                    sceneNodeMatch = false;\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        MaxLODLevel++;\r\n\r\n        if (!sceneNodeMatch || primaryScenes.empty())\r\n        {\r\n            // Mis-match or empty scene; either way cannot merge Lod in\r\n            throw new std::runtime_error(\"Primary Scene either empty or does not match scene node count of LOD gltf\");\r\n        }\r\n\r\n        std::string nodeLodLabel = \"_lod\" + std::to_string(MaxLODLevel);\r\n\r\n        // lod merge is performed from the lowest reference back upwards\r\n        // e.g. buffers/samplers/extensions do not reference any other part of the gltf manifest    \r\n        size_t buffersOffset = gltfLod.buffers.Size();\r\n        size_t samplersOffset = sharedMaterials ? 0 : gltfLod.samplers.Size();\r\n        {\r\n            auto lodBuffers = lod.buffers.Elements();\r\n            for (auto buffer : lodBuffers)\r\n            {\r\n                AddIndexOffset(buffer.id, buffersOffset);\r\n                std::string relativePathUtf8 = std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(relativePath);\r\n                buffer.uri = relativePathUtf8 + buffer.uri;\r\n                gltfLod.buffers.Append(std::move(buffer));\r\n            }\r\n\r\n            if (!sharedMaterials)\r\n            {\r\n                auto lodSamplers = lod.samplers.Elements();\r\n                for (auto sampler : lodSamplers)\r\n                {\r\n                    AddIndexOffset(sampler.id, samplersOffset);\r\n                    gltfLod.samplers.Append(std::move(sampler));\r\n                }\r\n            }\r\n\r\n            for (const auto& extension : lod.extensionsUsed)\r\n            {\r\n                gltfLod.extensionsUsed.insert(extension);\r\n            }\r\n            // ensure that MSFT_LOD extension is specified as being used\r\n            gltfLod.extensionsUsed.insert(Toolkit::EXTENSION_MSFT_LOD);\r\n        }\r\n\r\n        size_t accessorOffset = gltfLod.accessors.Size();\r\n        size_t texturesOffset = gltfLod.textures.Size();\r\n        {\r\n            // Buffer Views depend upon Buffers\r\n            size_t bufferViewsOffset = gltfLod.bufferViews.Size();\r\n            auto lodBufferViews = lod.bufferViews.Elements();\r\n            for (auto bufferView : lodBufferViews)\r\n            {\r\n                AddIndexOffset(bufferView.id, bufferViewsOffset);\r\n                AddIndexOffset(bufferView.bufferId, buffersOffset);\r\n                gltfLod.bufferViews.Append(std::move(bufferView));\r\n            }\r\n\r\n            // Accessors depend upon Buffer views        \r\n            auto lodAccessors = lod.accessors.Elements();\r\n            for (auto accessor : lodAccessors)\r\n            {\r\n                AddIndexOffset(accessor.id, accessorOffset);\r\n                AddIndexOffset(accessor.bufferViewId, bufferViewsOffset);\r\n                gltfLod.accessors.Append(std::move(accessor));\r\n            }\r\n\r\n            // Images depend upon Buffer views\r\n            size_t imageOffset = sharedMaterials ? 0 : gltfLod.images.Size();\r\n            if (!sharedMaterials)\r\n            {\r\n                auto lodImages = lod.images.Elements();\r\n                for (auto image : lodImages)\r\n                {\r\n\r\n                    AddIndexOffset(image.id, imageOffset);\r\n                    AddIndexOffset(image.bufferViewId, bufferViewsOffset);\r\n\r\n                    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;\r\n                    std::wstring uri = conv.from_bytes(image.uri);\r\n                    if (std::experimental::filesystem::path(uri).is_relative()) {\r\n                        // to be able to reference images with the same name, prefix with relative path\r\n                        std::string relativePathUtf8 = conv.to_bytes(relativePath);\r\n                        image.uri = relativePathUtf8 + image.uri;\r\n                    }\r\n                    gltfLod.images.Append(std::move(image));\r\n                }\r\n\r\n                // Textures depend upon Samplers and Images\r\n                auto lodTextures = lod.textures.Elements();\r\n                for (auto texture : lodTextures)\r\n                {\r\n                    AddIndexOffset(texture.id, texturesOffset);\r\n                    AddIndexOffset(texture.samplerId, samplersOffset);\r\n                    AddIndexOffset(texture.imageId, imageOffset);\r\n\r\n                    // MSFT_texture_dds extension\r\n                    auto ddsExtensionIt = texture.extensions.find(EXTENSION_MSFT_TEXTURE_DDS);\r\n                    if (ddsExtensionIt != texture.extensions.end() && !ddsExtensionIt->second.empty())\r\n                    {\r\n                        rapidjson::Document ddsJson = RapidJsonUtils::CreateDocumentFromString(ddsExtensionIt->second);\r\n\r\n                        if (ddsJson.HasMember(\"source\"))\r\n                        {\r\n                            auto index = ddsJson[\"source\"].GetInt();\r\n                            ddsJson[\"source\"] = index + imageOffset;\r\n                        }\r\n\r\n                        rapidjson::StringBuffer buffer;\r\n                        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\r\n                        ddsJson.Accept(writer);\r\n\r\n                        ddsExtensionIt->second = buffer.GetString();\r\n                    }\r\n\r\n                    gltfLod.textures.Append(std::move(texture));\r\n                }\r\n            }\r\n        }\r\n\r\n        // Material Merge\r\n        // Note the extension KHR_materials_pbrSpecularGlossiness will be also updated\r\n        // Materials depend upon textures\r\n        size_t materialOffset = sharedMaterials ? 0 : gltfLod.materials.Size();\r\n        if (!sharedMaterials)\r\n        {\r\n            auto lodMaterials = lod.materials.Elements();\r\n            for (auto material : lodMaterials)\r\n            {\r\n                // post-fix with lod level indication; \r\n                // no functional reason other than making it easier to natively read gltf files with lods\r\n                material.name += nodeLodLabel;\r\n                AddIndexOffset(material.id, materialOffset);\r\n\r\n                AddIndexOffset(material.normalTexture.textureId, texturesOffset);\r\n                AddIndexOffset(material.occlusionTexture.textureId, texturesOffset);\r\n                AddIndexOffset(material.emissiveTexture.textureId, texturesOffset);\r\n\r\n                AddIndexOffset(material.metallicRoughness.baseColorTexture.textureId, texturesOffset);\r\n                AddIndexOffset(material.metallicRoughness.metallicRoughnessTexture.textureId, texturesOffset);\r\n\r\n                if (material.HasExtension<KHR::Materials::PBRSpecularGlossiness>())\r\n                {\r\n                    AddIndexOffset(material.GetExtension<KHR::Materials::PBRSpecularGlossiness>().diffuseTexture.textureId, texturesOffset);\r\n                    AddIndexOffset(material.GetExtension<KHR::Materials::PBRSpecularGlossiness>().specularGlossinessTexture.textureId, texturesOffset);\r\n                }\r\n\r\n                // MSFT_packing_occlusionRoughnessMetallic packed textures\r\n                auto ormExtensionIt = material.extensions.find(EXTENSION_MSFT_PACKING_ORM);\r\n                if (ormExtensionIt != material.extensions.end() && !ormExtensionIt->second.empty())\r\n                {\r\n                    rapidjson::Document ormJson = RapidJsonUtils::CreateDocumentFromString(ormExtensionIt->second);\r\n\r\n                    AddIndexOffsetPacked(ormJson, MSFT_PACKING_ORM_ORMTEXTURE_KEY, texturesOffset);\r\n                    AddIndexOffsetPacked(ormJson, MSFT_PACKING_ORM_RMOTEXTURE_KEY, texturesOffset);\r\n                    AddIndexOffsetPacked(ormJson, MSFT_PACKING_ORM_NORMALTEXTURE_KEY, texturesOffset);\r\n\r\n                    rapidjson::StringBuffer buffer;\r\n                    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\r\n                    ormJson.Accept(writer);\r\n\r\n                    ormExtensionIt->second = buffer.GetString();\r\n                }\r\n\r\n                // MSFT_packing_normalRoughnessMetallic packed texture\r\n                auto nrmExtensionIt = material.extensions.find(EXTENSION_MSFT_PACKING_NRM);\r\n                if (nrmExtensionIt != material.extensions.end() && !nrmExtensionIt->second.empty())\r\n                {\r\n                    rapidjson::Document nrmJson = RapidJsonUtils::CreateDocumentFromString(nrmExtensionIt->second);\r\n\r\n                    AddIndexOffsetPacked(nrmJson, MSFT_PACKING_NRM_KEY, texturesOffset);\r\n                    \r\n                    rapidjson::StringBuffer buffer;\r\n                    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\r\n                    nrmJson.Accept(writer);\r\n\r\n                    nrmExtensionIt->second = buffer.GetString();\r\n                }\r\n\r\n                gltfLod.materials.Append(std::move(material));\r\n            }\r\n        }\r\n\r\n        // Meshs depend upon Accessors and Materials\r\n        size_t meshOffset = gltfLod.meshes.Size();\r\n        {\r\n            auto lodMeshes = lod.meshes.Elements();\r\n            for (auto mesh : lodMeshes)\r\n            {\r\n                // post-fix with lod level indication; \r\n                // no functional reason other than making it easier to natively read gltf files with lods\r\n                mesh.name += nodeLodLabel;\r\n                AddIndexOffset(mesh.id, meshOffset);\r\n\r\n                for (auto &primitive : mesh.primitives)\r\n                {\r\n                    AddIndexOffset(primitive.indicesAccessorId, accessorOffset);\r\n                    AddIndexOffset(primitive, ACCESSOR_POSITION, accessorOffset);\r\n                    AddIndexOffset(primitive, ACCESSOR_NORMAL, accessorOffset);\r\n                    AddIndexOffset(primitive, ACCESSOR_TEXCOORD_0, accessorOffset);\r\n                    AddIndexOffset(primitive, ACCESSOR_TEXCOORD_1, accessorOffset);\r\n                    AddIndexOffset(primitive, ACCESSOR_COLOR_0, accessorOffset);\r\n                    AddIndexOffset(primitive, ACCESSOR_TANGENT, accessorOffset);\r\n                    AddIndexOffset(primitive, ACCESSOR_JOINTS_0, accessorOffset);\r\n                    AddIndexOffset(primitive, ACCESSOR_WEIGHTS_0, accessorOffset);\r\n\r\n                    if (sharedMaterials)\r\n                    {\r\n                        // lower quality LODs can have fewer images and textures than the highest LOD,\r\n                        // so we need to find the correct material index for the same material from the highest LOD\r\n\r\n                        const Material& localMaterial = lod.materials.Get(primitive.materialId);\r\n\r\n                        // find merged material index for the given material index in this LOD\r\n                        auto iter = std::find_if(gltfLod.materials.Elements().begin(),\r\n                                gltfLod.materials.Elements().end(),\r\n                                [localMaterial](const Material& globalMaterial) {\r\n                                    // check that the materials are the same, noting that the texture and material ids will differ\r\n                                    return localMaterial.name == globalMaterial.name &&\r\n                                           localMaterial.alphaMode == globalMaterial.alphaMode &&\r\n                                           localMaterial.alphaCutoff == globalMaterial.alphaCutoff &&\r\n                                           localMaterial.emissiveFactor == globalMaterial.emissiveFactor &&\r\n                                           localMaterial.doubleSided == globalMaterial.doubleSided &&\r\n                                           localMaterial.metallicRoughness.baseColorFactor == globalMaterial.metallicRoughness.baseColorFactor &&\r\n                                           localMaterial.metallicRoughness.metallicFactor == globalMaterial.metallicRoughness.metallicFactor &&\r\n                                           localMaterial.occlusionTexture.strength == globalMaterial.occlusionTexture.strength &&\r\n                                           localMaterial.HasExtension<KHR::Materials::PBRSpecularGlossiness>() == globalMaterial.HasExtension<KHR::Materials::PBRSpecularGlossiness>() && \r\n                                           (!localMaterial.HasExtension<KHR::Materials::PBRSpecularGlossiness>() ||\r\n                                             (localMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().diffuseFactor == globalMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().diffuseFactor &&\r\n                                              localMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().glossinessFactor == globalMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().glossinessFactor &&\r\n                                              localMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().specularFactor == globalMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().specularFactor)\r\n                                           );\r\n                                }\r\n                        );\r\n\r\n                        if (iter != gltfLod.materials.Elements().end())\r\n                        {\r\n                            size_t newMaterialIndex = std::distance(gltfLod.materials.Elements().begin(), iter);\r\n                            primitive.materialId = std::to_string(newMaterialIndex);\r\n                        }\r\n                        else\r\n                        {\r\n                            throw new std::runtime_error(\"Couldn't find the shared material in the highest LOD.\");\r\n                        }\r\n                    }\r\n                    else\r\n                    {\r\n                        AddIndexOffset(primitive.materialId, materialOffset);\r\n                    }\r\n                }\r\n\r\n                gltfLod.meshes.Append(std::move(mesh));\r\n            }\r\n        }\r\n\r\n        // Nodes depend upon Nodes and Meshes\r\n        size_t nodeOffset = gltfLod.nodes.Size();\r\n        // Skins depend upon Nodes\r\n        size_t skinOffset = gltfLod.skins.Size();\r\n        {\r\n            auto nodes = lod.nodes.Elements();\r\n            for (auto node : nodes)\r\n            {\r\n                // post-fix with lod level indication; \r\n                // no functional reason other than making it easier to natively read gltf files with lods\r\n                node.name += nodeLodLabel;\r\n                AddIndexOffset(node.id, nodeOffset);\r\n                AddIndexOffset(node.meshId, meshOffset);\r\n                if (!node.skinId.empty())\r\n                {\r\n                    AddIndexOffset(node.skinId, skinOffset);\r\n                }\r\n\r\n                for (auto &child : node.children)\r\n                {\r\n                    AddIndexOffset(child, nodeOffset);\r\n                }\r\n\r\n                gltfLod.nodes.Append(std::move(node));\r\n            }\r\n        }\r\n\r\n        {\r\n            auto skins = lod.skins.Elements();\r\n            for (auto skin : skins)\r\n            {\r\n                // post-fix with lod level indication; \r\n                // no functional reason other than making it easier to natively read gltf files with lods\r\n                skin.name += nodeLodLabel;\r\n                AddIndexOffset(skin.id, skinOffset);\r\n                AddIndexOffset(skin.skeletonId, nodeOffset);\r\n                AddIndexOffset(skin.inverseBindMatricesAccessorId, accessorOffset);\r\n\r\n                for (auto &jointId : skin.jointIds)\r\n                {\r\n                    AddIndexOffset(jointId, nodeOffset);\r\n                }\r\n\r\n                gltfLod.skins.Append(std::move(skin));\r\n            }\r\n        }\r\n\r\n        // Animation channels depend upon Nodes and Accessors\r\n        {\r\n            for (size_t animationIndex = 0; animationIndex < gltfLod.animations.Size(); animationIndex++)\r\n            {\r\n                const auto &baseAnimation = gltfLod.animations[animationIndex];\r\n                Animation newAnimation(baseAnimation);\r\n                const auto &lodAnimation = lod.animations[animationIndex];\r\n\r\n                size_t samplerOffset = baseAnimation.samplers.Size();\r\n                for (const auto &sampler : lodAnimation.samplers.Elements())\r\n                {\r\n                    AnimationSampler newSampler(sampler);\r\n                    AddIndexOffset(newSampler.id, samplerOffset);\r\n                    AddIndexOffset(newSampler.inputAccessorId, accessorOffset);\r\n                    AddIndexOffset(newSampler.outputAccessorId, accessorOffset);\r\n                    newAnimation.samplers.Append(std::move(newSampler));\r\n                }\r\n                \r\n                size_t channelOffset = baseAnimation.channels.Size();\r\n                for (auto channel : lodAnimation.channels.Elements())\r\n                {\r\n                    AddIndexOffset(channel.id, channelOffset);\r\n                    AddIndexOffset(channel.target.nodeId, nodeOffset);\r\n                    AddIndexOffset(channel.samplerId, samplerOffset);\r\n\r\n                    newAnimation.channels.Append(std::move(channel));\r\n                }\r\n                gltfLod.animations.Replace(newAnimation);\r\n            }\r\n        }\r\n\r\n        // update the primary GLTF root nodes lod extension to reference the new lod root node\r\n        // N.B. new lods are always added to the back\r\n        for (size_t sceneIdx = 0; sceneIdx < primaryScenes.size(); sceneIdx++)\r\n        {\r\n            for (size_t rootNodeIdx = 0; rootNodeIdx < primaryScenes[sceneIdx].nodes.size(); rootNodeIdx++)\r\n            {\r\n                auto idx = primaryScenes[sceneIdx].nodes[rootNodeIdx];\r\n                Node nodeWithLods(gltfLod.nodes.Get(idx));\r\n                int lodRootIdx = std::stoi(lodScenes[sceneIdx].nodes[rootNodeIdx]) + static_cast<int>(nodeOffset);\r\n                auto primaryNodeLod = primaryLods.at(nodeWithLods.id);\r\n                primaryNodeLod->emplace_back(std::to_string(lodRootIdx));\r\n            }\r\n        }\r\n\r\n        return gltfLod;\r\n    }\r\n}\r\n\r\nLODMap GLTFLODUtils::ParseDocumentNodeLODs(const Document& doc)\r\n{\r\n    LODMap lodMap;\r\n\r\n    for (auto node : doc.nodes.Elements())\r\n    {\r\n        lodMap.emplace(node.id, std::move(std::make_shared<std::vector<std::string>>(ParseExtensionMSFTLod(node))));\r\n    }\r\n\r\n    return lodMap;\r\n}\r\n\r\nDocument GLTFLODUtils::MergeDocumentsAsLODs(const std::vector<Document>& docs, const std::vector<std::wstring>& relativePaths, const bool& sharedMaterials)\r\n{\r\n    if (docs.empty())\r\n    {\r\n        throw std::invalid_argument(\"MergeDocumentsAsLODs passed empty vector\");\r\n    }\r\n\r\n    Document gltfPrimary(docs[0]);\r\n    LODMap lods = ParseDocumentNodeLODs(gltfPrimary);\r\n\r\n    for (size_t i = 1; i < docs.size(); i++)\r\n    {\r\n        gltfPrimary = AddGLTFNodeLOD(gltfPrimary, lods, docs[i], (relativePaths.size() == docs.size() - 1 ? relativePaths[i - 1] : L\"\"), sharedMaterials);\r\n    }\r\n\r\n    for (auto lod : lods)\r\n    {\r\n        if (lod.second == nullptr || lod.second->size() == 0)\r\n        {\r\n            continue;\r\n        }\r\n\r\n        auto node = gltfPrimary.nodes.Get(lod.first);\r\n\r\n        auto lodExtensionValue = SerializeExtensionMSFTLod<Node>(node, *lod.second, gltfPrimary);\r\n        if (!lodExtensionValue.empty())\r\n        {\r\n            node.extensions.emplace(EXTENSION_MSFT_LOD, lodExtensionValue);\r\n            gltfPrimary.nodes.Replace(node);\r\n        }\r\n    }\r\n\r\n    return gltfPrimary;\r\n}\r\n\r\nDocument GLTFLODUtils::MergeDocumentsAsLODs(const std::vector<Document>& docs, const std::vector<double>& screenCoveragePercentages, const std::vector<std::wstring>& relativePaths, const bool& sharedMaterials)\r\n{\r\n    Document merged = MergeDocumentsAsLODs(docs, relativePaths, sharedMaterials);\r\n\r\n    if (screenCoveragePercentages.size() == 0)\r\n    {\r\n        return merged;\r\n    }\r\n\r\n    for (auto scene : merged.scenes.Elements())\r\n    {\r\n        for (auto rootNodeIndex : scene.nodes)\r\n        {\r\n            auto primaryRootNode = merged.nodes.Get(rootNodeIndex);\r\n\r\n            rapidjson::Document extrasJson(rapidjson::kObjectType);\r\n            if (!primaryRootNode.extras.empty())\r\n            {\r\n                extrasJson.Parse(primaryRootNode.extras.c_str());\r\n            }\r\n            rapidjson::Document::AllocatorType& allocator = extrasJson.GetAllocator();\r\n\r\n            rapidjson::Value screenCoverageArray = RapidJsonUtils::ToJsonArray(screenCoveragePercentages, allocator);\r\n\r\n            extrasJson.AddMember(\"MSFT_screencoverage\", screenCoverageArray, allocator);\r\n\r\n            rapidjson::StringBuffer buffer;\r\n            rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\r\n            extrasJson.Accept(writer);\r\n\r\n            primaryRootNode.extras = buffer.GetString();\r\n\r\n            merged.nodes.Replace(primaryRootNode);\r\n        }\r\n    }\r\n\r\n    return merged;\r\n}\r\n\r\nuint32_t GLTFLODUtils::NumberOfNodeLODLevels(const Document& doc, const LODMap& lods)\r\n{\r\n    size_t maxLODLevel = 0;\r\n    for (auto node : doc.nodes.Elements())\r\n    {\r\n        maxLODLevel = std::max(maxLODLevel, lods.at(node.id)->size());\r\n    }\r\n\r\n    return static_cast<uint32_t>(maxLODLevel);\r\n}\r\n\r\n"
  },
  {
    "path": "glTF-Toolkit/src/GLTFMeshCompressionUtils.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See LICENSE in the project root for license information.\n\n#include \"pch.h\"\n#include \"AccessorUtils.h\"\n\n#include \"GLTFMeshCompressionUtils.h\"\n#include \"GLTFSDK/MeshPrimitiveUtils.h\"\n#include \"GLTFSDK/ExtensionsKHR.h\"\n#include \"GLTFSDK/BufferBuilder.h\"\n\n#pragma warning(push)\n#pragma warning(disable: 4018 4081 4244 4267 4389)\n#include \"draco/compression/encode.h\"\n#include \"draco/core/cycle_timer.h\"\n#include \"draco/io/mesh_io.h\"\n#include \"draco/io/point_cloud_io.h\"\n#pragma warning(pop)\n\n// Usings for glTF\nusing namespace Microsoft::glTF;\nusing namespace Microsoft::glTF::Toolkit;\n\nstd::wstring PathConcat(const std::wstring& part1, const std::wstring& part2)\n{\n    wchar_t uriAbsoluteRaw[MAX_PATH];\n    // Note: PathCchCombine will return the last argument if it's an absolute path\n    if (FAILED(::PathCchCombine(uriAbsoluteRaw, ARRAYSIZE(uriAbsoluteRaw), part1.c_str(), part2.c_str())))\n    {\n        auto msg = L\"Could not combine the path names: \" + part1 + L\" and \" + part2;\n        throw std::invalid_argument(std::string(msg.begin(), msg.end()));\n    }\n\n    return uriAbsoluteRaw;\n}\n\nstd::string PathConcat(const std::string& part1, const std::string& part2)\n{\n    std::wstring part1W = std::wstring(part1.begin(), part1.end());\n    std::wstring part2W = std::wstring(part2.begin(), part2.end());\n\n    auto pathW = PathConcat(part1W, part2W);\n    return std::string(pathW.begin(), pathW.end());\n}\n\nclass FilepathStreamWriter : public IStreamWriter\n{\npublic:\n    FilepathStreamWriter(std::string uriBase) : m_uriBase(uriBase) {}\n\n    virtual ~FilepathStreamWriter() override {}\n    virtual std::shared_ptr<std::ostream> GetOutputStream(const std::string& filename) const override\n    {\n        return std::make_shared<std::ofstream>(PathConcat(m_uriBase, filename), std::ios::binary);\n    }\nprivate:\n    const std::string m_uriBase;\n};\n\ndraco::GeometryAttribute::Type GetTypeFromAttributeName(const std::string& name)\n{\n    if (name == ACCESSOR_POSITION)\n    {\n        return draco::GeometryAttribute::Type::POSITION;\n    }\n    if (name == ACCESSOR_NORMAL)\n    {\n        return draco::GeometryAttribute::Type::NORMAL;\n    }\n    if (name == ACCESSOR_TEXCOORD_0)\n    {\n        return draco::GeometryAttribute::Type::TEX_COORD;\n    }\n    if (name == ACCESSOR_TEXCOORD_1)\n    {\n        return draco::GeometryAttribute::Type::TEX_COORD;\n    }\n    if (name == ACCESSOR_COLOR_0)\n    {\n        return draco::GeometryAttribute::Type::COLOR;\n    }\n    if (name == ACCESSOR_JOINTS_0)\n    {\n        return draco::GeometryAttribute::Type::GENERIC;\n    }\n    if (name == ACCESSOR_WEIGHTS_0)\n    {\n        return draco::GeometryAttribute::Type::GENERIC;\n    }\n    if (name == ACCESSOR_TANGENT)\n    {\n        return draco::GeometryAttribute::Type::GENERIC;\n    }\n    return draco::GeometryAttribute::Type::GENERIC;\n}\n\ndraco::DataType GetDataType(const Accessor& accessor)\n{\n    switch (accessor.componentType)\n    {\n    case COMPONENT_BYTE: return draco::DataType::DT_INT8;\n    case COMPONENT_UNSIGNED_BYTE: return draco::DataType::DT_UINT8;\n    case COMPONENT_SHORT: return draco::DataType::DT_INT16;\n    case COMPONENT_UNSIGNED_SHORT: return draco::DataType::DT_UINT16;\n    case COMPONENT_UNSIGNED_INT: return draco::DataType::DT_UINT32;\n    case COMPONENT_FLOAT: return draco::DataType::DT_FLOAT32;\n    }\n    return draco::DataType::DT_INVALID;\n}\n\ntemplate<typename T>\nint InitializePointAttribute(draco::Mesh& dracoMesh, const std::string& attributeName, const Document& doc, GLTFResourceReader& reader, Accessor& accessor)\n{\n    auto stride = sizeof(T) * Accessor::GetTypeCount(accessor.type);\n    auto numComponents = Accessor::GetTypeCount(accessor.type);\n    draco::PointAttribute pointAttr;\n    pointAttr.Init(GetTypeFromAttributeName(attributeName), nullptr, numComponents, GetDataType(accessor), accessor.normalized, stride, 0);\n    int attId = dracoMesh.AddAttribute(pointAttr, true, static_cast<unsigned int>(accessor.count));\n    auto attrActual = dracoMesh.attribute(attId);\n\n    std::vector<T> values = reader.ReadBinaryData<T>(doc, accessor);\n\n    if ((accessor.min.empty() || accessor.max.empty()) && !values.empty())\n    {\n        auto minmax = AccessorUtils::CalculateMinMax(accessor, values);\n        accessor.min = minmax.first;\n        accessor.max = minmax.second;\n    }\n\n    for (draco::PointIndex i(0); i < static_cast<uint32_t>(accessor.count); ++i)\n    {\n        attrActual->SetAttributeValue(attrActual->mapped_index(i), &values[i.value() * numComponents]);\n    }\n    if (dracoMesh.num_points() == 0) \n    {\n        dracoMesh.set_num_points(static_cast<unsigned int>(accessor.count));\n    }\n    else if (dracoMesh.num_points() != accessor.count)\n    {\n        throw GLTFException(\"Inconsistent points count.\");\n    }\n\n    return attId;\n}\n\nvoid SetEncoderOptions(draco::Encoder& encoder, const CompressionOptions& options)\n{\n    encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, options.PositionQuantizationBits);\n    encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, options.TexCoordQuantizationBits);\n    encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, options.NormalQuantizationBits);\n    encoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR, options.ColorQuantizationBits);\n    encoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, options.GenericQuantizationBits);\n    encoder.SetSpeedOptions(options.Speed, options.Speed);\n    encoder.SetTrackEncodedProperties(true);\n}\n\nDocument GLTFMeshCompressionUtils::CompressMesh(\n    std::shared_ptr<IStreamReader> streamReader,\n    const Document & doc,\n    CompressionOptions options,\n    const Mesh & mesh,\n    BufferBuilder* builder,\n    std::unordered_set<std::string>& bufferViewsToRemove)\n{\n    GLTFResourceReader reader(streamReader);\n    Document resultDocument(doc);\n    draco::Encoder encoder;\n    SetEncoderOptions(encoder, options);\n\n    Mesh resultMesh(mesh);\n    resultMesh.primitives.clear();\n    for (const auto& primitive : mesh.primitives)\n    {\n        if (primitive.HasExtension<KHR::MeshPrimitives::DracoMeshCompression>())\n        {\n            resultMesh.primitives.emplace_back(primitive);\n            continue;\n        }\n        auto dracoExtension = std::make_unique<KHR::MeshPrimitives::DracoMeshCompression>();\n        draco::Mesh dracoMesh;\n        auto indices = MeshPrimitiveUtils::GetIndices32(doc, reader, primitive);\n        size_t numFaces = indices.size() / 3;\n        dracoMesh.SetNumFaces(numFaces);\n        for (uint32_t i = 0; i < numFaces; i++)\n        {\n            draco::Mesh::Face face;\n            face[0] = indices[(i * 3) + 0];\n            face[1] = indices[(i * 3) + 1];\n            face[2] = indices[(i * 3) + 2];\n            dracoMesh.SetFace(draco::FaceIndex(i), face);\n        }\n\n        Accessor indiciesAccessor(doc.accessors[primitive.indicesAccessorId]);\n        bufferViewsToRemove.emplace(indiciesAccessor.bufferViewId);\n        indiciesAccessor.bufferViewId = \"\";\n        indiciesAccessor.byteOffset = 0;\n        resultDocument.accessors.Replace(indiciesAccessor);\n\n        for (const auto& attribute : primitive.attributes)\n        {\n            const auto& accessor = doc.accessors[attribute.second];\n            Accessor attributeAccessor(accessor);\n            int attId;\n            switch (accessor.componentType)\n            {\n            case COMPONENT_BYTE:           attId = InitializePointAttribute<int8_t>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;\n            case COMPONENT_UNSIGNED_BYTE:  attId = InitializePointAttribute<uint8_t>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;\n            case COMPONENT_SHORT:          attId = InitializePointAttribute<int16_t>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;\n            case COMPONENT_UNSIGNED_SHORT: attId = InitializePointAttribute<uint16_t>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;\n            case COMPONENT_UNSIGNED_INT:   attId = InitializePointAttribute<uint32_t>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;\n            case COMPONENT_FLOAT:          attId = InitializePointAttribute<float>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;\n            default: throw GLTFException(\"Unknown component type.\");\n            }\n            \n            bufferViewsToRemove.emplace(accessor.bufferViewId);\n            attributeAccessor.bufferViewId = \"\";\n            attributeAccessor.byteOffset = 0;\n            resultDocument.accessors.Replace(attributeAccessor);\n\n            dracoExtension->attributes.emplace(attribute.first, dracoMesh.attribute(attId)->unique_id());\n        }\n        if (primitive.targets.size() > 0)\n        {\n            // Set sequential encoding to preserve order of vertices.\n            encoder.SetEncodingMethod(draco::MESH_SEQUENTIAL_ENCODING);\n        }\n\n        dracoMesh.DeduplicateAttributeValues();\n        dracoMesh.DeduplicatePointIds();\n        draco::EncoderBuffer buffer;\n        const draco::Status status = encoder.EncodeMeshToBuffer(dracoMesh, &buffer);\n        if (!status.ok()) {\n            throw GLTFException(std::string(\"Failed to encode the mesh: \") + status.error_msg());\n        }\n\n        // We must update the original accessors to the encoding out values.\n        Accessor encodedIndexAccessor(resultDocument.accessors[primitive.indicesAccessorId]);\n        encodedIndexAccessor.count = encoder.num_encoded_faces() * 3;\n        resultDocument.accessors.Replace(encodedIndexAccessor);\n\n        for (const auto& dracoAttribute : dracoExtension->attributes)\n        {\n            auto accessorId = primitive.attributes.at(dracoAttribute.first);\n            Accessor encodedAccessor(resultDocument.accessors[accessorId]);\n            encodedAccessor.count = encoder.num_encoded_points();\n            resultDocument.accessors.Replace(encodedAccessor);\n        }\n\n        // Finally put the encoded data in place.\n        auto bufferView = builder->AddBufferView(buffer.data(), buffer.size());\n        dracoExtension->bufferViewId = bufferView.id;\n        MeshPrimitive resultPrim(primitive);\n        resultPrim.SetExtension(std::move(dracoExtension));\n        resultMesh.primitives.emplace_back(resultPrim);\n    }\n    resultDocument.meshes.Replace(resultMesh);\n\n    return resultDocument;\n}\n\nDocument GLTFMeshCompressionUtils::CompressMeshes(std::shared_ptr<IStreamReader> streamReader, const Document & doc, CompressionOptions options, const std::string& outputDirectory)\n{\n    Document resultDocument(doc);\n\n    auto writerStream = std::make_shared<FilepathStreamWriter>(outputDirectory);\n    auto writer = std::make_unique<GLTFResourceWriter>(writerStream);\n    writer->SetUriPrefix(PathConcat(outputDirectory, \"MeshCompression\"));\n    std::unique_ptr<BufferBuilder> builder = std::make_unique<BufferBuilder>(std::move(writer),\n        [&doc](const BufferBuilder& builder) { return std::to_string(doc.buffers.Size() + builder.GetBufferCount()); },\n        [&doc](const BufferBuilder& builder) { return std::to_string(doc.bufferViews.Size() + builder.GetBufferViewCount()); },\n        [&doc](const BufferBuilder& builder) { return std::to_string(doc.accessors.Size() + builder.GetAccessorCount()); });\n    auto buffer = builder->AddBuffer();\n    std::unordered_set<std::string> bufferViewsToRemove;\n    for (const auto& mesh : doc.meshes.Elements())\n    {\n        resultDocument = CompressMesh(streamReader, resultDocument, options, mesh, builder.get(), bufferViewsToRemove);\n    }\n    for (const auto& bufferViewId : bufferViewsToRemove)\n    {\n        if (resultDocument.bufferViews.Has(bufferViewId))\n        {\n            resultDocument.bufferViews.Remove(bufferViewId);\n        }\n    }\n\n    builder->Output(resultDocument);\n    resultDocument.extensionsUsed.emplace(KHR::MeshPrimitives::DRACOMESHCOMPRESSION_NAME);\n    resultDocument.extensionsRequired.emplace(KHR::MeshPrimitives::DRACOMESHCOMPRESSION_NAME);\n\n    return resultDocument;\n}\n"
  },
  {
    "path": "glTF-Toolkit/src/GLTFSpecularGlossinessUtils.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See LICENSE in the project root for license information.\n\n#include \"pch.h\"\n\n#include \"GLTFTextureUtils.h\"\n#include \"GLTFSDK/ExtensionsKHR.h\"\n#include \"GLTFSDK/PBRUtils.h\"\n\n#include \"GLTFSpecularGlossinessUtils.h\"\n\n// Usings for glTF\nusing namespace Microsoft::glTF;\nusing namespace Toolkit;\nusing namespace DirectX;\n\nvoid ConvertEntrySpecularGlossinessToMetallicRoughness(\n    const XMVECTORF32& diffuseColor,\n    const XMVECTORF32& specGloss,\n    XMVECTORF32& diffuseOut,\n    float& metallicOut,\n    float& roughnessOut)\n{\n    SpecularGlossinessValue sg;\n    sg.diffuse = Color3(diffuseColor[0], diffuseColor[1], diffuseColor[2]);\n    sg.opacity = diffuseColor[3];\n    sg.specular = Color3(specGloss[0], specGloss[1], specGloss[2]);\n    sg.glossiness = specGloss[3];\n\n    MetallicRoughnessValue mr = SGToMR(sg);\n\n    roughnessOut = mr.roughness;\n    metallicOut = mr.metallic;\n    diffuseOut = { mr.base.r, mr.base.g, mr.base.b, mr.opacity };\n}\n\n\nvoid ConvertTextureSpecularGlossinessToMetallicRoughness(\n    ScratchImage& out_metallicRoughnessTexture,\n    ScratchImage& out_modulatedDiffuseTexture, \n    const std::unique_ptr<ScratchImage>& diffuseTexture, \n    const XMVECTORF32& diffuseFactor,\n    const std::unique_ptr<ScratchImage>& specularGlossinessTexture,\n    const XMVECTORF32& specularFactor)\n{\n    size_t targetWidth = 4;\n    size_t targetHeight = 4;\n\n    uint8_t* diffusePixels = nullptr;\n    if (diffuseTexture != nullptr)\n    {\n        targetWidth = diffuseTexture->GetMetadata().width;\n        targetHeight = diffuseTexture->GetMetadata().height;\n        diffusePixels = diffuseTexture->GetPixels();\n    }\n    else if (specularGlossinessTexture != nullptr)\n    {\n        targetWidth = specularGlossinessTexture->GetMetadata().width;\n        targetHeight = specularGlossinessTexture->GetMetadata().height;\n    }\n\n    uint8_t* specGlossPixels = nullptr;\n    if (specularGlossinessTexture)\n    {\n        GLTFTextureUtils::ResizeIfNeeded(specularGlossinessTexture, targetWidth, targetHeight);\n        specGlossPixels = specularGlossinessTexture->GetPixels();\n    }\n    \n    out_modulatedDiffuseTexture.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, targetWidth, targetHeight, 1, 1);\n    out_metallicRoughnessTexture.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, targetWidth, targetHeight, 1, 1);\n\n    auto diffuseOutPixels = out_modulatedDiffuseTexture.GetPixels();\n    auto metalRoughPixels = out_metallicRoughnessTexture.GetPixels();\n\n    for (uint32_t i = 0; i < targetHeight * targetWidth; ++i)\n    {\n        XMVECTORF32 diffuseColor { 1.0f, 1.0f, 1.0f, 1.0f };\n        if (diffusePixels != nullptr)\n        {\n            memcpy_s(&diffuseColor, 16, GLTFTextureUtils::GetChannelValue(diffusePixels, i, Red), 16);\n        }\n        diffuseColor.v = diffuseColor * diffuseFactor;\n\n        XMVECTORF32 specGloss { 1.0f, 1.0f, 1.0f, 1.0f };\n        if (specularGlossinessTexture != nullptr)\n        {\n            memcpy_s(&specGloss, 16, GLTFTextureUtils::GetChannelValue(specGlossPixels, i, Red), 16);\n        }\n        specGloss.v = specGloss * specularFactor;\n\n        float metallic;\n        float roughness;\n        XMVECTORF32 diffuseColorOut;\n        ConvertEntrySpecularGlossinessToMetallicRoughness(diffuseColor, specGloss, diffuseColorOut, metallic, roughness);\n\n        *GLTFTextureUtils::GetChannelValue(metalRoughPixels, i, Green) = roughness;\n        *GLTFTextureUtils::GetChannelValue(metalRoughPixels, i, Blue) = metallic;\n        auto diffuseOutPtr = GLTFTextureUtils::GetChannelValue(diffuseOutPixels, i, Red);\n        memcpy_s(diffuseOutPtr, 16, diffuseColorOut, 16);\n    }\n}\n\n\nDocument GLTFSpecularGlossinessUtils::ConvertMaterial(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const Material & material, const std::string& outputDirectory)\n{\n    if (!material.HasExtension<KHR::Materials::PBRSpecularGlossiness>())\n    {\n        return doc;\n    }\n\n    Document resultDoc(doc);\n    Material resultMaterial(material);\n    resultMaterial.RemoveExtension<KHR::Materials::PBRSpecularGlossiness>();\n\n    const auto& specularGlossiness = material.GetExtension<KHR::Materials::PBRSpecularGlossiness>();\n\n    XMVECTORF32 diffuseFactorIn = {\n        specularGlossiness.diffuseFactor.r,\n        specularGlossiness.diffuseFactor.g,\n        specularGlossiness.diffuseFactor.b,\n        specularGlossiness.diffuseFactor.a\n    };\n\n    XMVECTORF32 specularFactor = {\n        specularGlossiness.specularFactor.r,\n        specularGlossiness.specularFactor.g,\n        specularGlossiness.specularFactor.b,\n        specularGlossiness.glossinessFactor\n    };\n\n    // First, we check if there actually is a diffuse or specular glossiness texture to convert.\n    // If not, we only perform the conversion on the materials parameters and early out.\n    if (specularGlossiness.diffuseTexture.textureId.empty() &&\n        specularGlossiness.specularGlossinessTexture.textureId.empty())\n    {\n        XMVECTORF32 diffuseFactor;\n        float metallicFactor;\n        float roughnessFactor;\n\n        ConvertEntrySpecularGlossinessToMetallicRoughness(diffuseFactorIn, specularFactor, diffuseFactor, metallicFactor, roughnessFactor);\n        resultMaterial.metallicRoughness.baseColorFactor.r = diffuseFactor.f[0];\n        resultMaterial.metallicRoughness.baseColorFactor.g = diffuseFactor.f[1];\n        resultMaterial.metallicRoughness.baseColorFactor.b = diffuseFactor.f[2];\n        resultMaterial.metallicRoughness.baseColorFactor.a = diffuseFactor.f[3];\n        resultMaterial.metallicRoughness.metallicFactor = metallicFactor;\n        resultMaterial.metallicRoughness.roughnessFactor = roughnessFactor;\n\n        resultDoc.materials.Replace(resultMaterial);\n    }\n\n    std::string samplerId;\n\n    // Diffuse texture\n    std::unique_ptr<ScratchImage> diffuseTexture;\n    if (!specularGlossiness.diffuseTexture.textureId.empty())\n    {\n        try\n        {\n            diffuseTexture = std::make_unique<ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, specularGlossiness.diffuseTexture.textureId, false));\n            samplerId = doc.textures[specularGlossiness.diffuseTexture.textureId].samplerId;\n        }\n        catch (GLTFException)\n        {\n            throw GLTFException(\"Failed to load diffuse texture.\");\n        }\n    }\n\n    // SpecularGlossiness texture\n    std::unique_ptr<ScratchImage> specularGlossinessTexture;\n    if (!specularGlossiness.specularGlossinessTexture.textureId.empty())\n    {\n        try\n        {\n            specularGlossinessTexture = std::make_unique<ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, specularGlossiness.specularGlossinessTexture.textureId, false));\n            samplerId = samplerId.empty() ? doc.textures[specularGlossiness.specularGlossinessTexture.textureId].samplerId : samplerId;\n        }\n        catch (GLTFException)\n        {\n            throw GLTFException(\"Failed to load specular glossiness texture.\");\n        }\n    }\n\n    ScratchImage metallicRoughnessTexture;\n    ScratchImage modulatedDiffuseTexture;\n\n    ConvertTextureSpecularGlossinessToMetallicRoughness(\n        metallicRoughnessTexture,\n        modulatedDiffuseTexture,\n        diffuseTexture,\n        diffuseFactorIn, // will be baked into texture\n        specularGlossinessTexture,\n        specularFactor);\n\n    Material::PBRMetallicRoughness gltfPBRMetallicRoughness;\n\n    {\n        DirectX::ScratchImage converted;\n        if (FAILED(DirectX::Convert(*metallicRoughnessTexture.GetImage(0, 0, 0), DXGI_FORMAT_B8G8R8X8_UNORM, DirectX::TEX_FILTER_SRGB_IN, DirectX::TEX_THRESHOLD_DEFAULT, converted)))\n        {\n            throw GLTFException(\"Failed to convert texture to DXGI_FORMAT_B8G8R8X8_UNORM for processing.\");\n        }\n\n        auto metallicRoughnessPath = GLTFTextureUtils::SaveAsPng(&converted, \"metallicRoughness_\" + material.id + \".png\", outputDirectory);\n        auto metallicRoughnessImageId = GLTFTextureUtils::AddImageToDocument(resultDoc, metallicRoughnessPath);\n        Texture mrTexture;\n        mrTexture.samplerId = samplerId;\n        mrTexture.imageId = metallicRoughnessImageId;\n        gltfPBRMetallicRoughness.metallicRoughnessTexture.textureId = resultDoc.textures.Append(mrTexture, AppendIdPolicy::GenerateOnEmpty).id;\n    }\n\n    {\n        DirectX::ScratchImage converted;\n        if (FAILED(DirectX::Convert(*modulatedDiffuseTexture.GetImage(0, 0, 0), DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DirectX::TEX_FILTER_DEFAULT, DirectX::TEX_THRESHOLD_DEFAULT, converted)))\n        {\n            throw GLTFException(\"Failed to convert texture to DXGI_FORMAT_B8G8R8A8_UNORM_SRGB for processing.\");\n        }\n        auto diffusePath = GLTFTextureUtils::SaveAsPng(&converted, \"diffuse_\" + material.id + \".png\", outputDirectory, &GUID_WICPixelFormat32bppBGRA);\n        auto diffuseImageId = GLTFTextureUtils::AddImageToDocument(resultDoc, diffusePath);\n        Texture diffusGltfTexture;\n        diffusGltfTexture.samplerId = samplerId;\n        diffusGltfTexture.imageId = diffuseImageId;\n        gltfPBRMetallicRoughness.baseColorTexture.textureId = resultDoc.textures.Append(diffusGltfTexture, AppendIdPolicy::GenerateOnEmpty).id;\n    }\n\n    resultMaterial.metallicRoughness = gltfPBRMetallicRoughness;\n    resultDoc.materials.Replace(resultMaterial);\n\n    return resultDoc;\n}\n\n\nDocument GLTFSpecularGlossinessUtils::ConvertMaterials(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const std::string & outputDirectory)\n{\n    Document resultDocument(doc);\n    for (const auto& material : doc.materials.Elements())\n    {\n        resultDocument = ConvertMaterial(streamReader, resultDocument, material, outputDirectory);\n    }\n\n    resultDocument.extensionsUsed.erase(KHR::Materials::PBRSPECULARGLOSSINESS_NAME);\n    resultDocument.extensionsRequired.erase(KHR::Materials::PBRSPECULARGLOSSINESS_NAME);\n\n    return resultDocument;\n}\n"
  },
  {
    "path": "glTF-Toolkit/src/GLTFTextureCompressionUtils.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n\r\n#include \"GLTFTextureUtils.h\"\r\n#include \"GLTFTexturePackingUtils.h\"\r\n#include \"GLTFTextureCompressionUtils.h\"\r\n#include \"DeviceResources.h\"\r\n\r\n// Usings for ComPtr\r\nusing namespace ABI::Windows::Foundation;\r\nusing namespace Microsoft::WRL;\r\n\r\n// Usings for glTF\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\n#include <DirectXTex.h>\r\n\r\nconst char* Microsoft::glTF::Toolkit::EXTENSION_MSFT_TEXTURE_DDS = \"MSFT_texture_dds\";\r\n\r\nDocument GLTFTextureCompressionUtils::CompressTextureAsDDS(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const Texture & texture, TextureCompression compression, const std::string& outputDirectory, size_t maxTextureSize, bool generateMipMaps, bool retainOriginalImage, bool treatAsLinear)\r\n{\r\n    Document outputDoc(doc);\r\n\r\n    // Early return cases:\r\n    // - No compression requested\r\n    // - This texture doesn't have an image associated\r\n    // - The texture already has a DDS extension\r\n    if (compression == TextureCompression::None ||\r\n        texture.imageId.empty() ||\r\n        texture.extensions.find(EXTENSION_MSFT_TEXTURE_DDS) != texture.extensions.end())\r\n    {\r\n        // Return copy of document\r\n        return outputDoc;\r\n    }\r\n\r\n    auto image = std::make_unique<DirectX::ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, texture.id, treatAsLinear));\r\n\r\n    // Resize up to a multiple of 4\r\n    auto metadata = image->GetMetadata();\r\n    auto resizedWidth = metadata.width;\r\n    auto resizedHeight = metadata.height;\r\n\r\n    if (maxTextureSize < resizedWidth || maxTextureSize < resizedHeight)\r\n    {\r\n        // Scale\r\n        auto scaleFactor = static_cast<double>(maxTextureSize) / std::max(metadata.width, metadata.height);\r\n        resizedWidth = static_cast<size_t>(std::llround(metadata.width * scaleFactor));\r\n        resizedHeight = static_cast<size_t>(std::llround(metadata.height * scaleFactor));\r\n    }\r\n\r\n    if (resizedWidth % 4 != 0 || resizedHeight % 4 != 0)\r\n    {\r\n        static const std::function<size_t(size_t)> roundUpToMultipleOf4 = [](size_t input)\r\n        {\r\n            return input % 4 == 0 ? input : (input + 4) - (input % 4);\r\n        };\r\n\r\n        resizedWidth = roundUpToMultipleOf4(resizedWidth);\r\n        resizedHeight = roundUpToMultipleOf4(resizedHeight);\r\n    }\r\n\r\n    if (resizedWidth != metadata.width || resizedHeight != metadata.height)\r\n    {\r\n        auto resized = std::make_unique<DirectX::ScratchImage>();\r\n        if (FAILED(DirectX::Resize(image->GetImages(), image->GetImageCount(), image->GetMetadata(), resizedWidth, resizedHeight, DirectX::TEX_FILTER_SEPARATE_ALPHA, *resized)))\r\n        {\r\n            throw GLTFException(\"Failed to resize image.\");\r\n        }\r\n\r\n        image = std::move(resized);\r\n    }\r\n\r\n    if (generateMipMaps)\r\n    {\r\n        auto mipChain = std::make_unique<DirectX::ScratchImage>();\r\n        if (FAILED(DirectX::GenerateMipMaps(image->GetImages(), image->GetImageCount(), image->GetMetadata(), DirectX::TEX_FILTER_SEPARATE_ALPHA, 0, *mipChain)))\r\n        {\r\n            throw GLTFException(\"Failed to generate mip maps.\");\r\n        }\r\n\r\n        image = std::move(mipChain);\r\n    }\r\n\r\n    CompressImage(*image, compression);\r\n\r\n    // Save image to file\r\n    std::string outputImagePath = \"texture_\" + texture.id;\r\n\r\n    if (!generateMipMaps)\r\n    {\r\n        // The default is to have mips, so note on the texture when it doesn't\r\n        outputImagePath += \"_nomips\";\r\n    }\r\n\r\n    switch (compression)\r\n    {\r\n    case TextureCompression::BC3:\r\n        outputImagePath += \"_BC3\";\r\n        break;\r\n    case TextureCompression::BC5:\r\n        outputImagePath += \"_BC5\";\r\n        break;\r\n    case TextureCompression::BC7:\r\n    case TextureCompression::BC7_SRGB:\r\n        outputImagePath += \"_BC7\";\r\n        break;\r\n    default:\r\n        throw GLTFException(\"Invalid compression.\");\r\n        break;\r\n    }\r\n\r\n    outputImagePath += \".dds\";\r\n    std::wstring outputImagePathW(outputImagePath.begin(), outputImagePath.end());\r\n\r\n    wchar_t outputImageFullPath[MAX_PATH];\r\n\r\n    std::wstring outputDirectoryW(outputDirectory.begin(), outputDirectory.end());\r\n\r\n    if (FAILED(::PathCchCombine(outputImageFullPath, ARRAYSIZE(outputImageFullPath), outputDirectoryW.c_str(), outputImagePathW.c_str())))\r\n    {\r\n        throw GLTFException(\"Failed to compose output file path.\");\r\n    }\r\n\r\n    if (FAILED(SaveToDDSFile(image->GetImages(), image->GetImageCount(), image->GetMetadata(), DirectX::DDS_FLAGS::DDS_FLAGS_NONE, outputImageFullPath)))\r\n    {\r\n        throw GLTFException(\"Failed to save image as DDS.\");\r\n    }\r\n\r\n    std::wstring outputImageFullPathW(outputImageFullPath);\r\n    std::string outputImageFullPathA(outputImageFullPathW.begin(), outputImageFullPathW.end());\r\n\r\n    // Add back to GLTF\r\n    std::string ddsImageId(texture.imageId);\r\n\r\n    Image ddsImage(doc.images.Get(texture.imageId));\r\n    ddsImage.mimeType = \"image/vnd-ms.dds\";\r\n    ddsImage.uri = outputImageFullPathA;\r\n\r\n    if (retainOriginalImage)\r\n    {\r\n        ddsImage.id.clear();\r\n        ddsImageId = outputDoc.images.Append(ddsImage, AppendIdPolicy::GenerateOnEmpty).id;\r\n    }\r\n    else\r\n    {\r\n        outputDoc.images.Replace(ddsImage);\r\n    }\r\n\r\n    Texture ddsTexture(texture);\r\n\r\n    // Create the JSON for the DDS extension element\r\n    rapidjson::Document ddsExtensionJson;\r\n    ddsExtensionJson.SetObject();\r\n\r\n    ddsExtensionJson.AddMember(\"source\", rapidjson::Value(outputDoc.images.GetIndex(ddsImageId)), ddsExtensionJson.GetAllocator());\r\n\r\n    rapidjson::StringBuffer buffer;\r\n    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\r\n    ddsExtensionJson.Accept(writer);\r\n\r\n    ddsTexture.extensions.insert(std::pair<std::string, std::string>(EXTENSION_MSFT_TEXTURE_DDS, buffer.GetString()));\r\n\r\n    outputDoc.textures.Replace(ddsTexture);\r\n\r\n    outputDoc.extensionsUsed.insert(EXTENSION_MSFT_TEXTURE_DDS);\r\n\r\n    if (!retainOriginalImage)\r\n    {\r\n        outputDoc.extensionsRequired.insert(EXTENSION_MSFT_TEXTURE_DDS);\r\n    }\r\n\r\n    return outputDoc;\r\n}\r\n\r\nDocument GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const std::string& outputDirectory, size_t maxTextureSize, bool retainOriginalImages)\r\n{\r\n    Document outputDoc(doc);\r\n\r\n    for (auto material : doc.materials.Elements())\r\n    {\r\n        auto compressIfNotEmpty = [&outputDoc, &streamReader, &outputDirectory, maxTextureSize, retainOriginalImages](const std::string& textureId, TextureCompression compression, bool treatAsLinear = true)\r\n        {\r\n            if (!textureId.empty())\r\n            {\r\n                outputDoc = CompressTextureAsDDS(streamReader, outputDoc, outputDoc.textures.Get(textureId), compression, outputDirectory, maxTextureSize, true, retainOriginalImages, treatAsLinear);\r\n            }\r\n        };\r\n\r\n        // Compress base and emissive texture as BC7\r\n        compressIfNotEmpty(material.metallicRoughness.baseColorTexture.textureId, TextureCompression::BC7_SRGB, false);\r\n        compressIfNotEmpty(material.emissiveTexture.textureId, TextureCompression::BC7_SRGB, false);\r\n\r\n        // Get textures from the MSFT_packing_occlusionRoughnessMetallic extension\r\n        if (material.extensions.find(EXTENSION_MSFT_PACKING_ORM) != material.extensions.end())\r\n        {\r\n            rapidjson::Document packingOrmContents;\r\n            packingOrmContents.Parse(material.extensions[EXTENSION_MSFT_PACKING_ORM].c_str());\r\n\r\n            // Compress packed textures as BC7\r\n            if (packingOrmContents.HasMember(MSFT_PACKING_ORM_RMOTEXTURE_KEY))\r\n            {\r\n                auto rmoTextureId = packingOrmContents[MSFT_PACKING_ORM_RMOTEXTURE_KEY][MSFT_PACKING_INDEX_KEY].GetInt();\r\n                compressIfNotEmpty(std::to_string(rmoTextureId), TextureCompression::BC7);\r\n            }\r\n\r\n            if (packingOrmContents.HasMember(MSFT_PACKING_ORM_ORMTEXTURE_KEY))\r\n            {\r\n                auto ormTextureId = packingOrmContents[MSFT_PACKING_ORM_ORMTEXTURE_KEY][MSFT_PACKING_INDEX_KEY].GetInt();\r\n                compressIfNotEmpty(std::to_string(ormTextureId), TextureCompression::BC7);\r\n            }\r\n\r\n            // Compress normal texture as BC5\r\n            if (packingOrmContents.HasMember(MSFT_PACKING_ORM_NORMALTEXTURE_KEY))\r\n            {\r\n                auto normalTextureId = packingOrmContents[MSFT_PACKING_ORM_NORMALTEXTURE_KEY][MSFT_PACKING_INDEX_KEY].GetInt();\r\n                compressIfNotEmpty(std::to_string(normalTextureId), TextureCompression::BC5);\r\n            }\r\n        }\r\n\r\n        // Get textures from the MSFT_packing_normalRoughnessMetallic extension\r\n        if (material.extensions.find(EXTENSION_MSFT_PACKING_NRM) != material.extensions.end())\r\n        {\r\n            rapidjson::Document packingNrmContents;\r\n            packingNrmContents.Parse(material.extensions[EXTENSION_MSFT_PACKING_NRM].c_str());\r\n\r\n            // Compress packed texture as BC7\r\n            if (packingNrmContents.HasMember(MSFT_PACKING_NRM_KEY))\r\n            {\r\n                auto nrmTextureId = packingNrmContents[MSFT_PACKING_NRM_KEY][MSFT_PACKING_INDEX_KEY].GetInt();\r\n                compressIfNotEmpty(std::to_string(nrmTextureId), TextureCompression::BC7, false); // This tool generates sRGB-packaged images\r\n            }\r\n        }\r\n    }\r\n\r\n    return outputDoc;\r\n}\r\n\r\nvoid GLTFTextureCompressionUtils::CompressImage(DirectX::ScratchImage& image, TextureCompression compression)\r\n{\r\n    if (compression == TextureCompression::None)\r\n    {\r\n        return;\r\n    }\r\n\r\n    DXGI_FORMAT compressionFormat = DXGI_FORMAT_BC7_UNORM;\r\n    switch (compression)\r\n    {\r\n    case TextureCompression::BC3:\r\n        compressionFormat = DXGI_FORMAT_BC3_UNORM;\r\n        break;\r\n    case TextureCompression::BC5:\r\n        compressionFormat = DXGI_FORMAT_BC5_UNORM;\r\n        break;\r\n    case TextureCompression::BC7:\r\n        compressionFormat = DXGI_FORMAT_BC7_UNORM;\r\n        break;\r\n    case TextureCompression::BC7_SRGB:\r\n        compressionFormat = DXGI_FORMAT_BC7_UNORM_SRGB;\r\n        break;\r\n    default:\r\n        throw std::invalid_argument(\"Invalid compression specified.\");\r\n        break;\r\n    }\r\n\r\n    bool gpuCompressionSuccessful = false;\r\n    DirectX::ScratchImage compressedImage;\r\n\r\n    try\r\n    {\r\n        DX::DeviceResources deviceResources;\r\n        deviceResources.CreateDeviceResources();\r\n        ComPtr<ID3D11Device> device(deviceResources.GetD3DDevice());\r\n\r\n        if (device != nullptr)\r\n        {\r\n            if (SUCCEEDED(DirectX::Compress(device.Get(), image.GetImages(), image.GetImageCount(), image.GetMetadata(), compressionFormat, DirectX::TEX_COMPRESS_DEFAULT, 1, compressedImage)))\r\n            {\r\n                gpuCompressionSuccessful = true;\r\n            }\r\n        }\r\n    }\r\n    catch (std::exception e)\r\n    {\r\n        // Failed to initialize device - GPU is not available\r\n    }\r\n\r\n    if (!gpuCompressionSuccessful)\r\n    {\r\n        // Try software compression\r\n        if (FAILED(DirectX::Compress(image.GetImages(), image.GetImageCount(), image.GetMetadata(), compressionFormat, DirectX::TEX_COMPRESS_PARALLEL, 1, compressedImage)))\r\n        {\r\n            throw GLTFException(\"Failed to compress data using software compression\");\r\n        }\r\n    }\r\n\r\n    image = std::move(compressedImage);\r\n}"
  },
  {
    "path": "glTF-Toolkit/src/GLTFTexturePackingUtils.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n\r\n#include <DirectXTex.h>\r\n\r\n#include \"GLTFTextureUtils.h\"\r\n#include \"GLTFTexturePackingUtils.h\"\r\n\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\nconst char* Microsoft::glTF::Toolkit::EXTENSION_MSFT_PACKING_ORM = \"MSFT_packing_occlusionRoughnessMetallic\";\r\nconst char* Microsoft::glTF::Toolkit::EXTENSION_MSFT_PACKING_NRM = \"MSFT_packing_normalRoughnessMetallic\";\r\nconst char* Microsoft::glTF::Toolkit::MSFT_PACKING_INDEX_KEY = \"index\";\r\nconst char* Microsoft::glTF::Toolkit::MSFT_PACKING_ORM_ORMTEXTURE_KEY = \"occlusionRoughnessMetallicTexture\";\r\nconst char* Microsoft::glTF::Toolkit::MSFT_PACKING_ORM_RMOTEXTURE_KEY = \"roughnessMetallicOcclusionTexture\";\r\nconst char* Microsoft::glTF::Toolkit::MSFT_PACKING_ORM_NORMALTEXTURE_KEY = \"normalTexture\";\r\nconst char* Microsoft::glTF::Toolkit::MSFT_PACKING_NRM_KEY = \"normalRoughnessMetallicTexture\";\r\n\r\nnamespace\r\n{\r\n    void AddTextureToExtension(const std::string& imageId, TexturePacking packing, Document& doc, rapidjson::Value& packedExtensionJson, rapidjson::MemoryPoolAllocator<>& a)\r\n    {\r\n        Texture packedTexture;\r\n        packedTexture.imageId = imageId;\r\n        auto textureId = doc.textures.Append(std::move(packedTexture), AppendIdPolicy::GenerateOnEmpty).id;\r\n\r\n        rapidjson::Value packedTextureJson(rapidjson::kObjectType);\r\n        {\r\n            packedTextureJson.AddMember(rapidjson::StringRef(MSFT_PACKING_INDEX_KEY), rapidjson::Value(doc.textures.GetIndex(textureId)), a);\r\n        }\r\n        switch (packing)\r\n        {\r\n        case TexturePacking::OcclusionRoughnessMetallic:\r\n            packedExtensionJson.AddMember(rapidjson::StringRef(MSFT_PACKING_ORM_ORMTEXTURE_KEY), packedTextureJson, a);\r\n            break;\r\n        case TexturePacking::RoughnessMetallicOcclusion:\r\n            packedExtensionJson.AddMember(rapidjson::StringRef(MSFT_PACKING_ORM_RMOTEXTURE_KEY), packedTextureJson, a);\r\n            break;\r\n        case TexturePacking::NormalRoughnessMetallic:\r\n            packedExtensionJson.AddMember(rapidjson::StringRef(MSFT_PACKING_NRM_KEY), packedTextureJson, a);\r\n            break;\r\n        default:\r\n            throw GLTFException(\"Invalid packing.\");\r\n        }\r\n    }\r\n\r\n\r\n    void Renormalize(std::unique_ptr<DirectX::ScratchImage> &normalImage, DirectX::ScratchImage &renormalizedImage)\r\n    {\r\n        auto image = normalImage->GetImage(0, 0, 0);\r\n        if (FAILED(renormalizedImage.Initialize2D(image->format, image->width, image->height, 1, 1)))\r\n        {\r\n            throw GLTFException(\"Failed to initialize from texture.\");\r\n        }\r\n\r\n        uint8_t *normalPixels = normalImage->GetPixels();\r\n        auto metadata = normalImage->GetMetadata();\r\n\r\n        auto renormalizedPixels = renormalizedImage.GetPixels();\r\n\r\n        const auto two = DirectX::XMVectorReplicate(2.0f);\r\n        const auto minusOne = DirectX::XMVectorReplicate(-1.0f);\r\n        const auto half = DirectX::XMVectorReplicate(0.5f);\r\n\r\n        for (size_t i = 0; i < metadata.width * metadata.height; i += 1)\r\n        {\r\n            // renormalizedPixels = 0.5 * normalize(normalPixel * 2 - 1) + 0.5\r\n            const auto value = DirectX::XMVectorSet(\r\n                *GLTFTextureUtils::GetChannelValue(normalPixels, i, Channel::Red),\r\n                *GLTFTextureUtils::GetChannelValue(normalPixels, i, Channel::Green),\r\n                *GLTFTextureUtils::GetChannelValue(normalPixels, i, Channel::Blue),\r\n                0.0f);\r\n\r\n            auto normal = DirectX::XMVectorMultiplyAdd(value, two, minusOne);\r\n            normal = DirectX::XMVector3Normalize(normal);\r\n            const auto result = DirectX::XMVectorMultiplyAdd(half, normal, half);\r\n\r\n            *GLTFTextureUtils::GetChannelValue(renormalizedPixels, i, Channel::Red) = DirectX::XMVectorGetX(result);\r\n            *GLTFTextureUtils::GetChannelValue(renormalizedPixels, i, Channel::Green) = DirectX::XMVectorGetY(result);\r\n            *GLTFTextureUtils::GetChannelValue(renormalizedPixels, i, Channel::Blue) = DirectX::XMVectorGetZ(result);\r\n        }\r\n    }\r\n\r\n    void AdjustRoughness(std::unique_ptr<DirectX::ScratchImage> &roughnessImage, std::unique_ptr<DirectX::ScratchImage> &normalImage, DirectX::ScratchImage &adjustedImage)\r\n    {\r\n        auto image = roughnessImage->GetImage(0, 0, 0);\r\n        if (FAILED(adjustedImage.Initialize2D(image->format, image->width, image->height, 1, 1)))\r\n        {\r\n            throw GLTFException(\"Failed to initialize from texture.\");\r\n        }\r\n\r\n        const auto two = DirectX::XMVectorReplicate(2.0f);\r\n        const auto minusOne = DirectX::XMVectorReplicate(-1.0f);\r\n\r\n        uint8_t *normalPixels = normalImage->GetPixels();\r\n        auto metadata = normalImage->GetMetadata();\r\n\r\n        auto adjustedPixels = adjustedImage.GetPixels();\r\n        uint8_t *roughnessPixels = roughnessImage->GetPixels();\r\n\r\n        for (size_t i = 0; i < metadata.width * metadata.height; i += 1)\r\n        {\r\n            auto normal = DirectX::XMVectorSet(\r\n                *GLTFTextureUtils::GetChannelValue(normalPixels, i, Channel::Red),\r\n                *GLTFTextureUtils::GetChannelValue(normalPixels, i, Channel::Green),\r\n                *GLTFTextureUtils::GetChannelValue(normalPixels, i, Channel::Blue),\r\n                0.0f);\r\n            normal = DirectX::XMVectorMultiplyAdd(normal, two, minusOne);\r\n            auto avgNormalLengthSquare = DirectX::XMVector3LengthSq(normal);\r\n            float avgNormalLengthSquareF = DirectX::XMVectorGetX(avgNormalLengthSquare);\r\n\r\n            float oldRoughness = *GLTFTextureUtils::GetChannelValue(roughnessPixels, i, Channel::Green);\r\n            if (avgNormalLengthSquareF < 1.0f)\r\n            {\r\n                auto avgNormalLength = DirectX::XMVectorSqrt(avgNormalLengthSquare);\r\n                float avgNormalLengthF = DirectX::XMVectorGetX(avgNormalLength);\r\n                float kappa = (3.0f * avgNormalLengthF - avgNormalLengthF * avgNormalLengthSquareF) / (1.0f - avgNormalLengthSquareF);\r\n                float variance = 1.0f / (2.0f * kappa);\r\n\r\n                float newRoughness = sqrt(oldRoughness * oldRoughness + variance);\r\n\r\n                *GLTFTextureUtils::GetChannelValue(adjustedPixels, i, Channel::Green) = newRoughness;\r\n            }\r\n            else\r\n            {\r\n                *GLTFTextureUtils::GetChannelValue(adjustedPixels, i, Channel::Green) = oldRoughness;\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nstd::unordered_set<int> GLTFTexturePackingUtils::GetTextureIndicesFromMsftExtensions(const Material& material)\r\n{\r\n    static const char* extensionKeys[] = {\r\n        EXTENSION_MSFT_PACKING_ORM,\r\n        EXTENSION_MSFT_PACKING_NRM\r\n    };\r\n\r\n    static const char* textureKeys[] = {\r\n        MSFT_PACKING_ORM_ORMTEXTURE_KEY,\r\n        MSFT_PACKING_ORM_RMOTEXTURE_KEY,\r\n        MSFT_PACKING_ORM_NORMALTEXTURE_KEY,\r\n        MSFT_PACKING_NRM_KEY\r\n    };\r\n\r\n    std::unordered_set<int> textureIndices;\r\n\r\n    for (const auto& extensionKey : extensionKeys)\r\n    {\r\n        auto extensionIt = material.extensions.find(extensionKey);\r\n        if (extensionIt != material.extensions.end() && !extensionIt->second.empty())\r\n        {\r\n            rapidjson::Document extJson = RapidJsonUtils::CreateDocumentFromString(extensionIt->second);\r\n\r\n            for (const auto& textureKey : textureKeys)\r\n            {\r\n                if (extJson.HasMember(textureKey))\r\n                {\r\n                    const auto index = extJson[textureKey][MSFT_PACKING_INDEX_KEY].GetInt();\r\n                    textureIndices.insert(index);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    return textureIndices;\r\n}\r\n\r\nDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document& doc, const Material& material, TexturePacking packing, const std::string& outputDirectory)\r\n{\r\n    Document outputDoc(doc);\r\n\r\n    // No packing requested, return copy of document\r\n    if (packing == TexturePacking::None)\r\n    {\r\n        return outputDoc;\r\n    }\r\n\r\n    // Read images from material\r\n    auto metallicRoughness = material.metallicRoughness.metallicRoughnessTexture.textureId;\r\n    auto normal = material.normalTexture.textureId;\r\n    auto occlusion = material.occlusionTexture.textureId;\r\n\r\n    bool hasMR = !metallicRoughness.empty();\r\n    bool hasNormal = !normal.empty();\r\n    bool hasOcclusion = !occlusion.empty();\r\n\r\n    // Early return if there's nothing to pack\r\n    if (!hasMR && !hasOcclusion && !hasNormal)\r\n    {\r\n        // RM, O and Normal are empty, and the packing requires at least one of them\r\n        return outputDoc;\r\n    }\r\n\r\n    // TODO: Optimization - If the texture pair (MR + O) has already been packed together with the \r\n    // current packing, point to that existing texture instead of creating a new one\r\n\r\n    Material outputMaterial = outputDoc.materials.Get(material.id);\r\n\r\n    // Create the JSON for the material extension element\r\n    rapidjson::Document ormExtensionJson;\r\n    ormExtensionJson.SetObject();\r\n    rapidjson::MemoryPoolAllocator<>& ormAllocator = ormExtensionJson.GetAllocator();\r\n\r\n    rapidjson::Document nrmExtensionJson;\r\n    nrmExtensionJson.SetObject();\r\n    rapidjson::MemoryPoolAllocator<>& nrmAllocator = nrmExtensionJson.GetAllocator();\r\n\r\n    std::unique_ptr<DirectX::ScratchImage> metallicRoughnessImage = nullptr;\r\n    if (hasMR)\r\n    {\r\n        try\r\n        {\r\n            metallicRoughnessImage = std::make_unique<DirectX::ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, metallicRoughness));\r\n        }\r\n        catch (GLTFException)\r\n        {\r\n            throw GLTFException(\"Failed to load metallic roughness texture.\");\r\n        }\r\n    }\r\n\r\n    bool packingIncludesOrm = (packing & (TexturePacking::OcclusionRoughnessMetallic | TexturePacking::RoughnessMetallicOcclusion)) > 0;\r\n\r\n    std::unique_ptr<DirectX::ScratchImage> occlusionImage = nullptr;\r\n    if (hasOcclusion && packingIncludesOrm)\r\n    {\r\n        try\r\n        {\r\n            occlusionImage = std::make_unique<DirectX::ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, occlusion));\r\n        }\r\n        catch (GLTFException)\r\n        {\r\n            throw GLTFException(\"Failed to load occlusion texture.\");\r\n        }\r\n    }\r\n\r\n    if (hasMR && hasOcclusion && packingIncludesOrm)\r\n    {\r\n        GLTFTextureUtils::ResizeToLargest(metallicRoughnessImage, occlusionImage);\r\n    }\r\n\r\n    bool packingIncludesNrm = (packing & TexturePacking::NormalRoughnessMetallic) > 0;\r\n\r\n    std::unique_ptr<DirectX::ScratchImage> normalImage = nullptr;\r\n    if (hasNormal && packingIncludesNrm)\r\n    {\r\n        try\r\n        {\r\n            normalImage = std::make_unique<DirectX::ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, normal));\r\n        }\r\n        catch (GLTFException)\r\n        {\r\n            throw GLTFException(\"Failed to load normal texture.\");\r\n        }\r\n    }\r\n\r\n    if (hasMR && hasNormal && packingIncludesNrm)\r\n    {\r\n        GLTFTextureUtils::ResizeToLargest(metallicRoughnessImage, normalImage);\r\n    }\r\n\r\n    uint8_t *mrPixels = metallicRoughnessImage != nullptr ? metallicRoughnessImage->GetPixels() : nullptr;\r\n    uint8_t *occlusionPixels = occlusionImage != nullptr ? occlusionImage->GetPixels() : nullptr;\r\n    uint8_t *normalPixels = normalImage != nullptr ? normalImage->GetPixels() : nullptr;\r\n\r\n    // Pack textures using DirectXTex\r\n\r\n    if (packing & TexturePacking::OcclusionRoughnessMetallic && (hasMR || hasOcclusion))\r\n    {\r\n        std::string ormImageId;\r\n\r\n        // If occlusion and metallic roughness are pointing to the same texture,\r\n        // according to the GLTF spec, that texture is already packed as ORM\r\n        // (occlusion = R, roughness = G, metalness = B)\r\n        if (occlusion == metallicRoughness && hasOcclusion)\r\n        {\r\n            ormImageId = metallicRoughness;\r\n        }\r\n        else\r\n        {\r\n            DirectX::ScratchImage orm;\r\n\r\n            auto sourceImage = hasMR ? *metallicRoughnessImage->GetImage(0, 0, 0) : *occlusionImage->GetImage(0, 0, 0);\r\n            if (FAILED(orm.Initialize2D(sourceImage.format, sourceImage.width, sourceImage.height, 1, 1)))\r\n            {\r\n                throw GLTFException(\"Failed to initialize from texture.\");\r\n            }\r\n\r\n            auto ormPixels = orm.GetPixels();\r\n            auto metadata = orm.GetMetadata();\r\n\r\n            for (size_t i = 0; i < metadata.width * metadata.height; i += 1)\r\n            {\r\n                // Occlusion: Occ [R] -> ORM [R]\r\n                *GLTFTextureUtils::GetChannelValue(ormPixels, i, Channel::Red) = hasOcclusion ? *GLTFTextureUtils::GetChannelValue(occlusionPixels, i, Channel::Red) : 255.0f;\r\n                // Roughness: MR [G] -> ORM [G]\r\n                *GLTFTextureUtils::GetChannelValue(ormPixels, i, Channel::Green) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Green) : 255.0f;\r\n                // Metalness: MR [B] -> ORM [B]\r\n                *GLTFTextureUtils::GetChannelValue(ormPixels, i, Channel::Blue) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Blue) : 255.0f;\r\n            }\r\n\r\n            // Convert with assumed sRGB because PNG defaults to that color space.\r\n            DirectX::ScratchImage converted;\r\n            if (FAILED(DirectX::Convert(*orm.GetImage(0, 0, 0), DXGI_FORMAT_B8G8R8X8_UNORM, DirectX::TEX_FILTER_SRGB_IN, DirectX::TEX_THRESHOLD_DEFAULT, converted)))\r\n            {\r\n                throw GLTFException(\"Failed to convert texture to DXGI_FORMAT_B8G8R8X8_UNORM for storage.\");\r\n            }\r\n\r\n            auto imagePath = GLTFTextureUtils::SaveAsPng(&converted, \"packing_orm_\" + material.id + \".png\", outputDirectory);\r\n\r\n            ormImageId = GLTFTextureUtils::AddImageToDocument(outputDoc, imagePath);\r\n        }\r\n\r\n        AddTextureToExtension(ormImageId, TexturePacking::OcclusionRoughnessMetallic, outputDoc, ormExtensionJson, ormAllocator);\r\n    }\r\n\r\n    if (packing & TexturePacking::RoughnessMetallicOcclusion && (hasMR || hasOcclusion))\r\n    {\r\n        DirectX::ScratchImage rmo;\r\n\r\n        auto sourceImage = hasMR ? *metallicRoughnessImage->GetImage(0, 0, 0) : *occlusionImage->GetImage(0, 0, 0);\r\n        if (FAILED(rmo.Initialize2D(sourceImage.format, sourceImage.width, sourceImage.height, 1, 1)))\r\n        {\r\n            throw GLTFException(\"Failed to initialize from texture.\");\r\n        }\r\n\r\n        auto rmoPixels = rmo.GetPixels();\r\n        auto metadata = rmo.GetMetadata();\r\n\r\n        for (size_t i = 0; i < metadata.width * metadata.height; i += 1)\r\n        {\r\n            // Roughness: MR [G] -> RMO [R]\r\n            *GLTFTextureUtils::GetChannelValue(rmoPixels, i, Channel::Red) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Green) : 255.0f;\r\n            // Metalness: MR [B] -> RMO [G]\r\n            *GLTFTextureUtils::GetChannelValue(rmoPixels, i, Channel::Green) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Blue) : 255.0f;\r\n            // Occlusion: Occ [R] -> RMO [B]\r\n            *GLTFTextureUtils::GetChannelValue(rmoPixels, i, Channel::Blue) = hasOcclusion ? *GLTFTextureUtils::GetChannelValue(occlusionPixels, i, Channel::Red) : 255.0f;\r\n        }\r\n\r\n        // Convert with assumed sRGB because PNG defaults to that color space.\r\n        DirectX::ScratchImage converted;\r\n        if (FAILED(DirectX::Convert(*rmo.GetImage(0, 0, 0), DXGI_FORMAT_B8G8R8X8_UNORM, DirectX::TEX_FILTER_SRGB_IN, DirectX::TEX_THRESHOLD_DEFAULT, converted)))\r\n        {\r\n            throw GLTFException(\"Failed to convert texture to DXGI_FORMAT_B8G8R8X8_UNORM for storage.\");\r\n        }\r\n\r\n        auto imagePath = GLTFTextureUtils::SaveAsPng(&converted, \"packing_rmo_\" + material.id + \".png\", outputDirectory);\r\n\r\n        // Add back to GLTF\r\n        auto rmoImageId = GLTFTextureUtils::AddImageToDocument(outputDoc, imagePath);\r\n\r\n        AddTextureToExtension(rmoImageId, TexturePacking::RoughnessMetallicOcclusion, outputDoc, ormExtensionJson, ormAllocator);\r\n    }\r\n\r\n    if (packingIncludesNrm && (hasMR || hasNormal))\r\n    {\r\n        uint8_t *renormalPixels = normalPixels;\r\n        DirectX::ScratchImage renormalizedImage;\r\n        uint8_t *roughnessPixels = mrPixels;\r\n        DirectX::ScratchImage adjustRoughnessImage;\r\n\r\n        if (hasNormal)\r\n        {\r\n            Renormalize(normalImage, renormalizedImage);\r\n            renormalPixels = renormalizedImage.GetPixels();\r\n\r\n            if (hasMR)\r\n            {\r\n                AdjustRoughness(metallicRoughnessImage, normalImage, adjustRoughnessImage);\r\n                roughnessPixels = adjustRoughnessImage.GetPixels();\r\n            }\r\n        }\r\n\r\n\r\n        DirectX::ScratchImage nrm;\r\n\r\n        auto sourceImage = hasMR ? *metallicRoughnessImage->GetImage(0, 0, 0) : *normalImage->GetImage(0, 0, 0);\r\n        if (FAILED(nrm.Initialize2D(sourceImage.format, sourceImage.width, sourceImage.height, 1, 1)))\r\n        {\r\n            throw GLTFException(\"Failed to initialize from texture.\");\r\n        }\r\n\r\n        auto nrmPixels = nrm.GetPixels();\r\n        auto metadata = nrm.GetMetadata();\r\n\r\n        for (size_t i = 0; i < metadata.width * metadata.height; i += 1)\r\n        {\r\n            // Normal: N [RG] -> NRM [RG]\r\n            *GLTFTextureUtils::GetChannelValue(nrmPixels, i, Channel::Red) = hasNormal ? *GLTFTextureUtils::GetChannelValue(renormalPixels, i, Channel::Red) : 255.0f;\r\n            *GLTFTextureUtils::GetChannelValue(nrmPixels, i, Channel::Green) = hasNormal ? *GLTFTextureUtils::GetChannelValue(renormalPixels, i, Channel::Green) : 255.0f;\r\n            // Roughness: MR [G] -> NRM [B]\r\n            *GLTFTextureUtils::GetChannelValue(nrmPixels, i, Channel::Blue) = hasMR ? *GLTFTextureUtils::GetChannelValue(roughnessPixels, i, Channel::Green) : 255.0f;\r\n            // Metalness: MR [B] -> NRM [A]\r\n            *GLTFTextureUtils::GetChannelValue(nrmPixels, i, Channel::Alpha) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Blue) : 255.0f;\r\n        }\r\n\r\n        // Assumed sRGB because PNG defaults to that color space.\r\n        auto imagePath = GLTFTextureUtils::SaveAsPng(&nrm, \"packing_nrm_\" + material.id + \".png\", outputDirectory, &GUID_WICPixelFormat32bppBGRA);\r\n\r\n        // Add back to GLTF\r\n        auto nrmImageId = GLTFTextureUtils::AddImageToDocument(outputDoc, imagePath);\r\n\r\n        AddTextureToExtension(nrmImageId, TexturePacking::NormalRoughnessMetallic, outputDoc, nrmExtensionJson, nrmAllocator);\r\n    }\r\n\r\n    if (packingIncludesOrm)\r\n    {\r\n        if (hasNormal)\r\n        {\r\n            rapidjson::Value ormNormalTextureJson(rapidjson::kObjectType);\r\n            {\r\n                ormNormalTextureJson.AddMember(rapidjson::StringRef(MSFT_PACKING_INDEX_KEY), rapidjson::Value(std::stoi(normal)), ormAllocator);\r\n            }\r\n            ormExtensionJson.AddMember(rapidjson::StringRef(MSFT_PACKING_ORM_NORMALTEXTURE_KEY), ormNormalTextureJson, ormAllocator);\r\n        }\r\n\r\n        rapidjson::StringBuffer buffer;\r\n        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\r\n        ormExtensionJson.Accept(writer);\r\n\r\n        outputMaterial.extensions.insert(std::pair<std::string, std::string>(EXTENSION_MSFT_PACKING_ORM, buffer.GetString()));\r\n\r\n        outputDoc.extensionsUsed.insert(EXTENSION_MSFT_PACKING_ORM);\r\n    }\r\n\r\n    if (packingIncludesNrm)\r\n    {\r\n        rapidjson::StringBuffer buffer;\r\n        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\r\n        nrmExtensionJson.Accept(writer);\r\n\r\n        outputMaterial.extensions.insert(std::pair<std::string, std::string>(EXTENSION_MSFT_PACKING_NRM, buffer.GetString()));\r\n\r\n        outputDoc.extensionsUsed.insert(EXTENSION_MSFT_PACKING_NRM);\r\n    }\r\n\r\n    outputDoc.materials.Replace(outputMaterial);\r\n\r\n    return outputDoc;\r\n}\r\n\r\nDocument GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document & doc, TexturePacking packing, const std::string& outputDirectory)\r\n{\r\n    Document outputDoc(doc);\r\n\r\n    // No packing requested, return copy of document\r\n    if (packing == TexturePacking::None)\r\n    {\r\n        return outputDoc;\r\n    }\r\n\r\n    for (auto material : doc.materials.Elements())\r\n    {\r\n        outputDoc = PackMaterialForWindowsMR(streamReader, outputDoc, material, packing, outputDirectory);\r\n    }\r\n\r\n    return outputDoc;\r\n}"
  },
  {
    "path": "glTF-Toolkit/src/GLTFTextureUtils.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See LICENSE in the project root for license information.\n\n#include \"pch.h\"\n\n#include \"GLTFTextureUtils.h\"\n#include <GLTFSDK/PBRUtils.h>\n#include \"GLTFTextureCompressionUtils.h\"\n#include \"GLTFTexturePackingUtils.h\"\n\nusing namespace Microsoft::glTF;\nusing namespace Microsoft::glTF::Toolkit;\n\nDirectX::ScratchImage GLTFTextureUtils::LoadTexture(std::shared_ptr<const IStreamReader> streamReader, const Document& doc, const std::string& textureId, bool treatAsLinear)\n{\n    DirectX::ScratchImage output;\n\n    const Texture& texture = doc.textures.Get(textureId);\n\n    GLTFResourceReader gltfResourceReader(streamReader);\n\n    const Image& image = doc.images.Get(texture.imageId);\n\n    std::vector<uint8_t> imageData = gltfResourceReader.ReadBinaryData(doc, image);\n\n    DirectX::TexMetadata info;\n    if (FAILED(DirectX::LoadFromDDSMemory(imageData.data(), imageData.size(), DirectX::DDS_FLAGS_NONE, &info, output)))\n    {\n        // DDS failed, try WIC\n        // Note: try DDS first since WIC can load some DDS (but not all), so we wouldn't want to get \n        // a partial or invalid DDS loaded from WIC.\n        if (FAILED(DirectX::LoadFromWICMemory(imageData.data(), imageData.size(), treatAsLinear ? DirectX::WIC_FLAGS_IGNORE_SRGB : DirectX::WIC_FLAGS_NONE, &info, output)))\n        {\n            throw GLTFException(\"Failed to load image - Image could not be loaded as DDS or read by WIC.\");\n        }\n    }\n\n    if (info.format == DXGI_FORMAT_R32G32B32A32_FLOAT && treatAsLinear)\n    {\n        return output;\n    }\n    else \n    {\n        DirectX::ScratchImage converted;\n        if (FAILED(DirectX::Convert(*output.GetImage(0, 0, 0), DXGI_FORMAT_R32G32B32A32_FLOAT, treatAsLinear ? DirectX::TEX_FILTER_DEFAULT : DirectX::TEX_FILTER_SRGB_IN, DirectX::TEX_THRESHOLD_DEFAULT, converted)))\n        {\n            throw GLTFException(\"Failed to convert texture to DXGI_FORMAT_R32G32B32A32_FLOAT for processing.\");\n        }\n\n        return converted;\n    }\n}\n\n// Constants for the format DXGI_FORMAT_R32G32B32A32_FLOAT\nconstexpr size_t DXGI_FORMAT_R32G32B32A32_FLOAT_STRIDE = 16;\n\nfloat* GLTFTextureUtils::GetChannelValue(uint8_t * imageData, size_t offset, Channel channel)\n{\n    return reinterpret_cast<float*>(imageData + offset * DXGI_FORMAT_R32G32B32A32_FLOAT_STRIDE + channel);\n}\n\nstd::string GLTFTextureUtils::SaveAsPng(DirectX::ScratchImage* image, const std::string& fileName, const std::string& directory, const GUID* targetFormat)\n{\n    wchar_t outputImageFullPath[MAX_PATH];\n    auto fileNameW = std::wstring(fileName.begin(), fileName.end());\n    auto directoryW = std::wstring(directory.begin(), directory.end());\n\n    if (FAILED(::PathCchCombine(outputImageFullPath, ARRAYSIZE(outputImageFullPath), directoryW.c_str(), fileNameW.c_str())))\n    {\n        throw GLTFException(\"Failed to compose output file path.\");\n    }\n\n    const DirectX::Image* img = image->GetImage(0, 0, 0);\n    if (FAILED(SaveToWICFile(*img, DirectX::WIC_FLAGS::WIC_FLAGS_NONE, GUID_ContainerFormatPng, outputImageFullPath, targetFormat)))\n    {\n        throw GLTFException(\"Failed to save file.\");\n    }\n\n    std::wstring outputImageFullPathStr(outputImageFullPath);\n    return std::string(outputImageFullPathStr.begin(), outputImageFullPathStr.end());\n}\n\nstd::string GLTFTextureUtils::AddImageToDocument(Document& doc, const std::string& imageUri)\n{\n    Image image;\n    image.uri = imageUri;\n    return doc.images.Append(std::move(image), AppendIdPolicy::GenerateOnEmpty).id;\n}\n\nvoid GLTFTextureUtils::ResizeIfNeeded(const std::unique_ptr<DirectX::ScratchImage>& image, size_t resizedWidth, size_t resizedHeight)\n{\n    auto metadata = image->GetMetadata();\n    if (resizedWidth != metadata.width || resizedHeight != metadata.height)\n    {\n        DirectX::ScratchImage resized;\n        if (FAILED(DirectX::Resize(image->GetImages(), image->GetImageCount(), metadata, resizedWidth, resizedHeight, DirectX::TEX_FILTER_DEFAULT, resized)))\n        {\n            throw GLTFException(\"Failed to resize image while packing.\");\n        }\n\n        *image = std::move(resized);\n    }\n}\n\nDocument GLTFTextureUtils::RemoveRedundantTexturesAndImages(const Document& doc)\n{\n    Document resultDocument(doc);\n\n    // 1. Find used textures\n    std::unordered_set<std::string> usedTextureIds;\n    for (const auto& material : doc.materials.Elements())\n    {\n        std::unordered_set<std::string> textureIds = {\n            material.metallicRoughness.baseColorTexture.textureId,\n            material.metallicRoughness.metallicRoughnessTexture.textureId,\n            material.normalTexture.textureId,\n            material.occlusionTexture.textureId,\n            material.emissiveTexture.textureId\n        };\n\n        if (material.HasExtension<KHR::Materials::PBRSpecularGlossiness>())\n        {\n            textureIds.insert(material.GetExtension<KHR::Materials::PBRSpecularGlossiness>().diffuseTexture.textureId);\n            textureIds.insert(material.GetExtension<KHR::Materials::PBRSpecularGlossiness>().specularGlossinessTexture.textureId);\n        }\n\n        auto textureIndices = GLTFTexturePackingUtils::GetTextureIndicesFromMsftExtensions(material);\n\n        for (const auto& textureIndex : textureIndices)\n        {\n            textureIds.insert(doc.textures.Get(textureIndex).id);\n        }\n\n        for (const auto& textureId : textureIds)\n        {\n            if (!textureId.empty())\n            {\n                usedTextureIds.insert(textureId);\n            }\n        }\n    }\n\n    // 2. Find used images and remove unused textures\n    std::unordered_set<std::string> usedImageIds;\n    for (const auto& texture : doc.textures.Elements())\n    {\n        const auto textureIsUsed = usedTextureIds.find(texture.id) != usedTextureIds.end();\n        \n        if (textureIsUsed)\n        {\n            usedImageIds.insert(texture.imageId);\n\n            // MSFT_texture_dds extension\n            auto ddsExtensionIt = texture.extensions.find(EXTENSION_MSFT_TEXTURE_DDS);\n            if (ddsExtensionIt != texture.extensions.end() && !ddsExtensionIt->second.empty())\n            {\n                rapidjson::Document ddsJson = RapidJsonUtils::CreateDocumentFromString(ddsExtensionIt->second);\n\n                if (ddsJson.HasMember(\"source\"))\n                {\n                    const auto index = ddsJson[\"source\"].GetInt();\n                    const auto imageId = doc.images.Get(index).id;\n                    usedImageIds.insert(imageId);\n                }\n            }\n        }\n        else\n        {\n            resultDocument.textures.Remove(texture.id);\n        }\n    }\n\n    // 3. Remove unused images\n    for (const auto& image : doc.images.Elements())\n    {\n        auto imageIsUsed = usedImageIds.find(image.id) != usedImageIds.end();\n\n        if (!imageIsUsed)\n        {\n            resultDocument.images.Remove(image.id);\n        }\n    }\n\n    return resultDocument;\n}\n\nvoid GLTFTextureUtils::ResizeToLargest(std::unique_ptr<DirectX::ScratchImage>& image1, std::unique_ptr<DirectX::ScratchImage>& image2)\n{\n    auto metadata1 = image1->GetMetadata();\n    auto metadata2 = image2->GetMetadata();\n    if (metadata1.height != metadata2.height || metadata1.width != metadata2.width)\n    {\n        auto resizedWidth = std::max(metadata1.width, metadata2.width);\n        auto resizedHeight = std::max(metadata1.height, metadata2.height);\n\n        ResizeIfNeeded(image1, resizedWidth, resizedHeight);\n        ResizeIfNeeded(image2, resizedWidth, resizedHeight);\n    }\n}"
  },
  {
    "path": "glTF-Toolkit/src/SerializeBinary.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n\r\n#include \"AccessorUtils.h\"\r\n#include \"SerializeBinary.h\"\r\n\r\n#include \"GLTFSDK/GLTF.h\"\r\n#include \"GLTFSDK/Document.h\"\r\n#include \"GLTFSDK/GLBResourceReader.h\"\r\n#include \"GLTFSDK/GLBResourceWriter.h\"\r\n#include \"GLTFSDK/Serialize.h\"\r\n#include \"GLTFSDK/BufferBuilder.h\"\r\n#include \"GLTFSDK/ExtensionsKHR.h\"\r\n\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\nnamespace\r\n{\r\n    static std::string MimeTypeFromUri(const std::string& uri)\r\n    {\r\n        auto extension = uri.substr(uri.rfind('.') + 1, 3);\r\n        std::transform(extension.begin(), extension.end(), extension.begin(), [](char c) { return static_cast<char>(::tolower(static_cast<int>(c))); });\r\n\r\n        if (extension == \"dds\")\r\n        {\r\n            return \"image/vnd-ms.dds\";\r\n        }\r\n\r\n        if (extension == FILE_EXT_JPEG)\r\n        {\r\n            return MIMETYPE_JPEG;\r\n        }\r\n\r\n        if (extension == FILE_EXT_PNG)\r\n        {\r\n            return MIMETYPE_PNG;\r\n        }\r\n\r\n        return \"text/plain\";\r\n    }\r\n\r\n    template <typename T>\r\n    void SaveAccessor(const Accessor& accessor, const std::vector<T> accessorContents, BufferBuilder& builder)\r\n    {\r\n        auto min = accessor.min;\r\n        auto max = accessor.max;\r\n        if ((min.empty() || max.empty()) && !accessorContents.empty())\r\n        {\r\n            auto minmax = AccessorUtils::CalculateMinMax(accessor, accessorContents);\r\n            min = minmax.first;\r\n            max = minmax.second;\r\n        }\r\n\r\n        builder.AddAccessor(accessorContents, AccessorDesc(accessor.type, accessor.componentType, accessor.normalized, min, max));\r\n    }\r\n\r\n    template <typename OriginalType, typename NewType>\r\n    static std::vector<NewType> vector_static_cast(const std::vector<OriginalType>& original)\r\n    {\r\n        auto newData = std::vector<NewType>(original.size());\r\n\r\n        std::transform(original.begin(), original.end(), newData.begin(),\r\n            [](const OriginalType& element)\r\n        {\r\n            return static_cast<NewType>(element);\r\n        });\r\n\r\n        return newData;\r\n    }\r\n\r\n    template <typename T>\r\n    void ConvertAndSaveAccessor(const Accessor& accessor, const std::vector<T> accessorContents, BufferBuilder& builder)\r\n    {\r\n        switch (accessor.componentType)\r\n        {\r\n        case COMPONENT_BYTE:\r\n            SaveAccessor(accessor, vector_static_cast<T, int8_t>(accessorContents), builder);\r\n            break;\r\n        case COMPONENT_UNSIGNED_BYTE:\r\n            SaveAccessor(accessor, vector_static_cast<T, uint8_t>(accessorContents), builder);\r\n            break;\r\n        case COMPONENT_SHORT:\r\n            SaveAccessor(accessor, vector_static_cast<T, int16_t>(accessorContents), builder);\r\n            break;\r\n        case COMPONENT_UNSIGNED_SHORT:\r\n            SaveAccessor(accessor, vector_static_cast<T, uint16_t>(accessorContents), builder);\r\n            break;\r\n        case COMPONENT_UNSIGNED_INT:\r\n            SaveAccessor(accessor, vector_static_cast<T, uint32_t>(accessorContents), builder);\r\n            break;\r\n        case COMPONENT_FLOAT:\r\n            SaveAccessor(accessor, vector_static_cast<T, float>(accessorContents), builder);\r\n            break;\r\n        default:\r\n            throw GLTFException(\"Unsupported accessor ComponentType\");\r\n        }\r\n    }\r\n\r\n    template <typename T>\r\n    void SerializeAccessor(const Accessor& accessor, const Document& doc, const GLTFResourceReader& reader, BufferBuilder& builder, const AccessorConversionStrategy& accessorConversion)\r\n    {\r\n        builder.AddBufferView(doc.bufferViews.Get(accessor.bufferViewId).target);\r\n        const std::vector<T>& accessorContents = reader.ReadBinaryData<T>(doc, accessor);\r\n\r\n        if (accessorConversion != nullptr && accessorConversion(accessor) != accessor.componentType)\r\n        {\r\n            Accessor updatedAccessor(accessor);\r\n            updatedAccessor.componentType = accessorConversion(accessor);\r\n\r\n            // Force recalculation of min and max\r\n            updatedAccessor.min.clear();\r\n            updatedAccessor.max.clear();\r\n\r\n            ConvertAndSaveAccessor(updatedAccessor, accessorContents, builder);\r\n        }\r\n        else\r\n        {\r\n            SaveAccessor(accessor, accessorContents, builder);\r\n        }\r\n    }\r\n\r\n    void SerializeAccessor(const Accessor& accessor, const Document& doc, const GLTFResourceReader& reader, BufferBuilder& builder, const AccessorConversionStrategy& accessorConversion)\r\n    {\r\n        switch (accessor.componentType)\r\n        {\r\n        case COMPONENT_BYTE:\r\n            SerializeAccessor<int8_t>(accessor, doc, reader, builder, accessorConversion);\r\n            break;\r\n        case COMPONENT_UNSIGNED_BYTE:\r\n            SerializeAccessor<uint8_t>(accessor, doc, reader, builder, accessorConversion);\r\n            break;\r\n        case COMPONENT_SHORT:\r\n            SerializeAccessor<int16_t>(accessor, doc, reader, builder, accessorConversion);\r\n            break;\r\n        case COMPONENT_UNSIGNED_SHORT:\r\n            SerializeAccessor<uint16_t>(accessor, doc, reader, builder, accessorConversion);\r\n            break;\r\n        case COMPONENT_UNSIGNED_INT:\r\n            SerializeAccessor<uint32_t>(accessor, doc, reader, builder, accessorConversion);\r\n            break;\r\n        case COMPONENT_FLOAT:\r\n            SerializeAccessor<float>(accessor, doc, reader, builder, accessorConversion);\r\n            break;\r\n        default:\r\n            throw GLTFException(\"Unsupported accessor ComponentType\");\r\n        }\r\n    }\r\n}\r\n\r\nvoid Microsoft::glTF::Toolkit::SerializeBinary(const Document& document,\r\n                                               const GLTFResourceReader& resourceReader,\r\n                                               std::shared_ptr<const IStreamWriter> outputStreamWriter,\r\n                                               const AccessorConversionStrategy& accessorConversion)\r\n{\r\n    auto writer = std::make_unique<GLBResourceWriter>(std::move(outputStreamWriter));\r\n\r\n    Document outputDoc(document);\r\n\r\n    outputDoc.buffers.Clear();\r\n    outputDoc.bufferViews.Clear();\r\n    outputDoc.accessors.Clear();\r\n\r\n    // Get the collection of bufferViews we won't move around\r\n    IndexedContainer<const BufferView> staticBufferViews = document.bufferViews;\r\n    for (const auto& accessor : document.accessors.Elements())\r\n    {\r\n        if (!accessor.bufferViewId.empty() && staticBufferViews.Has(accessor.bufferViewId))\r\n        {\r\n            staticBufferViews.Remove(accessor.bufferViewId);\r\n        }\r\n    }\r\n\r\n    for (const auto& image : outputDoc.images.Elements())\r\n    {\r\n        if (!image.bufferViewId.empty() && staticBufferViews.Has(image.bufferViewId))\r\n        {\r\n            staticBufferViews.Remove(image.bufferViewId);\r\n        }\r\n    }\r\n\r\n    size_t currentAccessorId = 0;\r\n    std::string currentAccessorIdStr = std::to_string(currentAccessorId);\r\n    size_t currentBufferViewId = 0;\r\n    std::string currentBufferViewIdStr = std::to_string(currentBufferViewId);\r\n    auto AdvanceAccessorId = [&currentAccessorId, &currentAccessorIdStr]()\r\n    {\r\n        currentAccessorId++;\r\n        currentAccessorIdStr = std::to_string(currentAccessorId);\r\n    };\r\n    auto AdvanceBufferViewId = [&currentBufferViewId, &currentBufferViewIdStr, &staticBufferViews]()\r\n    {\r\n        do\r\n        {\r\n            currentBufferViewId++;\r\n            currentBufferViewIdStr = std::to_string(currentBufferViewId);\r\n        } while (staticBufferViews.Has(currentBufferViewIdStr));\r\n    };\r\n    std::unique_ptr<BufferBuilder> builder = std::make_unique<BufferBuilder>(std::move(writer),\r\n        [](const BufferBuilder&) { return GLB_BUFFER_ID; },\r\n        [&currentBufferViewIdStr](const BufferBuilder&) { return currentBufferViewIdStr; },\r\n        [&currentAccessorIdStr](const BufferBuilder&) { return currentAccessorIdStr; });\r\n\r\n    // GLB buffer\r\n    builder->AddBuffer(GLB_BUFFER_ID);\r\n\r\n    // Add those bufferView to the builder.\r\n    for (const auto& bufferView : staticBufferViews.Elements())\r\n    {\r\n        currentBufferViewIdStr = bufferView.id;\r\n        auto data = resourceReader.ReadBinaryData<uint8_t>(document, bufferView);\r\n        builder->AddBufferView(data);\r\n    }\r\n    // Return value to tracked state\r\n    currentBufferViewIdStr = std::to_string(currentBufferViewId);\r\n    if (staticBufferViews.Has(currentBufferViewIdStr))\r\n    {\r\n        AdvanceBufferViewId();\r\n    }\r\n\r\n    // Serialize accessors\r\n    for (const auto& accessor : document.accessors.Elements())\r\n    {\r\n        if (!accessor.bufferViewId.empty() && accessor.count > 0)\r\n        {\r\n            SerializeAccessor(accessor, document, resourceReader, *builder, accessorConversion);\r\n            AdvanceBufferViewId();\r\n        }\r\n        else\r\n        {\r\n            outputDoc.accessors.Append(accessor);\r\n        }\r\n        AdvanceAccessorId();\r\n    }\r\n\r\n    // Serialize images\r\n    for (const auto& image : outputDoc.images.Elements())\r\n    {\r\n        Image newImage(image);\r\n\r\n        auto data = resourceReader.ReadBinaryData(document, image);\r\n\r\n        auto imageBufferView = builder->AddBufferView(data);\r\n        AdvanceBufferViewId();\r\n\r\n        newImage.bufferViewId = imageBufferView.id;\r\n        if (image.mimeType.empty())\r\n        {\r\n            newImage.mimeType = MimeTypeFromUri(image.uri);\r\n        }\r\n\r\n        newImage.uri.clear();\r\n\r\n        outputDoc.images.Replace(newImage);\r\n    }\r\n\r\n    // Collect anything in extensions that looks like it should to be packed for the GLB.\r\n    for (auto& extension : outputDoc.extensions)\r\n    {\r\n        rapidjson::Document extensionJson;\r\n        extensionJson.Parse(extension.second.c_str());\r\n        if (!extensionJson.IsObject())\r\n        {\r\n            continue;\r\n        }\r\n        for (auto& member : extensionJson.GetObject())\r\n        {\r\n            if (!member.value.IsArray())\r\n            {\r\n                continue;\r\n            }\r\n            for (auto& possibleBuffer : member.value.GetArray())\r\n            {\r\n                if (!possibleBuffer.IsObject())\r\n                {\r\n                    continue;\r\n                }\r\n                // Build an Image to object to use to load the data from.\r\n                Image tmpImg;\r\n                if (possibleBuffer.HasMember(\"uri\"))\r\n                {\r\n                    tmpImg.uri = possibleBuffer[\"uri\"].GetString();\r\n                }\r\n                else\r\n                {\r\n                    continue;\r\n                }\r\n                try\r\n                {\r\n                    auto data = resourceReader.ReadBinaryData(document, tmpImg);\r\n                    auto bufferView = builder->AddBufferView(data);\r\n                    AdvanceBufferViewId();\r\n\r\n                    possibleBuffer.RemoveMember(\"uri\");\r\n                    possibleBuffer.RemoveMember(\"bufferView\");\r\n                    possibleBuffer.AddMember(\"bufferView\", rapidjson::Value(std::stoi(bufferView.id)), extensionJson.GetAllocator());\r\n                }\r\n                catch (...) \r\n                {\r\n                    // Didn't work out.\r\n                    continue;\r\n                }\r\n            }\r\n        }\r\n\r\n        rapidjson::StringBuffer buffer;\r\n        rapidjson::Writer<rapidjson::StringBuffer> jsonWriter(buffer);\r\n        extensionJson.Accept(jsonWriter);\r\n\r\n        extension.second = buffer.GetString();\r\n    }\r\n\r\n    // Fill in any gaps in the bufferViewList.\r\n    for (const auto& bufferView : staticBufferViews.Elements())\r\n    {\r\n        auto bufferViewId = std::stoul(bufferView.id);\r\n        while (bufferViewId > currentBufferViewId)\r\n        {\r\n            std::vector<uint8_t> data;\r\n            data.resize(4);\r\n            builder->AddBufferView(data);\r\n            AdvanceBufferViewId();\r\n        }\r\n    }\r\n\r\n    builder->Output(outputDoc);\r\n\r\n    // Add extensions and extras to bufferViews, if any\r\n    for (auto bufferView : document.bufferViews.Elements())\r\n    {\r\n        auto fixedBufferView = outputDoc.bufferViews.Get(bufferView.id);\r\n        fixedBufferView.extensions = bufferView.extensions;\r\n        fixedBufferView.extras = bufferView.extras;\r\n\r\n        outputDoc.bufferViews.Replace(fixedBufferView);\r\n    }\r\n\r\n    // We may have put the bufferViews in the IndexedContainer out of order sort them now.\r\n    auto finalBufferViewList = outputDoc.bufferViews;\r\n    outputDoc.bufferViews.Clear();\r\n    for (size_t i = 0; i < finalBufferViewList.Size(); i++)\r\n    {\r\n        outputDoc.bufferViews.Append(finalBufferViewList[std::to_string(i)]);\r\n    }\r\n\r\n    auto manifest = Serialize(outputDoc, KHR::GetKHRExtensionSerializer());\r\n\r\n    auto outputWriter = dynamic_cast<GLBResourceWriter*>(&builder->GetResourceWriter());\r\n    if (outputWriter != nullptr)\r\n    {\r\n        outputWriter->Flush(manifest, std::string());\r\n    }\r\n}\r\n\r\nvoid Microsoft::glTF::Toolkit::SerializeBinary(const Document& document, std::shared_ptr<const IStreamReader> inputStreamReader,\r\n                                               std::shared_ptr<const IStreamWriter> outputStreamWriter,\r\n                                               const AccessorConversionStrategy& accessorConversion)\r\n{\r\n    SerializeBinary(document, GLTFResourceReader{inputStreamReader}, std::move(outputStreamWriter), accessorConversion);\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit/src/pch.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\""
  },
  {
    "path": "glTF-Toolkit.Test/GLBSerializerTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n#include <CppUnitTest.h>  \r\n\r\n#include \"GLTFSDK/IStreamWriter.h\"\r\n#include \"GLTFSDK/Constants.h\"\r\n#include \"GLTFSDK/Deserialize.h\"\r\n#include \"GLTFSDK/GLBResourceWriter.h\"\r\n#include \"GLTFSDK/GLBResourceReader.h\"\r\n#include \"GLTFSDK/GLTFResourceWriter.h\"\r\n\r\n#include \"SerializeBinary.h\"\r\n\r\n#include \"Helpers/TestUtils.h\"\r\n#include \"Helpers/WStringUtils.h\"\r\n#include \"Helpers/StreamMock.h\"\r\n\r\nusing namespace Microsoft::VisualStudio::CppUnitTestFramework;\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\nnamespace Microsoft::glTF::Toolkit::Test\r\n{\r\n    class InMemoryStream : public Microsoft::glTF::IStreamWriter\r\n    {\r\n    public:\r\n        InMemoryStream(std::shared_ptr<std::stringstream> stream) :\r\n            m_stream(stream)\r\n        { }\r\n\r\n        std::shared_ptr<std::ostream> GetOutputStream(const std::string&) const\r\n        {\r\n            return m_stream;\r\n        }\r\n\r\n    private:\r\n        std::shared_ptr<std::stringstream> m_stream;\r\n    };\r\n\r\n    TEST_CLASS(GLBSerializerTests)\r\n    {\r\n\r\n        static std::string ReadLocalJson(const char * relativePath)\r\n        {\r\n            auto input = TestUtils::ReadLocalAsset(TestUtils::GetAbsolutePath(relativePath));\r\n            auto json = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());\r\n            return json;\r\n        }\r\n\r\n        static std::shared_ptr<Document> ImportGLB(const std::shared_ptr<IStreamReader>& streamReader, const std::shared_ptr<std::istream>& glbStream)\r\n        {\r\n            GLBResourceReader resourceReader(streamReader, glbStream);\r\n            auto json = resourceReader.GetJson();\r\n\r\n            auto doc = Deserialize(json);\r\n\r\n            return std::make_shared<Document>(doc);\r\n        }\r\n\r\n        static std::shared_ptr<Document> ImportGLTF(const std::shared_ptr<IStreamReader>& streamReader, const std::shared_ptr<std::istream>& stream)\r\n        {\r\n            GLTFResourceReader resourceReader(streamReader);\r\n            auto json = std::string(std::istreambuf_iterator<char>(*stream), std::istreambuf_iterator<char>());\r\n\r\n            auto doc = Deserialize(json);\r\n\r\n            return std::make_shared<Document>(doc);\r\n        }\r\n\r\n        const char* c_waterBottleJson = \"Resources\\\\gltf\\\\WaterBottle\\\\WaterBottle.gltf\";\r\n\r\n        TEST_METHOD(GLBSerializerTests_RoundTrip_Simple)\r\n        {\r\n            auto data = ReadLocalJson(c_waterBottleJson);\r\n            auto input = std::make_shared<std::stringstream>(data);\r\n            try\r\n            {\r\n                // Deserialize input json\r\n                auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());\r\n                auto doc = Deserialize(inputJson);\r\n\r\n                // Serialize Document to GLB\r\n                auto streamReader = std::make_shared<TestStreamReader>(TestUtils::GetAbsolutePath(c_waterBottleJson));\r\n                auto stream = std::make_shared<std::stringstream>(std::ios_base::app | std::ios_base::binary | std::ios_base::in | std::ios_base::out);\r\n                SerializeBinary(doc, streamReader, std::make_shared<InMemoryStream>(stream));\r\n\r\n                // Deserialize the GLB again\r\n                auto glbReader = std::make_unique<GLBResourceReader>(streamReader, stream);\r\n                auto outputJson = glbReader->GetJson();\r\n                auto outputDoc = Deserialize(outputJson);\r\n\r\n                // Check some structural elements\r\n                Assert::AreEqual(doc.nodes.Size(), outputDoc.nodes.Size());\r\n                Assert::AreEqual(doc.images.Size(), outputDoc.images.Size());\r\n\r\n                // There must be only one buffer, and it can't have a URI\r\n                Assert::AreEqual(static_cast<size_t>(1), outputDoc.buffers.Size());\r\n                auto glbBuffer = outputDoc.buffers.Elements()[0];\r\n                Assert::IsTrue(glbBuffer.uri.empty());\r\n\r\n                // Check that the images that were stored as URI are now bufferViews\r\n                for (auto image : outputDoc.images.Elements())\r\n                {\r\n                    // Images in GLB don't have a URI\r\n                    Assert::IsTrue(image.uri.empty());\r\n\r\n                    // Images in GLB are stored in a buffer\r\n                    Assert::IsFalse(image.bufferViewId.empty());\r\n\r\n                    // Images in original GLTF have a URI\r\n                    Assert::IsFalse(doc.images.Get(image.id).uri.empty());\r\n                }\r\n\r\n                // All buffer views must point to the GLB buffer\r\n                for (auto bufferView : outputDoc.bufferViews.Elements())\r\n                {\r\n                    Assert::IsTrue(bufferView.bufferId == glbBuffer.id);\r\n                }\r\n\r\n                // Read one of the images and check it's identical\r\n                auto gltfReader = std::make_unique<GLTFResourceReader>(streamReader);\r\n                std::vector<uint8_t> gltfImage = gltfReader->ReadBinaryData(doc, doc.images.Elements()[0]);\r\n                std::vector<uint8_t> glbImage = glbReader->ReadBinaryData(outputDoc, outputDoc.images.Elements()[0]);\r\n                Assert::IsTrue(gltfImage == glbImage); // Vector comparison\r\n            }\r\n            catch (std::exception ex)\r\n            {\r\n                std::stringstream ss;\r\n                ss << \"Received exception was unexpected. Got: \" << ex.what();\r\n                Assert::Fail(WStringUtils::ToWString(ss).c_str());\r\n            }\r\n        }\r\n    };\r\n}"
  },
  {
    "path": "glTF-Toolkit.Test/GLBtoGLTFTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n#include <CppUnitTest.h>  \r\n\r\n#include <numeric>\r\n#include <GLTFSDK/Document.h>\r\n#include <GLTFSDK/Deserialize.h>\r\n#include <GLTFSDK/Serialize.h>\r\n#include <GLBtoGLTF.h>\r\n\r\nusing namespace Microsoft::VisualStudio::CppUnitTestFramework;\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\nnamespace Microsoft::glTF::Toolkit::Test\r\n{\r\n    std::wstring utf8Decode(const std::string& s)\r\n    {\r\n        std::wstring ret;\r\n        std::for_each(s.begin(), s.end(), [&ret](char c)\r\n        {\r\n            ret += (wchar_t)c;\r\n        });\r\n        return ret;\r\n    }\r\n\r\n    std::string binBufferString(const std::vector<char>& vec)\r\n    {\r\n        std::string ret = \"{\";\r\n        for (size_t i = 0; i < vec.size(); i++)\r\n        {\r\n            ret += (i ? \",\" : \"\") + std::to_string((int)vec[i]);\r\n        }\r\n        return ret += \"}\";\r\n    }\r\n\r\n    // Setup a GLTF document with 3 bufferviews and 2 images\r\n    Document setupGLBDocument1()\r\n    {\r\n        Document glbDoc;\r\n        Scene sc; sc.id = \"0\";\r\n        glbDoc.scenes.Append(std::move(sc));\r\n        Accessor acc0; acc0.bufferViewId = \"0\"; acc0.byteOffset = 0; acc0.id = \"0\";\r\n        Accessor acc1; acc1.bufferViewId = \"2\"; acc1.byteOffset = 12; acc1.id = \"1\";\r\n        Accessor acc2; acc2.bufferViewId = \"1\"; acc2.byteOffset = 4; acc2.id = \"2\";\r\n        const std::vector<Accessor> accessors = { acc0, acc1, acc2 };\r\n        std::for_each(accessors.begin(), accessors.end(), [&glbDoc](auto a)\r\n        {\r\n            glbDoc.accessors.Append(std::move(a));\r\n        });\r\n        BufferView bv0; bv0.bufferId = \"0\"; bv0.byteOffset = 0; bv0.byteLength = 8; bv0.id = \"0\";\r\n        BufferView bv1; bv1.bufferId = \"0\"; bv1.byteOffset = 32; bv1.byteLength = 4; bv1.id = \"1\";\r\n        BufferView bv2; bv2.bufferId = \"0\"; bv2.byteOffset = 72; bv2.byteLength = 2; bv2.id = \"2\";\r\n        const std::vector<BufferView> bufferViews = { bv0, bv1, bv2 };\r\n        std::for_each(bufferViews.begin(), bufferViews.end(), [&glbDoc](auto b)\r\n        {\r\n            glbDoc.bufferViews.Append(std::move(b));\r\n        });\r\n        Buffer b; b.id = \"0\", b.byteLength = 100;\r\n        const std::vector<Buffer> buffers = { b };\r\n        std::for_each(buffers.begin(), buffers.end(), [&glbDoc](auto b)\r\n        {\r\n            glbDoc.buffers.Append(std::move(b));\r\n        });\r\n        Image img0; img0.id = \"0\"; img0.mimeType = \"image/png\"; img0.bufferViewId = \"1\";\r\n        Image img1; img1.id = \"1\"; img1.mimeType = \"image/jpeg\"; img1.bufferViewId = \"2\";\r\n        const std::vector<Image> images = { img0, img1 };\r\n        std::for_each(images.begin(), images.end(), [&glbDoc](auto img)\r\n        {\r\n            glbDoc.images.Append(std::move(img));\r\n        });\r\n        return glbDoc;\r\n    }\r\n\r\n    //sets up a stream with 'size' number of bytes, where reading the stream k times returns k\r\n    std::stringstream* setupGLBStream(char size)\r\n    {\r\n        std::stringstream* ss = new std::stringstream();\r\n        char* inputStream = new char[size];\r\n        for (int i = 0; i < size; i++) inputStream[i] = (char)i;\r\n        ss->write(inputStream, size);\r\n        return ss;\r\n    }\r\n\r\n    TEST_CLASS(GLBToGLTFTests)\r\n    {\r\n        TEST_METHOD(GLBtoGLTF_NoImagesJSON)\r\n        {\r\n            Document glbDoc;\r\n            Scene s1; s1.id = \"0\";\r\n            glbDoc.scenes.Append(std::move(s1));\r\n            Accessor acc; acc.bufferViewId = \"0\"; acc.byteOffset = 36; acc.id = \"0\";\r\n            const std::vector<Accessor> accessors = {};\r\n            std::for_each(accessors.begin(), accessors.end(), [&glbDoc](auto a)\r\n            {\r\n                glbDoc.accessors.Append(std::move(a));\r\n            });\r\n            const std::vector<BufferView> bufferViews = {};\r\n            std::for_each(bufferViews.begin(), bufferViews.end(), [&glbDoc](auto b)\r\n            {\r\n                glbDoc.bufferViews.Append(std::move(b));\r\n            });\r\n            const std::vector<Buffer> buffers = {};\r\n            std::for_each(buffers.begin(), buffers.end(), [&glbDoc](auto b)\r\n            {\r\n                glbDoc.buffers.Append(std::move(b));\r\n            });\r\n            const std::vector<Image> images = {};\r\n            std::for_each(images.begin(), images.end(), [&glbDoc](auto img)\r\n            {\r\n                glbDoc.images.Append(std::move(img));\r\n            });\r\n            Document expectedGLTFDoc;\r\n            Scene s2; s2.id = \"0\";\r\n            expectedGLTFDoc.scenes.Append(std::move(s2));\r\n            std::unordered_set<std::string> unpackedBufferViews;\r\n            auto actualGLTFDoc = GLBToGLTF::CreateGLTFDocument(glbDoc, \"name\", unpackedBufferViews);\r\n\r\n            // for debugging\r\n            const auto expectedJSON = Serialize(expectedGLTFDoc, SerializeFlags::Pretty);\r\n            const auto actualJSON = Serialize(actualGLTFDoc, SerializeFlags::Pretty);\r\n            Assert::IsTrue(expectedGLTFDoc == actualGLTFDoc, utf8Decode(expectedJSON + \"\\n\\n\" + actualJSON).c_str());\r\n        }\r\n\r\n        TEST_METHOD(GLBtoGLTF_ImagesWithOffsetJSON)\r\n        {\r\n            Document glbDoc;\r\n            Scene sc; sc.id = \"0\";\r\n            glbDoc.scenes.Append(std::move(sc));\r\n            Accessor acc0; acc0.bufferViewId = \"0\"; acc0.byteOffset = 0; acc0.id = \"0\";\r\n            Accessor acc1; acc1.bufferViewId = \"3\"; acc1.byteOffset = 12; acc1.id = \"1\";\r\n            Accessor acc2; acc2.bufferViewId = \"1\"; acc2.byteOffset = 4; acc2.id = \"2\";\r\n            Accessor acc3; acc3.bufferViewId = \"2\"; acc3.byteOffset = 4; acc3.id = \"3\";\r\n            const std::vector<Accessor> accessors = { acc0, acc1, acc2, acc3 };\r\n            std::for_each(accessors.begin(), accessors.end(), [&glbDoc](auto a)\r\n            {\r\n                glbDoc.accessors.Append(std::move(a));\r\n            });\r\n            BufferView bv0; bv0.bufferId = \"0\"; bv0.byteOffset = 0; bv0.byteLength = 400; bv0.id = \"0\";\r\n            BufferView bv1; bv1.bufferId = \"0\"; bv1.byteOffset = 420; bv1.byteLength = 200; bv1.id = \"1\";\r\n            BufferView bv2; bv2.bufferId = \"0\"; bv2.byteOffset = 620; bv2.byteLength = 320; bv2.id = \"2\";\r\n            BufferView bv3; bv3.bufferId = \"0\"; bv3.byteOffset = 960; bv3.byteLength = 2000; bv3.id = \"3\";\r\n            const std::vector<BufferView> bufferViews = { bv0, bv1, bv2, bv3 };\r\n            std::for_each(bufferViews.begin(), bufferViews.end(), [&glbDoc](auto b)\r\n            {\r\n                glbDoc.bufferViews.Append(std::move(b));\r\n            });\r\n            Buffer b; b.id = \"0\", b.byteLength = 3000;\r\n            const std::vector<Buffer> buffers = { b };\r\n            std::for_each(buffers.begin(), buffers.end(), [&glbDoc](auto b)\r\n            {\r\n                glbDoc.buffers.Append(std::move(b));\r\n            });\r\n            Image img0; img0.id = \"0\"; img0.mimeType = \"image/png\"; img0.bufferViewId = \"1\";\r\n            Image img1; img1.id = \"1\"; img1.mimeType = \"image/jpeg\"; img1.bufferViewId = \"3\";\r\n            const std::vector<Image> images = { img0, img1 };\r\n            std::for_each(images.begin(), images.end(), [&glbDoc](auto img)\r\n            {\r\n                glbDoc.images.Append(std::move(img));\r\n            });\r\n            std::unordered_set<std::string> unpackedBufferViews;\r\n            auto actualGLTFDoc = GLBToGLTF::CreateGLTFDocument(glbDoc, \"test\", unpackedBufferViews);\r\n\r\n            Document expectedGLTFDoc;\r\n            Accessor exp_acc0; exp_acc0.bufferViewId = \"0\"; exp_acc0.byteOffset = 0; exp_acc0.id = \"0\";\r\n            Accessor exp_acc1; exp_acc1.bufferViewId = \"1\"; exp_acc1.byteOffset = 4; exp_acc1.id = \"3\";\r\n            expectedGLTFDoc.accessors.Append(std::move(exp_acc0));\r\n            expectedGLTFDoc.accessors.Append(std::move(exp_acc1));\r\n\r\n            BufferView exp_bv0; exp_bv0.bufferId = \"0\"; exp_bv0.byteOffset = 0; exp_bv0.byteLength = 400; exp_bv0.id = \"0\";\r\n            BufferView exp_bv1; exp_bv1.bufferId = \"0\"; exp_bv1.byteOffset = 400; exp_bv1.byteLength = 320; exp_bv1.id = \"1\";\r\n            expectedGLTFDoc.bufferViews.Append(std::move(exp_bv0));\r\n            expectedGLTFDoc.bufferViews.Append(std::move(exp_bv1));\r\n\r\n            Image exp_img0; exp_img0.id = \"0\"; exp_img0.uri = \"test_image0.png\";\r\n            Image exp_img1; exp_img1.id = \"1\"; exp_img1.uri = \"test_image1.jpg\";\r\n            expectedGLTFDoc.images.Append(std::move(exp_img0));\r\n            expectedGLTFDoc.images.Append(std::move(exp_img1));\r\n\r\n            Buffer exp_b; exp_b.id = \"0\"; exp_b.byteLength = 720; exp_b.uri = \"test.bin\";\r\n            expectedGLTFDoc.buffers.Append(std::move(exp_b));\r\n\r\n            Scene sc2; sc2.id = \"0\";\r\n            expectedGLTFDoc.scenes.Append(std::move(sc2));\r\n\r\n            // for debugging\r\n            const auto expectedJSON = Serialize(expectedGLTFDoc, SerializeFlags::Pretty);\r\n            const auto actualJSON = Serialize(actualGLTFDoc, SerializeFlags::Pretty);\r\n            Assert::IsTrue(expectedGLTFDoc == actualGLTFDoc, utf8Decode(expectedJSON + \"\\n\\n\" + actualJSON).c_str());\r\n        }\r\n\r\n        TEST_METHOD(GLBtoGLTF_ImageDataTest)\r\n        {\r\n            auto glbDoc = setupGLBDocument1();\r\n            auto glbStream = setupGLBStream(100);\r\n            const std::string TEST_NAME = \"test3\";\r\n            const size_t BYTE_OFFSET = 12;\r\n            auto imageData = GLBToGLTF::GetImagesData(glbStream, glbDoc, TEST_NAME, BYTE_OFFSET);\r\n            delete glbStream;\r\n\r\n            // these bytes corresponds to bytes of image0 and image1 in setupGLBDocument1\r\n            std::vector<std::vector<char>> expectedImage = {\r\n                {BYTE_OFFSET + 32, BYTE_OFFSET + 33, BYTE_OFFSET + 34, BYTE_OFFSET + 35},\r\n                {BYTE_OFFSET + 72, BYTE_OFFSET + 73},\r\n            };\r\n\r\n            int imgId = 0;\r\n            for (auto it = imageData.begin(); it != imageData.end(); it++, imgId++)\r\n            {\r\n                Assert::IsTrue(it->second == expectedImage[imgId], utf8Decode(binBufferString(it->second) + '\\n' + binBufferString(expectedImage[imgId])).c_str());\r\n            }\r\n        }\r\n\r\n        TEST_METHOD(GLBtoGLTF_MeshDataTest)\r\n        {\r\n            auto glbDoc = setupGLBDocument1();\r\n            auto glbStream = setupGLBStream(100);\r\n            const size_t BYTE_OFFSET = 12;\r\n            std::unordered_set<std::string> unpackedBufferViews;\r\n            auto outputDoc = GLBToGLTF::CreateGLTFDocument(glbDoc, \"name\", unpackedBufferViews);\r\n            auto actualData = GLBToGLTF::SaveBin(glbStream, glbDoc, BYTE_OFFSET, 8, unpackedBufferViews);\r\n\r\n            //these bytes correspond to bytes of bufferviews in steupGLTFDocument1 which don't belong to any image\r\n            std::vector<char> expectedData = { BYTE_OFFSET + 0, BYTE_OFFSET + 1, BYTE_OFFSET + 2, BYTE_OFFSET + 3,\r\n                BYTE_OFFSET + 4, BYTE_OFFSET + 5, BYTE_OFFSET + 6, BYTE_OFFSET + 7 };\r\n            Assert::IsTrue(actualData == expectedData, utf8Decode(binBufferString(actualData) + '\\n' + binBufferString(expectedData)).c_str());\r\n        }\r\n    };\r\n}"
  },
  {
    "path": "glTF-Toolkit.Test/GLTFLODUtilsTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n#include <CppUnitTest.h>  \r\n\r\n#include \"GLTFSDK/IStreamWriter.h\"\r\n#include \"GLTFSDK/Constants.h\"\r\n#include \"GLTFSDK/Serialize.h\"\r\n#include \"GLTFSDK/Deserialize.h\"\r\n#include \"GLTFSDK/GLBResourceReader.h\"\r\n#include \"GLTFSDK/GLTFResourceWriter.h\"\r\n#include \"GLTFSDK/RapidJsonUtils.h\"\r\n#include \"GLTFSDK/ExtensionsKHR.h\"\r\n\r\n#include \"GLTFLODUtils.h\"\r\n\r\n#include \"Helpers/WStringUtils.h\"\r\n#include \"Helpers/TestUtils.h\"\r\n\r\nusing namespace Microsoft::VisualStudio::CppUnitTestFramework;\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\nnamespace Microsoft::glTF::Toolkit::Test\r\n{\r\n    TEST_CLASS(GLTFLODUtilsTests)\r\n    {\r\n        static void CheckGLTFLODNodeCountAgainstOriginal(Document& doc, Document& docWLod, size_t lodCount)\r\n        {\r\n            // All elements in the lod'd doc should be double the original\r\n            Assert::IsTrue(doc.buffers.Size() * lodCount == docWLod.buffers.Size());\r\n            Assert::IsTrue(doc.accessors.Size() * lodCount == docWLod.accessors.Size());\r\n            Assert::IsTrue(doc.bufferViews.Size() * lodCount == docWLod.bufferViews.Size());\r\n            Assert::IsTrue(doc.materials.Size() * lodCount == docWLod.materials.Size());\r\n            Assert::IsTrue(doc.images.Size() * lodCount == docWLod.images.Size());\r\n            Assert::IsTrue(doc.meshes.Size() * lodCount == docWLod.meshes.Size());\r\n            Assert::IsTrue(doc.nodes.Size() * lodCount == docWLod.nodes.Size());\r\n            Assert::IsTrue(doc.textures.Size() * lodCount == docWLod.textures.Size());\r\n            Assert::IsTrue(doc.samplers.Size() * lodCount == docWLod.samplers.Size());\r\n\r\n            // Scene count should be untouched\r\n            Assert::IsTrue(doc.scenes.Size() == docWLod.scenes.Size());\r\n        }\r\n\r\n        static void CheckGLTFLODCount(const char * gltfDocPath, uint32_t expectedNumberOfLods)\r\n        {\r\n            auto input = TestUtils::ReadLocalAsset(TestUtils::GetAbsolutePath(gltfDocPath));\r\n            auto readwriter = std::make_shared<StreamMock>();\r\n            try\r\n            {\r\n                GLTFResourceReader resourceReader(readwriter);\r\n                auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());\r\n                auto doc = Deserialize(inputJson, KHR::GetKHRExtensionDeserializer());\r\n                auto lods = GLTFLODUtils::ParseDocumentNodeLODs(doc);\r\n\r\n                Assert::IsTrue(GLTFLODUtils::NumberOfNodeLODLevels(doc, lods) == expectedNumberOfLods);\r\n            }\r\n            catch (std::exception ex)\r\n            {\r\n                std::stringstream ss;\r\n                ss << \"Received exception was unexpected. Got: \" << ex.what();\r\n                Assert::Fail(WStringUtils::ToWString(ss).c_str());\r\n            }\r\n        }\r\n\r\n        static std::shared_ptr<Document> ImportGLTF(const std::shared_ptr<IStreamReader>& streamReader, const std::shared_ptr<std::istream>& stream)\r\n        {\r\n            GLTFResourceReader resourceReader(streamReader);\r\n            auto json = std::string(std::istreambuf_iterator<char>(*stream), std::istreambuf_iterator<char>());\r\n\r\n            auto doc = Deserialize(json, KHR::GetKHRExtensionDeserializer());\r\n\r\n            return std::make_shared<Document>(doc);\r\n        }\r\n\r\n        const char* c_cubeAsset3DJson = \"Resources\\\\gltf\\\\cubeAsset3D.gltf\";\r\n        const char* c_cubeWithLODJson = \"Resources\\\\gltf\\\\cubeWithLOD.gltf\";\r\n\r\n        TEST_METHOD(GLTFLODUtils_NodeLodCount)\r\n        {\r\n            CheckGLTFLODCount(c_cubeAsset3DJson, 0);\r\n        }\r\n        TEST_METHOD(GLTFLODUtils_NodeLodCount_DocWithLODs)\r\n        {\r\n            CheckGLTFLODCount(c_cubeWithLODJson, 1);\r\n        }\r\n\r\n        TEST_METHOD(GLTFLODUtils_GLTFNodeLODMerge)\r\n        {\r\n            auto input = TestUtils::ReadLocalAsset(TestUtils::GetAbsolutePath(c_cubeAsset3DJson));\r\n            auto readwriter = std::make_shared<StreamMock>();\r\n            try\r\n            {\r\n                // Deserialize input json\r\n                GLTFResourceReader resourceReader(readwriter);\r\n                auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());\r\n                auto doc = Deserialize(inputJson, KHR::GetKHRExtensionDeserializer());\r\n\r\n                std::vector<Document> docs;\r\n                docs.push_back(doc);\r\n                docs.push_back(doc);\r\n                auto newlodgltfDoc = GLTFLODUtils::MergeDocumentsAsLODs(docs);\r\n\r\n                // Serialize Document back to json\r\n                auto outputJson = Serialize(newlodgltfDoc, KHR::GetKHRExtensionSerializer());\r\n\r\n                CheckGLTFLODNodeCountAgainstOriginal(doc, newlodgltfDoc, 2);\r\n\r\n                // Check Node Lods are correctly stored and labelled in the document\r\n                auto nodes = newlodgltfDoc.nodes.Elements();\r\n                auto lods = GLTFLODUtils::ParseDocumentNodeLODs(newlodgltfDoc);\r\n                bool validLodExtension = false;\r\n                bool containsLOD1RootNode = false;\r\n                bool containsLOD1PolyNode = false;\r\n                for (auto node : nodes)\r\n                {\r\n                    if (node.name == \"root\" && (std::find(lods[node.id]->begin(), lods[node.id]->end(), \"3\") != lods[node.id]->end()))\r\n                    {\r\n                        validLodExtension = true;\r\n                    }\r\n                    if (node.name == \"root_lod1\")\r\n                    {\r\n                        containsLOD1RootNode = true;\r\n                    }\r\n                    if (node.name == \"polygon_lod1\")\r\n                    {\r\n                        containsLOD1PolyNode = true;\r\n                    }\r\n                }\r\n                Assert::IsTrue(validLodExtension);\r\n                Assert::IsTrue(containsLOD1RootNode);\r\n                Assert::IsTrue(containsLOD1PolyNode);\r\n            }\r\n            catch (std::exception ex)\r\n            {\r\n                std::stringstream ss;\r\n                ss << \"Received exception was unexpected. Got: \" << ex.what();\r\n                Assert::Fail(WStringUtils::ToWString(ss).c_str());\r\n            }\r\n        }\r\n\r\n        TEST_METHOD(GLTFLODUTils_GLTFNodeLODMergeMultiple)\r\n        {\r\n            auto input = TestUtils::ReadLocalAsset(TestUtils::GetAbsolutePath(c_cubeAsset3DJson));\r\n            auto readwriter = std::make_shared<StreamMock>();\r\n            try\r\n            {\r\n                // Deserialize input json\r\n                GLTFResourceReader resourceReader(readwriter);\r\n                auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());\r\n                auto doc = Deserialize(inputJson, KHR::GetKHRExtensionDeserializer());\r\n\r\n                std::vector<Document> docs;\r\n                docs.push_back(doc);\r\n                docs.push_back(doc);\r\n                docs.push_back(doc);\r\n\r\n                auto newlodgltfDoc = GLTFLODUtils::MergeDocumentsAsLODs(docs);\r\n\r\n                CheckGLTFLODNodeCountAgainstOriginal(doc, newlodgltfDoc, 3);\r\n\r\n                // Check Node Lods are correctly stored and labelled in the document\r\n                auto nodes = newlodgltfDoc.nodes.Elements();\r\n                auto lods = GLTFLODUtils::ParseDocumentNodeLODs(newlodgltfDoc);\r\n                bool validLodExtension = false;\r\n                bool containsLOD1RootNode = false;\r\n                bool containsLOD1PolyNode = false;\r\n                bool containsLOD2RootNode = false;\r\n                bool containsLOD2PolyNode = false;\r\n                for (auto node : nodes)\r\n                {\r\n                    if (node.name == \"root\" &&\r\n                        (std::find(lods[node.id]->begin(), lods[node.id]->end(), \"3\") != lods[node.id]->end()) &&\r\n                        (std::find(lods[node.id]->begin(), lods[node.id]->end(), \"5\") != lods[node.id]->end())\r\n                        )\r\n                    {\r\n                        validLodExtension = true;\r\n                    }\r\n                    if (node.name == \"root_lod1\") containsLOD1RootNode = true;\r\n                    if (node.name == \"polygon_lod1\") containsLOD1PolyNode = true;\r\n                    if (node.name == \"root_lod2\") containsLOD2RootNode = true;\r\n                    if (node.name == \"polygon_lod2\") containsLOD2PolyNode = true;\r\n                }\r\n\r\n                Assert::IsTrue(validLodExtension);\r\n                Assert::IsTrue(containsLOD1RootNode);\r\n                Assert::IsTrue(containsLOD1PolyNode);\r\n                Assert::IsTrue(containsLOD2RootNode);\r\n                Assert::IsTrue(containsLOD2PolyNode);\r\n\r\n                // Serialize Document back to json\r\n                auto outputJson = Serialize(newlodgltfDoc, KHR::GetKHRExtensionSerializer());\r\n            }\r\n            catch (std::exception ex)\r\n            {\r\n                std::stringstream ss;\r\n                ss << \"Received exception was unexpected. Got: \" << ex.what();\r\n                Assert::Fail(WStringUtils::ToWString(ss).c_str());\r\n            }\r\n        }\r\n\r\n        TEST_METHOD(GLTFLODUtils_GLTFNodeLODMergeScreenCoverage)\r\n        {\r\n            auto input = TestUtils::ReadLocalAsset(TestUtils::GetAbsolutePath(c_cubeAsset3DJson));\r\n            auto readwriter = std::make_shared<StreamMock>();\r\n            try\r\n            {\r\n                // Deserialize input json\r\n                GLTFResourceReader resourceReader(readwriter);\r\n                auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());\r\n                auto doc = Deserialize(inputJson, KHR::GetKHRExtensionDeserializer());\r\n\r\n                std::vector<Document> docs;\r\n                docs.push_back(doc);\r\n                docs.push_back(doc);\r\n                docs.push_back(doc);\r\n\r\n                std::vector<double> screenCoverages{ 0.5, 0.2, 0.01 };\r\n\r\n                auto newlodgltfDoc = GLTFLODUtils::MergeDocumentsAsLODs(docs, screenCoverages);\r\n\r\n                CheckGLTFLODNodeCountAgainstOriginal(doc, newlodgltfDoc, 3);\r\n\r\n                // Check Node Lods have correct screen coverage values\r\n                auto nodes = newlodgltfDoc.nodes.Elements();\r\n                bool rootNodeContainsCoverage = false;\r\n                for (auto node : nodes)\r\n                {\r\n                    if (node.name == \"root\" && !node.extras.empty())\r\n                    {\r\n                        auto extrasJson = RapidJsonUtils::CreateDocumentFromString(node.extras);\r\n\r\n                        Assert::IsTrue(extrasJson.IsObject());\r\n                        Assert::IsTrue(extrasJson[\"MSFT_screencoverage\"].IsArray());\r\n                        Assert::IsTrue(extrasJson[\"MSFT_screencoverage\"].GetArray().Size() == 3);\r\n\r\n                        rootNodeContainsCoverage = true;\r\n                    }\r\n                }\r\n\r\n                Assert::IsTrue(rootNodeContainsCoverage);\r\n\r\n                // Serialize Document back to json\r\n                auto outputJson = Serialize(newlodgltfDoc, KHR::GetKHRExtensionSerializer());\r\n            }\r\n            catch (std::exception ex)\r\n            {\r\n                std::stringstream ss;\r\n                ss << \"Received exception was unexpected. Got: \" << ex.what();\r\n                Assert::Fail(WStringUtils::ToWString(ss).c_str());\r\n            }\r\n        }\r\n\r\n        TEST_METHOD(GLTFLODUtils_DeserialiseNodeLODExtension)\r\n        {\r\n            auto input = TestUtils::ReadLocalAsset(TestUtils::GetAbsolutePath(c_cubeWithLODJson));\r\n            auto readwriter = std::make_shared<StreamMock>();\r\n            try\r\n            {\r\n                auto gltfDoc = ImportGLTF(readwriter, input);\r\n                auto nodes = gltfDoc->nodes.Elements();\r\n                Assert::IsTrue(nodes.size() == 4);\r\n                auto lods = GLTFLODUtils::ParseDocumentNodeLODs(*gltfDoc);\r\n                bool validLodExtension = false;\r\n                for (auto node : nodes)\r\n                {\r\n                    if (node.name == \"root\" && (std::find(lods[node.id]->begin(), lods[node.id]->end(), \"3\") != lods[node.id]->end()))\r\n                    {\r\n                        validLodExtension = true;\r\n                        break;\r\n                    }\r\n                }\r\n                Assert::IsTrue(validLodExtension);\r\n            }\r\n            catch (std::exception ex)\r\n            {\r\n                std::stringstream ss;\r\n                ss << \"Received exception was unexpected. Got: \" << ex.what();\r\n                Assert::Fail(WStringUtils::ToWString(ss).c_str());\r\n            }\r\n        }\r\n\r\n        TEST_METHOD(GLTFLODUtils_DeserializeSerializeLoopNodeLODExtension)\r\n        {\r\n            auto input = TestUtils::ReadLocalAsset(TestUtils::GetAbsolutePath(c_cubeWithLODJson));\r\n            auto readwriter = std::make_shared<StreamMock>();\r\n            try\r\n            {\r\n                // Deserialize input json\r\n                GLTFResourceReader resourceReader(readwriter);\r\n                auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());\r\n                auto doc = Deserialize(inputJson, KHR::GetKHRExtensionDeserializer());\r\n\r\n                // Serialize Document back to json\r\n                auto outputJson = Serialize(doc, KHR::GetKHRExtensionSerializer());\r\n                auto outputDoc = Deserialize(outputJson, KHR::GetKHRExtensionDeserializer());\r\n\r\n                // Compare input and output GLTFDocuments\r\n                Assert::AreNotSame(doc == outputDoc, true, L\"Input gltf and output gltf are not equal\");\r\n\r\n                // Specifically ensure Node LODs are preserved through de/serialization loop\r\n                auto nodes = outputDoc.nodes.Elements();\r\n                Assert::IsTrue(nodes.size() == 4);\r\n                auto lods = GLTFLODUtils::ParseDocumentNodeLODs(outputDoc);\r\n                bool validLodExtension = false;\r\n                for (auto node : nodes)\r\n                {\r\n                    if (node.name == \"root\" && (std::find(lods[node.id]->begin(), lods[node.id]->end(), \"3\") != lods[node.id]->end()))\r\n                    {\r\n                        validLodExtension = true;\r\n                        break;\r\n                    }\r\n                }\r\n                Assert::IsTrue(validLodExtension);\r\n            }\r\n            catch (std::exception ex)\r\n            {\r\n                std::stringstream ss;\r\n                ss << \"Received exception was unexpected. Got: \" << ex.what();\r\n                Assert::Fail(WStringUtils::ToWString(ss).c_str());\r\n            }\r\n        }\r\n    };\r\n}\r\n\r\n"
  },
  {
    "path": "glTF-Toolkit.Test/GLTFTextureCompressionUtilsTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n#include \"pch.h\"\r\n#include <CppUnitTest.h>  \r\n\r\n#include \"GLTFSDK/IStreamWriter.h\"\r\n#include \"GLTFSDK/Constants.h\"\r\n#include \"GLTFSDK/Serialize.h\"\r\n#include \"GLTFSDK/Deserialize.h\"\r\n#include \"GLTFSDK/GLBResourceReader.h\"\r\n#include \"GLTFSDK/GLTFResourceWriter.h\"\r\n\r\n#include \"GLTFTextureCompressionUtils.h\"\r\n\r\n#include \"Helpers/WStringUtils.h\"\r\n#include \"Helpers/StreamMock.h\"\r\n#include \"Helpers/TestUtils.h\"\r\n\r\n#include <DirectXTex.h>\r\n\r\n\r\nusing namespace Microsoft::VisualStudio::CppUnitTestFramework;\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\nnamespace Microsoft::glTF::Toolkit::Test\r\n{\r\n    // Note: some tests are using BC3 since it's faster to run that algorithm vs. BC7\r\n\r\n    TEST_CLASS(GLTFTextureCompressionUtilsTests)\r\n    {\r\n        const char* c_baseColorPng = \"Resources\\\\gltf\\\\WaterBottle_ORM\\\\WaterBottle_baseColor.png\";\r\n        const char* c_baseColorBC7 = \"Resources\\\\gltf\\\\WaterBottle_ORM\\\\WaterBottle_baseColor.DDS\";\r\n        const char* c_waterBottleORMJson = \"Resources\\\\gltf\\\\WaterBottle_ORM\\\\WaterBottle.gltf\";\r\n        const char* c_nonMultipleOf4TextureJson = \"Resources\\\\gltf\\\\TextureTest\\\\TextureTest.gltf\";\r\n\r\n        TEST_METHOD(GLTFTextureCompressionUtils_CompressImage_BC7)\r\n        {\r\n            // Load png\r\n            auto png = TestUtils::ReadLocalAsset(TestUtils::GetAbsolutePath(c_baseColorPng));\r\n            std::vector<uint8_t> pngData = StreamUtils::ReadBinaryFull<uint8_t>(*png);\r\n\r\n            // ddsImage <= load DDS\r\n            DirectX::ScratchImage ddsImage;\r\n            DirectX::TexMetadata info;\r\n            DirectX::LoadFromDDSFile(TestUtils::GetAbsolutePathW(c_baseColorBC7).c_str(), DirectX::WIC_FLAGS_NONE, &info, ddsImage);\r\n\r\n            // compressedPng <= convert using BC7\r\n            DirectX::ScratchImage compressedPng;\r\n            DirectX::LoadFromWICMemory(pngData.data(), pngData.size(), DirectX::WIC_FLAGS_NONE, &info, compressedPng);\r\n\r\n            GLTFTextureCompressionUtils::CompressImage(compressedPng, TextureCompression::BC7);\r\n\r\n            auto ddsMip0 = ddsImage.GetImage(0, 0, 0);\r\n            size_t ddsImageSize = ddsMip0->height * ddsMip0->width;\r\n            Assert::AreEqual(ddsImageSize, compressedPng.GetPixelsSize(), L\"ddsImage and compressedPng lengths are not the same\");\r\n\r\n            Assert::IsTrue(memcmp(ddsMip0->pixels, compressedPng.GetPixels(), ddsImageSize), L\"ddsImage and compressedPng are not the same\");\r\n        }\r\n\r\n        TEST_METHOD(GLTFTextureCompressionUtils_CompressTextureAsDDS_NoCompression)\r\n        {\r\n            // This asset has all textures\r\n            TestUtils::LoadAndExecuteGLTFTest(c_waterBottleORMJson, [](auto doc, auto path)\r\n            {\r\n                auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(std::make_shared<TestStreamReader>(path), doc, doc.textures.Get(\"0\"), TextureCompression::None, \"\");\r\n\r\n                // Check that nothing changed\r\n                Assert::IsTrue(doc == compressedDoc);\r\n            });\r\n        }\r\n\r\n        TEST_METHOD(GLTFTextureCompressionUtils_CompressTextureAsDDS_CompressBC3_NoMips_Retain)\r\n        {\r\n            // This asset has all textures\r\n            TestUtils::LoadAndExecuteGLTFTest(c_waterBottleORMJson, [](auto doc, auto path)\r\n            {\r\n                auto maxTextureSize = std::numeric_limits<size_t>::max();\r\n                auto generateMipMaps = false;\r\n                auto retainOriginalImages = true;\r\n                auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(std::make_shared<TestStreamReader>(path), doc, doc.textures.Get(\"0\"), TextureCompression::BC3, \"\", maxTextureSize, generateMipMaps, retainOriginalImages);\r\n\r\n                auto originalTexture = doc.textures.Get(\"0\");\r\n                auto compressedTexture = compressedDoc.textures.Get(\"0\");\r\n\r\n                // Check that the image has not been replaced\r\n                Assert::IsTrue(originalTexture.imageId == compressedTexture.imageId);\r\n\r\n                // Check that the image has been added\r\n                Assert::IsTrue(doc.images.Size() + 1 == compressedDoc.images.Size());\r\n\r\n                // Check that the texture now has the extension\r\n                Assert::IsTrue(originalTexture.extensions.size() + 1 == compressedTexture.extensions.size());\r\n\r\n                // Check the new extension is not empty\r\n                auto ddsExtension = compressedTexture.extensions.at(std::string(EXTENSION_MSFT_TEXTURE_DDS));\r\n                Assert::IsFalse(ddsExtension.empty());\r\n\r\n                // Check the new extension contains a DDS image\r\n                rapidjson::Document ddsJson;\r\n                ddsJson.Parse(ddsExtension.c_str());\r\n\r\n                Assert::IsTrue(ddsJson[\"source\"].IsInt());\r\n\r\n                auto ddsImageId = std::to_string(ddsJson[\"source\"].GetInt());\r\n\r\n                Assert::IsTrue(compressedDoc.images.Get(ddsImageId).mimeType == \"image/vnd-ms.dds\");\r\n                Assert::IsTrue(compressedDoc.images.Get(ddsImageId).uri == \"texture_0_nomips_BC3.dds\");\r\n            });\r\n        }\r\n\r\n        TEST_METHOD(GLTFTextureCompressionUtils_CompressTextureAsDDS_CompressBC3_NoMips_Replace)\r\n        {\r\n            // This asset has all textures\r\n            TestUtils::LoadAndExecuteGLTFTest(c_waterBottleORMJson, [](auto doc, auto path)\r\n            {\r\n                auto maxTextureSize = std::numeric_limits<size_t>::max();\r\n                auto generateMipMaps = false;\r\n                auto retainOriginalImages = false;\r\n                auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(std::make_shared<TestStreamReader>(path), doc, doc.textures.Get(\"0\"), TextureCompression::BC3, \"\", maxTextureSize, generateMipMaps, retainOriginalImages);\r\n\r\n                auto originalTexture = doc.textures.Get(\"0\");\r\n                auto compressedTexture = compressedDoc.textures.Get(\"0\");\r\n\r\n                // Check that the texture is still pointing to the same image\r\n                Assert::IsTrue(originalTexture.imageId == compressedTexture.imageId);\r\n\r\n                // Check that an image has not been added\r\n                Assert::IsTrue(doc.images.Size() == compressedDoc.images.Size());\r\n\r\n                // Check that the texture now has the extension\r\n                Assert::IsTrue(originalTexture.extensions.size() + 1 == compressedTexture.extensions.size());\r\n\r\n                // Check the new extension is not empty\r\n                auto ddsExtension = compressedTexture.extensions.at(std::string(EXTENSION_MSFT_TEXTURE_DDS));\r\n                Assert::IsFalse(ddsExtension.empty());\r\n\r\n                // Check the new extension contains a DDS image\r\n                rapidjson::Document ddsJson;\r\n                ddsJson.Parse(ddsExtension.c_str());\r\n\r\n                Assert::IsTrue(ddsJson[\"source\"].IsInt());\r\n\r\n                auto ddsImageId = std::to_string(ddsJson[\"source\"].GetInt());\r\n\r\n                Assert::IsTrue(compressedDoc.images.Get(ddsImageId).mimeType == \"image/vnd-ms.dds\");\r\n                Assert::IsTrue(compressedDoc.images.Get(ddsImageId).uri == \"texture_0_nomips_BC3.dds\");\r\n\r\n                // Check the extension points to the same image as the source (image was replaced)\r\n                Assert::AreEqual(compressedTexture.imageId, ddsImageId);\r\n            });\r\n        }\r\n\r\n        TEST_METHOD(GLTFTextureCompressionUtils_CompressTextureAsDDS_CompressBC7_Mips_Retain)\r\n        {\r\n            // This asset has all textures\r\n            TestUtils::LoadAndExecuteGLTFTest(c_waterBottleORMJson, [](auto doc, auto path)\r\n            {\r\n                auto maxTextureSize = std::numeric_limits<size_t>::max();\r\n                auto generateMipMaps = true;\r\n                auto retainOriginalImages = true;\r\n                auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(std::make_shared<TestStreamReader>(path), doc, doc.textures.Get(\"0\"), TextureCompression::BC7, \"\", maxTextureSize, generateMipMaps, retainOriginalImages);\r\n\r\n                auto originalTexture = doc.textures.Get(\"0\");\r\n                auto compressedTexture = compressedDoc.textures.Get(\"0\");\r\n\r\n                // Check that the image has not been replaced\r\n                Assert::IsTrue(originalTexture.imageId == compressedTexture.imageId);\r\n\r\n                // Check that the image has been added\r\n                Assert::IsTrue(doc.images.Size() + 1 == compressedDoc.images.Size());\r\n\r\n                // Check that the texture now has the extension\r\n                Assert::IsTrue(originalTexture.extensions.size() + 1 == compressedTexture.extensions.size());\r\n\r\n                // Check the new extension is not empty\r\n                auto ddsExtension = compressedTexture.extensions.at(std::string(EXTENSION_MSFT_TEXTURE_DDS));\r\n                Assert::IsFalse(ddsExtension.empty());\r\n\r\n                // Check the new extension contains a DDS image\r\n                rapidjson::Document ddsJson;\r\n                ddsJson.Parse(ddsExtension.c_str());\r\n\r\n                Assert::IsTrue(ddsJson[\"source\"].IsInt());\r\n\r\n                auto ddsImageId = std::to_string(ddsJson[\"source\"].GetInt());\r\n\r\n                Assert::IsTrue(compressedDoc.images.Get(ddsImageId).mimeType == \"image/vnd-ms.dds\");\r\n                Assert::IsTrue(compressedDoc.images.Get(ddsImageId).uri == \"texture_0_BC7.dds\");\r\n            });\r\n        }\r\n\r\n        TEST_METHOD(GLTFTextureCompressionUtils_CompressAllTexturesForWindowsMR_Retain)\r\n        {\r\n            // This asset has all textures\r\n            TestUtils::LoadAndExecuteGLTFTest(c_waterBottleORMJson, [](auto doc, auto path)\r\n            {\r\n                auto maxTextureSize = std::numeric_limits<size_t>::max();\r\n                auto retainOriginalImages = true;\r\n                auto compressedDoc = GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(std::make_shared<TestStreamReader>(path), doc, \"\", maxTextureSize, retainOriginalImages);\r\n\r\n                // Check that the materials and textures have not been replaced\r\n                // Check that the textures has not been replaced\r\n                Assert::IsTrue(doc.textures.Size() == compressedDoc.textures.Size());\r\n                Assert::IsTrue(doc.materials.Size() == compressedDoc.materials.Size());\r\n\r\n                // Check that the images have been added (base, emissive, RMO and normal)\r\n                Assert::AreEqual(doc.images.Size() + 4, compressedDoc.images.Size());\r\n\r\n                auto originalMaterial = doc.materials.Get(\"0\");\r\n                auto compressedMaterial = compressedDoc.materials.Get(\"0\");\r\n\r\n                // Check that all relevant textures now have the extension\r\n                Assert::IsTrue(doc.textures.Get(originalMaterial.metallicRoughness.baseColorTexture.textureId).extensions.size() + 1 == compressedDoc.textures.Get(compressedMaterial.metallicRoughness.baseColorTexture.textureId).extensions.size());\r\n                Assert::IsTrue(doc.textures.Get(originalMaterial.emissiveTexture.textureId).extensions.size() + 1 == compressedDoc.textures.Get(compressedMaterial.emissiveTexture.textureId).extensions.size());\r\n                // TODO: read the WMR (MSFT_packing...) textures as well\r\n\r\n                // Check the new extension is not empty\r\n                auto ddsExtension = compressedDoc.textures.Get(compressedMaterial.emissiveTexture.textureId).extensions.at(std::string(EXTENSION_MSFT_TEXTURE_DDS));\r\n                Assert::IsFalse(ddsExtension.empty());\r\n\r\n                // Check the new extension contains a DDS image\r\n                rapidjson::Document ddsJson;\r\n                ddsJson.Parse(ddsExtension.c_str());\r\n\r\n                Assert::IsTrue(ddsJson[\"source\"].IsInt());\r\n\r\n                auto ddsImageId = std::to_string(ddsJson[\"source\"].GetInt());\r\n\r\n                Assert::IsTrue(compressedDoc.images.Get(ddsImageId).mimeType == \"image/vnd-ms.dds\");\r\n                std::string expectedSuffix = \"_BC7.dds\";\r\n                Assert::IsTrue(compressedDoc.images.Get(ddsImageId).uri.compare(9, expectedSuffix.size(), expectedSuffix) == 0); // The emissive texture should have mips and be BC7\r\n            });\r\n        }\r\n\r\n        TEST_METHOD(GLTFTextureCompressionUtils_CompressTextureAsDDS_NotMultipleOf4)\r\n        {\r\n            // This asset has all textures\r\n            TestUtils::LoadAndExecuteGLTFTest(c_nonMultipleOf4TextureJson, [](auto doc, auto path)\r\n            {\r\n                auto maxTextureSize = std::numeric_limits<size_t>::max();\r\n                auto generateMipMaps = false;\r\n                auto retainOriginalImages = true;\r\n                auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(std::make_shared<TestStreamReader>(path), doc, doc.textures.Get(\"0\"), TextureCompression::BC3, \"\", maxTextureSize, generateMipMaps, retainOriginalImages);\r\n\r\n                auto originalUri = compressedDoc.images.Get(\"0\").uri;\r\n                auto compressedUri = compressedDoc.images.Get(\"1\").uri;\r\n\r\n                auto basePath = TestUtils::GetBasePath(path.c_str());\r\n\r\n                // load original\r\n                DirectX::ScratchImage originalImage;\r\n                DirectX::TexMetadata originalInfo;\r\n                DirectX::LoadFromWICFile(WStringUtils::ToWString(basePath + originalUri).c_str(), DirectX::WIC_FLAGS_NONE, &originalInfo, originalImage);\r\n                \r\n                Assert::IsTrue(101 == originalInfo.width);\r\n                Assert::IsTrue(51 == originalInfo.height);\r\n\r\n                // load compressed\r\n                DirectX::ScratchImage compressedImage;\r\n                DirectX::TexMetadata compressedInfo;\r\n                DirectX::LoadFromDDSFile(WStringUtils::ToWString(compressedUri).c_str(), DirectX::DDS_FLAGS_NONE, &compressedInfo, compressedImage);\r\n\r\n                // Check resize\r\n                Assert::IsTrue(104 == compressedInfo.width);\r\n                Assert::IsTrue(52 == compressedInfo.height);\r\n            });\r\n        }\r\n    };\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit.Test/GLTFTexturePackingUtilsTests.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n#include \"pch.h\"\r\n#include <CppUnitTest.h>  \r\n\r\n#include \"GLTFSDK/IStreamWriter.h\"\r\n#include \"GLTFSDK/Constants.h\"\r\n#include \"GLTFSDK/Serialize.h\"\r\n#include \"GLTFSDK/Deserialize.h\"\r\n#include \"GLTFSDK/GLBResourceReader.h\"\r\n#include \"GLTFSDK/GLTFResourceWriter.h\"\r\n\r\n#include \"GLTFTexturePackingUtils.h\"\r\n\r\n#include \"Helpers/WStringUtils.h\"\r\n#include \"Helpers/TestUtils.h\"\r\n\r\nusing namespace Microsoft::VisualStudio::CppUnitTestFramework;\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\n\r\nnamespace Microsoft::glTF::Toolkit::Test\r\n{\r\n    TEST_CLASS(GLTFTexturePackingUtilsTests)\r\n    {\r\n        // Asset with no materials\r\n        const char* c_cubeAsset3DJson = \"Resources\\\\gltf\\\\cubeAsset3D.gltf\";\r\n\r\n        // Asset with loose images and all textures\r\n        const char* c_waterBottleJson = \"Resources\\\\gltf\\\\WaterBottle\\\\WaterBottle.gltf\";\r\n\r\n        // Loads and packs a complex asset with the specified packing\r\n        void ExecutePackingTest(const char* gltfRelativePath, TexturePacking packing)\r\n        {\r\n            // This asset has all textures\r\n            TestUtils::LoadAndExecuteGLTFTest(gltfRelativePath, [packing](auto doc, auto path)\r\n            {\r\n                auto material = doc.materials.Elements()[0];\r\n                auto packedDoc = GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::make_shared<TestStreamReader>(path), doc, material, packing, \"\");\r\n                auto packedMaterial = packedDoc.materials.Elements()[0];\r\n\r\n                // Check that the material changed\r\n                Assert::IsTrue(material != packedMaterial);\r\n\r\n                // Check that the new material replaces the old one\r\n                Assert::IsTrue(material.id == packedMaterial.id);\r\n                Assert::IsTrue(doc.materials.Size() == packedDoc.materials.Size());\r\n\r\n                size_t expectedExtensionsSize = material.extensions.size();\r\n\r\n                // Check the new extension is not empty\r\n                if (packing & (TexturePacking::OcclusionRoughnessMetallic | TexturePacking::RoughnessMetallicOcclusion))\r\n                {\r\n                    expectedExtensionsSize++;\r\n\r\n                    auto packingOrmExtension = packedMaterial.extensions.at(std::string(EXTENSION_MSFT_PACKING_ORM));\r\n                    Assert::IsFalse(packingOrmExtension.empty());\r\n\r\n                    // Check the new extension contains an ORM texture\r\n                    rapidjson::Document ormJson;\r\n                    ormJson.Parse(packingOrmExtension.c_str());\r\n\r\n                    if (packing & TexturePacking::OcclusionRoughnessMetallic)\r\n                    {\r\n                        Assert::IsTrue(ormJson[MSFT_PACKING_ORM_ORMTEXTURE_KEY].IsObject());\r\n                        Assert::IsTrue(ormJson[MSFT_PACKING_ORM_ORMTEXTURE_KEY].HasMember(MSFT_PACKING_INDEX_KEY));\r\n                    }\r\n\r\n                    if (packing & TexturePacking::RoughnessMetallicOcclusion)\r\n                    {\r\n                        Assert::IsTrue(ormJson[MSFT_PACKING_ORM_RMOTEXTURE_KEY].IsObject());\r\n                        Assert::IsTrue(ormJson[MSFT_PACKING_ORM_RMOTEXTURE_KEY].HasMember(MSFT_PACKING_INDEX_KEY));\r\n                    }\r\n\r\n                    if (!material.normalTexture.textureId.empty())\r\n                    {\r\n                        // Check the new extension contains a normal texture\r\n                        Assert::IsTrue(ormJson[MSFT_PACKING_ORM_NORMALTEXTURE_KEY].IsObject());\r\n                        Assert::IsTrue(ormJson[MSFT_PACKING_ORM_NORMALTEXTURE_KEY].HasMember(MSFT_PACKING_INDEX_KEY));\r\n                    }\r\n                }\r\n\r\n                if (packing & TexturePacking::NormalRoughnessMetallic)\r\n                {\r\n                    expectedExtensionsSize++;\r\n\r\n                    auto packingNrmExtension = packedMaterial.extensions.at(std::string(EXTENSION_MSFT_PACKING_NRM));\r\n                    Assert::IsFalse(packingNrmExtension.empty());\r\n\r\n                    // Check the new extension contains an NRM texture\r\n                    rapidjson::Document nrmJson;\r\n                    nrmJson.Parse(packingNrmExtension.c_str());\r\n\r\n                    Assert::IsTrue(nrmJson[MSFT_PACKING_NRM_KEY].IsObject());\r\n                    Assert::IsTrue(nrmJson[MSFT_PACKING_NRM_KEY].HasMember(MSFT_PACKING_INDEX_KEY));\r\n                }\r\n\r\n                // Check that the packed material has the new extension\r\n                Assert::IsTrue(expectedExtensionsSize == packedMaterial.extensions.size());\r\n            });\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_NoMaterials)\r\n        {\r\n            // This asset has no textures\r\n            TestUtils::LoadAndExecuteGLTFTest(c_cubeAsset3DJson, [](auto doc, auto path)\r\n            {\r\n                auto material = doc.materials.Elements()[0];\r\n                auto packedDoc = GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::make_shared<TestStreamReader>(path), doc, material, TexturePacking::OcclusionRoughnessMetallic, \"\");\r\n\r\n                // Check that nothing changed\r\n                Assert::IsTrue(doc == packedDoc);\r\n            });\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_NoPacking)\r\n        {\r\n            // This asset has all textures\r\n            TestUtils::LoadAndExecuteGLTFTest(c_waterBottleJson, [](auto doc, auto path)\r\n            {\r\n                auto material = doc.materials.Elements()[0];\r\n                auto packedDoc = GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::make_shared<TestStreamReader>(path), doc, material, TexturePacking::None, \"\");\r\n\r\n                // Check that nothing changed\r\n                Assert::IsTrue(doc == packedDoc);\r\n            });\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_PackORM)\r\n        {\r\n            ExecutePackingTest(c_waterBottleJson, TexturePacking::OcclusionRoughnessMetallic);\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_PackRMO)\r\n        {\r\n            ExecutePackingTest(c_waterBottleJson, TexturePacking::RoughnessMetallicOcclusion);\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_PackORMandRMO)\r\n        {\r\n            ExecutePackingTest(c_waterBottleJson, (TexturePacking)(TexturePacking::OcclusionRoughnessMetallic | TexturePacking::RoughnessMetallicOcclusion));\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_PackNRM)\r\n        {\r\n            ExecutePackingTest(c_waterBottleJson, TexturePacking::NormalRoughnessMetallic);\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_PackNRMandORM)\r\n        {\r\n            // Default for RS4+ compatible with both HoloLens and Desktop\r\n            ExecutePackingTest(c_waterBottleJson, (TexturePacking)(TexturePacking::OcclusionRoughnessMetallic | TexturePacking::NormalRoughnessMetallic));\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_PackNRMandORMandRMO)\r\n        {\r\n            // Maximum compatibility: all packings\r\n            ExecutePackingTest(c_waterBottleJson, (TexturePacking)(TexturePacking::OcclusionRoughnessMetallic | TexturePacking::NormalRoughnessMetallic | TexturePacking::RoughnessMetallicOcclusion));\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_PackAllWithNoMaterials)\r\n        {\r\n            // This asset has no materials\r\n            TestUtils::LoadAndExecuteGLTFTest(c_cubeAsset3DJson, [](auto doc, auto path)\r\n            {\r\n                auto packedDoc = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(std::make_shared<TestStreamReader>(path), doc, TexturePacking::OcclusionRoughnessMetallic, \"\");\r\n\r\n                // Check that nothing changed\r\n                Assert::IsTrue(doc == packedDoc);\r\n            });\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_PackAllWithPackingNone)\r\n        {\r\n            // This asset has all textures\r\n            TestUtils::LoadAndExecuteGLTFTest(c_waterBottleJson, [](auto doc, auto path)\r\n            {\r\n                auto packedDoc = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(std::make_shared<TestStreamReader>(path), doc, TexturePacking::None, \"\");\r\n\r\n                // Check that nothing changed\r\n                Assert::IsTrue(doc == packedDoc);\r\n            });\r\n        }\r\n\r\n        TEST_METHOD(GLTFTexturePackingUtils_PackAllWithOneMaterial)\r\n        {\r\n            std::unique_ptr<Document> documentPackedSingleTexture;\r\n            std::unique_ptr<Document> documentPackedAllTextures;\r\n\r\n            // This asset has all textures\r\n            TestUtils::LoadAndExecuteGLTFTest(c_waterBottleJson, [&documentPackedSingleTexture](auto doc, auto path)\r\n            {\r\n                documentPackedSingleTexture = std::make_unique<Document>(GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::make_shared<TestStreamReader>(path), doc, doc.materials.Elements()[0], TexturePacking::OcclusionRoughnessMetallic, \"\"));\r\n            });\r\n\r\n            TestUtils::LoadAndExecuteGLTFTest(c_waterBottleJson, [&documentPackedAllTextures](auto doc, auto path)\r\n            {\r\n                documentPackedAllTextures = std::make_unique<Document>(GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(std::make_shared<TestStreamReader>(path), doc, TexturePacking::OcclusionRoughnessMetallic, \"\"));\r\n            });\r\n\r\n            // Assert there's one material\r\n            Assert::IsTrue(documentPackedSingleTexture->materials.Size() == 1);\r\n            Assert::IsTrue(documentPackedAllTextures->materials.Size() == 1);\r\n\r\n            // Check that they're the same when there's one material\r\n            Assert::IsTrue(*documentPackedSingleTexture == *documentPackedAllTextures);\r\n        }\r\n    };\r\n}\r\n\r\n"
  },
  {
    "path": "glTF-Toolkit.Test/Helpers/StreamMock.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n#include <memory>\r\n#include <string>\r\n#include <sstream>\r\n\r\n#include <GLTFSDK/IStreamReader.h>\r\n#include <GLTFSDK/IStreamWriter.h>\r\n\r\nnamespace Microsoft::glTF::Toolkit::Test\r\n{\r\n    class StreamMock : public Microsoft::glTF::IStreamWriter, public Microsoft::glTF::IStreamReader\r\n    {\r\n    public:\r\n        StreamMock() : m_stream(std::make_shared<std::stringstream>(std::ios_base::app | std::ios_base::binary | std::ios_base::in | std::ios_base::out))\r\n        {\r\n        }\r\n\r\n        std::shared_ptr<std::ostream> GetOutputStream(const std::string&) const override\r\n        {\r\n            return m_stream;\r\n        }\r\n\r\n        std::shared_ptr<std::istream> GetInputStream(const std::string&) const override\r\n        {\r\n            return m_stream;\r\n        }\r\n    private:\r\n        std::shared_ptr<std::stringstream> m_stream;\r\n    };\r\n}"
  },
  {
    "path": "glTF-Toolkit.Test/Helpers/TestUtils.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n#include <CppUnitTest.h>\r\n\r\n#include <memory>\r\n#include \"GLTFSDK/IStreamWriter.h\"\r\n#include \"GLTFSDK/Constants.h\"\r\n#include \"GLTFSDK/Serialize.h\"\r\n#include \"GLTFSDK/Deserialize.h\"\r\n\r\n#include <locale>\r\n#include <string>\r\n#include <memory>\r\n#include \"WStringUtils.h\"\r\n#include \"StreamMock.h\"\r\n#include <fstream>\r\n#include <mutex>\r\n#include <algorithm>\r\n#include <string>\r\n#include <iostream>\r\n\r\nnamespace Microsoft::glTF::Toolkit::Test\r\n{\r\n    class TestUtils\r\n    {\r\n    public:\r\n\r\n        static std::string GetBasePath(const char * absolutePath)\r\n        {\r\n            std::string path(absolutePath);\r\n#ifdef __APPLE__\r\n            return path.substr(0, path.rfind('/') + 1);\r\n#else\r\n            return path.substr(0, path.rfind('\\\\') + 1);\r\n#endif\r\n        }\r\n\r\n        static std::string GetAbsolutePath(const char * relativePath)\r\n        {\r\n#ifdef __APPLE__\r\n            // Leaving Win32 alone (below), but macOS requires working directory to be set\r\n            std::string finalPath(relativePath);\r\n            std::replace(finalPath.begin(), finalPath.end(), '\\\\', '/');\r\n            return finalPath;\r\n#else\r\n            std::string currentPath = __FILE__;\r\n            std::string sourcePath = currentPath.substr(0, currentPath.rfind('\\\\'));\r\n            std::string resourcePath = sourcePath.substr(0, sourcePath.rfind('\\\\'));\r\n            return resourcePath + \"\\\\\" + relativePath;\r\n#endif\r\n        }\r\n\r\n        static std::wstring GetAbsolutePathW(const char * relativePath)\r\n        {\r\n            std::string absolutePath = GetAbsolutePath(relativePath);\r\n            std::wstringstream wss;\r\n            wss << absolutePath.c_str();\r\n            return wss.str();\r\n        }\r\n\r\n        static std::shared_ptr<std::istream> ReadLocalAsset(const std::string& filename)\r\n        {\r\n            // Read local file\r\n            int64_t m_readPosition = 0;\r\n            std::shared_ptr<const std::vector<int8_t>> m_buffer;\r\n            std::ifstream ifs;\r\n            ifs.open(filename.c_str(), std::ifstream::in | std::ifstream::binary);\r\n            if (ifs.is_open())\r\n            {\r\n                std::streampos start = ifs.tellg();\r\n                ifs.seekg(0, std::ios::end);\r\n                m_buffer = std::make_shared<const std::vector<int8_t>>(static_cast<unsigned int>(ifs.tellg() - start));\r\n                ifs.seekg(0, std::ios::beg);\r\n                ifs.read(reinterpret_cast<char*>(const_cast<int8_t*>(m_buffer->data())), m_buffer->size());\r\n                ifs.close();\r\n            }\r\n            else\r\n            {\r\n                throw std::runtime_error(\"Could not open the file for reading\");\r\n            }\r\n\r\n            // To IStream\r\n            unsigned long writeBufferLength = 4096L * 1024L;\r\n            auto tempStream = std::make_shared<std::stringstream>();\r\n            auto tempBuffer = new char[writeBufferLength];\r\n            // Read the file for as long as we can fill the buffer completely.\r\n            // This means there is more content to be read.\r\n            unsigned long bytesRead;\r\n            do\r\n            {\r\n                auto bytesAvailable = m_buffer->size() - m_readPosition;\r\n                unsigned long br = std::min(static_cast<unsigned long>(bytesAvailable), writeBufferLength);\r\n#ifdef _WIN32\r\n                memcpy_s(tempBuffer, br, m_buffer->data() + m_readPosition, br);\r\n#else\r\n                memcpy(tempBuffer, m_buffer->data() + m_readPosition, br);\r\n#endif\r\n                m_readPosition += br;\r\n                bytesRead = br;\r\n\r\n                tempStream->write(tempBuffer, bytesRead);\r\n            } while (bytesRead == writeBufferLength);\r\n\r\n            delete[] tempBuffer;\r\n\r\n            if (tempStream.get()->bad())\r\n            {\r\n                throw std::runtime_error(\"Bad std::stringstream after copying the file\");\r\n            }\r\n\r\n            return tempStream;\r\n        }\r\n\r\n        typedef std::function<void(const Document& doc, const std::string& gltfAbsolutePath)> GLTFAction;\r\n\r\n        static void LoadAndExecuteGLTFTest(const char * gltfRelativePath, GLTFAction action)\r\n        {\r\n            // This asset has all textures\r\n            auto absolutePath = TestUtils::GetAbsolutePath(gltfRelativePath);\r\n            auto input = TestUtils::ReadLocalAsset(absolutePath);\r\n            try\r\n            {\r\n                // Deserialize input json\r\n                auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());\r\n                auto doc = Deserialize(inputJson);\r\n\r\n                action(doc, absolutePath);\r\n            }\r\n            catch (std::exception ex)\r\n            {\r\n                std::stringstream ss;\r\n                ss << \"Received exception was unexpected. Got: \" << ex.what();\r\n                Microsoft::VisualStudio::CppUnitTestFramework::Assert::Fail(WStringUtils::ToWString(ss).c_str());\r\n            }\r\n        }\r\n    };\r\n\r\n    class TestStreamReader : public IStreamReader\r\n    {\r\n    public:\r\n        TestStreamReader(std::string gltfAbsolutePath) : m_basePath(TestUtils::GetBasePath(gltfAbsolutePath.c_str())) {}\r\n\r\n        virtual ~TestStreamReader() override {}\r\n        virtual std::shared_ptr<std::istream> GetInputStream(const std::string& filename) const override\r\n        {\r\n            auto path = m_basePath;\r\n\r\n#ifdef __APPLE__\r\n            path += \"/\" + filename;\r\n#else\r\n            path += \"\\\\\" + filename;\r\n#endif\r\n\r\n            return std::make_shared<std::ifstream>(path, std::ios::binary);\r\n        }\r\n    private:\r\n        const std::string m_basePath;\r\n    };\r\n}"
  },
  {
    "path": "glTF-Toolkit.Test/Helpers/WStringUtils.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n#include <string>\r\n#include <sstream>\r\n#include <locale>\r\n#include <codecvt>\r\n\r\nnamespace Microsoft::glTF::Toolkit::Test\r\n{\r\n    class WStringUtils\r\n    {\r\n    public:\r\n        static std::wstring ToWString(const std::string& str)\r\n        {\r\n            return ToWString(str.c_str());\r\n        }\r\n\r\n        static std::wstring ToWString(const std::stringstream& ss)\r\n        {\r\n            return ToWString(ss.str());\r\n        }\r\n\r\n        static std::wstring ToWString(const char* str)\r\n        {\r\n            std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;\r\n            return converter.from_bytes(str);\r\n        }\r\n    };\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit.Test/Resources/gltf/CubeAsset3D.gltf",
    "content": "{\n\t\"asset\": {\n\t\t\"version\": \"2.0\",\n\t\t\"generator\": \"Microsoft GLTF Exporter 2.1.2-b21\"\n\t},\n\t\"accessors\": [{\n\t\t\t\"bufferView\": 0,\n\t\t\t\"byteOffset\": 0,\n\t\t\t\"componentType\": 5123,\n\t\t\t\"count\": 36,\n\t\t\t\"type\": \"SCALAR\",\n\t\t\t\"max\": [23.0],\n\t\t\t\"min\": [0.0]\n\t\t}, {\n\t\t\t\"bufferView\": 1,\n\t\t\t\"byteOffset\": 0,\n\t\t\t\"componentType\": 5126,\n\t\t\t\"count\": 24,\n\t\t\t\"type\": \"VEC3\",\n\t\t\t\"max\": [1.0, 1.0, 1.0],\n\t\t\t\"min\": [0.0, 0.0, 0.0]\n\t\t}, {\n\t\t\t\"bufferView\": 2,\n\t\t\t\"byteOffset\": 0,\n\t\t\t\"componentType\": 5126,\n\t\t\t\"count\": 24,\n\t\t\t\"type\": \"VEC3\",\n\t\t\t\"max\": [1.0, 1.0, 0.0],\n\t\t\t\"min\": [-1.0, -1.0, -1.0]\n\t\t}\n\t],\n\t\"bufferViews\": [{\n\t\t\t\"buffer\": 0,\n\t\t\t\"byteLength\": 72,\n\t\t\t\"byteOffset\": 0,\n\t\t\t\"target\": 34963\n\t\t}, {\n\t\t\t\"buffer\": 0,\n\t\t\t\"byteLength\": 288,\n\t\t\t\"byteOffset\": 72,\n\t\t\t\"target\": 34962\n\t\t}, {\n\t\t\t\"buffer\": 0,\n\t\t\t\"byteLength\": 288,\n\t\t\t\"byteOffset\": 360,\n\t\t\t\"target\": 34962\n\t\t}\n\t],\n\t\"buffers\": [{\n\t\t\t\"byteLength\": 648\n\t\t}\n\t],\n\t\"materials\": [{\n\t\t\t\"pbrMetallicRoughness\": {\n\t\t\t\t\"baseColorFactor\": [0.5187909007072449, 0.5187909007072449, 0.5187909007072449, 1.0],\n\t\t\t\t\"metallicFactor\": 0.0,\n\t\t\t\t\"roughnessFactor\": 0.0\n\t\t\t},\n\t\t\t\"name\": \"DefaultMaterial\",\n\t\t\t\"extensions\": {\n\t\t\t\t\"KHR_materials_pbrSpecularGlossiness\": {\n\t\t\t\t\t\"diffuseFactor\": [0.49803921580314639, 0.49803921580314639, 0.49803921580314639, 1.0],\n\t\t\t\t\t\"specularFactor\": [0.0, 0.0, 0.0]\n\t\t\t\t}\n\t\t\t}\n\t\t}, {\n\t\t\t\"pbrMetallicRoughness\": {\n\t\t\t\t\"baseColorFactor\": [0.5187909007072449, 0.5187909007072449, 0.5187909007072449, 1.0],\n\t\t\t\t\"metallicFactor\": 0.0,\n\t\t\t\t\"roughnessFactor\": 0.0\n\t\t\t},\n\t\t\t\"name\": \"DefaultMaterial\",\n\t\t\t\"extensions\": {\n\t\t\t\t\"KHR_materials_pbrSpecularGlossiness\": {\n\t\t\t\t\t\"diffuseFactor\": [0.49803921580314639, 0.49803921580314639, 0.49803921580314639, 1.0],\n\t\t\t\t\t\"specularFactor\": [0.0, 0.0, 0.0]\n\t\t\t\t}\n\t\t\t}\n\t\t}, {\n\t\t\t\"pbrMetallicRoughness\": {\n\t\t\t\t\"baseColorFactor\": [0.5187909007072449, 0.5187909007072449, 0.5187909007072449, 1.0],\n\t\t\t\t\"metallicFactor\": 0.0,\n\t\t\t\t\"roughnessFactor\": 0.0\n\t\t\t},\n\t\t\t\"name\": \"DefaultMaterial\",\n\t\t\t\"extensions\": {\n\t\t\t\t\"KHR_materials_pbrSpecularGlossiness\": {\n\t\t\t\t\t\"diffuseFactor\": [0.49803921580314639, 0.49803921580314639, 0.49803921580314639, 1.0],\n\t\t\t\t\t\"specularFactor\": [0.0, 0.0, 0.0]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t],\n\t\"meshes\": [{\n\t\t\t\"name\": \"polygon\",\n\t\t\t\"primitives\": [{\n\t\t\t\t\t\"attributes\": {\n\t\t\t\t\t\t\"NORMAL\": 2,\n\t\t\t\t\t\t\"POSITION\": 1\n\t\t\t\t\t},\n\t\t\t\t\t\"indices\": 0,\n\t\t\t\t\t\"material\": 0,\n\t\t\t\t\t\"mode\": 4\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"nodes\": [{\n\t\t\t\"matrix\": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0],\n\t\t\t\"mesh\": 0,\n\t\t\t\"name\": \"polygon\"\n\t\t}, {\n\t\t\t\"children\": [0],\n\t\t\t\"matrix\": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0],\n\t\t\t\"name\": \"root\"\n\t\t}\n\t],\n\t\"scenes\": [{\n\t\t\t\"nodes\": [1]\n\t\t}\n\t],\n\t\"scene\": 0,\n\t\"extensionsUsed\": [\"KHR_materials_pbrSpecularGlossiness\"]\n}\n"
  },
  {
    "path": "glTF-Toolkit.Test/Resources/gltf/CubeWithLOD.gltf",
    "content": "{\n\t\"asset\": {\n\t\t\"version\": \"2.0\",\n\t\t\"generator\": \"Microsoft GLTF Exporter 2.1.2-b21\"\n\t},\n\t\"accessors\": [{\n\t\t\t\"bufferView\": 0,\n\t\t\t\"byteOffset\": 0,\n\t\t\t\"componentType\": 5123,\n\t\t\t\"count\": 36,\n\t\t\t\"type\": \"SCALAR\"\n\t\t}, {\n\t\t\t\"bufferView\": 1,\n\t\t\t\"byteOffset\": 0,\n\t\t\t\"componentType\": 5126,\n\t\t\t\"count\": 24,\n\t\t\t\"type\": \"VEC3\"\n\t\t}, {\n\t\t\t\"bufferView\": 2,\n\t\t\t\"byteOffset\": 0,\n\t\t\t\"componentType\": 5126,\n\t\t\t\"count\": 24,\n\t\t\t\"type\": \"VEC3\"\n\t\t}\n\t],\n\t\"bufferViews\": [{\n\t\t\t\"buffer\": 0,\n\t\t\t\"byteLength\": 72,\n\t\t\t\"byteOffset\": 0,\n\t\t\t\"target\": 34963\n\t\t}, {\n\t\t\t\"buffer\": 0,\n\t\t\t\"byteLength\": 288,\n\t\t\t\"byteOffset\": 72,\n\t\t\t\"target\": 34962\n\t\t}, {\n\t\t\t\"buffer\": 0,\n\t\t\t\"byteLength\": 288,\n\t\t\t\"byteOffset\": 360,\n\t\t\t\"target\": 34962\n\t\t}\n\t],\n\t\"buffers\": [{\n\t\t\t\"byteLength\": 648\n\t\t}\n\t],\n\t\"materials\": [{\n\t\t\t\"pbrMetallicRoughness\": {\n\t\t\t\t\"baseColorFactor\": [0.5187909007072449, 0.5187909007072449, 0.5187909007072449, 1.0],\n\t\t\t\t\"metallicFactor\": 0.0,\n\t\t\t\t\"roughnessFactor\": 0.0\n\t\t\t},\n\t\t\t\"name\": \"DefaultMaterial\",\n\t\t\t\"extensions\": {\n\t\t\t\t\"KHR_materials_pbrSpecularGlossiness\": {\n\t\t\t\t\t\"diffuseFactor\": [0.49803921580314639, 0.49803921580314639, 0.49803921580314639, 1.0],\n\t\t\t\t\t\"specularFactor\": [0.0, 0.0, 0.0]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t],\n\t\"meshes\": [{\n\t\t\t\"name\": \"polygon\",\n\t\t\t\"primitives\": [{\n\t\t\t\t\t\"attributes\": {\n\t\t\t\t\t\t\"NORMAL\": 2,\n\t\t\t\t\t\t\"POSITION\": 1\n\t\t\t\t\t},\n\t\t\t\t\t\"indices\": 0,\n\t\t\t\t\t\"material\": 0,\n\t\t\t\t\t\"mode\": 4\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"nodes\": [{\n\t\t\t\"mesh\": 0,\n\t\t\t\"name\": \"polygon\"\n\t\t}, {\n\t\t\t\"children\": [0],\n\t\t\t\"name\": \"root\",\n\t\t\t\"extensions\": {\n                \"MSFT_lod\": {\n                    \"ids\": [ 3 ]\n                }\n            }\n\t\t}, {\n\t\t\t\"mesh\": 0,\n\t\t\t\"name\": \"polygon_lod1\"\n\t\t}, {\n\t\t\t\"children\": [2],\n\t\t\t\"name\": \"root_lod1\"\n\t\t}\n\t],\n\t\"scenes\": [{\n\t\t\t\"nodes\": [1]\n\t\t}\n\t],\n\t\"scene\": 0,\n\t\"extensionsUsed\": [\"KHR_materials_pbrSpecularGlossiness\", \"MSFT_lod\"]\n}\n"
  },
  {
    "path": "glTF-Toolkit.Test/Resources/gltf/TextureTest/TextureTest.gltf",
    "content": "{\r\n  \"asset\" : {\r\n    \"version\" : \"2.0\"\r\n  },\r\n  \"textures\": [\r\n    {\r\n      \"sampler\": 0,\r\n      \"source\": 0\r\n    }\r\n  ],\r\n  \"images\": [\r\n    {\r\n      \"uri\": \"0.png\"\r\n    }\r\n  ]\r\n}"
  },
  {
    "path": "glTF-Toolkit.Test/Resources/gltf/WaterBottle/WaterBottle.gltf",
    "content": "{\n  \"accessors\": [\n    {\n      \"bufferView\": 0,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC2\"\n    },\n    {\n      \"bufferView\": 1,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC3\"\n    },\n    {\n      \"bufferView\": 2,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC4\"\n    },\n    {\n      \"bufferView\": 3,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC3\",\n      \"max\": [\n        0.05445001,\n        0.130220339,\n        0.0544500239\n      ],\n      \"min\": [\n        -0.05445001,\n        -0.130220339,\n        -0.0544500239\n      ]\n    },\n    {\n      \"bufferView\": 4,\n      \"componentType\": 5123,\n      \"count\": 13530,\n      \"type\": \"SCALAR\"\n    }\n  ],\n  \"asset\": {\n    \"generator\": \"glTF Tools for Unity\",\n    \"version\": \"2.0\"\n  },\n  \"bufferViews\": [\n    {\n      \"buffer\": 0,\n      \"byteLength\": 20392\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 20392,\n      \"byteLength\": 30588\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 50980,\n      \"byteLength\": 40784\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 91764,\n      \"byteLength\": 30588\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 122352,\n      \"byteLength\": 27060\n    }\n  ],\n  \"buffers\": [\n    {\n      \"uri\": \"WaterBottle.bin\",\n      \"byteLength\": 149412\n    }\n  ],\n  \"extensionsUsed\": [\n    \"KHR_materials_pbrSpecularGlossiness\"\n  ],\n  \"images\": [\n    {\n      \"uri\": \"WaterBottle_baseColor.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_roughnessMetallic.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_normal.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_emissive.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_occlusion.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_diffuse.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_specularGlossiness.png\"\n    }\n  ],\n  \"meshes\": [\n    {\n      \"primitives\": [\n        {\n          \"attributes\": {\n            \"TEXCOORD_0\": 0,\n            \"NORMAL\": 1,\n            \"TANGENT\": 2,\n            \"POSITION\": 3\n          },\n          \"indices\": 4,\n          \"material\": 0\n        }\n      ],\n      \"name\": \"WaterBottle\"\n    }\n  ],\n  \"materials\": [\n    {\n      \"pbrMetallicRoughness\": {\n        \"baseColorTexture\": {\n          \"index\": 0\n        },\n        \"metallicRoughnessTexture\": {\n          \"index\": 1\n        }\n      },\n      \"normalTexture\": {\n        \"index\": 2\n      },\n      \"occlusionTexture\": {\n        \"index\": 4\n      },\n      \"emissiveFactor\": [\n        1.0,\n        1.0,\n        1.0\n      ],\n      \"emissiveTexture\": {\n        \"index\": 3\n      },\n      \"name\": \"BottleMat\",\n      \"extensions\": {\n        \"KHR_materials_pbrSpecularGlossiness\": {\n          \"diffuseTexture\": {\n            \"index\": 5\n          },\n          \"specularGlossinessTexture\": {\n            \"index\": 6\n          }\n        }\n      }\n    }\n  ],\n  \"nodes\": [\n    {\n      \"mesh\": 0,\n      \"name\": \"WaterBottle\"\n    }\n  ],\n  \"scene\": 0,\n  \"scenes\": [\n    {\n      \"nodes\": [\n        0\n      ]\n    }\n  ],\n  \"textures\": [\n    {\n      \"source\": 0\n    },\n    {\n      \"source\": 1\n    },\n    {\n      \"source\": 2\n    },\n    {\n      \"source\": 3\n    },\n    {\n      \"source\": 4\n    },\n    {\n      \"source\": 5\n    },\n    {\n      \"source\": 6\n    }\n  ]\n}"
  },
  {
    "path": "glTF-Toolkit.Test/Resources/gltf/WaterBottle_ORM/WaterBottle.gltf",
    "content": "{\n  \"accessors\": [\n    {\n      \"bufferView\": 0,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC2\"\n    },\n    {\n      \"bufferView\": 1,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC3\"\n    },\n    {\n      \"bufferView\": 2,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC4\"\n    },\n    {\n      \"bufferView\": 3,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC3\",\n      \"max\": [\n        0.05445001,\n        0.130220339,\n        0.0544500239\n      ],\n      \"min\": [\n        -0.05445001,\n        -0.130220339,\n        -0.0544500239\n      ]\n    },\n    {\n      \"bufferView\": 4,\n      \"componentType\": 5123,\n      \"count\": 13530,\n      \"type\": \"SCALAR\"\n    }\n  ],\n  \"asset\": {\n    \"generator\": \"glTF Tools for Unity\",\n    \"version\": \"2.0\"\n  },\n  \"bufferViews\": [\n    {\n      \"buffer\": 0,\n      \"byteLength\": 20392\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 20392,\n      \"byteLength\": 30588\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 50980,\n      \"byteLength\": 40784\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 91764,\n      \"byteLength\": 30588\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 122352,\n      \"byteLength\": 27060\n    }\n  ],\n  \"buffers\": [\n    {\n      \"uri\": \"WaterBottle.bin\",\n      \"byteLength\": 149412\n    }\n  ],\n  \"extensionsUsed\": [\n    \"KHR_materials_pbrSpecularGlossiness\",\n    \"MSFT_packing_occlusionRoughnessMetallic\"\n  ],\n  \"images\": [\n    {\n      \"uri\": \"WaterBottle_baseColor.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_roughnessMetallic.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_normal.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_emissive.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_occlusion.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_diffuse.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_specularGlossiness.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_occlusionRoughnessMetallic.png\"\n    }\n  ],\n  \"meshes\": [\n    {\n      \"primitives\": [\n        {\n          \"attributes\": {\n            \"TEXCOORD_0\": 0,\n            \"NORMAL\": 1,\n            \"TANGENT\": 2,\n            \"POSITION\": 3\n          },\n          \"indices\": 4,\n          \"material\": 0\n        }\n      ],\n      \"name\": \"WaterBottle\"\n    }\n  ],\n  \"materials\": [\n    {\n      \"pbrMetallicRoughness\": {\n        \"baseColorTexture\": {\n          \"index\": 0\n        },\n        \"metallicRoughnessTexture\": {\n          \"index\": 1\n        }\n      },\n      \"normalTexture\": {\n        \"index\": 2\n      },\n      \"occlusionTexture\": {\n        \"index\": 4\n      },\n      \"emissiveFactor\": [\n        1.0,\n        1.0,\n        1.0\n      ],\n      \"emissiveTexture\": {\n        \"index\": 3\n      },\n      \"name\": \"BottleMat\",\n      \"extensions\": {\n        \"KHR_materials_pbrSpecularGlossiness\": {\n          \"diffuseTexture\": {\n            \"index\": 5\n          },\n          \"specularGlossinessTexture\": {\n            \"index\": 6\n          }\n        },\n        \"MSFT_packing_occlusionRoughnessMetallic\": {\n          \"occlusionRoughnessMetallicTexture\": {\n            \"index\": 7\n          },\n          \"normalTexture\": {\n            \"index\": 2\n          }\n        }\n      }\n    }\n  ],\n  \"nodes\": [\n    {\n      \"mesh\": 0,\n      \"name\": \"WaterBottle\"\n    }\n  ],\n  \"scene\": 0,\n  \"scenes\": [\n    {\n      \"nodes\": [\n        0\n      ]\n    }\n  ],\n  \"textures\": [\n    {\n      \"source\": 0\n    },\n    {\n      \"source\": 1\n    },\n    {\n      \"source\": 2\n    },\n    {\n      \"source\": 3\n    },\n    {\n      \"source\": 4\n    },\n    {\n      \"source\": 5\n    },\n    {\n      \"source\": 6\n    },\n    {\n      \"source\": 7\n    }\n  ]\n}"
  },
  {
    "path": "glTF-Toolkit.Test/Resources/gltf/WaterBottle_ORM/WaterBottle_WindowsMR.gltf",
    "content": "{\n  \"accessors\": [\n    {\n      \"bufferView\": 0,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC2\"\n    },\n    {\n      \"bufferView\": 1,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC3\"\n    },\n    {\n      \"bufferView\": 2,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC4\"\n    },\n    {\n      \"bufferView\": 3,\n      \"componentType\": 5126,\n      \"count\": 2549,\n      \"type\": \"VEC3\",\n      \"max\": [\n        0.05445001,\n        0.130220339,\n        0.0544500239\n      ],\n      \"min\": [\n        -0.05445001,\n        -0.130220339,\n        -0.0544500239\n      ]\n    },\n    {\n      \"bufferView\": 4,\n      \"componentType\": 5123,\n      \"count\": 13530,\n      \"type\": \"SCALAR\"\n    }\n  ],\n  \"asset\": {\n    \"generator\": \"glTF Tools for Unity\",\n    \"version\": \"2.0\"\n  },\n  \"bufferViews\": [\n    {\n      \"buffer\": 0,\n      \"byteLength\": 20392\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 20392,\n      \"byteLength\": 30588\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 50980,\n      \"byteLength\": 40784\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 91764,\n      \"byteLength\": 30588\n    },\n    {\n      \"buffer\": 0,\n      \"byteOffset\": 122352,\n      \"byteLength\": 27060\n    }\n  ],\n  \"buffers\": [\n    {\n      \"uri\": \"WaterBottle.bin\",\n      \"byteLength\": 149412\n    }\n  ],\n  \"extensionsUsed\": [\n    \"KHR_materials_pbrSpecularGlossiness\",\n    \"MSFT_packing_occlusionRoughnessMetallic\",\n    \"MSFT_texture_dds\"\n  ],\n  \"images\": [\n    {\n      \"uri\": \"WaterBottle_baseColor.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_roughnessMetallic.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_normal.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_emissive.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_occlusion.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_diffuse.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_specularGlossiness.png\"\n    },\n    {\n      \"uri\": \"WaterBottle_occlusionRoughnessMetallic.png\"\n    },\n    {\n      \"mimeType\": \"image/vnd-ms.dds\",\n      \"uri\": \"WaterBottle_occlusionRoughnessMetallic.dds\"\n    },\n    {\n      \"mimeType\": \"image/vnd-ms.dds\",\n      \"uri\": \"WaterBottle_normal.dds\"\n    },\n    {\n      \"mimeType\": \"image/vnd-ms.dds\",\n      \"uri\": \"WaterBottle_baseColor.dds\"\n    },\n    {\n      \"mimeType\": \"image/vnd-ms.dds\",\n      \"uri\": \"WaterBottle_emissive.dds\"\n    }\n  ],\n  \"meshes\": [\n    {\n      \"primitives\": [\n        {\n          \"attributes\": {\n            \"TEXCOORD_0\": 0,\n            \"NORMAL\": 1,\n            \"TANGENT\": 2,\n            \"POSITION\": 3\n          },\n          \"indices\": 4,\n          \"material\": 0\n        }\n      ],\n      \"name\": \"WaterBottle\"\n    }\n  ],\n  \"materials\": [\n    {\n      \"pbrMetallicRoughness\": {\n        \"baseColorTexture\": {\n          \"index\": 0\n        },\n        \"metallicRoughnessTexture\": {\n          \"index\": 1\n        }\n      },\n      \"normalTexture\": {\n        \"index\": 2\n      },\n      \"occlusionTexture\": {\n        \"index\": 4\n      },\n      \"emissiveFactor\": [\n        1.0,\n        1.0,\n        1.0\n      ],\n      \"emissiveTexture\": {\n        \"index\": 3\n      },\n      \"name\": \"BottleMat\",\n      \"extensions\": {\n        \"KHR_materials_pbrSpecularGlossiness\": {\n          \"diffuseTexture\": {\n            \"index\": 5\n          },\n          \"specularGlossinessTexture\": {\n            \"index\": 6\n          }\n        },\n        \"MSFT_packing_occlusionRoughnessMetallic\": {\n          \"occlusionRoughnessMetallicTexture\": {\n            \"index\": 8\n          },\n          \"normalTexture\": {\n            \"index\": 2\n          }\n        }\n      }\n    }\n  ],\n  \"nodes\": [\n    {\n      \"mesh\": 0,\n      \"name\": \"WaterBottle\"\n    }\n  ],\n  \"scene\": 0,\n  \"scenes\": [\n    {\n      \"nodes\": [\n        0\n      ]\n    }\n  ],\n  \"textures\": [\n    {\n      \"source\": 0,\n      \"extensions\": {\n        \"MSFT_texture_dds\": {\n          \"source\": 10\n        }\n      }\n    },\n    {\n      \"source\": 1\n    },\n    {\n      \"source\": 2,\n      \"extensions\": {\n        \"MSFT_texture_dds\": {\n          \"source\": 9\n        }\n      }\n    },\n    {\n      \"source\": 3,\n      \"extensions\": {\n        \"MSFT_texture_dds\": {\n          \"source\": 11\n        }\n      }\n    },\n    {\n      \"source\": 4\n    },\n    {\n      \"source\": 5\n    },\n    {\n      \"source\": 6\n    },\n    {\n      \"source\": 7\n    },\n    {\n      \"source\": 8,\n      \"extensions\": {\n        \"MSFT_texture_dds\": {\n          \"source\": 8\n        }\n      }\n    }\n  ]\n}"
  },
  {
    "path": "glTF-Toolkit.Test/glTF-Toolkit.Test.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"..\\glTF-Toolkit\\src\\pch.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"GLBSerializerTests.cpp\" />\r\n    <ClCompile Include=\"GLBtoGLTFTests.cpp\" />\r\n    <ClCompile Include=\"GLTFLODUtilsTests.cpp\" />\r\n    <ClCompile Include=\"GLTFTextureCompressionUtilsTests.cpp\" />\r\n    <ClCompile Include=\"GLTFTexturePackingUtilsTests.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"packages.config\" />\r\n    <None Include=\"Resources\\gltf\\CubeAsset3D.gltf\" />\r\n    <None Include=\"Resources\\gltf\\CubeWithLOD.gltf\" />\r\n    <None Include=\"Resources\\gltf\\TextureTest\\TextureTest.gltf\" />\r\n    <None Include=\"Resources\\gltf\\WaterBottle\\WaterBottle.bin\" />\r\n    <None Include=\"Resources\\gltf\\WaterBottle\\WaterBottle.gltf\" />\r\n    <None Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle.bin\" />\r\n    <None Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle.gltf\" />\r\n    <None Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_WindowsMR.gltf\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Image Include=\"Resources\\gltf\\TextureTest\\0.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_baseColor.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_diffuse.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_emissive.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_normal.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_occlusion.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_roughnessMetallic.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_specularGlossiness.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_baseColor.DDS\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_baseColor.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_diffuse.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_emissive.DDS\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_emissive.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_normal.dds\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_normal.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_occlusion.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_occlusionRoughnessMetallic.dds\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_occlusionRoughnessMetallic.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_roughnessMetallic.png\" />\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_specularGlossiness.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"Helpers\\StreamMock.h\" />\r\n    <ClInclude Include=\"Helpers\\TestUtils.h\" />\r\n    <ClInclude Include=\"Helpers\\WStringUtils.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\glTF-Toolkit\\glTF-Toolkit.vcxproj\">\r\n      <Project>{ff0275f1-58cb-4745-ba81-f6c1df66e206}</Project>\r\n    </ProjectReference>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <VCProjectVersion>15.0</VCProjectVersion>\r\n    <ProjectGuid>{B2AF77B5-8433-46AD-860D-23A4831F6830}</ProjectGuid>\r\n    <Keyword>Win32Proj</Keyword>\r\n    <RootNamespace>glTFToolkitTest</RootNamespace>\r\n    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>\r\n    <ProjectSubType>NativeUnitTestProject</ProjectSubType>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <UseOfMfc>false</UseOfMfc>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <UseOfMfc>false</UseOfMfc>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <UseOfMfc>false</UseOfMfc>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <UseOfMfc>false</UseOfMfc>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\" />\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc;$(VCInstallDir)UnitTest\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <UseFullPaths>true</UseFullPaths>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <AdditionalDependencies>d3d11.lib;dxgi.lib;pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc;$(VCInstallDir)UnitTest\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <UseFullPaths>true</UseFullPaths>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <AdditionalDependencies>d3d11.lib;dxgi.lib;pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc;$(VCInstallDir)UnitTest\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <UseFullPaths>true</UseFullPaths>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <AdditionalDependencies>d3d11.lib;dxgi.lib;pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc;$(VCInstallDir)UnitTest\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <UseFullPaths>true</UseFullPaths>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <AdditionalDependencies>d3d11.lib;dxgi.lib;pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n    <Import Project=\"$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets\" Condition=\"Exists('$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets')\" />\r\n  </ImportGroup>\r\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\r\n    <PropertyGroup>\r\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>\r\n    </PropertyGroup>\r\n    <Error Condition=\"!Exists('$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\directxtex_desktop_2015.2018.8.5.1\\build\\native\\directxtex_desktop_2015.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets'))\" />\r\n  </Target>\r\n</Project>"
  },
  {
    "path": "glTF-Toolkit.Test/glTF-Toolkit.Test.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <ClCompile Include=\"GLBSerializerTests.cpp\" />\r\n    <ClCompile Include=\"GLTFLODUtilsTests.cpp\" />\r\n    <ClCompile Include=\"GLTFTextureCompressionUtilsTests.cpp\" />\r\n    <ClCompile Include=\"GLTFTexturePackingUtilsTests.cpp\" />\r\n    <ClCompile Include=\"..\\glTF-Toolkit\\src\\pch.cpp\" />\r\n    <ClCompile Include=\"GLBtoGLTFTests.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Filter Include=\"Helpers\">\r\n      <UniqueIdentifier>{7294793d-6c71-438a-828f-68361c3db329}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Resources\">\r\n      <UniqueIdentifier>{53c10f0a-e8fc-42e4-b612-17631dcd7755}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Resources\\WaterBottle\">\r\n      <UniqueIdentifier>{29129a4d-ff37-427e-9047-6d1044de85b0}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Resources\\WaterBottle_ORM\">\r\n      <UniqueIdentifier>{c7fc3736-b68e-4f6d-b93b-1bb4eda5b1ff}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Resources\\TextureTest\">\r\n      <UniqueIdentifier>{e4d4222d-e5af-4dad-b539-28e2dc1c716a}</UniqueIdentifier>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"Resources\\gltf\\CubeAsset3D.gltf\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"Resources\\gltf\\CubeWithLOD.gltf\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"packages.config\" />\r\n    <None Include=\"Resources\\gltf\\WaterBottle\\WaterBottle.bin\">\r\n      <Filter>Resources\\WaterBottle</Filter>\r\n    </None>\r\n    <None Include=\"Resources\\gltf\\WaterBottle\\WaterBottle.gltf\">\r\n      <Filter>Resources\\WaterBottle</Filter>\r\n    </None>\r\n    <None Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle.bin\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </None>\r\n    <None Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle.gltf\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </None>\r\n    <None Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_WindowsMR.gltf\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </None>\r\n    <None Include=\"Resources\\gltf\\TextureTest\\TextureTest.gltf\">\r\n      <Filter>Resources\\TextureTest</Filter>\r\n    </None>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_baseColor.png\">\r\n      <Filter>Resources\\WaterBottle</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_diffuse.png\">\r\n      <Filter>Resources\\WaterBottle</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_emissive.png\">\r\n      <Filter>Resources\\WaterBottle</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_normal.png\">\r\n      <Filter>Resources\\WaterBottle</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_occlusion.png\">\r\n      <Filter>Resources\\WaterBottle</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_roughnessMetallic.png\">\r\n      <Filter>Resources\\WaterBottle</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle\\WaterBottle_specularGlossiness.png\">\r\n      <Filter>Resources\\WaterBottle</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_baseColor.DDS\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_baseColor.png\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_diffuse.png\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_emissive.DDS\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_emissive.png\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_normal.dds\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_normal.png\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_occlusion.png\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_occlusionRoughnessMetallic.dds\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_occlusionRoughnessMetallic.png\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_roughnessMetallic.png\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\WaterBottle_ORM\\WaterBottle_specularGlossiness.png\">\r\n      <Filter>Resources\\WaterBottle_ORM</Filter>\r\n    </Image>\r\n    <Image Include=\"Resources\\gltf\\TextureTest\\0.png\">\r\n      <Filter>Resources\\TextureTest</Filter>\r\n    </Image>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"Helpers\\TestUtils.h\">\r\n      <Filter>Helpers</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"Helpers\\StreamMock.h\">\r\n      <Filter>Helpers</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"Helpers\\WStringUtils.h\">\r\n      <Filter>Helpers</Filter>\r\n    </ClInclude>\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "glTF-Toolkit.Test/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<packages>\r\n  <package id=\"directxtex_desktop_2015\" version=\"2018.8.5.1\" targetFramework=\"native\" />\r\n  <package id=\"draco.CPP\" version=\"1.3.3.1\" targetFramework=\"native\" />\r\n  <package id=\"Microsoft.glTF.CPP\" version=\"1.6.1.0\" targetFramework=\"native\" />\r\n  <package id=\"rapidjson.temprelease\" version=\"0.0.2.20\" targetFramework=\"native\" />\r\n</packages>"
  },
  {
    "path": "glTF-Toolkit.UWP/GLTFSerialization.cpp",
    "content": "﻿// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n#include \"GLTFSerialization.h\"\r\n#include \"GLTFStreams.h\"\r\n\r\n#include <GLBtoGLTF.h>\r\n#include <SerializeBinary.h>\r\n\r\n#include <GLTFSDK/Document.h>\r\n\r\nusing namespace Concurrency;\r\nusing namespace Microsoft::glTF;\r\nusing namespace Microsoft::glTF::Toolkit;\r\nusing namespace Microsoft::glTF::Toolkit::UWP;\r\nusing namespace Platform;\r\nusing namespace Windows::Foundation;\r\nusing namespace Windows::Storage;\r\n\r\nIAsyncOperation<StorageFile^>^ GLTFSerialization::UnpackGLBAsync(StorageFile^ glbFile, StorageFolder^ outputFolder)\r\n{\r\n    String^ glbFilePath = glbFile->Path;\r\n    std::wstring glbPathW = glbFilePath->Data();\r\n    std::string glbPathA = std::string(glbPathW.begin(), glbPathW.end());\r\n\r\n    String^ outputFolderPath = outputFolder->Path + \"\\\\\";\r\n    std::wstring outputFolderPathW = outputFolderPath->Data();\r\n    std::string outputFolderPathA = std::string(outputFolderPathW.begin(), outputFolderPathW.end());\r\n\r\n    String^ baseFileName = glbFile->DisplayName;\r\n    std::wstring baseFileNameW = baseFileName->Data();\r\n    std::string baseFileNameA = std::string(baseFileNameW.begin(), baseFileNameW.end());\r\n\r\n    return create_async([glbPathA, outputFolderPathA, baseFileNameA, outputFolder, baseFileNameW]\r\n    {\r\n        GLBToGLTF::UnpackGLB(glbPathA, outputFolderPathA, baseFileNameA);\r\n\r\n        return outputFolder->GetFileAsync(ref new String((baseFileNameW + L\".gltf\").c_str()));\r\n    });\r\n}\r\n\r\nIAsyncOperation<StorageFile^>^ GLTFSerialization::PackGLTFAsync(StorageFile^ sourceGltf, StorageFolder^ outputFolder, String^ glbName)\r\n{\r\n    return create_async([sourceGltf, outputFolder, glbName]() \r\n    {\r\n        std::wstring gltfPathW = sourceGltf->Path->Data();\r\n\r\n        auto stream = std::make_shared<std::ifstream>(gltfPathW, std::ios::in);\r\n\r\n        return create_task([stream]()\r\n        {\r\n            return std::make_shared<Document>(Deserialize(*stream));\r\n        })\r\n        .then([sourceGltf, outputFolder, glbName](std::shared_ptr<Document> document)\r\n        {\r\n            return create_task(sourceGltf->GetParentAsync())\r\n            .then([outputFolder, glbName, document](StorageFolder^ gltfFolder)\r\n            { \r\n                auto streamReader = std::make_shared<GLTFStreamReader>(gltfFolder);\r\n\r\n                String^ outputGlbPath = outputFolder->Path + \"\\\\\" + glbName;\r\n                std::wstring outputGlbPathW = outputGlbPath->Data();\r\n                SerializeBinary(*document, streamReader, std::make_shared<GLBStreamWriter>(outputGlbPathW));\r\n\r\n                return outputFolder->GetFileAsync(glbName);\r\n            });\r\n        });\r\n    });\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit.UWP/GLTFSerialization.h",
    "content": "﻿// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\nnamespace Microsoft::glTF::Toolkit::UWP\r\n{\r\n    public ref class GLTFSerialization sealed\r\n    {\r\n    public:\r\n        /// <summary>\r\n        /// Unpacks a GLB asset into a GLTF manifest and its \r\n        /// resources (bin files and images).\r\n        /// </summary>\r\n        /// <param name=\"glbFile\">The GLB file to unpack. The name of the GLB file, without the extension, \r\n        /// will be used as a prefix to all unpacked resources.</param>\r\n        /// <param name=\"outputFolder\">The output folder to which the glTF manifest and resources will be unpacked.</param>\r\n        static Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ UnpackGLBAsync(Windows::Storage::StorageFile^ glbFile, Windows::Storage::StorageFolder^ outputFolder);\r\n\r\n        /// <summary>\r\n        /// Serializes a glTF asset as a glTF binary (GLB) file.\r\n        /// </summary>\r\n        /// <param name=\"sourceGltf\">The glTF file to be serialized.</param>\r\n        /// <param name=\"outputFolder\">The output folder where you want the glb file to be placed.</param>\r\n        /// <param name=\"glbName\">The glb filename.</param>\r\n        /// <returns>\r\n        /// The resulting GLB file, named with glbName and located in outputFolder.\r\n        /// </returns>\r\n        static Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ PackGLTFAsync(Windows::Storage::StorageFile^ sourceGltf, Windows::Storage::StorageFolder^ outputFolder, Platform::String^ glbName);\r\n    };\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit.UWP/GLTFStreams.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n#include <filesystem>\r\n#include <GLTFSDK/IStreamReader.h>\r\n#include <GLTFSDK/IStreamWriter.h>\r\n\r\nnamespace Microsoft::glTF::Toolkit::UWP\r\n{\r\n    class GLTFStreamReader : public IStreamReader\r\n    {\r\n    public:\r\n        GLTFStreamReader(Windows::Storage::StorageFolder^ gltfFolder) \r\n        {\r\n            m_uriBase = std::experimental::filesystem::path(gltfFolder->Path->Data());\r\n        }\r\n\r\n        virtual ~GLTFStreamReader() override {}\r\n        virtual std::shared_ptr<std::istream> GetInputStream(const std::string& filename) const override\r\n        {\r\n            std::wstring filenameW(filename.begin(), filename.end());\r\n            std::experimental::filesystem::path path(filenameW);\r\n\r\n            auto absolutePath = path.wstring();\r\n\r\n            if (path.is_relative())\r\n            {\r\n                absolutePath = (m_uriBase / path).wstring();\r\n            }\r\n\r\n            return std::make_shared<std::ifstream>(absolutePath, std::ios::binary);\r\n        }\r\n    private:\r\n        std::experimental::filesystem::path m_uriBase;\r\n    };\r\n\r\n    class GLBStreamWriter : public Microsoft::glTF::IStreamWriter\r\n    {\r\n    public:\r\n        GLBStreamWriter(const std::wstring& filename) :\r\n            m_stream(std::make_shared<std::ofstream>(filename, std::ios_base::binary | std::ios_base::out))\r\n        { }\r\n\r\n        std::shared_ptr<std::ostream> GetOutputStream(const std::string&) const override\r\n        {\r\n            return m_stream;\r\n        }\r\n\r\n    private:\r\n        std::shared_ptr<std::ofstream> m_stream;\r\n    };\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit.UWP/WindowsMRConversion.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n#include \"WindowsMRConversion.h\"\r\n#include \"GLTFSerialization.h\"\r\n#include \"GLTFStreams.h\"\r\n\r\n#include <ppltasks.h>\r\n#include <GLTFTexturePackingUtils.h>\r\n#include <GLTFTextureCompressionUtils.h>\r\n#include <GLTFMeshCompressionUtils.h>\r\n#include <GLTFSpecularGlossinessUtils.h>\r\n#include <SerializeBinary.h>\r\n#include <GLBtoGLTF.h>\r\n#include <GLTFTextureUtils.h>\r\n\r\n#include <GLTFSDK/Document.h>\r\n#include <GLTFSDK/IStreamReader.h>\r\n#include <GLTFSDK/IStreamWriter.h>\r\n#include <GLTFSDK/ExtensionsKHR.h>\r\n\r\nusing namespace concurrency;\r\nusing namespace Platform;\r\nusing namespace Windows::Foundation;\r\nusing namespace Windows::Foundation::Metadata;\r\nusing namespace Windows::Storage;\r\nusing namespace Windows::System::Profile;\r\n\r\nusing namespace Microsoft::glTF::Toolkit::UWP;\r\n\r\nIAsyncOperation<StorageFile^>^ WindowsMRConversion::ConvertAssetForWindowsMR(StorageFile^ gltfOrGlbFile, StorageFolder^ outputFolder)\r\n{\r\n    return ConvertAssetForWindowsMR(gltfOrGlbFile, outputFolder, 512);\r\n}\r\n\r\nIAsyncOperation<StorageFile^>^ WindowsMRConversion::ConvertAssetForWindowsMR(StorageFile^ gltfOrGlbFile, StorageFolder^ outputFolder, size_t maxTextureSize)\r\n{\r\n    UWP::TexturePacking detectedPacking = UWP::TexturePacking::None;\r\n\r\n    if (AnalyticsInfo::VersionInfo->DeviceFamily == \"Windows.Holographic\")\r\n    {\r\n        detectedPacking = UWP::TexturePacking::NormalRoughnessMetallic;\r\n    }\r\n    else\r\n    {\r\n        bool isVersion1803OrNewer = ApiInformation::IsApiContractPresent(\"Windows.Foundation.UniversalApiContract\", 6);\r\n        detectedPacking = isVersion1803OrNewer ? UWP::TexturePacking::OcclusionRoughnessMetallic : UWP::TexturePacking::RoughnessMetallicOcclusion;\r\n    }\r\n\r\n    return ConvertAssetForWindowsMR(gltfOrGlbFile, outputFolder, maxTextureSize, detectedPacking);\r\n}\r\n\r\nIAsyncOperation<StorageFile^>^ WindowsMRConversion::ConvertAssetForWindowsMR(StorageFile ^ gltfOrGlbFile, StorageFolder ^ outputFolder, size_t maxTextureSize, TexturePacking packing)\r\n{\r\n    return ConvertAssetForWindowsMR(gltfOrGlbFile, outputFolder, maxTextureSize, packing, false);\r\n}\r\n\r\nIAsyncOperation<StorageFile^>^ WindowsMRConversion::ConvertAssetForWindowsMR(StorageFile ^ gltfOrGlbFile, StorageFolder ^ outputFolder, size_t maxTextureSize, TexturePacking packing, bool meshCompression)\r\n{\r\n    auto isGlb = gltfOrGlbFile->FileType == L\".glb\";\r\n\r\n    return create_async([gltfOrGlbFile, maxTextureSize, outputFolder, isGlb, packing, meshCompression]()\r\n    {\r\n        return create_task([gltfOrGlbFile, isGlb]()\r\n        {\r\n            if (isGlb)\r\n            {\r\n                return create_task(GLTFSerialization::UnpackGLBAsync(gltfOrGlbFile, ApplicationData::Current->TemporaryFolder));\r\n            }\r\n            else\r\n            {\r\n                return task_from_result<StorageFile^>(gltfOrGlbFile);\r\n            }\r\n        })\r\n        .then([maxTextureSize, outputFolder, isGlb, packing, meshCompression](StorageFile^ gltfFile)\r\n        {\r\n            auto stream = std::make_shared<std::ifstream>(gltfFile->Path->Data(), std::ios::in);\r\n            Document document = Deserialize(*stream, KHR::GetKHRExtensionDeserializer());\r\n\r\n            return create_task(gltfFile->GetParentAsync())\r\n            .then([document, maxTextureSize, outputFolder, gltfFile, isGlb, packing, meshCompression](StorageFolder^ baseFolder)\r\n            {\r\n                auto streamReader = std::make_shared<GLTFStreamReader>(baseFolder);\r\n                auto tempDirectory = std::wstring(ApplicationData::Current->TemporaryFolder->Path->Data());\r\n                auto tempDirectoryA = std::string(tempDirectory.begin(), tempDirectory.end());\r\n\r\n                // 0. Specular Glossiness conversion\r\n                auto convertedDoc = GLTFSpecularGlossinessUtils::ConvertMaterials(streamReader, document, tempDirectoryA);\r\n\r\n                // 1. Remove redundant textures and images\r\n                convertedDoc = GLTFTextureUtils::RemoveRedundantTexturesAndImages(convertedDoc);\r\n\r\n                // 2. Texture Packing\r\n                convertedDoc = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(streamReader, convertedDoc, static_cast<Toolkit::TexturePacking>(packing), tempDirectoryA);\r\n\r\n                // 3. Texture Compression\r\n                convertedDoc = GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(streamReader, convertedDoc, tempDirectoryA, maxTextureSize, false /* retainOriginalImages */);\r\n\r\n                // 4. Make sure there's a default scene set\r\n                if (!convertedDoc.HasDefaultScene())\r\n                {\r\n                    convertedDoc.defaultSceneId = convertedDoc.scenes.Elements()[0].id;\r\n                }\r\n\r\n                // 5. Compress the meshes\r\n                if (meshCompression)\r\n                {\r\n                    convertedDoc = GLTFMeshCompressionUtils::CompressMeshes(streamReader, convertedDoc, {}, tempDirectoryA);\r\n                }\r\n\r\n                // 6. GLB Export\r\n\r\n                // The Windows MR Fall Creators update has restrictions on the supported\r\n                // component types of accessors.\r\n                AccessorConversionStrategy accessorConversion = [](const Accessor& accessor)\r\n                {\r\n                    if (accessor.type == AccessorType::TYPE_SCALAR)\r\n                    {\r\n                        switch (accessor.componentType)\r\n                        {\r\n                        case ComponentType::COMPONENT_BYTE:\r\n                        case ComponentType::COMPONENT_UNSIGNED_BYTE:\r\n                        case ComponentType::COMPONENT_SHORT:\r\n                            return ComponentType::COMPONENT_UNSIGNED_SHORT;\r\n                        default:\r\n                            return accessor.componentType;\r\n                        }\r\n                    }\r\n                    else if (accessor.type == AccessorType::TYPE_VEC2 || accessor.type == AccessorType::TYPE_VEC3)\r\n                    {\r\n                        return ComponentType::COMPONENT_FLOAT;\r\n                    }\r\n\r\n                    return accessor.componentType;\r\n                };\r\n\r\n                auto glbName = std::wstring(gltfFile->Name->Data());\r\n                glbName = glbName.substr(0, glbName.rfind(gltfFile->FileType->Data()));\r\n\r\n                if (isGlb)\r\n                {\r\n                    glbName += L\"_converted\";\r\n                }\r\n\r\n                glbName += L\".glb\";\r\n\r\n                std::wstring outputGlbPathW = std::wstring(outputFolder->Path->Data()) + L\"\\\\\" + glbName;\r\n                SerializeBinary(convertedDoc, streamReader, std::make_shared<GLBStreamWriter>(outputGlbPathW), accessorConversion);\r\n\r\n                return create_task(outputFolder->GetFileAsync(ref new String(glbName.c_str())));\r\n            });\r\n        });\r\n    });\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit.UWP/WindowsMRConversion.h",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n#include <GLTFTexturePackingUtils.h>\r\n\r\nnamespace Microsoft::glTF::Toolkit::UWP\r\n{\r\n    [Platform::Metadata::Flags]\r\n    public enum class TexturePacking : unsigned int\r\n    {\r\n        None = Toolkit::TexturePacking::None,\r\n        OcclusionRoughnessMetallic = Toolkit::TexturePacking::OcclusionRoughnessMetallic,\r\n        RoughnessMetallicOcclusion = Toolkit::TexturePacking::RoughnessMetallicOcclusion,\r\n        NormalRoughnessMetallic = Toolkit::TexturePacking::NormalRoughnessMetallic\r\n    };\r\n\r\n    public ref class WindowsMRConversion sealed\r\n    {\r\n    public:\r\n        static Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ ConvertAssetForWindowsMR(Windows::Storage::StorageFile^ gltfOrGlbFile, Windows::Storage::StorageFolder^ outputFolder);\r\n        static Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ ConvertAssetForWindowsMR(Windows::Storage::StorageFile^ gltfOrGlbFile, Windows::Storage::StorageFolder^ outputFolder, size_t maxTextureSize);\r\n        static Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ ConvertAssetForWindowsMR(Windows::Storage::StorageFile^ gltfOrGlbFile, Windows::Storage::StorageFolder^ outputFolder, size_t maxTextureSize, UWP::TexturePacking packing);\r\n        static Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ ConvertAssetForWindowsMR(Windows::Storage::StorageFile^ gltfOrGlbFile, Windows::Storage::StorageFolder^ outputFolder, size_t maxTextureSize, UWP::TexturePacking packing, bool meshCompression);\r\n    };\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit.UWP/glTF-Toolkit.UWP.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|ARM\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>ARM</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|ARM\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>ARM</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <ProjectGuid>{697462fb-c8e9-4ea5-a499-033df330e212}</ProjectGuid>\r\n    <Keyword>WindowsRuntimeComponent</Keyword>\r\n    <RootNamespace>Microsoft.glTF.Toolkit.UWP</RootNamespace>\r\n    <DefaultLanguage>en-US</DefaultLanguage>\r\n    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>\r\n    <AppContainerApplication>true</AppContainerApplication>\r\n    <ApplicationType>Windows Store</ApplicationType>\r\n    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>\r\n    <WindowsTargetPlatformMinVersion>10.0.16299.0</WindowsTargetPlatformMinVersion>\r\n    <ApplicationTypeRevision>10.0</ApplicationTypeRevision>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <PlatformToolset>v141</PlatformToolset>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <GenerateManifest>false</GenerateManifest>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n    <TargetName>$(RootNamespace)</TargetName>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <GenerateManifest>false</GenerateManifest>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n    <TargetName>$(RootNamespace)</TargetName>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <GenerateManifest>false</GenerateManifest>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n    <TargetName>$(RootNamespace)</TargetName>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\">\r\n    <GenerateManifest>false</GenerateManifest>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n    <TargetName>$(RootNamespace)</TargetName>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <GenerateManifest>false</GenerateManifest>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n    <TargetName>$(RootNamespace)</TargetName>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\">\r\n    <GenerateManifest>false</GenerateManifest>\r\n    <OutDir>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntDir>$(SolutionDir)Built\\Int\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntDir>\r\n    <TargetName>$(RootNamespace)</TargetName>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>\r\n      <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>\r\n      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r\n      <DisableSpecificWarnings>28204;4634;4996</DisableSpecificWarnings>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <CompileAsManaged>\r\n      </CompileAsManaged>\r\n      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\r\n      <CompileAsWinRT>true</CompileAsWinRT>\r\n      <ExceptionHandling>Sync</ExceptionHandling>\r\n      <WarningLevel>Level4</WarningLevel>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r\n      <AdditionalDependencies>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\glTF-Toolkit\\glTF-Toolkit.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>\r\n      <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>\r\n      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r\n      <DisableSpecificWarnings>28204;4634;4996</DisableSpecificWarnings>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <CompileAsManaged>\r\n      </CompileAsManaged>\r\n      <WarningLevel>Level4</WarningLevel>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r\n      <AdditionalDependencies>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\glTF-Toolkit\\glTF-Toolkit.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>\r\n      <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>\r\n      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r\n      <DisableSpecificWarnings>28204;4634;4996</DisableSpecificWarnings>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <WarningLevel>Level4</WarningLevel>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r\n      <AdditionalDependencies>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\glTF-Toolkit\\glTF-Toolkit.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>\r\n      <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>\r\n      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r\n      <DisableSpecificWarnings>28204;4634;4996</DisableSpecificWarnings>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <WarningLevel>Level4</WarningLevel>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r\n      <AdditionalDependencies>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\glTF-Toolkit\\glTF-Toolkit.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>\r\n      <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>\r\n      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r\n      <DisableSpecificWarnings>28204;4634;4996</DisableSpecificWarnings>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <CompileAsManaged>\r\n      </CompileAsManaged>\r\n      <WarningLevel>Level4</WarningLevel>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r\n      <AdditionalDependencies>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\glTF-Toolkit\\glTF-Toolkit.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\">\r\n    <ClCompile>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n      <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>\r\n      <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>\r\n      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r\n      <DisableSpecificWarnings>28204;4634;4996</DisableSpecificWarnings>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <AdditionalIncludeDirectories>$(SolutionDir)glTF-Toolkit\\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <CompileAsManaged>\r\n      </CompileAsManaged>\r\n      <WarningLevel>Level4</WarningLevel>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r\n      <AdditionalDependencies>$(SolutionDir)Built\\Out\\$(PlatformToolset)\\$(Platform)\\$(Configuration)\\glTF-Toolkit\\glTF-Toolkit.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"GLTFStreams.h\" />\r\n    <ClInclude Include=\"pch.h\" />\r\n    <ClInclude Include=\"GLTFSerialization.h\" />\r\n    <ClInclude Include=\"WindowsMRConversion.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"pch.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\">Create</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"GLTFSerialization.cpp\" />\r\n    <ClCompile Include=\"WindowsMRConversion.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"packages.config\">\r\n      <SubType>Designer</SubType>\r\n    </None>\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n    <Import Project=\"$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets\" Condition=\"Exists('$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\directxtex_uwp.2018.8.5.1\\build\\native\\directxtex_uwp.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\directxtex_uwp.2018.8.5.1\\build\\native\\directxtex_uwp.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets')\" />\r\n    <Import Project=\"$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets')\" />\r\n  </ImportGroup>\r\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\r\n    <PropertyGroup>\r\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>\r\n    </PropertyGroup>\r\n    <Error Condition=\"!Exists('$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\\rapidjson.temprelease.0.0.2.20\\build\\native\\rapidjson.temprelease.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\directxtex_uwp.2018.8.5.1\\build\\native\\directxtex_uwp.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\directxtex_uwp.2018.8.5.1\\build\\native\\directxtex_uwp.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\Microsoft.glTF.CPP.1.6.1.0\\build\\native\\Microsoft.glTF.CPP.targets'))\" />\r\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\draco.CPP.1.3.3.1\\build\\native\\draco.CPP.targets'))\" />\r\n  </Target>\r\n</Project>"
  },
  {
    "path": "glTF-Toolkit.UWP/glTF-Toolkit.UWP.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Resources\">\r\n      <UniqueIdentifier>580617e3-8f49-420a-8fbd-2f691cec17ac</UniqueIdentifier>\r\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"pch.cpp\" />\r\n    <ClCompile Include=\"GLTFSerialization.cpp\" />\r\n    <ClCompile Include=\"WindowsMRConversion.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"pch.h\" />\r\n    <ClInclude Include=\"GLTFSerialization.h\" />\r\n    <ClInclude Include=\"WindowsMRConversion.h\" />\r\n    <ClInclude Include=\"GLTFStreams.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"packages.config\" />\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "glTF-Toolkit.UWP/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<packages>\r\n  <package id=\"directxtex_uwp\" version=\"2018.8.5.1\" targetFramework=\"native\" />\r\n  <package id=\"draco.CPP\" version=\"1.3.3.1\" targetFramework=\"native\" />\r\n  <package id=\"Microsoft.glTF.CPP\" version=\"1.6.1.0\" targetFramework=\"native\" />\r\n  <package id=\"rapidjson.temprelease\" version=\"0.0.2.20\" targetFramework=\"native\" />\r\n</packages>"
  },
  {
    "path": "glTF-Toolkit.UWP/pch.cpp",
    "content": "﻿// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#include \"pch.h\"\r\n"
  },
  {
    "path": "glTF-Toolkit.UWP/pch.h",
    "content": "﻿// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\n#pragma once\r\n\r\n// Use the C++ standard templated min/max\r\n#define NOMINMAX\r\n\r\n// DirectX apps don't need GDI\r\n#define NODRAWTEXT\r\n#define NOGDI\r\n#define NOBITMAP\r\n\r\n// Include <mcx.h> if you need this\r\n#define NOMCX\r\n\r\n// Include <winsvc.h> if you need this\r\n#define NOSERVICE\r\n\r\n// WinHelp is deprecated\r\n#define NOHELP\r\n\r\n#include <collection.h>\r\n#include <ppltasks.h>\r\n\r\n#include <fstream>\r\n#include <iostream>\r\n#include <sstream>\r\n"
  },
  {
    "path": "glTF-Toolkit.UWP.Test/Package.appxmanifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Package\n  xmlns=\"http://schemas.microsoft.com/appx/manifest/foundation/windows10\"\n  xmlns:mp=\"http://schemas.microsoft.com/appx/2014/phone/manifest\"\n  xmlns:uap=\"http://schemas.microsoft.com/appx/manifest/uap/windows10\"\n  IgnorableNamespaces=\"uap mp\">\n\n  <Identity Name=\"b09cc82d-5ac2-4f40-97e2-3f6b2685107a\"\n            Publisher=\"CN=jofalcon\"\n            Version=\"1.0.0.0\" />\n\n  <mp:PhoneIdentity PhoneProductId=\"b09cc82d-5ac2-4f40-97e2-3f6b2685107a\" PhonePublisherId=\"00000000-0000-0000-0000-000000000000\"/>\n\n  <Properties>\n    <DisplayName>glTF-Toolkit.UWP.Test</DisplayName>\n    <PublisherDisplayName>jofalcon</PublisherDisplayName>\n    <Logo>Assets\\StoreLogo.png</Logo>\n  </Properties>\n\n  <Dependencies>\n    <TargetDeviceFamily Name=\"Windows.Universal\" MinVersion=\"10.0.0.0\" MaxVersionTested=\"10.0.0.0\" />\n  </Dependencies>\n\n  <Resources>\n    <Resource Language=\"x-generate\" />\n  </Resources>\n  <Applications>\n    <Application Id=\"vstest.executionengine.universal.App\"\n        Executable=\"$targetnametoken$.exe\"\n        EntryPoint=\"glTF_Toolkit.UWP.Test.App\">\n      <uap:VisualElements\n        DisplayName=\"glTF-Toolkit.UWP.Test\"\n        Square150x150Logo=\"Assets\\Square150x150Logo.png\"\n        Square44x44Logo=\"Assets\\Square44x44Logo.png\"\n        Description=\"glTF-Toolkit.UWP.Test\"\n        BackgroundColor=\"transparent\">\n        <uap:DefaultTile Wide310x150Logo=\"Assets\\Wide310x150Logo.png\"/>\n        <uap:SplashScreen Image=\"Assets\\SplashScreen.png\" />\n      </uap:VisualElements>\n    </Application>\n  </Applications>\n  <Capabilities>\n    <Capability Name=\"internetClientServer\" />\n  </Capabilities>\n</Package>"
  },
  {
    "path": "glTF-Toolkit.UWP.Test/Properties/AssemblyInfo.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n[assembly: AssemblyTitle(\"glTF-Toolkit.UWP.Test\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"glTF-Toolkit.UWP.Test\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2017\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n[assembly: AssemblyMetadata(\"TargetPlatform\",\"UAP\")]\n\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n[assembly: ComVisible(false)]"
  },
  {
    "path": "glTF-Toolkit.UWP.Test/Properties/UnitTestApp.rd.xml",
    "content": "<!--\n    This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most\n    developers. However, you can modify these parameters to modify the behavior of the .NET Native\n    optimizer.\n\n    Runtime Directives are documented at http://go.microsoft.com/fwlink/?LinkID=391919\n\n    To fully enable reflection for App1.MyClass and all of its public/private members\n    <Type Name=\"App1.MyClass\" Dynamic=\"Required All\"/>\n\n    To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32\n    <TypeInstantiation Name=\"App1.AppClass\" Arguments=\"System.Int32\" Activate=\"Required Public\" />\n\n    Using the Namespace directive to apply reflection policy to all the types in a particular namespace\n    <Namespace Name=\"DataClasses.ViewModels\" Seralize=\"All\" />\n-->\n\n<Directives xmlns=\"http://schemas.microsoft.com/netfx/2013/01/metadata\">\n  <Application>\n    <!--\n      An Assembly element with Name=\"*Application*\" applies to all assemblies in\n      the application package. The asterisks are not wildcards.\n    -->\n    <Assembly Name=\"*Application*\" Dynamic=\"Required All\" />\n    <!-- Add your application specific runtime directives here. -->\n\n\n  </Application>\n</Directives>"
  },
  {
    "path": "glTF-Toolkit.UWP.Test/UWPTest.cs",
    "content": "﻿// Copyright (c) Microsoft Corporation. All rights reserved.\r\n// Licensed under the MIT License. See LICENSE in the project root for license information.\r\n\r\nusing System;\r\nusing System.Threading.Tasks;\r\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\r\nusing Windows.Foundation;\r\nusing Windows.Security.Cryptography;\r\nusing Windows.Storage;\r\n\r\nnamespace Microsoft.glTF.Toolkit.UWP.Test\r\n{\r\n    [TestClass]\r\n    public class UWPTest\r\n    {\r\n        private async Task<StorageFile> CopyFileToTempFolderAsync(Uri uri)\r\n        {\r\n            StorageFile appxAssetFile = await StorageFile.GetFileFromApplicationUriAsync(uri);\r\n            StorageFile destinationFile = await appxAssetFile.CopyAsync(ApplicationData.Current.TemporaryFolder, appxAssetFile.Name, NameCollisionOption.ReplaceExisting);\r\n            return destinationFile;\r\n        }\r\n\r\n        private IAsyncOperation<StorageFolder> CreateTemporaryOutputFolderAsync(string folderName)\r\n        {\r\n            return ApplicationData.Current.TemporaryFolder.CreateFolderAsync(folderName, CreationCollisionOption.ReplaceExisting);\r\n        }\r\n\r\n        private async Task<bool> CompareFilesAsync(StorageFile file1, StorageFile file2)\r\n        {\r\n            var buffer1 = await FileIO.ReadBufferAsync(file1);\r\n            var buffer2 = await FileIO.ReadBufferAsync(file2);\r\n\r\n            return CryptographicBuffer.Compare(buffer1, buffer2);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task GLBDeserializeSerialize()\r\n        {\r\n            const string glbBaseName = \"WaterBottle\";\r\n            const string glbFileName = glbBaseName + \".glb\";\r\n\r\n            StorageFile sourceGlbFile = await CopyFileToTempFolderAsync(new Uri(\"ms-appx:///Assets/3DModels/\" + glbFileName));\r\n\r\n            StorageFolder outputFolder = await CreateTemporaryOutputFolderAsync(\"Out_\" + glbBaseName);\r\n\r\n            // unpack the glb into gltf and all its companion files\r\n            await GLTFSerialization.UnpackGLBAsync(sourceGlbFile, outputFolder);\r\n\r\n            // compare one of the extracted images to the source images\r\n            StorageFile sourceImageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(\"ms-appx:///Assets/3DModels/WaterBottle_diffuse.png\"));\r\n            StorageFile outputImageFile = await outputFolder.GetFileAsync(glbBaseName + \"_image5.png\");\r\n            Assert.IsTrue(await CompareFilesAsync(sourceImageFile, outputImageFile), \"images\");\r\n\r\n            // compare the extracted model (.bin) to the source model (.bin) file\r\n            StorageFile sourceBinFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(\"ms-appx:///Assets/3DModels/\" + glbBaseName + \".bin\"));\r\n            StorageFile outputBinFile = await outputFolder.GetFileAsync(glbBaseName + \".bin\");\r\n            Assert.IsTrue(await CompareFilesAsync(sourceBinFile, outputBinFile), \"bins\");\r\n\r\n            // Pack the gltf back into a glb file\r\n            StorageFile gltfFile = await outputFolder.GetFileAsync(glbBaseName + \".gltf\");\r\n            StorageFile outputGlbFile = await GLTFSerialization.PackGLTFAsync(gltfFile, outputFolder, glbFileName);\r\n\r\n            // compare the new glb to the old glb\r\n            Assert.IsTrue(await CompareFilesAsync(sourceGlbFile, outputGlbFile), \"glb\");\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task GLBConvertToWindowsMR()\r\n        {\r\n            const string glbBaseName = \"WaterBottle\";\r\n            const string glbFileName = glbBaseName + \".glb\";\r\n\r\n            StorageFile sourceGlbFile = await CopyFileToTempFolderAsync(new Uri(\"ms-appx:///Assets/3DModels/\" + glbFileName));\r\n\r\n            StorageFolder outputFolder = await CreateTemporaryOutputFolderAsync(\"Out_\" + glbBaseName);\r\n\r\n            var converted = await WindowsMRConversion.ConvertAssetForWindowsMR(sourceGlbFile, outputFolder, 512, TexturePacking.OcclusionRoughnessMetallic, true);\r\n\r\n            Assert.IsTrue(converted.Name == \"WaterBottle_converted.glb\");\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "glTF-Toolkit.UWP.Test/UnitTestApp.xaml",
    "content": "﻿<!-- \r\n    Copyright (c) Microsoft Corporation. All rights reserved.\r\n    Licensed under the MIT License. See LICENSE in the project root for license information. \n-->\n<Application \n    x:Class=\"glTF_Toolkit.UWP.Test.App\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:local=\"using:glTF_Toolkit.UWP.Test\"\n    RequestedTheme=\"Light\">\n\n</Application>\n"
  },
  {
    "path": "glTF-Toolkit.UWP.Test/UnitTestApp.xaml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices.WindowsRuntime;\nusing Windows.ApplicationModel;\nusing Windows.ApplicationModel.Activation;\nusing Windows.Foundation;\nusing Windows.Foundation.Collections;\nusing Windows.UI.Xaml;\nusing Windows.UI.Xaml.Controls;\nusing Windows.UI.Xaml.Controls.Primitives;\nusing Windows.UI.Xaml.Data;\nusing Windows.UI.Xaml.Input;\nusing Windows.UI.Xaml.Media;\nusing Windows.UI.Xaml.Navigation;\n\nnamespace glTF_Toolkit.UWP.Test\n{\n    /// <summary>\n    /// Provides application-specific behavior to supplement the default Application class.\n    /// </summary>\n    sealed partial class App : Application\n    {\n        /// <summary>\n        /// Initializes the singleton application object.  This is the first line of authored code\n        /// executed, and as such is the logical equivalent of main() or WinMain().\n        /// </summary>\n        public App()\n        {\n            this.InitializeComponent();\n            this.Suspending += OnSuspending;\n        }\n\n        /// <summary>\n        /// Invoked when the application is launched normally by the end user.  Other entry points\n        /// will be used such as when the application is launched to open a specific file.\n        /// </summary>\n        /// <param name=\"e\">Details about the launch request and process.</param>\n        protected override void OnLaunched(LaunchActivatedEventArgs e)\n        {\n\n#if DEBUG\n            if (System.Diagnostics.Debugger.IsAttached)\n            {\n                this.DebugSettings.EnableFrameRateCounter = true;\n            }\n#endif\n\n            Frame rootFrame = Window.Current.Content as Frame;\n\n            // Do not repeat app initialization when the Window already has content,\n            // just ensure that the window is active\n            if (rootFrame == null)\n            {\n                // Create a Frame to act as the navigation context and navigate to the first page\n                rootFrame = new Frame();\n\n                rootFrame.NavigationFailed += OnNavigationFailed;\n\n                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)\n                {\n                    //TODO: Load state from previously suspended application\n                }\n\n                // Place the frame in the current Window\n                Window.Current.Content = rootFrame;\n            }\n            \n            Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI();\n\n            // Ensure the current window is active\n            Window.Current.Activate();\n\n            Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(e.Arguments);\n        }\n\n        /// <summary>\n        /// Invoked when Navigation to a certain page fails\n        /// </summary>\n        /// <param name=\"sender\">The Frame which failed navigation</param>\n        /// <param name=\"e\">Details about the navigation failure</param>\n        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)\n        {\n            throw new Exception(\"Failed to load Page \" + e.SourcePageType.FullName);\n        }\n\n        /// <summary>\n        /// Invoked when application execution is being suspended.  Application state is saved\n        /// without knowing whether the application will be terminated or resumed with the contents\n        /// of memory still intact.\n        /// </summary>\n        /// <param name=\"sender\">The source of the suspend request.</param>\n        /// <param name=\"e\">Details about the suspend request.</param>\n        private void OnSuspending(object sender, SuspendingEventArgs e)\n        {\n            var deferral = e.SuspendingOperation.GetDeferral();\n            //TODO: Save application state and stop any background activity\n            deferral.Complete();\n        }\n    }\n}\n"
  },
  {
    "path": "glTF-Toolkit.UWP.Test/glTF-Toolkit.UWP.Test.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"15.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\r\n  <PropertyGroup>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">x86</Platform>\r\n    <ProjectGuid>{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}</ProjectGuid>\r\n    <OutputType>AppContainerExe</OutputType>\r\n    <AppDesignerFolder>Properties</AppDesignerFolder>\r\n    <RootNamespace>Microsoft.glTF.Toolkit.UWP.Test</RootNamespace>\r\n    <AssemblyName>glTF-Toolkit.UWP.Test</AssemblyName>\r\n    <DefaultLanguage>en-US</DefaultLanguage>\r\n    <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>\r\n    <TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>\r\n    <TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>\r\n    <MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>\r\n    <FileAlignment>512</FileAlignment>\r\n    <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\r\n    <UnitTestPlatformVersion Condition=\"'$(UnitTestPlatformVersion)' == ''\">$(VisualStudioVersion)</UnitTestPlatformVersion>\r\n    <OutDir>$(SolutionDir)Built\\Out\\v141\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</OutDir>\r\n    <IntermediateOutputPath>$(SolutionDir)Built\\Int\\v141\\$(Platform)\\$(Configuration)\\$(MSBuildProjectName)\\</IntermediateOutputPath>\r\n  </PropertyGroup>\r\n  <PropertyGroup Label=\"UserMacros\">\r\n    <AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>bin\\x86\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\r\n    <NoWarn>;2008</NoWarn>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <UseVSHostingProcess>false</UseVSHostingProcess>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\r\n    <OutputPath>bin\\x86\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <NoWarn>;2008</NoWarn>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <UseVSHostingProcess>false</UseVSHostingProcess>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|ARM'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>bin\\ARM\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\r\n    <NoWarn>;2008</NoWarn>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>ARM</PlatformTarget>\r\n    <UseVSHostingProcess>false</UseVSHostingProcess>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|ARM'\">\r\n    <OutputPath>bin\\ARM\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <NoWarn>;2008</NoWarn>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>ARM</PlatformTarget>\r\n    <UseVSHostingProcess>false</UseVSHostingProcess>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>bin\\x64\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\r\n    <NoWarn>;2008</NoWarn>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <UseVSHostingProcess>false</UseVSHostingProcess>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\r\n    <OutputPath>bin\\x64\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\r\n    <Optimize>true</Optimize>\r\n    <NoWarn>;2008</NoWarn>\r\n    <DebugType>pdbonly</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <UseVSHostingProcess>false</UseVSHostingProcess>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <Prefer32Bit>true</Prefer32Bit>\r\n    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>\r\n  </PropertyGroup>\r\n  <PropertyGroup>\r\n    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <SDKReference Include=\"TestPlatform.Universal, Version=$(UnitTestPlatformVersion)\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\r\n    <Compile Include=\"UnitTestApp.xaml.cs\">\r\n      <DependentUpon>UnitTestApp.xaml</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"UWPTest.cs\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ApplicationDefinition Include=\"UnitTestApp.xaml\">\r\n      <Generator>MSBuild:Compile</Generator>\r\n      <SubType>Designer</SubType>\r\n    </ApplicationDefinition>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <AppxManifest Include=\"Package.appxmanifest\">\r\n      <SubType>Designer</SubType>\r\n    </AppxManifest>\r\n    <Content Include=\"Assets\\3DModels\\WaterBottle.bin\" />\r\n    <Content Include=\"Assets\\3DModels\\WaterBottle.glb\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Content Include=\"Assets\\3DModels\\WaterBottle_diffuse.png\" />\r\n    <Content Include=\"Properties\\UnitTestApp.rd.xml\" />\r\n    <Content Include=\"Assets\\LockScreenLogo.scale-200.png\" />\r\n    <Content Include=\"Assets\\SplashScreen.scale-200.png\" />\r\n    <Content Include=\"Assets\\Square150x150Logo.scale-200.png\" />\r\n    <Content Include=\"Assets\\Square44x44Logo.scale-200.png\" />\r\n    <Content Include=\"Assets\\Square44x44Logo.targetsize-24_altform-unplated.png\" />\r\n    <Content Include=\"Assets\\StoreLogo.png\" />\r\n    <Content Include=\"Assets\\Wide310x150Logo.scale-200.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <PackageReference Include=\"Microsoft.NETCore.UniversalWindowsPlatform\">\r\n      <Version>6.2.0-Preview1-26502-02</Version>\r\n    </PackageReference>\r\n    <PackageReference Include=\"MSTest.TestAdapter\">\r\n      <Version>1.3.2</Version>\r\n    </PackageReference>\r\n    <PackageReference Include=\"MSTest.TestFramework\">\r\n      <Version>1.3.2</Version>\r\n    </PackageReference>\r\n  </ItemGroup>\r\n  <ItemGroup Condition=\"'$(Platform)'=='x86'\">\r\n    <Reference Include=\"Microsoft.glTF.Toolkit.UWP\">\r\n      <HintPath>..\\Built\\Out\\v141\\Win32\\$(Configuration)\\glTF-Toolkit.UWP\\Microsoft.glTF.Toolkit.UWP.winmd</HintPath>\r\n    </Reference>\r\n  </ItemGroup>\r\n  <ItemGroup Condition=\"'$(Platform)'!='x86'\">\r\n    <Reference Include=\"Microsoft.glTF.Toolkit.UWP\">\r\n      <HintPath>..\\Built\\Out\\v141\\$(Platform)\\$(Configuration)\\glTF-Toolkit.UWP\\Microsoft.glTF.Toolkit.UWP.winmd</HintPath>\r\n    </Reference>\r\n  </ItemGroup>\r\n  <PropertyGroup Condition=\" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' \">\r\n    <VisualStudioVersion>14.0</VisualStudioVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(MSBuildExtensionsPath)\\Microsoft\\WindowsXaml\\v$(VisualStudioVersion)\\Microsoft.Windows.UI.Xaml.CSharp.targets\" />\r\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r\n       Other similar extension points exist, see Microsoft.Common.targets.\r\n  <Target Name=\"BeforeBuild\">\r\n  </Target>\r\n  <Target Name=\"AfterBuild\">\r\n  </Target>\r\n  -->\r\n</Project>"
  },
  {
    "path": "glTF-Toolkit.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio 15\r\nVisualStudioVersion = 15.0.27004.2010\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"glTF-Toolkit\", \"glTF-Toolkit\\glTF-Toolkit.vcxproj\", \"{FF0275F1-58CB-4745-BA81-F6C1DF66E206}\"\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"glTF-Toolkit.Test\", \"glTF-Toolkit.Test\\glTF-Toolkit.Test.vcxproj\", \"{B2AF77B5-8433-46AD-860D-23A4831F6830}\"\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"WindowsMRAssetConverter\", \"WindowsMRAssetConverter\\WindowsMRAssetConverter.vcxproj\", \"{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}\"\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{E50FE4A3-A16D-4A05-A221-71CA2D972CF7}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\t.gitignore = .gitignore\r\n\t\tLICENSE = LICENSE\r\n\t\tREADME.md = README.md\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"glTF-Toolkit.UWP\", \"glTF-Toolkit.UWP\\glTF-Toolkit.UWP.vcxproj\", \"{697462FB-C8E9-4EA5-A499-033DF330E212}\"\r\n\tProjectSection(ProjectDependencies) = postProject\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206} = {FF0275F1-58CB-4745-BA81-F6C1DF66E206}\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"glTF-Toolkit.UWP.Test\", \"glTF-Toolkit.UWP.Test\\glTF-Toolkit.UWP.Test.csproj\", \"{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}\"\r\n\tProjectSection(ProjectDependencies) = postProject\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212} = {697462FB-C8E9-4EA5-A499-033DF330E212}\r\n\tEndProjectSection\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug Static Runtime|ARM = Debug Static Runtime|ARM\r\n\t\tDebug Static Runtime|x64 = Debug Static Runtime|x64\r\n\t\tDebug Static Runtime|x86 = Debug Static Runtime|x86\r\n\t\tDebug|ARM = Debug|ARM\r\n\t\tDebug|x64 = Debug|x64\r\n\t\tDebug|x86 = Debug|x86\r\n\t\tRelease Static Runtime|ARM = Release Static Runtime|ARM\r\n\t\tRelease Static Runtime|x64 = Release Static Runtime|x64\r\n\t\tRelease Static Runtime|x86 = Release Static Runtime|x86\r\n\t\tRelease|ARM = Release|ARM\r\n\t\tRelease|x64 = Release|x64\r\n\t\tRelease|x86 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug Static Runtime|ARM.ActiveCfg = Debug Static Runtime|ARM\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug Static Runtime|ARM.Build.0 = Debug Static Runtime|ARM\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug Static Runtime|x64.ActiveCfg = Debug Static Runtime|x64\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug Static Runtime|x64.Build.0 = Debug Static Runtime|x64\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug Static Runtime|x86.ActiveCfg = Debug Static Runtime|Win32\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug Static Runtime|x86.Build.0 = Debug Static Runtime|Win32\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug|ARM.ActiveCfg = Debug|ARM\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug|ARM.Build.0 = Debug|ARM\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release Static Runtime|ARM.ActiveCfg = Release Static Runtime|ARM\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release Static Runtime|ARM.Build.0 = Release Static Runtime|ARM\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release Static Runtime|x64.ActiveCfg = Release Static Runtime|x64\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release Static Runtime|x64.Build.0 = Release Static Runtime|x64\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release Static Runtime|x86.ActiveCfg = Release Static Runtime|Win32\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release Static Runtime|x86.Build.0 = Release Static Runtime|Win32\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release|ARM.ActiveCfg = Release|ARM\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release|ARM.Build.0 = Release|ARM\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release|x64.Build.0 = Release|x64\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{FF0275F1-58CB-4745-BA81-F6C1DF66E206}.Release|x86.Build.0 = Release|Win32\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Debug Static Runtime|ARM.ActiveCfg = Release|Win32\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Debug Static Runtime|x64.ActiveCfg = Debug|x64\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Debug Static Runtime|x86.ActiveCfg = Debug|Win32\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Debug|ARM.ActiveCfg = Debug|Win32\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Release Static Runtime|ARM.ActiveCfg = Release|Win32\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Release Static Runtime|x64.ActiveCfg = Release|x64\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Release Static Runtime|x86.ActiveCfg = Release|Win32\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Release|ARM.ActiveCfg = Release|Win32\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Release|x64.Build.0 = Release|x64\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{B2AF77B5-8433-46AD-860D-23A4831F6830}.Release|x86.Build.0 = Release|Win32\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Debug Static Runtime|ARM.ActiveCfg = Release|Win32\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Debug Static Runtime|x64.ActiveCfg = Debug|x64\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Debug Static Runtime|x86.ActiveCfg = Debug|Win32\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Debug|ARM.ActiveCfg = Debug|Win32\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Release Static Runtime|ARM.ActiveCfg = Release|Win32\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Release Static Runtime|x64.ActiveCfg = Release|x64\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Release Static Runtime|x86.ActiveCfg = Release|Win32\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Release|ARM.ActiveCfg = Release|Win32\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Release|x64.Build.0 = Release|x64\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{8A19D99C-78DC-4267-AB57-DB1DDBFBEFDF}.Release|x86.Build.0 = Release|Win32\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Debug Static Runtime|ARM.ActiveCfg = Debug|ARM\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Debug Static Runtime|x64.ActiveCfg = Debug|x64\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Debug Static Runtime|x86.ActiveCfg = Debug|Win32\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Debug|ARM.ActiveCfg = Debug|ARM\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Debug|ARM.Build.0 = Debug|ARM\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Release Static Runtime|ARM.ActiveCfg = Release|ARM\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Release Static Runtime|x64.ActiveCfg = Release|x64\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Release Static Runtime|x86.ActiveCfg = Release|Win32\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Release|ARM.ActiveCfg = Release|ARM\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Release|ARM.Build.0 = Release|ARM\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Release|x64.Build.0 = Release|x64\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{697462FB-C8E9-4EA5-A499-033DF330E212}.Release|x86.Build.0 = Release|Win32\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug Static Runtime|ARM.ActiveCfg = Debug|ARM\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug Static Runtime|x64.ActiveCfg = Debug|x64\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug Static Runtime|x86.ActiveCfg = Debug|x86\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug|ARM.ActiveCfg = Debug|ARM\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug|ARM.Build.0 = Debug|ARM\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug|ARM.Deploy.0 = Debug|ARM\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug|x64.Deploy.0 = Debug|x64\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug|x86.ActiveCfg = Debug|x86\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug|x86.Build.0 = Debug|x86\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Debug|x86.Deploy.0 = Debug|x86\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release Static Runtime|ARM.ActiveCfg = Release|ARM\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release Static Runtime|x64.ActiveCfg = Release|x64\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release Static Runtime|x86.ActiveCfg = Release|x86\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release|ARM.ActiveCfg = Release|ARM\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release|ARM.Build.0 = Release|ARM\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release|ARM.Deploy.0 = Release|ARM\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release|x64.Build.0 = Release|x64\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release|x64.Deploy.0 = Release|x64\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release|x86.ActiveCfg = Release|x86\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release|x86.Build.0 = Release|x86\r\n\t\t{5365C33C-A3F9-4169-8C6F-A2DD3FABA575}.Release|x86.Deploy.0 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {04F37F7A-2349-4424-B26C-33237D33B0A4}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  }
]