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