From cde69aa1355778d46f8e56113aecec9f0f0d12ec Mon Sep 17 00:00:00 2001 From: Ian Keough Date: Sun, 7 Aug 2022 15:50:21 -0400 Subject: [PATCH] In memory images for textures. --- Elements/src/Analysis/AnalysisImage.cs | 28 ++- Elements/src/Image.cs | 80 ++++++++ Elements/src/Material.cs | 178 ++++++++++++++++-- Elements/src/ModelText.cs | 53 +++--- .../src/Serialization/glTF/GltfExtensions.cs | 69 ++++--- .../Serialization/glTF/GltfMergingUtils.cs | 2 +- Elements/test/MaterialTests.cs | 27 ++- Elements/test/TopographyTests.cs | 16 +- 8 files changed, 353 insertions(+), 100 deletions(-) create mode 100644 Elements/src/Image.cs diff --git a/Elements/src/Analysis/AnalysisImage.cs b/Elements/src/Analysis/AnalysisImage.cs index e20db305a..41c8a08f9 100644 --- a/Elements/src/Analysis/AnalysisImage.cs +++ b/Elements/src/Analysis/AnalysisImage.cs @@ -4,8 +4,6 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; -using System.IO; - namespace Elements.Analysis { /// @@ -63,13 +61,14 @@ public AnalysisImage(Polygon perimeter, double vLength, ColorScale colorScale, Func analyze, - Guid id = default(Guid), + Guid id = default, string name = null) : base(perimeter, uLength, vLength, colorScale, analyze, id, name) { } /// /// Compute a value for each grid cell, and create the required material. /// - public override void Analyze() { + public override void Analyze() + { base.Analyze(); _perimBounds = new BBox3(new[] { this.Perimeter }); @@ -83,14 +82,14 @@ public override void Analyze() { var image = new Image(_imgPixels, _imgPixels); - foreach (var result in this._results) + foreach (var (cell, value) in this._results) { - var center = result.cell.Center(); + var center = cell.Center(); if (this.Perimeter.Contains(center)) { - var vertexColor = this.ColorScale.GetColor(result.value); - var u = (result.cell.Min.X - _perimBounds.Min.X) / _perimW * (_numPixelsX / _imgPixels); - var v = (result.cell.Min.Y - _perimBounds.Min.Y) / _perimH * (_numPixelsY / _imgPixels); + var vertexColor = this.ColorScale.GetColor(value); + var u = (cell.Min.X - _perimBounds.Min.X) / _perimW * (_numPixelsX / _imgPixels); + var v = (cell.Min.Y - _perimBounds.Min.Y) / _perimH * (_numPixelsY / _imgPixels); var pX = (int)Math.Round(u * _imgPixels); // pixels in world coordinates var pY = (int)Math.Round(v * _imgPixels); // pixels in world coordinates @@ -108,7 +107,7 @@ public override void Analyze() { image[x, y] = rgbaColor; // Extend this color to the right - if (Math.Abs(result.cell.Max.X - _perimBounds.Max.X) < Vector3.EPSILON) + if (Math.Abs(cell.Max.X - _perimBounds.Max.X) < Vector3.EPSILON) { while (x < _imgPixels - 1) { @@ -118,7 +117,7 @@ public override void Analyze() { } // Extend this color to the top - if (Math.Abs(result.cell.Max.Y - _perimBounds.Max.Y) < Vector3.EPSILON) + if (Math.Abs(cell.Max.Y - _perimBounds.Max.Y) < Vector3.EPSILON) { while (y >= 0) { @@ -129,16 +128,13 @@ public override void Analyze() { } } - var imagePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png"); - image.Save(imagePath); - - this.Material = new Material($"Analysis_{Guid.NewGuid().ToString()}", Colors.White, 0, 0, imagePath, true, true, interpolateTexture:false, id: Guid.NewGuid()); + this.Material = new Material($"Analysis_{Guid.NewGuid()}", Colors.White, image, 0, 0, true, true, interpolateTexture: false, id: Guid.NewGuid()); } /// /// Gives an element with a mapped texture. /// - public override void Tessellate(ref Mesh mesh, Transform transform = null, Elements.Geometry.Color color = default(Elements.Geometry.Color)) + public override void Tessellate(ref Mesh mesh, Transform transform = null, Elements.Geometry.Color color = default) { var meshVertices = new List(); diff --git a/Elements/src/Image.cs b/Elements/src/Image.cs new file mode 100644 index 000000000..9307047df --- /dev/null +++ b/Elements/src/Image.cs @@ -0,0 +1,80 @@ +using System; +using System.IO; +using System.Net; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +namespace Elements +{ + /// + /// An image. + /// + internal class Image + { + /// + /// Create an image. + /// + /// The URI of the image. + /// An image or null if an image cannot be created from the provided URI. + internal static Image CreateFromUri(Uri uri) + { + if (!RemoteFileExists(uri)) + { + return null; + } + + var webClient = new WebClient(); + byte[] imageBytes = webClient.DownloadData(uri); + + // We don't wrap this in a using statement because + // we hold onto the image in other places. + var texImage = SixLabors.ImageSharp.Image.Load(imageBytes); + + // Flip the texture image vertically + // to align with OpenGL convention. + // 0,1 1,1 + // 0,0 1,0 + texImage.Mutate(x => x.Flip(FlipMode.Vertical)); + + return texImage; + } + + /// + /// Create an image. + /// + /// A byte array containing the image data. + /// An image. + internal static Image CreateFromBytes(byte[] data) + { + var texImage = SixLabors.ImageSharp.Image.Load(data); + return texImage; + } + + internal static bool RemoteFileExists(Uri uri) + { + if (uri.IsFile) + { + var localPath = uri.LocalPath; + return File.Exists(localPath); + } + + // https://stackoverflow.com/questions/924679/c-sharp-how-can-i-check-if-a-url-exists-is-valid + try + { + HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest; + request.Method = "HEAD"; + HttpWebResponse response = request.GetResponse() as HttpWebResponse; + var ok = response.StatusCode == HttpStatusCode.OK; + response.Close(); + return ok; + } + catch (Exception ex) + { + //Any exception will returns false. + Console.WriteLine(ex.Message); + return false; + } + } + } +} \ No newline at end of file diff --git a/Elements/src/Material.cs b/Elements/src/Material.cs index 5d7d38de4..c36706c9c 100644 --- a/Elements/src/Material.cs +++ b/Elements/src/Material.cs @@ -1,9 +1,12 @@ using System; using System.Collections; using System.IO; +using System.Reflection; using Elements.Geometry; using Elements.Validators; using Newtonsoft.Json; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; namespace Elements { @@ -15,10 +18,25 @@ namespace Elements /// public class Material : Element { + /// + /// The texture image. + /// + internal Image _texture; + + /// + /// The normal texture image. + /// + internal Image _normalTexture; + + /// + /// The emissive texture image. + /// + internal Image _emissiveTexture; + /// The material's color. [JsonProperty("Color", Required = Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Color Color { get; set; } = new Color(); + public Geometry.Color Color { get; set; } = new Geometry.Color(); /// The specular factor between 0.0 and 1.0. [JsonProperty("SpecularFactor", Required = Required.Always)] @@ -101,7 +119,7 @@ public Material() /// The id of the material. /// The name of the material. [JsonConstructor] - public Material(Color @color, + public Material(Geometry.Color @color, double @specularFactor, double @glossinessFactor, bool @unlit, @@ -117,27 +135,36 @@ public Material(Color @color, string @name = null) : base(id, name) { - if (!Validator.DisableValidationOnConstruction) + if (texture != null) { - if (texture != null && !File.Exists(texture)) + // https://weblog.west-wind.com/posts/2019/Aug/20/UriAbsoluteUri-and-UrlEncoding-of-Local-File-Urls + _texture = Image.CreateFromUri(ConstructUri(texture)); + if (_texture == null) { - // If the file doesn't exist, set the texture to null, - // so the material is still created. - texture = null; + throw new ArgumentException("No image data could be found for the specified texture path."); } + } - if (normalTexture != null && !File.Exists(normalTexture)) + if (normalTexture != null) + { + _normalTexture = Image.CreateFromUri(ConstructUri(normalTexture)); + if (_normalTexture == null) { - // If the file doesn't exist, set the normalTexture to null, - // so the material is still created. - normalTexture = null; + throw new ArgumentException("No image data could be found for the specified normal texture path."); } + } - if (emissiveTexture != null && !File.Exists(emissiveTexture)) + if (emissiveTexture != null) + { + _emissiveTexture = Image.CreateFromUri(ConstructUri(emissiveTexture)); + if (_emissiveTexture == null) { - emissiveTexture = null; + throw new ArgumentException("No image data could be found for the specified emissive texture path."); } + } + if (!Validator.DisableValidationOnConstruction) + { if (specularFactor < 0.0 || glossinessFactor < 0.0) { throw new ArgumentOutOfRangeException("The material could not be created. Specular and glossiness values must be less greater than 0.0."); @@ -163,6 +190,18 @@ public Material(Color @color, this.DrawInFront = drawInFront; } + private Uri ConstructUri(string path) + { + if (path.StartsWith("https://") || path.StartsWith("http://") || path.StartsWith("file://")) + { + return new Uri(path); + } + else + { + return new Uri($"file://{Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), path)}"); + } + } + /// /// Construct a material. /// @@ -180,7 +219,8 @@ public Material(string name, Guid id = default) : base(id, name) /// The RGBA color of the material. /// The specular component of the color. Between 0.0 and 1.0. /// The glossiness component of the color. Between 0.0 and 1.0. - /// A relative path to a jpg or png image file to be used as a texture. + /// A path to a jpg or png image file to be used as a texture. The path will be + /// converted to a uri. It can be a local file path, a path relative to the executing assembly, or a url. /// Is this material affected by lights? /// Is this material to be rendered from both sides? /// Should the texture be repeated? The RepeatTexture property determines whether textures are clamped in the [0,0]->[1,1] range or repeat continuously. @@ -193,7 +233,7 @@ public Material(string name, Guid id = default) : base(id, name) /// Thrown when the specular or glossiness value is less than 0.0. /// Thrown when the specular or glossiness value is greater than 1.0. public Material(string name, - Color color, + Geometry.Color color, double specularFactor = 0.1, double glossinessFactor = 0.1, string texture = null, @@ -222,6 +262,114 @@ public Material(string name, name) { } + /// + /// Construct a material. + /// + /// The name of the material. + /// The color of the material. + /// The specular component of the color. Between 0.0 and 1.0. + /// The glossiness component of the color. Between 0.0 and 1.0. + /// The texture image. + /// Is this material affected by lights? + /// Is this material to be rendered from both sides? + /// Should the texture be repeated? The RepeatTexture property determines whether textures are clamped in the [0,0]->[1,1] range or repeat continuously. + /// The normal texture image. + /// Should the texture colors be interpolated between pixels? If false, renders hard pixels in the texture rather than fading between adjacent pixels. + /// The emissive texture image. + /// The scale, between 0.0 and 1.0, of the emissive texture's components. + /// Should objects with this material be drawn in front of all other objects? + /// The id of the material. + public Material(string name, + Geometry.Color color, + Image texture, + double specularFactor = 0.1, + double glossinessFactor = 0.1, + bool unlit = false, + bool doubleSided = false, + bool repeatTexture = true, + Image normalTexture = null, + bool interpolateTexture = true, + Image emissiveTexture = null, + double emissiveFactor = 1.0, + bool drawInFront = false, + Guid id = default) : + + this(color, + specularFactor, + glossinessFactor, + unlit, + null, + doubleSided, + repeatTexture, + null, + interpolateTexture, + null, + emissiveFactor, + drawInFront, + id != default ? id : Guid.NewGuid(), + name) + { + _texture = texture; + _normalTexture = normalTexture; + _emissiveTexture = emissiveTexture; + } + + public Material(string name, + Geometry.Color color, + byte[] texture, + double specularFactor = 0.1, + double glossinessFactor = 0.1, + bool unlit = false, + bool doubleSided = false, + bool repeatTexture = true, + byte[] normalTexture = null, + bool interpolateTexture = true, + byte[] emissiveTexture = null, + double emissiveFactor = 1.0, + bool drawInFront = false, + Guid id = default) : + + this(color, + specularFactor, + glossinessFactor, + unlit, + null, + doubleSided, + repeatTexture, + null, + interpolateTexture, + null, + emissiveFactor, + drawInFront, + id != default ? id : Guid.NewGuid(), + name) + { + _texture = Image.CreateFromBytes(texture); + _normalTexture = Image.CreateFromBytes(normalTexture); + _emissiveTexture = Image.CreateFromBytes(emissiveTexture); + } + + /// + /// Finalize the model text. + /// + ~Material() + { + if (_texture != null) + { + _texture.Dispose(); + } + + if (_normalTexture != null) + { + _normalTexture.Dispose(); + } + + if (_emissiveTexture != null) + { + _emissiveTexture.Dispose(); + } + } + /// /// Is this material equal to the provided material? /// diff --git a/Elements/src/ModelText.cs b/Elements/src/ModelText.cs index df3a88281..a60eaeb99 100644 --- a/Elements/src/ModelText.cs +++ b/Elements/src/ModelText.cs @@ -57,11 +57,11 @@ public class ModelText : MeshElement private static Font _font60; private static Font _font72; private static string _labelsDirectory; - private int _dpi = 72; - private int _maxTextureSize = 2048; + private readonly int _dpi = 72; + private readonly int _maxTextureSize = 2048; private List<(UV min, UV max, FontRectangle fontRect)> _textureAtlas; private DrawingOptions _options; - private string _texturePath; + private Image _texture; /// /// A collection of text data objects which specify the location, @@ -92,7 +92,7 @@ public ModelText(IList<(Vector3 location, Vector3 facingDirection, Vector3 lineD FontSize fontSize, double scale = 10.0) { - this.Texts = texts != null ? texts : new List<(Vector3 location, Vector3 facingDirection, Vector3 lineDirection, string text, Geometry.Color? color)>(); + this.Texts = texts ?? new List<(Vector3 location, Vector3 facingDirection, Vector3 lineDirection, string text, Geometry.Color? color)>(); this.FontSize = fontSize; this.Scale = scale; @@ -101,14 +101,25 @@ public ModelText(IList<(Vector3 location, Vector3 facingDirection, Vector3 lineD GenerateMesh(); this.Material = new Material($"{Guid.NewGuid()}_texture_atlas", - Elements.Geometry.Colors.White, + Colors.White, + _texture, 0.0, 0.0, - texture: _texturePath, repeatTexture: false, unlit: true); } + /// + /// Finalize the model text. + /// + ~ModelText() + { + if (_texture != null) + { + _texture.Dispose(); + } + } + private void Initialize() { if (_font12 == null) @@ -180,8 +191,6 @@ private void GenerateTextureAtlas() var x = 0.0f; var y = 0.0f; - _texturePath = Path.Combine(_labelsDirectory, $"{Guid.NewGuid()}.png"); - var textureLookup = new Dictionary(); foreach (var t in this.Texts) @@ -230,36 +239,34 @@ private void GenerateTextureAtlas() x += fontRectangle.Width; } - if (image != null) - { - image.Save(_texturePath); - image.Dispose(); - } + _texture = image; + + } private void GenerateMesh() { for (var i = 0; i < this.Texts.Count; i++) { - var t = this.Texts[i]; + var (location, facingDirection, lineDirection, _, _) = this.Texts[i]; - var td = t.facingDirection.IsZero() ? Vector3.ZAxis : t.facingDirection; - var ta = this._textureAtlas[i]; + var td = facingDirection.IsZero() ? Vector3.ZAxis : facingDirection; + var (min, max, fontRect) = this._textureAtlas[i]; - var sizeX = Units.InchesToMeters(ta.fontRect.Width / _dpi); - var sizeY = Units.InchesToMeters(ta.fontRect.Height / _dpi); + var sizeX = Units.InchesToMeters(fontRect.Width / _dpi); + var sizeY = Units.InchesToMeters(fontRect.Height / _dpi); - var tx = new Transform(t.location, t.lineDirection, td); + var tx = new Transform(location, lineDirection, td); var v1 = tx.OfPoint(new Vector3(-sizeX * this.Scale / 2, sizeY * this.Scale / 2)); var v2 = tx.OfPoint(new Vector3(-sizeX * this.Scale / 2, -sizeY * this.Scale / 2)); var v3 = tx.OfPoint(new Vector3(sizeX * this.Scale / 2, -sizeY * this.Scale / 2)); var v4 = tx.OfPoint(new Vector3(sizeX * this.Scale / 2, sizeY * this.Scale / 2)); - var uv1 = new UV(ta.min.U, ta.min.V); - var uv2 = new UV(ta.min.U, ta.max.V); - var uv3 = new UV(ta.max.U, ta.max.V); - var uv4 = new UV(ta.max.U, ta.min.V); + var uv1 = new UV(min.U, min.V); + var uv2 = new UV(min.U, max.V); + var uv3 = new UV(max.U, max.V); + var uv4 = new UV(max.U, min.V); var a = this.Mesh.AddVertex(v1, uv1); var b = this.Mesh.AddVertex(v2, uv2); diff --git a/Elements/src/Serialization/glTF/GltfExtensions.cs b/Elements/src/Serialization/glTF/GltfExtensions.cs index e52cd9c30..72cd26c4c 100644 --- a/Elements/src/Serialization/glTF/GltfExtensions.cs +++ b/Elements/src/Serialization/glTF/GltfExtensions.cs @@ -10,12 +10,11 @@ using System.Runtime.CompilerServices; using Elements.Geometry.Solids; using Elements.Geometry.Interfaces; -using SixLabors.ImageSharp.Processing; using Elements.Collections.Generics; using System.Net; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp; -using Image = glTFLoader.Schema.Image; +using SixLabors.ImageSharp.PixelFormats; [assembly: InternalsVisibleTo("Hypar.Elements.Tests")] [assembly: InternalsVisibleTo("Elements.Benchmarks")] @@ -178,7 +177,7 @@ internal static Dictionary AddMaterials(this Gltf gltf, var textureDict = new Dictionary(); // the name of the texture image, the id of the texture var textures = new List(); - var images = new List(); + var images = new List(); var samplers = new List(); var matId = 0; @@ -244,8 +243,10 @@ internal static Dictionary AddMaterials(this Gltf gltf, var textureHasTransparency = false; - if (material.Texture != null && File.Exists(material.Texture)) + if (material._texture != null) { + var key = $"{material.Id}_texture"; + // Add the texture var textureInfo = new TextureInfo(); gltfMaterial.PbrMetallicRoughness.BaseColorTexture = textureInfo; @@ -256,15 +257,15 @@ internal static Dictionary AddMaterials(this Gltf gltf, ((Dictionary)gltfMaterial.Extensions["KHR_materials_pbrSpecularGlossiness"])["diffuseTexture"] = textureInfo; } - if (textureDict.ContainsKey(material.Texture)) + if (textureDict.ContainsKey(key)) { - textureInfo.Index = textureDict[material.Texture]; + textureInfo.Index = textureDict[key]; } else { var texture = new Texture(); textures.Add(texture); - var image = CreateImage(material.Texture, bufferViews, buffer, out textureHasTransparency); + var image = CreateGlTFImage(material._texture, bufferViews, buffer, out textureHasTransparency); texture.Source = imageId; images.Add(image); @@ -276,7 +277,7 @@ internal static Dictionary AddMaterials(this Gltf gltf, texture.Sampler = samplerId; samplers.Add(sampler); - textureDict.Add(material.Texture, texId); + textureDict.Add(key, texId); texId++; imageId++; @@ -284,8 +285,10 @@ internal static Dictionary AddMaterials(this Gltf gltf, } } - if (material.NormalTexture != null && File.Exists(material.NormalTexture)) + if (material._normalTexture != null) { + var key = $"{material.Id}_normal"; + var textureInfo = new MaterialNormalTextureInfo(); gltfMaterial.NormalTexture = textureInfo; textureInfo.Index = texId; @@ -294,18 +297,18 @@ internal static Dictionary AddMaterials(this Gltf gltf, // base texture. textureInfo.TexCoord = 0; - if (textureDict.ContainsKey(material.NormalTexture)) + if (textureDict.ContainsKey(key)) { - textureInfo.Index = textureDict[material.NormalTexture]; + textureInfo.Index = textureDict[key]; } else { var texture = new Texture(); textures.Add(texture); - var image = CreateImage(material.NormalTexture, bufferViews, buffer, out _); + var image = CreateGlTFImage(material._normalTexture, bufferViews, buffer, out _); texture.Source = imageId; images.Add(image); - textureDict.Add(material.NormalTexture, texId); + textureDict.Add(key, texId); var sampler = CreateSampler(material.RepeatTexture); if (!material.InterpolateTexture) @@ -321,22 +324,24 @@ internal static Dictionary AddMaterials(this Gltf gltf, } } - if (material.EmissiveTexture != null && File.Exists(material.EmissiveTexture)) + if (material._emissiveTexture != null) { + var key = $"{material.Id}_emissive"; + var textureInfo = new TextureInfo(); gltfMaterial.EmissiveTexture = textureInfo; textureInfo.Index = texId; textureInfo.TexCoord = 0; - if (textureDict.ContainsKey(material.EmissiveTexture)) + if (textureDict.ContainsKey(key)) { - textureInfo.Index = textureDict[material.EmissiveTexture]; + textureInfo.Index = textureDict[key]; } else { var texture = new Texture(); textures.Add(texture); - var image = CreateImage(material.EmissiveTexture, bufferViews, buffer, out _); + var image = CreateGlTFImage(material._emissiveTexture, bufferViews, buffer, out _); texture.Source = imageId; images.Add(image); @@ -344,7 +349,7 @@ internal static Dictionary AddMaterials(this Gltf gltf, texture.Sampler = samplerId; samplers.Add(sampler); - textureDict.Add(material.EmissiveTexture, texId); + textureDict.Add(key, texId); texId++; imageId++; @@ -400,26 +405,18 @@ private static void AddExtension(Gltf gltf, glTFLoader.Schema.Material gltfMater gltfMaterial.Extensions.Add(extensionName, extensionAttributes); } - private static Image CreateImage(string path, List bufferViews, List buffer, out bool textureHasTransparency) + private static glTFLoader.Schema.Image CreateGlTFImage(Image image, List bufferViews, List buffer, out bool textureHasTransparency) { - var image = new Image(); + var glTFImage = new glTFLoader.Schema.Image(); using (var ms = new MemoryStream()) { - // Flip the texture image vertically - // to align with OpenGL convention. - // 0,1 1,1 - // 0,0 1,0 - using (var texImage = SixLabors.ImageSharp.Image.Load(path)) - { - PngMetadata meta = texImage.Metadata.GetPngMetadata(); - textureHasTransparency = meta.ColorType == PngColorType.RgbWithAlpha || meta.ColorType == PngColorType.GrayscaleWithAlpha; - texImage.Mutate(x => x.Flip(FlipMode.Vertical)); - texImage.Save(ms, new PngEncoder()); - } + image.Save(ms, new PngEncoder()); var imageData = ms.ToArray(); - image.BufferView = AddBufferView(bufferViews, 0, buffer.Count, imageData.Length, null, null); + glTFImage.BufferView = AddBufferView(bufferViews, 0, buffer.Count, imageData.Length, null, null); buffer.AddRange(imageData); + var meta = image.Metadata.GetPngMetadata(); + textureHasTransparency = meta.ColorType == PngColorType.RgbWithAlpha || meta.ColorType == PngColorType.GrayscaleWithAlpha; } while (buffer.Count % 4 != 0) @@ -427,8 +424,8 @@ private static Image CreateImage(string path, List bufferViews, List buffer.Add(0); } - image.MimeType = Image.MimeTypeEnum.image_png; - return image; + glTFImage.MimeType = glTFLoader.Schema.Image.MimeTypeEnum.image_png; + return glTFImage; } private static Sampler CreateSampler(bool repeatTexture) @@ -959,7 +956,7 @@ internal static Gltf InitializeGlTF(Model model, var accessors = new List(); var textures = new List(); - var images = new List(); + var images = new List(); var samplers = new List(); var materials = gltf.Materials != null ? gltf.Materials.ToList() : new List(); @@ -1072,7 +1069,7 @@ private static void GetRenderDataForElement(Element e, List accessors, List materials, List textures, - List images, + List images, List samplers, List meshes, List nodes, diff --git a/Elements/src/Serialization/glTF/GltfMergingUtils.cs b/Elements/src/Serialization/glTF/GltfMergingUtils.cs index b27deecf1..8d9dd5f74 100644 --- a/Elements/src/Serialization/glTF/GltfMergingUtils.cs +++ b/Elements/src/Serialization/glTF/GltfMergingUtils.cs @@ -25,7 +25,7 @@ public static List AddAllMeshesFromFromGlb(Stream glbStream, List meshes, List materials, List textures, - List images, + List images, List samplers, bool shouldAddMaterials, System.Guid contentElementId, diff --git a/Elements/test/MaterialTests.cs b/Elements/test/MaterialTests.cs index 4f26fd3d5..ddccea3aa 100644 --- a/Elements/test/MaterialTests.cs +++ b/Elements/test/MaterialTests.cs @@ -118,8 +118,33 @@ public void BuiltInMaterialsAlwaysHaveSameId() public void ImplicitConversion() { var material = new Material("A test", (0.5, 1, 0.2)); - Assert.Equal(new Color(0.9, 0.3, 0.5, 1.0), (0.9, 0.3, 0.5)); } + + [Fact] + public void RemoteTexture() + { + this.Name = "RemoteTexture"; + var m = new Material("test", + Colors.Gray, + 0.0f, + 0.0f, + "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png", + true); + var mass = new Mass(new Circle(Vector3.Origin, 5).ToPolygon(), 10, m); + this.Model.AddElement(mass); + } + + [Fact] + public void RemoteTextureThrowsWithBadUrl() + { + this.Name = "RemoteTexture"; + Assert.Throws(() => new Material("test", + Colors.Gray, + 0.0f, + 0.0f, + "https://www.noimage.com/noimage.png", + true)); + } } } \ No newline at end of file diff --git a/Elements/test/TopographyTests.cs b/Elements/test/TopographyTests.cs index 7450dc47c..aa04d68ca 100644 --- a/Elements/test/TopographyTests.cs +++ b/Elements/test/TopographyTests.cs @@ -192,14 +192,14 @@ public void MapboxTopography() var topoImage = new Image(512 * 2, 512 * 2); var mapImage = new Image(1024 * 2, 1024 * 2); - using (var map0 = Image.Load(maps[0])) - using (var map1 = Image.Load(maps[1])) - using (var map2 = Image.Load(maps[2])) - using (var map3 = Image.Load(maps[3])) - using (var topo0 = Image.Load(topos[0])) - using (var topo1 = Image.Load(topos[1])) - using (var topo2 = Image.Load(topos[2])) - using (var topo3 = Image.Load(topos[3])) + using (var map0 = SixLabors.ImageSharp.Image.Load(maps[0])) + using (var map1 = SixLabors.ImageSharp.Image.Load(maps[1])) + using (var map2 = SixLabors.ImageSharp.Image.Load(maps[2])) + using (var map3 = SixLabors.ImageSharp.Image.Load(maps[3])) + using (var topo0 = SixLabors.ImageSharp.Image.Load(topos[0])) + using (var topo1 = SixLabors.ImageSharp.Image.Load(topos[1])) + using (var topo2 = SixLabors.ImageSharp.Image.Load(topos[2])) + using (var topo3 = SixLabors.ImageSharp.Image.Load(topos[3])) { topoImage.Mutate(o => o .DrawImage(topo0, new Point(0, 0), 1.0f)