diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..d687a91 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,31 @@ +name: main + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + Build: + runs-on: windows-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + lfs: true + + - name: Restore packages + run: nuget restore + working-directory: ./Source + + - name: Setup build + uses: microsoft/setup-msbuild@v2 + + - name: Build targets + run: msbuild /t:ExplorerCommand /t:glTF /t:Tests /p:Configuration=Release /p:Platform=x64 + working-directory: ./Source + + - name: Run tests + run: dotnet test ./Build/Tests/bin/Release/AnyCPU/Tests.dll -s ./Source/.runsettings -v n diff --git a/.gitignore b/.gitignore index 72e650c..04da875 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ Build # published files end up here /Source/glTF/bin + +# launc settings +/Source/glTF/Properties/launchSettings.json diff --git a/Source/.runsettings b/Source/.runsettings new file mode 100644 index 0000000..c1b8723 --- /dev/null +++ b/Source/.runsettings @@ -0,0 +1,6 @@ + + + + ..\Build\Tests\Results + + \ No newline at end of file diff --git a/Source/glTF/Core/Binary.cs b/Source/Core/Binary.cs similarity index 100% rename from Source/glTF/Core/Binary.cs rename to Source/Core/Binary.cs diff --git a/Source/Core/Core.csproj b/Source/Core/Core.csproj new file mode 100644 index 0000000..34edaf8 --- /dev/null +++ b/Source/Core/Core.csproj @@ -0,0 +1,10 @@ + + + + net8.0 + enable + enable + glTF + + + diff --git a/Source/Core/Extensions/JsonExtensions.cs b/Source/Core/Extensions/JsonExtensions.cs new file mode 100644 index 0000000..d74611d --- /dev/null +++ b/Source/Core/Extensions/JsonExtensions.cs @@ -0,0 +1,79 @@ +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace glTF +{ + internal static class JsonExtensions + { + public static JsonArray? GetArray(this JsonNode node, string propertyName, JsonArray? defaultValue = null) + { + var propertyNode = node[propertyName]; + if (propertyNode == null || propertyNode.GetValueKind() != JsonValueKind.Array) + { + return defaultValue; + } + + return propertyNode.AsArray(); + } + + public static int GetInt(this JsonNode node, string propertyName, int defaultValue = -1) + { + var propertyNode = node[propertyName]; + if (propertyNode == null || propertyNode.GetValueKind() != JsonValueKind.Number) + { + return defaultValue; + } + + return propertyNode.GetValue(); + } + + public static string? GetString(this JsonNode node, string propertyName, string? defaultValue = null) + { + var propertyNode = node[propertyName]; + if (propertyNode == null || propertyNode.GetValueKind() != JsonValueKind.String) + { + return defaultValue; + } + + return propertyNode.GetValue(); + } + + public static string? GetLocalPath(this JsonNode node, string propertyName, Uri baseUri, string? defaultValue = null) + { + var uriString = node.GetString(propertyName); + if (uriString == null) + { + return defaultValue; + } + + if (!Uri.TryCreate(baseUri, uriString, out var uri) || !uri.IsFile) + { + return defaultValue; + } + + return uri.LocalPath; + } + + public static void SetInt(this JsonNode jsonNode, string propertyName, int value, int defaultValue) + { + if (value == defaultValue) + { + jsonNode.AsObject().Remove(propertyName); + } + else + { + jsonNode[propertyName] = JsonValue.Create(value); + } + } + + public static bool Remove(this JsonNode node, string propertyName) + { + if (node.GetValueKind() != JsonValueKind.Object) + { + return false; + } + + return node.AsObject().Remove(propertyName); + } + } +} diff --git a/Source/glTF/Extensions/StreamExtensions.cs b/Source/Core/Extensions/StreamExtensions.cs similarity index 100% rename from Source/glTF/Extensions/StreamExtensions.cs rename to Source/Core/Extensions/StreamExtensions.cs diff --git a/Source/Core/MimeType.cs b/Source/Core/MimeType.cs new file mode 100644 index 0000000..39da8b1 --- /dev/null +++ b/Source/Core/MimeType.cs @@ -0,0 +1,47 @@ +namespace glTF +{ + internal class MimeType + { + public static string ToFileExtension(string? mimeType) + { + switch (mimeType) + { + case "image/png": + return ".png"; + case "image/jpeg": + return ".jpg"; + case "image/vnd-ms.dds": + return ".dds"; + case "image/ktx2": + return ".ktx2"; + case "image/webp": + return ".webp"; + } + + return ".bin"; + } + + public static string FromFileExtension(string? fileExtension) + { + if (fileExtension != null) + { + switch (fileExtension.ToLower()) + { + case ".png": + return "image/png"; + case ".jpg": + case ".jpeg": + return "image/jpeg"; + case ".dds": + return "image/vnd-ms.dds"; + case ".ktx2": + return "image/ktx2"; + case ".webp": + return "image/webp"; + } + } + + return "application/octet-stream"; + } + } +} diff --git a/Source/Core/Packer.cs b/Source/Core/Packer.cs new file mode 100644 index 0000000..f3e3a05 --- /dev/null +++ b/Source/Core/Packer.cs @@ -0,0 +1,237 @@ +using System.IO.MemoryMappedFiles; +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace glTF +{ + public class Packer + { + private struct FileInfo + { + public MemoryMappedFile File; + public int FileLength; + public MemoryMappedViewStream Stream; + public int ByteOffset; + } + + public static void Pack(string inputFilePath, string outputFilePath) + { + var baseUri = new Uri(inputFilePath); + + var fileMap = new Dictionary(); + var byteOffset = 0; + + FileInfo AddFile(string filePath) + { + if (!fileMap.TryGetValue(filePath, out var fileInfo)) + { + var file = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open); + var fileLength = Tools.GetFileLength(filePath); + var stream = file.CreateViewStream(0, fileLength, MemoryMappedFileAccess.Read); + fileInfo = new() { File = file, FileLength = fileLength, Stream = stream, ByteOffset = byteOffset }; + fileMap.Add(filePath, fileInfo); + byteOffset = Tools.Align(byteOffset + fileLength); + } + + return fileInfo; + } + + JsonNode root; + using (var stream = File.OpenRead(inputFilePath)) + { + root = JsonNode.Parse(stream)!; + } + + var buffers = root.GetArray("buffers"); + var bufferViews = root.GetArray("bufferViews"); + + if (buffers != null) + { + for (var index = buffers.Count - 1; index >= 0; index--) + { + var buffer = buffers[index]; + if (buffer == null) + { + continue; + } + + var filePath = buffer.GetLocalPath("uri", baseUri); + if (filePath == null) + { + continue; + } + + var fileInfo = AddFile(filePath); + + if (bufferViews != null) + { + foreach (var bufferView in bufferViews) + { + if (bufferView == null) + { + continue; + } + + var bufferIndex = bufferView.GetInt("buffer"); + if (bufferIndex == -1) + { + continue; + } + + if (bufferIndex == index) + { + bufferView.Remove("buffer"); + bufferView.SetInt("byteOffset", fileInfo.ByteOffset + bufferView.GetInt("byteOffset", 0), 0); + } + else if (bufferIndex > index) + { + bufferView["buffer"] = bufferIndex - 1; + } + } + } + + buffers.RemoveAt(index); + } + } + + void ProcessArray(JsonArray array) + { + foreach (var element in array) + { + if (element == null) + { + continue; + } + + var filePath = element.GetLocalPath("uri", baseUri); + if (filePath == null) + { + continue; + } + + var fileInfo = AddFile(filePath); + + if (bufferViews == null) + { + bufferViews = []; + root["bufferViews"] = bufferViews; + } + + element.Remove("uri"); + element["bufferView"] = bufferViews.Count; + element["mimeType"] = MimeType.FromFileExtension(Path.GetExtension(filePath)); + + JsonNode bufferView = new JsonObject(); + bufferView.SetInt("byteOffset", fileInfo.ByteOffset, 0); + bufferView["byteLength"] = fileInfo.FileLength; + bufferViews.Add(bufferView); + } + } + + var images = root.GetArray("images"); + if (images != null) + { + ProcessArray(images); + } + + // EXT_lights_ies + var lights = root["extensions"]?.AsObject()["EXT_lights_ies"]?.AsObject().GetArray("lights"); + if (lights != null) + { + ProcessArray(lights); + } + + if (fileMap.Count != 0) + { + if (buffers == null) + { + buffers = []; + root["buffers"] = buffers; + } + + JsonNode buffer = new JsonObject(); + buffer["byteLength"] = byteOffset; + buffers.Insert(0, buffer); + + if (bufferViews != null) + { + foreach (var bufferView in bufferViews) + { + if (bufferView == null) + { + continue; + } + + var bufferIndex = bufferView.GetInt("buffer"); + bufferView["buffer"] = bufferIndex + 1; + } + } + } + + var outputDirectoryPath = Path.GetDirectoryName(outputFilePath); + if (outputDirectoryPath != null) + { + Directory.CreateDirectory(outputDirectoryPath); + } + + using (var fileStream = File.Create(outputFilePath)) + using (var binaryWriter = new BinaryWriter(fileStream)) + { + binaryWriter.Write(Binary.Magic); + binaryWriter.Write(Binary.Version); + + var chunksPosition = binaryWriter.BaseStream.Position; + + binaryWriter.Write(0U); // length + + var jsonChunkPosition = binaryWriter.BaseStream.Position; + + binaryWriter.Write(0U); // json chunk length + binaryWriter.Write(Binary.ChunkFormatJson); + + using (var jsonTextWriter = new Utf8JsonWriter(binaryWriter.BaseStream)) + { + root.WriteTo(jsonTextWriter); + } + + binaryWriter.BaseStream.Align(0x20); + var jsonChunkLength = checked((uint)(binaryWriter.BaseStream.Length - jsonChunkPosition)) - Binary.ChunkHeaderLength; + + binaryWriter.BaseStream.Seek(jsonChunkPosition, SeekOrigin.Begin); + binaryWriter.Write(jsonChunkLength); + + if (fileMap.Count != 0) + { + binaryWriter.BaseStream.Seek(0, SeekOrigin.End); + var binChunkPosition = binaryWriter.BaseStream.Position; + + binaryWriter.Write(0); // bin chunk length + binaryWriter.Write(Binary.ChunkFormatBin); + + foreach (var value in fileMap.Values) + { + binaryWriter.BaseStream.Align(); + value.Stream.CopyTo(binaryWriter.BaseStream); + } + + binaryWriter.BaseStream.Align(0x20); + var binChunkLength = checked((uint)(binaryWriter.BaseStream.Length - binChunkPosition)) - Binary.ChunkHeaderLength; + + binaryWriter.BaseStream.Seek(binChunkPosition, SeekOrigin.Begin); + binaryWriter.Write(binChunkLength); + } + + var length = checked((uint)binaryWriter.BaseStream.Length); + + binaryWriter.BaseStream.Seek(chunksPosition, SeekOrigin.Begin); + binaryWriter.Write(length); + } + + foreach (var value in fileMap.Values) + { + value.Stream.Dispose(); + value.File.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Source/glTF/Core/Tools.cs b/Source/Core/Tools.cs similarity index 89% rename from Source/glTF/Core/Tools.cs rename to Source/Core/Tools.cs index 0558708..3824676 100644 --- a/Source/glTF/Core/Tools.cs +++ b/Source/Core/Tools.cs @@ -1,6 +1,4 @@ -using System.IO; - -namespace glTF +namespace glTF { internal static class Tools { diff --git a/Source/glTF/Core/Unpacker.cs b/Source/Core/Unpacker.cs similarity index 63% rename from Source/glTF/Core/Unpacker.cs rename to Source/Core/Unpacker.cs index 2be4786..e8748e6 100644 --- a/Source/glTF/Core/Unpacker.cs +++ b/Source/Core/Unpacker.cs @@ -1,14 +1,10 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.MemoryMappedFiles; -using System.Linq; +using System.IO.MemoryMappedFiles; using System.Text.Json; using System.Text.Json.Nodes; namespace glTF { - internal class Unpacker + public class Unpacker { private readonly string inputFilePath; private readonly string inputDirectoryPath; @@ -19,7 +15,7 @@ internal class Unpacker private Unpacker(string inputFilePath, string outputDirectoryPath, bool unpackImages) { this.inputFilePath = inputFilePath; - this.inputDirectoryPath = Path.GetDirectoryName(this.inputFilePath); + this.inputDirectoryPath = Path.GetDirectoryName(this.inputFilePath)!; this.inputFileName = Path.GetFileNameWithoutExtension(this.inputFilePath); this.outputDirectoryPath = outputDirectoryPath; this.unpackImages = unpackImages; @@ -60,7 +56,7 @@ private void Unpack() using (var jsonStream = GetJsonChunk(binaryReader, memoryMappedFile)) { - jsonNode = JsonNode.Parse(jsonStream); + jsonNode = JsonNode.Parse(jsonStream)!; } var binChunkOffset = FindBinChunk(binaryReader); @@ -68,6 +64,7 @@ private void Unpack() this.ProcessBinFiles(jsonNode, memoryMappedFile, binChunkOffset); } + Directory.CreateDirectory(this.outputDirectoryPath); using (var fileStream = File.Create(Path.Combine(this.outputDirectoryPath, $"{this.inputFileName}.gltf"))) using (var jsonWriter = new Utf8JsonWriter(fileStream, new() { Indented = true })) { @@ -75,7 +72,7 @@ private void Unpack() } } - private static Stream GetJsonChunk(BinaryReader binaryReader, MemoryMappedFile memoryMappedFile) + private static MemoryMappedViewStream GetJsonChunk(BinaryReader binaryReader, MemoryMappedFile memoryMappedFile) { var chunkLength = binaryReader.ReadUInt32(); var chunkFormat = binaryReader.ReadUInt32(); @@ -119,12 +116,11 @@ private static long FindBinChunk(BinaryReader binaryReader) return -1; } - private void ProcessImageFiles(JsonNode jsonNode, MemoryMappedFile memoryMappedFile, long binChunkOffset) + private void ProcessImageFiles(JsonNode node, MemoryMappedFile memoryMappedFile, long binChunkOffset) { - var root = jsonNode.AsObject(); - var accessors = root["accessors"]?.AsArray(); - var bufferViews = root["bufferViews"]?.AsArray(); - var images = root["images"]?.AsArray(); + var accessors = node.GetArray("accessors"); + var bufferViews = node.GetArray("bufferViews"); + var images = node.GetArray("images"); var bufferViewIndicesToRemove = new List(); @@ -132,51 +128,63 @@ private void ProcessImageFiles(JsonNode jsonNode, MemoryMappedFile memoryMappedF { for (var index = 0; index < images.Count; index++) { - var image = images[index]?.AsObject(); - if (image != null) + var image = images[index]; + if (image == null) { - var uri = image["uri"]?.GetValue(); - if (Uri.IsWellFormedUriString(uri, UriKind.Relative)) - { - var sourceFilePath = Path.Combine(this.inputDirectoryPath, Path.GetFileName(uri)); - var fileExtension = Path.GetExtension(uri); - var fileName = $"{this.inputFileName}_image{index}.{fileExtension}"; + continue; + } - if (File.Exists(sourceFilePath)) - { - var destinationFilePath = Path.Combine(this.outputDirectoryPath, fileName); - File.Copy(sourceFilePath, destinationFilePath, true); - } + var uri = image.GetString("uri"); + if (uri != null && Uri.IsWellFormedUriString(uri, UriKind.Relative)) + { + var sourceFilePath = Path.Combine(this.inputDirectoryPath, uri.Replace('/', Path.DirectorySeparatorChar)); + var fileExtension = Path.GetExtension(uri); + var fileName = $"{this.inputFileName}_image{index}.{fileExtension}"; - image["uri"] = fileName; + if (File.Exists(sourceFilePath)) + { + var destinationFilePath = Path.Combine(this.outputDirectoryPath, fileName); + File.Copy(sourceFilePath, destinationFilePath, true); } - else if (this.unpackImages && bufferViews != null && binChunkOffset != -1) + + image["uri"] = fileName; + } + else if (this.unpackImages && bufferViews != null && binChunkOffset != -1) + { + var bufferViewIndex = image.GetInt("bufferView"); + if (bufferViewIndex != -1) { - var bufferViewIndex = (int)image["bufferView"]; var bufferView = bufferViews[bufferViewIndex]; - var bufferIndex = (int)bufferView["buffer"]; - if (bufferIndex == 0) + if (bufferView != null) { - var mimeType = (string)image["mimeType"]; - var fileExtension = MimeType.ToFileExtension(mimeType); - var fileName = $"{this.inputFileName}_image{index}{fileExtension}"; - - using (var fileStream = File.Create(Path.Combine(this.outputDirectoryPath, fileName))) + var bufferIndex = bufferView.GetInt("buffer"); + if (bufferIndex == 0) { - var byteOffset = (long?)bufferView["byteOffset"] ?? 0; - var byteLength = (int)bufferView["byteLength"]; - - using (var viewStream = memoryMappedFile.CreateViewStream(binChunkOffset + byteOffset, byteLength, MemoryMappedFileAccess.Read)) + var byteOffset = bufferView.GetInt("byteOffset", 0); + var byteLength = bufferView.GetInt("byteLength", -1); + if (byteLength != -1) { - viewStream.CopyTo(fileStream); - } - } + var mimeType = image.GetString("mimeType"); + var fileExtension = MimeType.ToFileExtension(mimeType); + var fileName = $"{this.inputFileName}_image{index}{fileExtension}"; + + Directory.CreateDirectory(this.outputDirectoryPath); + + using (var fileStream = File.Create(Path.Combine(this.outputDirectoryPath, fileName))) + { + using (var viewStream = memoryMappedFile.CreateViewStream(binChunkOffset + byteOffset, byteLength, MemoryMappedFileAccess.Read)) + { + viewStream.CopyTo(fileStream); + } + } - image.Remove("bufferView"); - image.Remove("mimeType"); - image["uri"] = fileName; + image.Remove("bufferView"); + image.Remove("mimeType"); + image["uri"] = fileName; - bufferViewIndicesToRemove.Add(bufferViewIndex); + bufferViewIndicesToRemove.Add(bufferViewIndex); + } + } } } } @@ -203,7 +211,7 @@ private void ProcessImageFiles(JsonNode jsonNode, MemoryMappedFile memoryMappedF if (newIndex == 0) { - root.Remove("bufferViews"); + node.Remove("bufferViews"); } else { @@ -218,10 +226,15 @@ private void ProcessImageFiles(JsonNode jsonNode, MemoryMappedFile memoryMappedF { foreach (var accessor in accessors) { - var bufferViewIndex = (int?)accessor["bufferView"]; - if (bufferViewIndex.HasValue) + if (accessor == null) + { + continue; + } + + var bufferViewIndex = accessor.GetInt("bufferView"); + if (bufferViewIndex != -1) { - if (bufferViewIndexMap.TryGetValue(bufferViewIndex.Value, out int newBufferViewIndex)) + if (bufferViewIndexMap.TryGetValue(bufferViewIndex, out int newBufferViewIndex)) { accessor["bufferView"] = newBufferViewIndex; } @@ -230,19 +243,23 @@ private void ProcessImageFiles(JsonNode jsonNode, MemoryMappedFile memoryMappedF } } - private void ProcessBinFiles(JsonNode jsonNode, MemoryMappedFile memoryMappedFile, long binChunkOffset) + private void ProcessBinFiles(JsonNode node, MemoryMappedFile memoryMappedFile, long binChunkOffset) { - var root = jsonNode.AsObject(); - var buffers = root["buffers"]?.AsArray(); + var buffers = node.GetArray("buffers"); if (buffers != null) { for (var index = 0; index < buffers.Count; index++) { var buffer = buffers[index]; - var uri = (string)buffer["uri"]; + if (buffer == null) + { + continue; + } + + var uri = buffer.GetString("uri"); if (uri != null && Uri.IsWellFormedUriString(uri, UriKind.Relative)) { - var sourceFilePath = Path.Combine(this.inputDirectoryPath, Path.GetFileName(uri)); + var sourceFilePath = Path.Combine(this.inputDirectoryPath, uri.Replace('/', Path.DirectorySeparatorChar)); var fileName = $"{this.inputFileName}{index}.bin"; if (File.Exists(sourceFilePath)) @@ -255,29 +272,36 @@ private void ProcessBinFiles(JsonNode jsonNode, MemoryMappedFile memoryMappedFil } } - var bufferViews = root["bufferViews"]?.AsArray(); + var firstBuffer = buffers[0]; + if (firstBuffer == null) + { + return; + } + + var bufferViews = node.GetArray("bufferViews"); if (bufferViews != null && binChunkOffset != -1) { - if (bufferViews.Any(bufferView => (int)bufferView["buffer"] == 0)) + if (bufferViews.Any(bufferView => bufferView != null && bufferView.GetInt("buffer") == 0)) { + Directory.CreateDirectory(this.outputDirectoryPath); + var binFileName = $"{this.inputFileName}.bin"; var binFilePath = Path.Combine(this.outputDirectoryPath, binFileName); using (var fileStream = File.Create(binFilePath)) { - var buffer = buffers[0]; - buffer["uri"] = binFileName; + firstBuffer["uri"] = binFileName; if (this.unpackImages) { foreach (var bufferView in bufferViews) { - if ((int)bufferView["buffer"] == 0) + if (bufferView != null && bufferView.GetInt("buffer") == 0) { fileStream.Align(); var outputOffset = fileStream.Position; - var byteOffset = (long?)bufferView["byteOffset"] ?? 0; - var byteLength = (int)bufferView["byteLength"]; + var byteOffset = bufferView.GetInt("byteOffset", 0); + var byteLength = bufferView.GetInt("byteLength", 0); using (var viewStream = memoryMappedFile.CreateViewStream(binChunkOffset + byteOffset, byteLength, MemoryMappedFileAccess.Read)) { viewStream.CopyTo(fileStream, byteLength); @@ -287,11 +311,11 @@ private void ProcessBinFiles(JsonNode jsonNode, MemoryMappedFile memoryMappedFil } } - buffer["byteLength"] = fileStream.Length; + firstBuffer["byteLength"] = fileStream.Length; } else { - var byteLength = (int)buffer["byteLength"]; + var byteLength = firstBuffer.GetInt("byteLength", 0); using (var viewStream = memoryMappedFile.CreateViewStream(binChunkOffset, byteLength, MemoryMappedFileAccess.Read)) { viewStream.CopyTo(fileStream, byteLength); @@ -302,12 +326,20 @@ private void ProcessBinFiles(JsonNode jsonNode, MemoryMappedFile memoryMappedFil else { buffers.RemoveAt(0); - root["buffers"] = buffers; + node["buffers"] = buffers; foreach (var bufferView in bufferViews) { - var bufferIndex = (int)bufferView["buffer"]; - bufferView["buffer"] = bufferIndex - 1; + if (bufferView == null) + { + continue; + } + + var bufferIndex = bufferView.GetInt("buffer", -1); + if (bufferIndex > 0) + { + bufferView["buffer"] = bufferIndex - 1; + } } } } diff --git a/Source/Package/Package.appxmanifest b/Source/Package/Package.appxmanifest index a9423fe..2489b17 100644 --- a/Source/Package/Package.appxmanifest +++ b/Source/Package/Package.appxmanifest @@ -13,7 +13,7 @@ + Version="0.4.3.0" /> diff --git a/Source/Package/Package.wapproj b/Source/Package/Package.wapproj index d3d2751..53ec9b6 100644 --- a/Source/Package/Package.wapproj +++ b/Source/Package/Package.wapproj @@ -36,7 +36,7 @@ 13b11981-bd9f-4769-b89e-84271568c258 - 10.0.26100.0 + 10.0.22621.0 10.0.17763.0 net8.0-windows$(TargetPlatformVersion);$(AssetTargetFallback) en-US diff --git a/Source/Tests/.gitattributes b/Source/Tests/.gitattributes new file mode 100644 index 0000000..a172cd4 --- /dev/null +++ b/Source/Tests/.gitattributes @@ -0,0 +1,4 @@ +External/**/*.exe filter=lfs diff=lfs merge=lfs -text +Assets/**/*.glb filter=lfs diff=lfs merge=lfs -text +Assets/**/*.png filter=lfs diff=lfs merge=lfs -text +Assets/**/*.jpg filter=lfs diff=lfs merge=lfs -text diff --git a/Source/Tests/Assets/Box/LICENSE.md b/Source/Tests/Assets/Box/LICENSE.md new file mode 100644 index 0000000..8478783 --- /dev/null +++ b/Source/Tests/Assets/Box/LICENSE.md @@ -0,0 +1,15 @@ +# LICENSE file for the model: Box + +All files in this directory tree are licensed as indicated below. + +* All files directly associated with the model including all text, image and binary files: + + * [CC BY 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"] + +* This file and all other metadocumentation files including "metadata.json": + + * [Creative Commons Attribtution 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"] + +Full license text of these licenses are available at the links above + +#### Generated by modelmetadata \ No newline at end of file diff --git a/Source/Tests/Assets/Box/glTF-Binary/Box.glb b/Source/Tests/Assets/Box/glTF-Binary/Box.glb new file mode 100644 index 0000000..5445f06 --- /dev/null +++ b/Source/Tests/Assets/Box/glTF-Binary/Box.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed52f7192b8311d700ac0ce80644e3852cd01537e4d62241b9acba023da3d54e +size 1664 diff --git a/Source/Tests/Assets/Box/glTF-Embedded/Box.gltf b/Source/Tests/Assets/Box/glTF-Embedded/Box.gltf new file mode 100644 index 0000000..ea0e8ad --- /dev/null +++ b/Source/Tests/Assets/Box/glTF-Embedded/Box.gltf @@ -0,0 +1,142 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.800000011920929, + 0.0, + 0.0, + 1.0 + ], + "metallicFactor": 0.0 + }, + "name": "Red" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 648, + "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" + } + ] +} diff --git a/Source/Tests/Assets/Box/glTF/Box.gltf b/Source/Tests/Assets/Box/glTF/Box.gltf new file mode 100644 index 0000000..7f603f0 --- /dev/null +++ b/Source/Tests/Assets/Box/glTF/Box.gltf @@ -0,0 +1,142 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.800000011920929, + 0.0, + 0.0, + 1.0 + ], + "metallicFactor": 0.0 + }, + "name": "Red" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 648, + "uri": "Box0.bin" + } + ] +} diff --git a/Source/Tests/Assets/Box/glTF/Box0.bin b/Source/Tests/Assets/Box/glTF/Box0.bin new file mode 100644 index 0000000..d7798ab Binary files /dev/null and b/Source/Tests/Assets/Box/glTF/Box0.bin differ diff --git a/Source/Tests/Assets/BoxTextured/LICENSE.md b/Source/Tests/Assets/BoxTextured/LICENSE.md new file mode 100644 index 0000000..766c3c9 --- /dev/null +++ b/Source/Tests/Assets/BoxTextured/LICENSE.md @@ -0,0 +1,17 @@ +# LICENSE file for the model: Box Textured + +All files in this directory tree are licensed as indicated below. + +* All files directly associated with the model including all text, image and binary files: + + * [CC-BY 4.0 International with Trademark Limitations]("") [SPDX license identifier: "LicenseRef-CC-BY-TM"] + + * [Cesium Trademark or Logo]("") [SPDX license identifier: "LicenseRef-LegalMark-Cesium"] + +* This file and all other metadocumentation files including "metadata.json": + + * [Creative Commons Attribtution 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"] + +Full license text of these licenses are available at the links above + +#### Generated by modelmetadata \ No newline at end of file diff --git a/Source/Tests/Assets/BoxTextured/glTF-Binary/BoxTextured.glb b/Source/Tests/Assets/BoxTextured/glTF-Binary/BoxTextured.glb new file mode 100644 index 0000000..6524740 --- /dev/null +++ b/Source/Tests/Assets/BoxTextured/glTF-Binary/BoxTextured.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d055d2d56a492d1b9302de6e733046b625cf51e5f2a3090bd3a8c11acc93c17 +size 6540 diff --git a/Source/Tests/Assets/BoxTextured/glTF-Embedded/BoxTextured.gltf b/Source/Tests/Assets/BoxTextured/glTF-Embedded/BoxTextured.gltf new file mode 100644 index 0000000..70fb0a7 --- /dev/null +++ b/Source/Tests/Assets/BoxTextured/glTF-Embedded/BoxTextured.gltf @@ -0,0 +1,181 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "name": "Texture" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "data:image/png;base64,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" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AADAQAAAAAAAAKBAAAAAAAAAwED+/38/AACgQP7/fz8AAIBAAAAAAAAAoEAAAAAAAACAQAAAgD8AAKBAAACAPwAAAEAAAAAAAACAPwAAAAAAAABAAACAPwAAgD8AAIA/AABAQAAAAAAAAIBAAAAAAAAAQEAAAIA/AACAQAAAgD8AAEBAAAAAAAAAAEAAAAAAAABAQAAAgD8AAABAAACAPwAAAAAAAAAAAAAAAP7/fz8AAIA/AAAAAAAAgD/+/38/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" + } + ] +} diff --git a/Source/Tests/Assets/BoxTextured/glTF/BoxTextured.gltf b/Source/Tests/Assets/BoxTextured/glTF/BoxTextured.gltf new file mode 100644 index 0000000..eff658f --- /dev/null +++ b/Source/Tests/Assets/BoxTextured/glTF/BoxTextured.gltf @@ -0,0 +1,181 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "name": "Texture" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "CesiumLogoFlat.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "BoxTextured0.bin" + } + ] +} diff --git a/Source/Tests/Assets/BoxTextured/glTF/BoxTextured0.bin b/Source/Tests/Assets/BoxTextured/glTF/BoxTextured0.bin new file mode 100644 index 0000000..d2a7355 Binary files /dev/null and b/Source/Tests/Assets/BoxTextured/glTF/BoxTextured0.bin differ diff --git a/Source/Tests/Assets/BoxTextured/glTF/CesiumLogoFlat.png b/Source/Tests/Assets/BoxTextured/glTF/CesiumLogoFlat.png new file mode 100644 index 0000000..1674d5e --- /dev/null +++ b/Source/Tests/Assets/BoxTextured/glTF/CesiumLogoFlat.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89b210e0ba3c0a1ac10c93f8881b62e24f220731643215a68568a72381d3313e +size 4333 diff --git a/Source/Tests/Assets/LightsIES/Example.gltf b/Source/Tests/Assets/LightsIES/Example.gltf new file mode 100644 index 0000000..bd60730 --- /dev/null +++ b/Source/Tests/Assets/LightsIES/Example.gltf @@ -0,0 +1,164 @@ +{ + "asset": { + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1, + 2 + ] + }, + { + "mesh": 0, + "scale": [ + 7.5, + 7.5, + 0.1 + ] + }, + { + "extensions": { + "EXT_lights_ies": { + "light": 0, + "color": [ + 0.181, + 0.485, + 0 + ] + } + }, + "translation": [ + 0, + 3, + 0.15 + ], + "rotation": [ + -0.7071068, + 0, + 0, + 0.7071068 + ] + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 1.0, + 1.0, + 1.0, + 1.0 + ], + "metallicFactor": 0.0 + }, + "name": "White" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 648, + "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" + } + ], + "extensions": { + "EXT_lights_ies": { + "lights": [ + { + "uri": "LightProfile.ies" + } + ] + } + }, + "extensionsUsed": [ + "EXT_lights_ies" + ] +} diff --git a/Source/Tests/Assets/LightsIES/Example_bufferView.gltf b/Source/Tests/Assets/LightsIES/Example_bufferView.gltf new file mode 100644 index 0000000..8fe5a63 --- /dev/null +++ b/Source/Tests/Assets/LightsIES/Example_bufferView.gltf @@ -0,0 +1,173 @@ +{ + "asset": { + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1, + 2 + ] + }, + { + "mesh": 0, + "scale": [ + 7.5, + 7.5, + 0.1 + ] + }, + { + "extensions": { + "EXT_lights_ies": { + "light": 0, + "color": [ + 0.181, + 0.485, + 0 + ] + } + }, + "translation": [ + 0, + 3, + 0.15 + ], + "rotation": [ + -0.7071068, + 0, + 0, + 0.7071068 + ] + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 1.0, + 1.0, + 1.0, + 1.0 + ], + "metallicFactor": 0.0 + }, + "name": "White" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 1, + "byteLength": 222 + } + ], + "buffers": [ + { + "byteLength": 648, + "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" + }, + { + "byteLength": 222, + "uri": "data:application/octet-stream;base64,SUVTOkxNLTYzLTIwMTkKW1RFU1RdIEV4YW1wbGUgUHJvZmlsZQpbVEVTVExBQl0gTlZJRElBCltJU1NVRURBVEVdIDAxLUpBTi0yMDIzCltNQU5VRkFDXSBOVklESUEKVElMVD1OT05FCjEgLTEgMSAxMCAxIDEgMSAtMC4yIC0wLjIgMAoxLjAgMS4xMDAwMSAyNQowIDEwIDIwIDMwIDQwIDUwIDYwIDcwIDgwIDkwCjAKODUwMCA1MDAwIDMyNTAgNTI1MCAyNzUwIDE1MDAgMjAwIDUwIDEwIDAK" + } + ], + "extensions": { + "EXT_lights_ies": { + "lights": [ + { + "bufferView": 2, + "mimeType": "application/x-ies-lm-63" + } + ] + } + }, + "extensionsUsed": [ + "EXT_lights_ies" + ] +} diff --git a/Source/Tests/Assets/LightsIES/Example_dataUri.gltf b/Source/Tests/Assets/LightsIES/Example_dataUri.gltf new file mode 100644 index 0000000..6519100 --- /dev/null +++ b/Source/Tests/Assets/LightsIES/Example_dataUri.gltf @@ -0,0 +1,164 @@ +{ + "asset": { + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1, + 2 + ] + }, + { + "mesh": 0, + "scale": [ + 7.5, + 7.5, + 0.1 + ] + }, + { + "extensions": { + "EXT_lights_ies": { + "light": 0, + "color": [ + 0.181, + 0.485, + 0 + ] + } + }, + "translation": [ + 0, + 3, + 0.15 + ], + "rotation": [ + -0.7071068, + 0, + 0, + 0.7071068 + ] + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 1.0, + 1.0, + 1.0, + 1.0 + ], + "metallicFactor": 0.0 + }, + "name": "White" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 648, + "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" + } + ], + "extensions": { + "EXT_lights_ies": { + "lights": [ + { + "uri": "data:application/x-ies-lm-63;base64,SUVTOkxNLTYzLTIwMTkNCltURVNUXSBFeGFtcGxlIFByb2ZpbGUNCltURVNUTEFCXSBOVklESUENCltJU1NVRURBVEVdIDAxLUpBTi0yMDIzDQpbTUFOVUZBQ10gTlZJRElBDQpUSUxUPU5PTkUNCjEgLTEgMSAxMCAxIDEgMSAtMC4yIC0wLjIgMA0KMS4wIDEuMTAwMDEgMjUNCjAgMTAgMjAgMzAgNDAgNTAgNjAgNzAgODAgOTANCjANCjg1MDAgNTAwMCAzMjUwIDUyNTAgMjc1MCAxNTAwIDIwMCA1MCAxMCAw" + } + ] + } + }, + "extensionsUsed": [ + "EXT_lights_ies" + ] +} diff --git a/Source/Tests/Assets/LightsIES/LightProfile.ies b/Source/Tests/Assets/LightsIES/LightProfile.ies new file mode 100644 index 0000000..c7cdeaa --- /dev/null +++ b/Source/Tests/Assets/LightsIES/LightProfile.ies @@ -0,0 +1,11 @@ +IES:LM-63-2019 +[TEST] Example Profile +[TESTLAB] NVIDIA +[ISSUEDATE] 01-JAN-2023 +[MANUFAC] NVIDIA +TILT=NONE +1 -1 1 10 1 1 1 -0.2 -0.2 0 +1.0 1.10001 25 +0 10 20 30 40 50 60 70 80 90 +0 +8500 5000 3250 5250 2750 1500 200 50 10 0 diff --git a/Source/Tests/Core.cs b/Source/Tests/Core.cs new file mode 100644 index 0000000..2ddcd08 --- /dev/null +++ b/Source/Tests/Core.cs @@ -0,0 +1,101 @@ +using System.Diagnostics; +using System.Reflection; + +namespace glTF +{ + [TestClass] + public sealed class Core(TestContext testContext) + { + private static readonly string ValidatorExePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "gltf_validator.exe"); + + private readonly CancellationToken cancellationToken = testContext.CancellationTokenSource.Token; + private readonly string resultsDirectoryPath = Path.Combine(testContext.TestRunDirectory!, testContext.TestName!); + private readonly string modelsDirectoryPath = Path.GetFullPath(Path.Combine(testContext.TestRunDirectory!, @"..\..\..\..\Source\Tests\Assets")); + + public async Task ValidateAsync(string filePath) + { + using var process = Process.Start(new ProcessStartInfo(ValidatorExePath, [filePath]) + { + RedirectStandardError = true, + RedirectStandardOutput = true, + })!; + + await process.WaitForExitAsync(this.cancellationToken); + if (process.ExitCode != 0) + { + throw new Exception("Validation failed"); + } + } + + private string Pack(string filePath) + { + var fileName = Path.GetFileNameWithoutExtension(filePath); + var inputFilePath = Path.Combine(this.modelsDirectoryPath, filePath); + var outputFilePath = Path.Combine(this.resultsDirectoryPath, $"{fileName}.glb"); + Packer.Pack(inputFilePath, outputFilePath); + return outputFilePath; + } + + private string Unpack(string filePath) + { + var fileName = Path.GetFileNameWithoutExtension(filePath); + var inputFilePath = Path.Combine(this.modelsDirectoryPath, filePath); + var outputDirectoryPath = Path.Combine(this.resultsDirectoryPath, fileName); + Unpacker.Unpack(inputFilePath, outputDirectoryPath, true); + return Path.Combine(outputDirectoryPath, $"{fileName}.gltf"); + } + + [TestMethod] + public async Task Pack_Box() + { + var outputFilePath = this.Pack(@"Box\glTF\Box.gltf"); + await this.ValidateAsync(outputFilePath); + } + + [TestMethod] + public async Task Pack_Box_Embedded() + { + var outputFilePath = this.Pack(@"Box\glTF-Embedded\Box.gltf"); + await this.ValidateAsync(outputFilePath); + } + + [TestMethod] + public async Task Pack_BoxTextured() + { + var outputFilePath = this.Pack(@"BoxTextured\glTF\BoxTextured.gltf"); + await this.ValidateAsync(outputFilePath); + } + + [TestMethod] + public async Task Unpack_Box() + { + var outputFilePath = this.Unpack(@"Box\glTF-Binary\Box.glb"); + await this.ValidateAsync(outputFilePath); + } + + [TestMethod] + public async Task Unpack_BoxTextured() + { + var outputFilePath = this.Unpack(@"BoxTextured\glTF-Binary\BoxTextured.glb"); + await this.ValidateAsync(outputFilePath); + } + + [TestMethod] + public async Task Pack_Unpack_BoxTextured_Embedded() + { + var outputFilePath = this.Unpack(this.Pack(@"BoxTextured\glTF-Embedded\BoxTextured.gltf")); + await this.ValidateAsync(outputFilePath); + } + + [TestMethod] + public async Task Pack_Unpack_LightsIES() + { + string[] filePaths = [@"LightsIES\Example.gltf", @"LightsIES\Example_bufferview.gltf", @"LightsIES\Example_dataUri.gltf"]; + foreach (var filePath in filePaths) + { + var outputFilePath = this.Unpack(this.Pack(filePath)); + await this.ValidateAsync(outputFilePath); + } + } + } +} diff --git a/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/LICENSE b/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/NOTICES b/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/NOTICES new file mode 100644 index 0000000..ec35524 --- /dev/null +++ b/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/NOTICES @@ -0,0 +1,435 @@ +Dart SDK + +Copyright 2012, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +args + +Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +collection + +Copyright 2015, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +isolate + +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +meta + +Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +path + +Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +source_span + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +string_scanner + +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +term_glyph + +Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +vector_math + +Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2013 Andrew Magill + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +-------------------------------------------------------------------------------- + +yaml + +Copyright (c) 2014, the Dart project authors. +Copyright (c) 2006, Kirill Simonov. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +-------------------------------------------------------------------------------- + +node_preamble + +The MIT License (MIT) + +Copyright (c) 2015 Michael Bullington + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=== + +Copyright 2012, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------------------- + +PrismJS + +MIT LICENSE + +Copyright (c) 2012 Lea Verou + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/docs/config-example.yaml b/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/docs/config-example.yaml new file mode 100644 index 0000000..da4d7d5 --- /dev/null +++ b/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/docs/config-example.yaml @@ -0,0 +1,14 @@ +# Maximum number of issues, 0 means unlimited +max-issues: 10 + +# List of ignored issues +ignore: + - UNEXPECTED_PROPERTY + +# List of only issues to consider. Cannot be used along with 'ignore'. +only: + - ACCESSOR_INVALID_FLOAT + +# Map of overridden severities. 0 - Error, 1 - Warning, 2 - Info, 3 - Hint +override: + ACCESSOR_INDEX_TRIANGLE_DEGENERATE: 0 \ No newline at end of file diff --git a/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/docs/validation.schema.json b/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/docs/validation.schema.json new file mode 100644 index 0000000..fad78a2 --- /dev/null +++ b/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/docs/validation.schema.json @@ -0,0 +1,266 @@ +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Validation Report", + "type": "object", + "description": "Output of glTF-Validator", + "definitions": { + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "positiveInteger": { + "type": "integer", + "exclusiveMinimum": 0 + } + }, + "properties": { + "uri": { + "type": "string", + "format": "uri-reference", + "description": "URI of validated asset." + }, + "mimeType": { + "description": "MIME type of validated asset. Undefined when file format is not recognized.", + "oneOf": [ + { + "const": "model/gltf+json", + "description": "glTF asset in plain text form." + }, + { + "const": "model/gltf-binary", + "description": "glTF asset in GLB container." + } + ] + }, + "validatorVersion": { + "type": "string", + "description": "Version string of glTF-Validator. Must follow semver syntax." + }, + "validatedAt": { + "description": "UTC timestamp of validation time.", + "type": "string", + "format": "date-time" + }, + "issues": { + "type": "object", + "properties": { + "numErrors": { + "$ref": "#/definitions/nonNegativeInteger" + }, + "numWarnings": { + "$ref": "#/definitions/nonNegativeInteger" + }, + "numInfos": { + "$ref": "#/definitions/nonNegativeInteger" + }, + "numHints": { + "$ref": "#/definitions/nonNegativeInteger" + }, + "messages": { + "type": "array", + "items": { + "properties": { + "code": { + "type": "string" + }, + "severity": { + "oneOf": [ + { + "const": 0, + "description": "Error" + }, + { + "const": 1, + "description": "Warning" + }, + { + "const": 2, + "description": "Information" + }, + { + "const": 3, + "description": "Hint" + } + ] + }, + "pointer": { + "description": "JSON Pointer to the object causing the issue.", + "type": "string", + "format": "json-pointer" + }, + "offset": { + "description": "Byte offset in GLB file. Applicable only to GLB issues.", + "$ref": "#/definitions/nonNegativeInteger" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "severity", + "message" + ], + "oneOf": [ + { + "required": [ + "pointer" + ] + }, + { + "required": [ + "offset" + ] + } + ] + } + }, + "truncated": { + "type": "boolean", + "description": "Indicates that validation output is incomplete due to too many messages." + } + }, + "required": [ + "numErrors", + "numWarnings", + "numInfos", + "numHints", + "messages", + "truncated" + ] + }, + "info": { + "type": "object", + "description": "An object containing various metrics about the validated asset. May be undefined for invalid inputs.", + "properties": { + "version": { + "type": "string", + "description": "The glTF version that this asset targets.", + "pattern": "^[0-9]+\\.[0-9]+$" + }, + "minVersion": { + "type": "string", + "description": "The minimum glTF version that this asset targets.", + "pattern": "^[0-9]+\\.[0-9]+$" + }, + "generator": { + "type": "string", + "description": "Tool that generated this glTF model." + }, + "extensionsUsed": { + "type": "array", + "description": "Names of glTF extensions used somewhere in this asset.", + "items": { + "type": "string" + }, + "uniqueItems": true, + "minItems": 1 + }, + "extensionsRequired": { + "type": "array", + "description": "Names of glTF extensions required to properly load this asset.", + "items": { + "type": "string" + }, + "uniqueItems": true, + "minItems": 1 + }, + "resources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "pointer": { + "type": "string", + "format": "json-pointer" + }, + "storage": { + "oneOf": [ + { + "const": "data-uri", + "description": "Resource is stored as Data-URI." + }, + { + "const": "buffer-view", + "description": "Resource is stored within glTF buffer and accessed via bufferView." + }, + { + "const": "glb", + "description": "Resource is stored in binary chunk of GLB container." + }, + { + "const": "external", + "description": "Resource is stored externally." + } + ] + }, + "mimeType": { + "type": "string" + }, + "byteLength": { + "$ref": "#/definitions/positiveInteger", + "description": "Byte length of the resource. Undefined when the resource wasn't available." + }, + "uri": { + "type": "string", + "format": "uri-reference", + "description": "URI. Defined only for external resources." + }, + "image": { + "type": "object", + "description": "Image-specific metadata.", + "properties": { + "width": { + "$ref": "#/definitions/positiveInteger" + }, + "height": { + "$ref": "#/definitions/positiveInteger" + }, + "format": { + "enum": [ + "rgb", + "rgba", + "luminance", + "luminance-alpha" + ] + }, + "primaries": { + "enum": [ + "srgb", + "custom" + ] + }, + "transfer": { + "enum": [ + "linear", + "srgb", + "custom" + ] + }, + "bits": { + "$ref": "#/definitions/positiveInteger" + } + }, + "required": [ + "width", + "height" + ] + } + } + }, + "required": [ + "pointer" + ], + "minItems": 1 + } + }, + "required": [ + "version" + ] + } + }, + "required": [ + "validatorVersion", + "issues" + ] +} \ No newline at end of file diff --git a/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/gltf_validator.exe b/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/gltf_validator.exe new file mode 100644 index 0000000..77dcc45 --- /dev/null +++ b/Source/Tests/External/gltf_validator-2.0.0-dev.3.10-win64/gltf_validator.exe @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4388a152ff90b68c6430ae03862e05e257a9d50a500ed7d0eb1cd420dc75ff96 +size 5520896 diff --git a/Source/Tests/MSTestSettings.cs b/Source/Tests/MSTestSettings.cs new file mode 100644 index 0000000..aaf278c --- /dev/null +++ b/Source/Tests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/Source/Tests/Tests.csproj b/Source/Tests/Tests.csproj new file mode 100644 index 0000000..dea6873 --- /dev/null +++ b/Source/Tests/Tests.csproj @@ -0,0 +1,38 @@ + + + + net8.0 + latest + enable + enable + glTF + + + + + + + + + + + + %(RecursiveDir)%(Filename)%(Extension) + PreserveNewest + + + + + + + + + + + + + + + + + diff --git a/Source/glTF-Shell-Extensions.sln b/Source/glTF-Shell-Extensions.sln index 4e3504d..499fa78 100644 --- a/Source/glTF-Shell-Extensions.sln +++ b/Source/glTF-Shell-Extensions.sln @@ -5,10 +5,14 @@ VisualStudioVersion = 17.11.35312.102 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerCommand", "ExplorerCommand\ExplorerCommand.vcxproj", "{294B1862-6E77-4F1E-A542-85F1FA7F7C05}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "glTF", "glTF\glTF.csproj", "{DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}" -EndProject Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Package", "Package\Package.wapproj", "{13B11981-BD9F-4769-B89E-84271568C258}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{87EBE349-E634-4590-AC30-B4C5D15BDD60}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{3B67A8DD-5B47-4D54-BDB1-64523EACCA94}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "glTF", "glTF\glTF.csproj", "{582200F6-950A-4AA2-B178-8CD4EE6F898C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -31,18 +35,6 @@ Global {294B1862-6E77-4F1E-A542-85F1FA7F7C05}.Release|x64.Build.0 = Release|x64 {294B1862-6E77-4F1E-A542-85F1FA7F7C05}.Release|x86.ActiveCfg = Release|Win32 {294B1862-6E77-4F1E-A542-85F1FA7F7C05}.Release|x86.Build.0 = Release|Win32 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Debug|ARM64.Build.0 = Debug|ARM64 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Debug|x64.ActiveCfg = Debug|x64 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Debug|x64.Build.0 = Debug|x64 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Debug|x86.ActiveCfg = Debug|x86 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Debug|x86.Build.0 = Debug|x86 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Release|ARM64.ActiveCfg = Release|ARM64 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Release|ARM64.Build.0 = Release|ARM64 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Release|x64.ActiveCfg = Release|x64 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Release|x64.Build.0 = Release|x64 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Release|x86.ActiveCfg = Release|x86 - {DB2FA8BC-AE9F-43C5-9EC3-E1E8F7DD0FE8}.Release|x86.Build.0 = Release|x86 {13B11981-BD9F-4769-B89E-84271568C258}.Debug|ARM64.ActiveCfg = Debug|ARM64 {13B11981-BD9F-4769-B89E-84271568C258}.Debug|ARM64.Build.0 = Debug|ARM64 {13B11981-BD9F-4769-B89E-84271568C258}.Debug|ARM64.Deploy.0 = Debug|ARM64 @@ -61,6 +53,42 @@ Global {13B11981-BD9F-4769-B89E-84271568C258}.Release|x86.ActiveCfg = Release|x86 {13B11981-BD9F-4769-B89E-84271568C258}.Release|x86.Build.0 = Release|x86 {13B11981-BD9F-4769-B89E-84271568C258}.Release|x86.Deploy.0 = Release|x86 + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Debug|ARM64.Build.0 = Debug|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Debug|x64.ActiveCfg = Debug|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Debug|x64.Build.0 = Debug|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Debug|x86.ActiveCfg = Debug|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Debug|x86.Build.0 = Debug|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Release|ARM64.ActiveCfg = Release|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Release|ARM64.Build.0 = Release|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Release|x64.ActiveCfg = Release|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Release|x64.Build.0 = Release|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Release|x86.ActiveCfg = Release|Any CPU + {87EBE349-E634-4590-AC30-B4C5D15BDD60}.Release|x86.Build.0 = Release|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Debug|ARM64.Build.0 = Debug|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Debug|x64.ActiveCfg = Debug|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Debug|x64.Build.0 = Debug|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Debug|x86.ActiveCfg = Debug|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Debug|x86.Build.0 = Debug|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Release|ARM64.ActiveCfg = Release|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Release|ARM64.Build.0 = Release|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Release|x64.ActiveCfg = Release|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Release|x64.Build.0 = Release|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Release|x86.ActiveCfg = Release|Any CPU + {3B67A8DD-5B47-4D54-BDB1-64523EACCA94}.Release|x86.Build.0 = Release|Any CPU + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Debug|ARM64.Build.0 = Debug|ARM64 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Debug|x64.ActiveCfg = Debug|x64 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Debug|x64.Build.0 = Debug|x64 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Debug|x86.ActiveCfg = Debug|x86 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Debug|x86.Build.0 = Debug|x86 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Release|ARM64.ActiveCfg = Release|ARM64 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Release|ARM64.Build.0 = Release|ARM64 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Release|x64.ActiveCfg = Release|x64 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Release|x64.Build.0 = Release|x64 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Release|x86.ActiveCfg = Release|x86 + {582200F6-950A-4AA2-B178-8CD4EE6F898C}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/glTF/App.manifest b/Source/glTF/App.manifest index 6e3532d..f11d757 100644 --- a/Source/glTF/App.manifest +++ b/Source/glTF/App.manifest @@ -1,6 +1,6 @@ - + diff --git a/Source/glTF/Core/MimeType.cs b/Source/glTF/Core/MimeType.cs deleted file mode 100644 index f06e328..0000000 --- a/Source/glTF/Core/MimeType.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.IO; - -namespace glTF -{ - internal class MimeType - { - public static string ToFileExtension(string mimeType) - { - switch (mimeType) - { - case "image/png": - return ".png"; - case "image/jpeg": - return ".jpg"; - case "image/vnd-ms.dds": - return ".dds"; - case "image/ktx2": - return ".ktx2"; - case "image/webp": - return ".webp"; - } - - throw new InvalidDataException($"Unsupported mime type: {mimeType}"); - } - - public static string FromFileExtension(string fileExtension) - { - switch (fileExtension.ToLower()) - { - case ".png": - return "image/png"; - case ".jpg": - case ".jpeg": - return "image/jpeg"; - case ".dds": - return "image/vnd-ms.dds"; - case ".ktx2": - return "image/ktx2"; - case ".webp": - return "image/webp"; - } - - throw new InvalidDataException($"Unsupported file extension: {fileExtension}"); - } - } -} diff --git a/Source/glTF/Core/Packer.cs b/Source/glTF/Core/Packer.cs deleted file mode 100644 index bcb5377..0000000 --- a/Source/glTF/Core/Packer.cs +++ /dev/null @@ -1,190 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.MemoryMappedFiles; -using System.Text.Json; -using System.Text.Json.Nodes; - -namespace glTF -{ - internal class Packer - { - public static void Pack(string inputFilePath, string outputFilePath) - { - var inputDirectoryPath = Path.GetDirectoryName(inputFilePath); - - JsonNode jsonNode; - using (var jsonStream = File.OpenRead(inputFilePath)) - { - jsonNode = JsonNode.Parse(jsonStream); - } - - var position = 0; - - var memoryMappedFiles = new Dictionary(); - var viewStreams = new List(); - - var buffers = jsonNode["buffers"]?.AsArray(); - var bufferViews = jsonNode["bufferViews"]?.AsArray(); - var images = jsonNode["images"]?.AsArray(); - - if (buffers != null) - { - for (var index = buffers.Count - 1; index >= 0; index--) - { - var buffer = buffers[index]; - var uri = (string)buffer["uri"]; - if (uri != null && Uri.IsWellFormedUriString(uri, UriKind.Relative)) - { - foreach (var bufferView in bufferViews) - { - var bufferIndex = (int)bufferView["buffer"]; - if (bufferIndex == index) - { - bufferView["buffer"] = -1; - - var byteOffset = (int?)bufferView["byteOffset"] ?? 0; - bufferView.SetValue("byteOffset", position + byteOffset, 0); - } - } - - var filePath = Path.Combine(inputDirectoryPath, uri); - if (!memoryMappedFiles.TryGetValue(filePath, out MemoryMappedFile memoryMappedFile)) - { - memoryMappedFile = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open); - memoryMappedFiles.Add(filePath, memoryMappedFile); - } - - var fileLength = Tools.GetFileLength(filePath); - viewStreams.Add(memoryMappedFile.CreateViewStream(0, fileLength, MemoryMappedFileAccess.Read)); - - position += fileLength; - position = Tools.Align(position); - - buffers.RemoveAt(index); - } - } - } - - if (images != null) - { - foreach (var image in images) - { - var uri = (string)image["uri"]; - if (uri != null && Uri.IsWellFormedUriString(uri, UriKind.Relative)) - { - var filePath = Path.Combine(inputDirectoryPath, uri); - if (!memoryMappedFiles.TryGetValue(filePath, out MemoryMappedFile memoryMappedFile)) - { - memoryMappedFile = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open); - memoryMappedFiles.Add(filePath, memoryMappedFile); - } - - var fileLength = Tools.GetFileLength(filePath); - viewStreams.Add(memoryMappedFile.CreateViewStream(0, fileLength, MemoryMappedFileAccess.Read)); - - image.AsObject().Remove("uri"); - image["bufferView"] = bufferViews.Count; - image["mimeType"] = MimeType.FromFileExtension(Path.GetExtension(uri)); - - position = Tools.Align(position); - - var bufferView = new JsonObject - { - ["buffer"] = -1, - ["byteLength"] = fileLength - }; - - bufferView.SetValue("byteOffset", position, 0); - bufferViews.Add((JsonNode)bufferView); - - position += fileLength; - } - } - } - - if (viewStreams.Count != 0) - { - if (buffers == null) - { - buffers = new JsonArray(); - jsonNode["buffers"] = buffers; - } - - buffers.Insert(0, new JsonObject - { - ["byteLength"] = position - }); - - foreach (var bufferView in bufferViews) - { - var bufferIndex = (int)bufferView["buffer"]; - bufferView["buffer"] = bufferIndex + 1; - } - } - - using (var fileStream = File.Create(outputFilePath)) - using (var binaryWriter = new BinaryWriter(fileStream)) - { - binaryWriter.Write(Binary.Magic); - binaryWriter.Write(Binary.Version); - - var chunksPosition = binaryWriter.BaseStream.Position; - - binaryWriter.Write(0U); // length - - var jsonChunkPosition = binaryWriter.BaseStream.Position; - - binaryWriter.Write(0U); // json chunk length - binaryWriter.Write(Binary.ChunkFormatJson); - - using (var jsonTextWriter = new Utf8JsonWriter(binaryWriter.BaseStream)) - { - jsonNode.WriteTo(jsonTextWriter); - } - - binaryWriter.BaseStream.Align(0x20); - var jsonChunkLength = checked((uint)(binaryWriter.BaseStream.Length - jsonChunkPosition)) - Binary.ChunkHeaderLength; - - binaryWriter.BaseStream.Seek(jsonChunkPosition, SeekOrigin.Begin); - binaryWriter.Write(jsonChunkLength); - - if (viewStreams.Count != 0) - { - binaryWriter.BaseStream.Seek(0, SeekOrigin.End); - var binChunkPosition = binaryWriter.BaseStream.Position; - - binaryWriter.Write(0); // bin chunk length - binaryWriter.Write(Binary.ChunkFormatBin); - - foreach (var viewStream in viewStreams) - { - binaryWriter.BaseStream.Align(); - viewStream.CopyTo(binaryWriter.BaseStream); - } - - binaryWriter.BaseStream.Align(0x20); - var binChunkLength = checked((uint)(binaryWriter.BaseStream.Length - binChunkPosition)) - Binary.ChunkHeaderLength; - - binaryWriter.BaseStream.Seek(binChunkPosition, SeekOrigin.Begin); - binaryWriter.Write(binChunkLength); - } - - var length = checked((uint)binaryWriter.BaseStream.Length); - - binaryWriter.BaseStream.Seek(chunksPosition, SeekOrigin.Begin); - binaryWriter.Write(length); - } - - foreach (var viewStream in viewStreams) - { - viewStream.Dispose(); - } - - foreach (var memoryMappedFile in memoryMappedFiles.Values) - { - memoryMappedFile.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Source/glTF/Extensions/JsonExtensions.cs b/Source/glTF/Extensions/JsonExtensions.cs deleted file mode 100644 index 63907bb..0000000 --- a/Source/glTF/Extensions/JsonExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Text.Json.Nodes; - -namespace glTF -{ - internal static class JsonExtensions - { - public static void SetValue(this JsonNode jsonNode, string propertyName, int value, int defaultValue) - { - if (value.Equals(defaultValue)) - { - jsonNode.AsObject().Remove(propertyName); - } - else - { - jsonNode[propertyName] = value; - } - } - } -} diff --git a/Source/glTF/UI/PackWindow.xaml b/Source/glTF/UI/PackWindow.xaml index d66a8c2..899e564 100644 --- a/Source/glTF/UI/PackWindow.xaml +++ b/Source/glTF/UI/PackWindow.xaml @@ -6,4 +6,5 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> + diff --git a/Source/glTF/UI/Win32.cs b/Source/glTF/UI/Win32.cs index 813e7b0..e52ac5b 100644 --- a/Source/glTF/UI/Win32.cs +++ b/Source/glTF/UI/Win32.cs @@ -37,5 +37,4 @@ public struct MONITORINFO [DllImport("user32.dll", SetLastError = true)] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint flags); } - } diff --git a/Source/glTF/UI/WindowExtensions.cs b/Source/glTF/UI/WindowExtensions.cs index 96371d4..a754833 100644 --- a/Source/glTF/UI/WindowExtensions.cs +++ b/Source/glTF/UI/WindowExtensions.cs @@ -39,7 +39,15 @@ public static void ApplySettings(this Window window) public static async Task ShowErrorDialogAsync(this Window window, string message, string title) { - var dialog = new ContentDialog() + if (window.Content.XamlRoot == null) + { + var taskCompletionSource = new TaskCompletionSource(); + (window.Content as FrameworkElement).Loaded += (sender, e) => taskCompletionSource.SetResult(); + window.Activate(); + await taskCompletionSource.Task; + } + + var dialog = new ContentDialog { XamlRoot = window.Content.XamlRoot, Title = title, diff --git a/Source/glTF/glTF.csproj b/Source/glTF/glTF.csproj index cda3c2f..b2e2478 100644 --- a/Source/glTF/glTF.csproj +++ b/Source/glTF/glTF.csproj @@ -1,7 +1,7 @@  WinExe - net8.0-windows10.0.26100.0 + net8.0-windows10.0.22621.0 10.0.17763.0 glTF App.manifest @@ -21,4 +21,8 @@ + + + + \ No newline at end of file