Browse Source

Improved model writing API
Fixed extensions writing

Vicente Penades 6 years ago
parent
commit
9539f1a44a

+ 0 - 3
src/SharpGLTF.Toolkit/Geometry/InterleavedMeshBuilder.cs

@@ -104,9 +104,6 @@ namespace SharpGLTF.Geometry
 
                 prim.Material = materialEvaluator(kvp.Key);
             }
-
-            root.MergeImages();
-            root.MergeBuffers();
         }
 
         #endregion

+ 4 - 3
src/SharpGLTF/Schema2/glb.Images.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Text;
 
 namespace SharpGLTF.Schema2
@@ -182,7 +183,7 @@ namespace SharpGLTF.Schema2
                 ?? uri._TryParseBase64Unchecked(EMBEDDEDOCTETSTREAM)
                 ?? uri._TryParseBase64Unchecked(EMBEDDEDJPEGBUFFER)
                 ?? uri._TryParseBase64Unchecked(EMBEDDEDPNGBUFFER)
-                ?? externalReferenceSolver?.Invoke(uri);
+                ?? externalReferenceSolver.Invoke(uri).ToArray();
         }
 
         #endregion
@@ -228,7 +229,7 @@ namespace SharpGLTF.Schema2
             {
                 _mimeType = null;
                 _uri = satelliteUri += ".png";
-                writer(_uri, _SatelliteImageContent);
+                writer(_uri, new ArraySegment<byte>(_SatelliteImageContent) );
                 return;
             }
 
@@ -236,7 +237,7 @@ namespace SharpGLTF.Schema2
             {
                 _mimeType = null;
                 _uri = satelliteUri += ".jpg";
-                writer(_uri, _SatelliteImageContent);
+                writer(_uri, new ArraySegment<byte>(_SatelliteImageContent) );
                 return;
             }
 

+ 1 - 1
src/SharpGLTF/Schema2/glb.cs

@@ -132,7 +132,7 @@ namespace SharpGLTF.Schema2
         {
             var ex = IsBinaryCompatible(model); if (ex != null) throw ex;
 
-            var jsonText = model.WriteJSON(Newtonsoft.Json.Formatting.None);
+            var jsonText = model.GetJSON(Newtonsoft.Json.Formatting.None);
             var jsonChunk = Encoding.UTF8.GetBytes(jsonText);
             var jsonPadding = jsonChunk.Length & 3; if (jsonPadding != 0) jsonPadding = 4 - jsonPadding;
 

+ 2 - 2
src/SharpGLTF/Schema2/gltf.Buffer.cs

@@ -57,7 +57,7 @@ namespace SharpGLTF.Schema2
         {
             return uri._TryParseBase64Unchecked(EMBEDDEDGLTFBUFFER)
                 ?? uri._TryParseBase64Unchecked(EMBEDDEDOCTETSTREAM)
-                ?? satelliteReferenceSolver?.Invoke(uri);
+                ?? satelliteReferenceSolver.Invoke(uri).ToArray();
         }
 
         #endregion
@@ -74,7 +74,7 @@ namespace SharpGLTF.Schema2
             this._uri = satelliteUri;
             this._byteLength = _Content.Length;
 
-            writer(satelliteUri, _Content.GetPaddedContent());
+            writer(satelliteUri, new ArraySegment<byte>(_Content.GetPaddedContent()) );
         }
 
         /// <summary>

+ 20 - 7
src/SharpGLTF/Schema2/gltf.ExtensionsFactory.cs

@@ -12,15 +12,15 @@ namespace SharpGLTF.Schema2
 
         static ExtensionsFactory()
         {
-            RegisterExtension("KHR_materials_pbrSpecularGlossiness", () => new MaterialPBRSpecularGlossiness_KHR());
-            RegisterExtension("KHR_materials_unlit", () => new MaterialUnlit_KHR());
+            RegisterExtension<MaterialPBRSpecularGlossiness_KHR>("KHR_materials_pbrSpecularGlossiness");
+            RegisterExtension<MaterialUnlit_KHR>("KHR_materials_unlit");
         }
 
         #endregion
 
         #region data
 
-        private static readonly Dictionary<string, Func<JsonSerializable>> _Extensions = new Dictionary<string, Func<JsonSerializable>>();
+        private static readonly Dictionary<string, Type> _Extensions = new Dictionary<string, Type>();
 
         #endregion
 
@@ -28,16 +28,29 @@ namespace SharpGLTF.Schema2
 
         public static IEnumerable<string> SupportedExtensions => _Extensions.Keys;
 
-        public static void RegisterExtension(string persistentName, Func<JsonSerializable> activator)
+        public static void RegisterExtension<T>(string persistentName)
+            where T : JsonSerializable
         {
-            _Extensions[persistentName] = activator;
+            _Extensions[persistentName] = typeof(T);
         }
 
         internal static JsonSerializable Create(string key)
         {
-            if (!_Extensions.TryGetValue(key, out Func<JsonSerializable> activator)) return null;
+            if (!_Extensions.TryGetValue(key, out Type t)) return null;
 
-            return activator.Invoke();
+            var instance = Activator.CreateInstance(t);
+
+            return instance as JsonSerializable;
+        }
+
+        internal static string Identify(Type type)
+        {
+            foreach (var kvp in _Extensions)
+            {
+                if (kvp.Value == type) return kvp.Key;
+            }
+
+            return null;
         }
 
         #endregion

+ 16 - 1
src/SharpGLTF/Schema2/gltf.Property.cs

@@ -81,7 +81,22 @@ namespace SharpGLTF.Schema2
         /// <param name="writer">The target writer.</param>
         protected override void SerializeProperties(JsonWriter writer)
         {
-            SerializeProperty(writer, "extensions", _extensions);
+            if (_extensions.Count > 0)
+            {
+                var dict = new Dictionary<string, JsonSerializable>();
+
+                foreach (var val in this._extensions)
+                {
+                    if (val == null) continue;
+                    var key = ExtensionsFactory.Identify(val.GetType());
+                    if (key == null) continue;
+
+                    dict[key] = val;
+                }
+
+                SerializeProperty(writer, "extensions", dict);
+            }
+
             if (_extras != null) SerializeProperty(writer, "extras", _extras);
         }
 

+ 193 - 87
src/SharpGLTF/Schema2/gltf.Serialization.cs

@@ -8,6 +8,7 @@ using Newtonsoft.Json;
 
 namespace SharpGLTF.Schema2
 {
+    using BYTES = ArraySegment<Byte>;
     using MODEL = ModelRoot;
 
     /// <summary>
@@ -15,14 +16,14 @@ namespace SharpGLTF.Schema2
     /// </summary>
     /// <param name="assetName">the asset relative path.</param>
     /// <returns>The file contents as a <see cref="byte"/> array.</returns>
-    public delegate Byte[] AssetReader(String assetName);
+    public delegate BYTES AssetReader(String assetName);
 
     /// <summary>
     /// Callback used for saving associated files of the current model.
     /// </summary>
     /// <param name="assetName">The asset relative path.</param>
     /// <param name="assetData">The file contents as a <see cref="byte"/> array.</param>
-    public delegate void AssetWriter(String assetName, Byte[] assetData);
+    public delegate void AssetWriter(String assetName, BYTES assetData);
 
     /// <summary>
     /// Configuration settings for reading model files.
@@ -44,7 +45,7 @@ namespace SharpGLTF.Schema2
 
             var dir = Path.GetDirectoryName(filePath);
 
-            FileReader = assetFileName => File.ReadAllBytes(Path.Combine(dir, assetFileName));
+            FileReader = assetFileName => new BYTES(File.ReadAllBytes(Path.Combine(dir, assetFileName)));
         }
 
         /// <summary>
@@ -53,6 +54,13 @@ namespace SharpGLTF.Schema2
         public AssetReader FileReader { get; set; }
     }
 
+    public enum ImageWriteMode
+    {
+        SatelliteFile,
+        BufferView,
+        Embedded
+    }
+
     /// <summary>
     /// Configuration settings for writing model files.
     /// </summary>
@@ -60,57 +68,144 @@ namespace SharpGLTF.Schema2
     {
         #region lifecycle
 
-        internal WriteSettings(string filePath)
+        internal static WriteSettings ForText(string filePath)
         {
             Guard.FilePathMustBeValid(filePath, nameof(filePath));
 
             var dir = Path.GetDirectoryName(filePath);
 
-            this.FileWriter = (fn, d) => File.WriteAllBytes(Path.Combine(dir, fn), d);
+            var settings = new WriteSettings
+            {
+                BinaryMode = false,
+                ImageWriting = ImageWriteMode.SatelliteFile,
+                MergeBuffers = true,
+                JsonFormatting = Formatting.Indented,
+
+                FileWriter = (fn, d) => File.WriteAllBytes(Path.Combine(dir, fn), d.ToArray())
+            };
+
+            return settings;
         }
 
-        internal WriteSettings(AssetWriter fileWriter)
+        internal static WriteSettings ForText(Dictionary<string, BYTES> dict)
         {
-            this.FileWriter = fileWriter;
+            var settings = new WriteSettings()
+            {
+                BinaryMode = false,
+                ImageWriting = ImageWriteMode.SatelliteFile,
+                MergeBuffers = false,
+                JsonFormatting = Formatting.None,
+
+                FileWriter = (fn, buff) => dict[fn] = buff
+            };
+
+            return settings;
         }
 
-        internal WriteSettings(Func<string, Stream> fileWriter)
+        internal static WriteSettings ForBinary(string filePath)
         {
-            void assetWriter(string n, byte[] d)
+            Guard.FilePathMustBeValid(filePath, nameof(filePath));
+
+            var dir = Path.GetDirectoryName(filePath);
+
+            var settings = new WriteSettings
             {
-                using (var s = fileWriter(n))
-                {
-                    s.Write(d, 0, d.Length);
-                }
-            }
+                BinaryMode = true,
+                ImageWriting = ImageWriteMode.BufferView,
+                MergeBuffers = true,
+                JsonFormatting = Formatting.None,
 
-            this.FileWriter = assetWriter;
+                FileWriter = (fn, d) => File.WriteAllBytes(Path.Combine(dir, fn), d.ToArray())
+            };
+
+            return settings;
         }
 
-        internal WriteSettings(MemoryStream memory)
+        internal static WriteSettings ForBinary(Stream stream)
         {
-            JSonFormatting = Formatting.None;
-            BinaryMode = true;
-            EmbedImages = true;
+            Guard.NotNull(stream, nameof(stream));
+            Guard.IsTrue(stream.CanWrite, nameof(stream));
+
+            var settings = new WriteSettings
+            {
+                BinaryMode = true,
+                ImageWriting = ImageWriteMode.BufferView,
+                MergeBuffers = true,
+                JsonFormatting = Formatting.None,
 
-            this.FileWriter = (fn, d) => memory.Write(d, 0, d.Length);
+                FileWriter = (fn, d) => stream.Write(d.Array, d.Offset, d.Count)
+            };
+
+            return settings;
         }
 
+        private WriteSettings() { }
+
         #endregion
 
         #region data
 
+        /// <summary>
+        /// Gets or sets a value indicating whether to write a GLTF or a GLB file
+        /// </summary>
         public Boolean BinaryMode { get; set; }
 
-        public Boolean EmbedImages { get; set; }
+        /// <summary>
+        /// Gets or sets a value indicating how to write the images of the model
+        /// </summary>
+        public ImageWriteMode ImageWriting { get; set; }
 
-        public Formatting JSonFormatting { get; set; }
+        /// <summary>
+        /// Gets or sets a value indicating whether to merge all the buffers in <see cref="MODEL.LogicalBuffers"/> into a single buffer.
+        /// </summary>
+        public Boolean MergeBuffers { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating how to format the JSON document of the glTF
+        /// </summary>
+        public Formatting JsonFormatting { get; set; }
 
         /// <summary>
         /// Gets or sets the <see cref="AssetWriter"/> delegate used to write satellite files.
         /// </summary>
         public AssetWriter FileWriter { get; set; }
 
+        internal bool _NoCloneWatchdog = false;
+
+        #endregion
+
+        #region API
+
+        /// <summary>
+        /// Prepares the model for writing with the appropiate settings, cloning it if neccesary.
+        /// </summary>
+        /// <param name="model">The source <see cref="MODEL"/> instance.</param>
+        /// <returns>The source <see cref="MODEL"/> instance, or a cloned and modified instance if current settings required it.</returns>
+        internal MODEL FilterModel(MODEL model)
+        {
+            Guard.NotNull(model,nameof(model));
+
+            var needsMergeBuffers = (this.MergeBuffers | this.BinaryMode) && model.LogicalBuffers.Count > 1;
+
+            var imagesAsBufferViews = model.LogicalImages.Count > 0 && this.ImageWriting == ImageWriteMode.BufferView;
+
+            if (needsMergeBuffers | imagesAsBufferViews)
+            {
+                if (_NoCloneWatchdog) throw new InvalidOperationException($"Current settings require a model rewrite, but {nameof(MODEL.DeepClone)} is not allowed in the current context");
+                model = model.DeepClone();
+            }
+
+            if (ImageWriting == ImageWriteMode.BufferView)
+            {
+                model.MergeImages();
+                needsMergeBuffers |= this.MergeBuffers | this.BinaryMode;
+            }
+
+            if (needsMergeBuffers) model.MergeBuffers();
+
+            return model;
+        }
+
         #endregion
     }
 
@@ -140,7 +235,7 @@ namespace SharpGLTF.Schema2
         /// </summary>
         /// <param name="glb">A <see cref="byte"/> array representing a GLB file</param>
         /// <returns>A <see cref="MODEL"/> instance.</returns>
-        public static MODEL ParseGLB(ArraySegment<Byte> glb)
+        public static MODEL ParseGLB(BYTES glb)
         {
             Guard.NotNull(glb, nameof(glb));
 
@@ -202,7 +297,7 @@ namespace SharpGLTF.Schema2
 
             if (chunks.ContainsKey(glb.CHUNKBIN))
             {
-                settings.FileReader = key => string.IsNullOrEmpty(key) ? chunks[glb.CHUNKBIN] : settings.FileReader?.Invoke(key);
+                settings.FileReader = key => string.IsNullOrEmpty(key) ? new BYTES(chunks[glb.CHUNKBIN]) : settings.FileReader.Invoke(key);
             }
 
             return ParseGLTF(dom, settings);
@@ -225,13 +320,13 @@ namespace SharpGLTF.Schema2
             }
         }
 
-        public static MODEL ReadFromDictionary(Dictionary<string, Byte[]> files, string fileName)
+        public static MODEL ReadFromDictionary(Dictionary<string, BYTES> files, string fileName)
         {
             var jsonBytes = files[fileName];
 
             var settings = new ReadSettings(fn => files[fn]);
 
-            using (var m = new MemoryStream(jsonBytes))
+            using (var m = new MemoryStream(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count))
             {
                 using (var s = new StreamReader(m))
                 {
@@ -282,18 +377,11 @@ namespace SharpGLTF.Schema2
         /// <param name="filePath">A valid file path to write to.</param>
         public void SaveGLB(string filePath)
         {
-            Guard.FilePathMustBeValid(filePath, nameof(filePath));
-
-            var settings = new WriteSettings(filePath)
-            {
-                JSonFormatting = Formatting.None,
-                BinaryMode = true,
-                EmbedImages = true
-            };
+            var settings = WriteSettings.ForBinary(filePath);
 
             var name = Path.GetFileNameWithoutExtension(filePath);
 
-            Write(settings, name);
+            _Write(settings, name, this);
         }
 
         /// <summary>
@@ -306,17 +394,13 @@ namespace SharpGLTF.Schema2
         /// </remarks>
         public void SaveGLTF(string filePath, Formatting fmt = Formatting.None)
         {
-            Guard.FilePathMustBeValid(filePath, nameof(filePath));
+            var settings = WriteSettings.ForText(filePath);
 
-            var settings = new WriteSettings(filePath)
-            {
-                JSonFormatting = fmt,
-                BinaryMode = false
-            };
+            settings.JsonFormatting = fmt;
 
             var name = Path.GetFileNameWithoutExtension(filePath);
 
-            Write(settings, name);
+            _Write(settings, name, this);
         }
 
         /// <summary>
@@ -324,30 +408,19 @@ namespace SharpGLTF.Schema2
         /// </summary>
         /// <param name="fileName">the base name to use for the dictionary keys</param>
         /// <returns>a dictionary instance.</returns>
-        public Dictionary<String, Byte[]> WriteToDictionary(string fileName)
+        public Dictionary<String, BYTES> WriteToDictionary(string fileName)
         {
-            var dict = new Dictionary<string, Byte[]>();
+            var dict = new Dictionary<string, BYTES>();
 
-            var settings = new WriteSettings((fn, buff) => dict[fn] = buff);
+            var settings = WriteSettings.ForText(dict);
 
-            this.Write(settings, fileName);
+            // WriteToDictionary is usually called by DeepClone, so allowing a setting that
+            // would imply cloning the model would cause an infine loop and a StackOverflow
+            settings._NoCloneWatchdog = true;
 
-            return dict;
-        }
-
-        /// <summary>
-        /// Writes this <see cref="MODEL"/> JSON document to a <see cref="TextWriter"/>.
-        /// </summary>
-        /// <param name="sw">The target <see cref="TextWriter"/>.</param>
-        /// <param name="fmt">The formatting of the JSON document.</param>
-        public void WriteJSON(TextWriter sw, Formatting fmt)
-        {
-            using (var writer = new JsonTextWriter(sw))
-            {
-                writer.Formatting = fmt;
+            _Write(settings, fileName, this);
 
-                this.Serialize(writer);
-            }
+            return dict;
         }
 
         /// <summary>
@@ -355,11 +428,11 @@ namespace SharpGLTF.Schema2
         /// </summary>
         /// <param name="fmt">The formatting of the JSON document.</param>
         /// <returns>A JSON content.</returns>
-        public string WriteJSON(Formatting fmt)
+        public string GetJSON(Formatting fmt)
         {
             using (var ss = new StringWriter())
             {
-                WriteJSON(ss, fmt);
+                _WriteJSON(ss, fmt);
                 return ss.ToString();
             }
         }
@@ -368,20 +441,28 @@ namespace SharpGLTF.Schema2
         /// Writes this <see cref="MODEL"/> to a <see cref="byte"/> array in GLB format.
         /// </summary>
         /// <returns>A <see cref="byte"/> array containing a GLB file.</returns>
-        public ArraySegment<Byte> WriteGLB()
+        public BYTES WriteGLB()
         {
             using (var m = new MemoryStream())
             {
-                var settings = new WriteSettings(m);
+                WriteGLB(m);
 
-                // ensure that images are embedded.
-                settings.EmbedImages = true;
+                return m.ToArraySegment();
+            }
+        }
 
-                Write(settings, "model");
+        /// <summary>
+        /// Writes this <see cref="MODEL"/> to a <see cref="Stream"/> in GLB format.
+        /// </summary>
+        /// <param name="stream">A <see cref="Stream"/> open for writing.</param>
+        public void WriteGLB(Stream stream)
+        {
+            Guard.NotNull(stream, nameof(stream));
+            Guard.IsTrue(stream.CanWrite, nameof(stream));
 
-                if (m.TryGetBuffer(out ArraySegment<Byte> buffer)) return buffer;
-                return new ArraySegment<byte>(m.ToArray());
-            }
+            var settings = WriteSettings.ForBinary(stream);
+
+            _Write(settings, "model", this);
         }
 
         /// <summary>
@@ -394,31 +475,56 @@ namespace SharpGLTF.Schema2
         /// </remarks>
         public void Write(WriteSettings settings, string baseName)
         {
+            _Write(settings, baseName, this);
+        }
+
+        private void _WriteJSON(TextWriter sw, Formatting fmt)
+        {
+            using (var writer = new JsonTextWriter(sw))
+            {
+                writer.Formatting = fmt;
+
+                this.Serialize(writer);
+            }
+        }
+
+        private static void _Write(WriteSettings settings, string baseName, MODEL model)
+        {
+            Guard.NotNull(settings, nameof(settings));
+            Guard.NotNullOrEmpty(baseName, nameof(baseName));
+            Guard.NotNull(model,nameof(model));
+
+            model = settings.FilterModel(model);
+
             if (settings.BinaryMode)
             {
-                var ex = glb.IsBinaryCompatible(this); if (ex != null) throw ex;
+                var ex = glb.IsBinaryCompatible(model);
+                if (ex != null) throw ex;
 
-                for (int i = 0; i < this._buffers.Count; ++i)
+                // setup all buffers to be written internally
+                for (int i = 0; i < model._buffers.Count; ++i)
                 {
-                    var buffer = this._buffers[i];
+                    var buffer = model._buffers[i];
                     buffer._WriteToInternal();
                 }
             }
             else
             {
-                for (int i = 0; i < this._buffers.Count; ++i)
+                // setup all buffers to be written as satellite files
+                for (int i = 0; i < model._buffers.Count; ++i)
                 {
-                    var buffer = this._buffers[i];
-                    var bname = this._buffers.Count != 1 ? $"{baseName}_{i}.bin" : $"{baseName}.bin";
+                    var buffer = model._buffers[i];
+                    var bname = model._buffers.Count != 1 ? $"{baseName}_{i}.bin" : $"{baseName}.bin";
                     buffer._WriteToSatellite(settings.FileWriter, bname);
                 }
             }
 
-            for (int i = 0; i < this._images.Count; ++i)
+            // setup all images to be written to the appropiate location.
+            for (int i = 0; i < model._images.Count; ++i)
             {
-                var image = this._images[i];
-                var iname = this._images.Count != 1 ? $"{baseName}_{i}" : $"{baseName}";
-                if (settings.EmbedImages) image._WriteToInternal();
+                var image = model._images[i];
+                var iname = model._images.Count != 1 ? $"{baseName}_{i}" : $"{baseName}";
+                if (settings.ImageWriting != ImageWriteMode.SatelliteFile) image._WriteToInternal();
                 else image._WriteToSatellite(settings.FileWriter, iname);
             }
 
@@ -428,24 +534,24 @@ namespace SharpGLTF.Schema2
                 {
                     using (var w = new BinaryWriter(m))
                     {
-                        glb.WriteBinaryModel(w, this);
+                        glb.WriteBinaryModel(w, model);
                     }
 
-                    settings.FileWriter($"{baseName}.glb", m.ToArray());
+                    settings.FileWriter($"{baseName}.glb", m.ToArraySegment());
                 }
                 else
                 {
                     using (var w = new StreamWriter(m))
                     {
-                        WriteJSON(w, settings.JSonFormatting);
+                        model._WriteJSON(w, settings.JsonFormatting);
                     }
 
-                    settings.FileWriter($"{baseName}.gltf", m.ToArray());
+                    settings.FileWriter($"{baseName}.gltf", m.ToArraySegment());
                 }
             }
 
-            foreach (var b in this._buffers) b._ClearAfterWrite();
-            foreach (var i in this._images) i._ClearAfterWrite();
+            foreach (var b in model._buffers) b._ClearAfterWrite();
+            foreach (var i in model._images) i._ClearAfterWrite();
         }
 
         #endregion

+ 6 - 0
src/SharpGLTF/_Extensions.cs

@@ -341,6 +341,12 @@ namespace SharpGLTF
 
         #region serialization
 
+        public static ArraySegment<Byte> ToArraySegment(this System.IO.MemoryStream m)
+        {
+            if (m.TryGetBuffer(out ArraySegment<Byte> data)) return data;
+            return new ArraySegment<byte>(m.ToArray());
+        }
+
         public static Byte[] GetPaddedContent(this Byte[] content)
         {
             if (content == null) return null;

+ 1 - 1
tests/SharpGLTF.Tests/Schema2/Authoring/CreateModelTests.cs

@@ -45,7 +45,7 @@ namespace SharpGLTF.Schema2.Authoring
                 ["D"] = new Dictionary<String, Object> { ["S"]= 1, ["T"] = 2 }
             };
 
-            var json = root.WriteJSON(Newtonsoft.Json.Formatting.Indented);
+            var json = root.GetJSON(Newtonsoft.Json.Formatting.Indented);
             var bytes = root.WriteGLB();
 
             var rootBis = ModelRoot.ParseGLB(bytes);

+ 0 - 3
tests/SharpGLTF.Tests/Schema2/Authoring/SimpleMeshBuilder.cs

@@ -97,9 +97,6 @@ namespace SharpGLTF.Schema2.Authoring
 
                 prim.Material = materialEvaluator(kvp.Key);
             }
-
-            root.MergeImages();
-            root.MergeBuffers();            
         }
 
         private Vector3[] _CalculateNormals()

+ 44 - 12
tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadModelTests.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Text;
 
 using NUnit.Framework;
@@ -80,6 +81,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
         public void TestLoadSampleModels(string section)
         {
             TestContext.CurrentContext.AttachShowDirLink();
+            TestContext.CurrentContext.AttachGltfValidatorLink();
 
             foreach (var f in TestFiles.GetSampleFilePaths())
             {
@@ -91,27 +93,57 @@ namespace SharpGLTF.Schema2.LoadAndSave
                 // evaluate and save all the triangles to a Wavefront Object
                 model.AttachToCurrentTest(System.IO.Path.ChangeExtension(System.IO.Path.GetFileName(f), ".obj"));
                 model.AttachToCurrentTest(System.IO.Path.ChangeExtension(System.IO.Path.GetFileName(f), ".glb"));
-
-                // attempt clone
-                var xclone = model.DeepClone();
-
+                
                 // do a model roundtrip
-                model.MergeImages();
-                model.MergeBuffers();
                 var bytes = model.WriteGLB();
 
                 var modelBis = ModelRoot.ParseGLB(bytes);
             }
         }
 
+        [TestCase(@"UnlitTest\glTF-Binary\UnlitTest.glb")]
+        public void TestLoadSpecialCaseModels(string filePath)
+        {
+            TestContext.CurrentContext.AttachShowDirLink();
+            TestContext.CurrentContext.AttachGltfValidatorLink();
+
+            var f = TestFiles.GetSampleFilePaths()
+                .FirstOrDefault(item => item.EndsWith(filePath));
+
+            var model = GltfUtils.LoadModel(f);
+            Assert.NotNull(model);
+
+            // evaluate and save all the triangles to a Wavefront Object
+            model.AttachToCurrentTest(System.IO.Path.ChangeExtension(System.IO.Path.GetFileName(f), ".obj"));
+            model.AttachToCurrentTest(System.IO.Path.ChangeExtension(System.IO.Path.GetFileName(f), ".glb"));
+            model.AttachToCurrentTest(System.IO.Path.ChangeExtension(System.IO.Path.GetFileName(f), ".gltf"));
+
+            // do a model roundtrip
+            var bytes = model.WriteGLB();
+            var modelBis = ModelRoot.ParseGLB(bytes);
+
+            // clone
+            var cloned = model.DeepClone();
+        }
+
         [Test]
-        public void TestLoadSampleModelsWithMaterialSpecularGlossiness()
+        public void TestLoadUnlitMode()
         {
-            foreach (var f in TestFiles.GetFilePathsWithSpecularGlossinessPBR())
-            {
-                var root = GltfUtils.LoadModel(f);
-                Assert.NotNull(root);
-            }
+            var f = TestFiles.GetSampleFilePaths()
+                .FirstOrDefault(item => item.EndsWith(@"UnlitTest\glTF-Binary\UnlitTest.glb"));
+
+            var model = GltfUtils.LoadModel(f);
+            Assert.NotNull(model);
+
+            Assert.IsTrue(model.LogicalMaterials[0].Unlit);
+
+            // do a model roundtrip
+            var modelBis = ModelRoot.ParseGLB(model.WriteGLB());
+            Assert.NotNull(modelBis);
+
+            Assert.IsTrue(modelBis.LogicalMaterials[0].Unlit);
+
+
         }
 
         #endregion

+ 0 - 5
tests/SharpGLTF.Tests/TestFiles.cs

@@ -96,11 +96,6 @@ namespace SharpGLTF
             return System.IO.Path.Combine(_GeneratedAssetsDir, $"Output\\Compatibility\\Compatibility_0{idx}.gltf");
         }
 
-        public static IEnumerable<string> GetFilePathsWithSpecularGlossinessPBR()
-        {
-            return GetSampleFilePaths().Where(p => p.Contains("\\glTF-pbrSpecularGlossiness\\"));            
-        }
-
         public static string GetPollyFilePath()
         {
             return System.IO.Path.Combine(_PollyModelsDir, "polly", "project_polly.glb");

+ 0 - 10
tests/SharpGLTF.Tests/TestUtils.cs

@@ -43,16 +43,6 @@ namespace SharpGLTF
         {
             // find the output path for the current test
             fileName = NUnit.Framework.TestContext.CurrentContext.GetAttachmentPath(fileName, true);
-
-            if (model.LogicalBuffers.Count > 1 || model.LogicalImages.Count > 0)
-            {
-                // clone the model so merging the buffers will not affect the source model.
-                model = model.DeepClone();
-
-                if (fileName.ToLower().EndsWith(".glb")) model.MergeImages();
-                model.MergeBuffers();
-            }
-
             
             if (fileName.ToLower().EndsWith(".glb"))
             {