diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b66e31c7..c613b1b14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ - Remove the BBox3 validator. - `RoutingConfiguration.MainLayer` and `RoutingConfiguration.LayerPenalty` are set obsolete. - `EdgeInfo.HasVerticalChange` is set obsolete. -- `AdaptiveGraphRouting.RenderElements` is no longer paint hint lines in two different colors. Instead regular edges are paint into three groups. Weights are included to additional properties of produced elements. +- `AdaptiveGraphRouting.RenderElements` is no longer paint hint lines in two different colors. Instead regular edges are paint into three groups. Weights are included to additional properties of produced elements. ### Fixed @@ -27,6 +27,8 @@ - Fix `Obstacle.FromLine` if line is vertical and start point is positioned higher than end. - Materials exported to glTF now have their `RoughnessFactor` set correctly. - Materials exported to glTF no longer use the `KHR_materials_pbrSpecularGlossiness` extension, as this extension is being sunset in favor of `KHR_materials_specular` and `KHR_materials_ior`. +- Gltfs that are merged that require additional extensions will also merge their extensions. +- Don't try to save test models that have no name, they can interfere with each other because they want to save to the same file. ## 1.3.0 diff --git a/Elements/src/Serialization/glTF/GltfExtensions.cs b/Elements/src/Serialization/glTF/GltfExtensions.cs index ee03fbb23..c540b39df 100644 --- a/Elements/src/Serialization/glTF/GltfExtensions.cs +++ b/Elements/src/Serialization/glTF/GltfExtensions.cs @@ -38,10 +38,10 @@ private static int GetNextId() /// /// In normal function use, this should be set to null. - /// If not null and set to a valid directory path, gltfs loaded for + /// If not null and set to a valid directory path, gltfs loaded for /// content elements will be cached to this directory, and can be /// explicitly loaded by calling LoadGltfCacheFromDisk(). This is used - /// by `hypar run` and test capabilities to speed up repeated runs. + /// by `hypar run` and test capabilities to speed up repeated runs. /// public static string GltfCachePath { @@ -904,9 +904,9 @@ internal static Gltf InitializeGlTF(Model model, // Attempt to pre-allocate these lists. This won't be perfect. // Before processing the geometry of an element we can't know - // how much to allocate. In the worst case, this will reduce + // how much to allocate. In the worst case, this will reduce // the list resizing. - // TODO: In future work where we update element geometry during + // TODO: In future work where we update element geometry during // UpdateRepresentations, we will know at this moment how big the // geometry for an element is, and we should tighten this up. var elementCount = model.AllElementsAssignableFromType().Count(); @@ -946,16 +946,19 @@ internal static Gltf InitializeGlTF(Model model, }; gltf.Scenes = new[] { scene }; - var lights = model.AllElementsOfType().ToList(); - gltf.ExtensionsUsed = lights.Any() ? new[] { - "KHR_materials_specular", - "KHR_materials_ior", - "KHR_materials_unlit", - "KHR_lights_punctual" - } : new[] { + var extensionsUsed = new HashSet { "KHR_materials_specular", "KHR_materials_ior", - "KHR_materials_unlit"}; + "KHR_materials_unlit" + }; + + var lights = model.AllElementsOfType().ToList(); + if (lights.Any()) + { + extensionsUsed.Add("KHR_lights_punctual"); + } + + gltf.ExtensionsUsed = extensionsUsed.ToArray(); var bufferViews = new List(); @@ -1025,6 +1028,7 @@ internal static Gltf InitializeGlTF(Model model, textures, images, samplers, + extensionsUsed, meshes, nodes, meshElementMap, @@ -1100,6 +1104,11 @@ internal static Gltf InitializeGlTF(Model model, gltf.Meshes = meshes.ToArray(meshes.Count); } + if (extensionsUsed.Count > 0) + { + gltf.ExtensionsUsed = extensionsUsed.ToArray(); + } + // This is a hack! For web assembly, the ToArray() call creates // a copy of all items in the list, and is extremely slow. We // get around this by accessing the underlying list directly. @@ -1125,6 +1134,7 @@ private static void GetRenderDataForElement(Element e, List textures, List images, List samplers, + HashSet extensions, List meshes, List nodes, Dictionary> meshElementMap, @@ -1155,6 +1165,7 @@ private static void GetRenderDataForElement(Element e, textures, images, samplers, + extensions, true, e.Id, out var parentNode); diff --git a/Elements/src/Serialization/glTF/GltfMergingUtils.cs b/Elements/src/Serialization/glTF/GltfMergingUtils.cs index b27deecf1..343a63fc0 100644 --- a/Elements/src/Serialization/glTF/GltfMergingUtils.cs +++ b/Elements/src/Serialization/glTF/GltfMergingUtils.cs @@ -27,6 +27,7 @@ public static List AddAllMeshesFromFromGlb(Stream glbStream, List textures, List images, List samplers, + HashSet extensions, bool shouldAddMaterials, System.Guid contentElementId, out ProtoNode parentNode @@ -60,6 +61,11 @@ out ProtoNode parentNode accessors.Add(originAccessor); } + foreach (var extension in loaded.ExtensionsUsed) + { + extensions.Add(extension); + } + var imageIncrement = images.Count; if (loaded.Images != null) { diff --git a/Elements/test/ContentTests.cs b/Elements/test/ContentTests.cs index c850f74a5..16c52ccf3 100644 --- a/Elements/test/ContentTests.cs +++ b/Elements/test/ContentTests.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System; using System.IO; +using glTFLoader; +using System.Linq; namespace Elements.Tests { @@ -56,6 +58,39 @@ public void CatalogSerialization() Assert.Equal("The Value", loadedCatalog.Content[0].AdditionalProperties["ImportantParameter"]); } + [Fact] + public void MergeExtensions() + { + Name = nameof(MergeExtensions); + // This piece of content uses the KHR_materials_pbrSpecularGlossiness extension which is no longer used in our models. + const string contentLocation = "../../../models/MergeGlTF/LittleShapes.glb"; + var littleShapeContent = new TestContentElem(contentLocation, + new BBox3(new Vector3(-0.5, -0.5, 0), new Vector3(0.5, 0.5, 3)), + new Vector3(), + new Transform(new Vector3(), Vector3.XAxis), + 20, + BuiltInMaterials.Default, + null, + true, + Guid.NewGuid(), + "LittleShapes"); + var anInstance = littleShapeContent.CreateInstance(new Transform(new Vector3(15, 0, 0)), "LittleShapes1"); + + var modelPath = $"./models/{nameof(MergeExtensions)}.glb"; + Model.AddElement(new Mass(Polygon.Rectangle(1, 1))); + Model.ToGlTF(modelPath); + var gltfModelEmpty = Interface.LoadModel(modelPath); + var initialExtensions = gltfModelEmpty.ExtensionsUsed; + + var gltfContent = Interface.LoadModel(contentLocation); + Model.AddElement(anInstance); + Model.ToGlTF(modelPath); + var gltfModelMerged = Interface.LoadModel(modelPath); + Assert.NotEmpty(gltfContent.ExtensionsUsed); + Assert.NotEmpty(gltfContent.ExtensionsUsed.Except(initialExtensions)); + Assert.All(gltfContent.ExtensionsUsed, (ext) => Assert.Contains(ext, gltfModelMerged.ExtensionsUsed)); + } + [Fact, Trait("Category", "Example")] public void InstanceContentElement() { diff --git a/Elements/test/ModelTest.cs b/Elements/test/ModelTest.cs index 087cb2f02..11c5ceef8 100644 --- a/Elements/test/ModelTest.cs +++ b/Elements/test/ModelTest.cs @@ -57,7 +57,7 @@ public ModelTest() public virtual void Dispose() { - if (this._model.Elements.Any()) + if (this._model.Elements.Any() && !String.IsNullOrEmpty(this._name)) { if (this.GenerateGlb) { diff --git a/Elements/test/models/MergeGlTF/LittleShapes.glb b/Elements/test/models/MergeGlTF/LittleShapes.glb new file mode 100644 index 000000000..4fcf8d77f Binary files /dev/null and b/Elements/test/models/MergeGlTF/LittleShapes.glb differ