Browse Source

Merge pull request #167 from MeltyPlayer/obj

Optimized file generation in WavefrontWriter.
Vicente Penades 2 years ago
parent
commit
8a7da18ecd
1 changed files with 67 additions and 62 deletions
  1. 67 62
      src/SharpGLTF.Toolkit/IO/WavefrontWriter.cs

+ 67 - 62
src/SharpGLTF.Toolkit/IO/WavefrontWriter.cs

@@ -1,10 +1,12 @@
 using System;
 using System;
 using System.Collections;
 using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Numerics;
 using System.Numerics;
 using System.Text;
 using System.Text;
 
 
+using SharpGLTF.Memory;
 using SharpGLTF.Schema2;
 using SharpGLTF.Schema2;
 
 
 using static System.FormattableString;
 using static System.FormattableString;
@@ -55,14 +57,13 @@ namespace SharpGLTF.IO
         {
         {
             Guard.NotNullOrEmpty(filePath, nameof(filePath));
             Guard.NotNullOrEmpty(filePath, nameof(filePath));
 
 
-            var files = GetFiles(System.IO.Path.GetFileNameWithoutExtension(filePath));
-
             var dir = System.IO.Path.GetDirectoryName(filePath);
             var dir = System.IO.Path.GetDirectoryName(filePath);
 
 
-            foreach (var f in files)
+            foreach (var fileNameAndGenerator in _GetFileGenerators(System.IO.Path.GetFileNameWithoutExtension(filePath)))
             {
             {
-                var fpath = System.IO.Path.Combine(dir, f.Key);
-                System.IO.File.WriteAllBytes(fpath, f.Value.ToArray());
+                var fpath = System.IO.Path.Combine(dir, fileNameAndGenerator.Key);
+                using var fs = File.OpenWrite(fpath);
+                fileNameAndGenerator.Value(fs);
             }
             }
         }
         }
 
 
@@ -81,17 +82,33 @@ namespace SharpGLTF.IO
             Guard.IsFalse(baseName.Any(c => char.IsWhiteSpace(c)), nameof(baseName), "Whitespace characters not allowed in filename");
             Guard.IsFalse(baseName.Any(c => char.IsWhiteSpace(c)), nameof(baseName), "Whitespace characters not allowed in filename");
 
 
             var files = new Dictionary<String, BYTES>();
             var files = new Dictionary<String, BYTES>();
+            foreach (var fileNameAndGenerator in _GetFileGenerators(baseName)) 
+            {
+                using var mem = new MemoryStream();
+                fileNameAndGenerator.Value(mem);
 
 
-            var materials = _WriteMaterials(files, baseName, _Mesh.Primitives.Select(item => item.Material));
-
-            var geocontent = _GetGeometryContent(materials, baseName + ".mtl");
+                mem.TryGetBuffer(out var bytes);
 
 
-            _WriteTextContent(files, baseName + ".obj", geocontent);
+                files[fileNameAndGenerator.Key] = bytes;
+            }
 
 
             return files;
             return files;
         }
         }
 
 
-        private static IReadOnlyDictionary<Material, string> _WriteMaterials(IDictionary<String, BYTES> files, string baseName, IEnumerable<Material> materials)
+        private IReadOnlyDictionary<String, Action<Stream>> _GetFileGenerators(string baseName) 
+        {
+            Guard.IsFalse(baseName.Any(c => char.IsWhiteSpace(c)), nameof(baseName), "Whitespace characters not allowed in filename");
+
+            var fileGenerators = new Dictionary<String, Action<Stream>>();
+
+            var materials = _GetMaterialFileGenerator(fileGenerators, baseName, _Mesh.Primitives.Select(item => item.Material));
+
+            fileGenerators[baseName + ".obj"] = fs => _GetGeometryContent(new StreamWriter(fs), materials, baseName + ".mtl");
+
+            return fileGenerators;
+        }
+
+        private static IReadOnlyDictionary<Material, string> _GetMaterialFileGenerator(IDictionary<String, Action<Stream>> fileGenerators, string baseName, IEnumerable<Material> materials)
         {
         {
             // write all image files
             // write all image files
             var images = materials
             var images = materials
@@ -101,76 +118,81 @@ namespace SharpGLTF.IO
 
 
             bool firstImg = true;
             bool firstImg = true;
 
 
+            var imageNameByImage = new Dictionary<MemoryImage, string>();
             foreach (var img in images)
             foreach (var img in images)
             {
             {
                 var imgName = firstImg
                 var imgName = firstImg
                     ? $"{baseName}.{img.FileExtension}"
                     ? $"{baseName}.{img.FileExtension}"
-                    : $"{baseName}_{files.Count}.{img.FileExtension}";
+                    : $"{baseName}_{fileGenerators.Count}.{img.FileExtension}";
 
 
-                files[imgName] = new BYTES(img.Content.ToArray());
+                fileGenerators[imgName] = fs => {
+                    var bytes = img.Content.ToArray();
+                    fs.Write(bytes, 0, bytes.Length);
+                };
                 firstImg = false;
                 firstImg = false;
+
+                imageNameByImage[img] = imgName;
             }
             }
 
 
             // write materials
             // write materials
 
 
             var mmap = new Dictionary<Material, string>();
             var mmap = new Dictionary<Material, string>();
-
-            var sb = new StringBuilder();
-
-            foreach (var m in materials)
+            foreach (var m in materials) 
             {
             {
                 mmap[m] = $"Material_{mmap.Count}";
                 mmap[m] = $"Material_{mmap.Count}";
-
-                sb.AppendLine($"newmtl {mmap[m]}");
-                sb.AppendLine("illum 2");
-                sb.AppendLine(Invariant($"Ka {m.DiffuseColor.X} {m.DiffuseColor.Y} {m.DiffuseColor.Z}"));
-                sb.AppendLine(Invariant($"Kd {m.DiffuseColor.X} {m.DiffuseColor.Y} {m.DiffuseColor.Z}"));
-                sb.AppendLine(Invariant($"Ks {m.SpecularColor.X} {m.SpecularColor.Y} {m.SpecularColor.Z}"));
-
-                if (m.DiffuseTexture.IsValid)
-                {
-                    var imgName = files.FirstOrDefault(kvp => new Memory.MemoryImage(kvp.Value) == m.DiffuseTexture ).Key;
-                    sb.AppendLine($"map_Kd {imgName}");
-                }
-
-                sb.AppendLine();
             }
             }
 
 
             // write material library
             // write material library
-            _WriteTextContent(files, baseName + ".mtl", sb);
+            fileGenerators[baseName + ".mtl"] = fs =>
+            {
+                var sw = new StreamWriter(fs);
+                foreach (var m in materials) 
+                {
+                    sw.WriteLine($"newmtl {mmap[m]}");
+                    sw.WriteLine("illum 2");
+                    sw.WriteLine(Invariant($"Ka {m.DiffuseColor.X} {m.DiffuseColor.Y} {m.DiffuseColor.Z}"));
+                    sw.WriteLine(Invariant($"Kd {m.DiffuseColor.X} {m.DiffuseColor.Y} {m.DiffuseColor.Z}"));
+                    sw.WriteLine(Invariant($"Ks {m.SpecularColor.X} {m.SpecularColor.Y} {m.SpecularColor.Z}"));
+
+                    if (m.DiffuseTexture.IsValid) {
+                        var imgName = imageNameByImage[m.DiffuseTexture];
+                        sw.WriteLine($"map_Kd {imgName}");
+                    }
+
+                    sw.WriteLine();
+                }
+            };
 
 
             return mmap;
             return mmap;
         }
         }
 
 
-        private StringBuilder _GetGeometryContent(IReadOnlyDictionary<Material, string> materials, string mtlLib)
+        private void _GetGeometryContent(StreamWriter sw, IReadOnlyDictionary<Material, string> materials, string mtlLib)
         {
         {
-            var sb = new StringBuilder();
-
-            sb.AppendLine($"mtllib {mtlLib}");
+            sw.WriteLine($"mtllib {mtlLib}");
 
 
-            sb.AppendLine();
+            sw.WriteLine();
 
 
             foreach (var p in _Mesh.Primitives)
             foreach (var p in _Mesh.Primitives)
             {
             {
                 foreach (var v in p.Vertices)
                 foreach (var v in p.Vertices)
                 {
                 {
                     var pos = v.Position;
                     var pos = v.Position;
-                    sb.AppendLine(Invariant($"v {pos.X} {pos.Y} {pos.Z}"));
+                    sw.WriteLine(Invariant($"v {pos.X} {pos.Y} {pos.Z}"));
                 }
                 }
             }
             }
 
 
-            sb.AppendLine();
+            sw.WriteLine();
 
 
             foreach (var p in _Mesh.Primitives)
             foreach (var p in _Mesh.Primitives)
             {
             {
                 foreach (var v in p.Vertices)
                 foreach (var v in p.Vertices)
                 {
                 {
                     var nrm = v.Geometry.Normal;
                     var nrm = v.Geometry.Normal;
-                    sb.AppendLine(Invariant($"vn {nrm.X} {nrm.Y} {nrm.Z}"));
+                    sw.WriteLine(Invariant($"vn {nrm.X} {nrm.Y} {nrm.Z}"));
                 }
                 }
             }
             }
 
 
-            sb.AppendLine();
+            sw.WriteLine();
 
 
             foreach (var p in _Mesh.Primitives)
             foreach (var p in _Mesh.Primitives)
             {
             {
@@ -179,13 +201,13 @@ namespace SharpGLTF.IO
                     var uv = v.Material.TexCoord;
                     var uv = v.Material.TexCoord;
                     uv.Y = 1 - uv.Y;
                     uv.Y = 1 - uv.Y;
 
 
-                    sb.AppendLine(Invariant($"vt {uv.X} {uv.Y}"));
+                    sw.WriteLine(Invariant($"vt {uv.X} {uv.Y}"));
                 }
                 }
             }
             }
 
 
-            sb.AppendLine();
+            sw.WriteLine();
 
 
-            sb.AppendLine("g default");
+            sw.WriteLine("g default");
 
 
             var baseVertexIndex = 1;
             var baseVertexIndex = 1;
 
 
@@ -193,7 +215,7 @@ namespace SharpGLTF.IO
             {
             {
                 var mtl = materials[p.Material];
                 var mtl = materials[p.Material];
 
 
-                sb.AppendLine($"usemtl {mtl}");
+                sw.WriteLine($"usemtl {mtl}");
 
 
                 foreach (var t in p.Triangles)
                 foreach (var t in p.Triangles)
                 {
                 {
@@ -201,28 +223,11 @@ namespace SharpGLTF.IO
                     var b = t.B + baseVertexIndex;
                     var b = t.B + baseVertexIndex;
                     var c = t.C + baseVertexIndex;
                     var c = t.C + baseVertexIndex;
 
 
-                    sb.AppendLine(Invariant($"f {a}/{a}/{a} {b}/{b}/{b} {c}/{c}/{c}"));
+                    sw.WriteLine(Invariant($"f {a}/{a}/{a} {b}/{b}/{b} {c}/{c}/{c}"));
                 }
                 }
 
 
                 baseVertexIndex += p.Vertices.Count;
                 baseVertexIndex += p.Vertices.Count;
             }
             }
-
-            return sb;
-        }
-
-        private static void _WriteTextContent(IDictionary<string, BYTES> files, string fileName, StringBuilder sb)
-        {
-            using (var mem = new System.IO.MemoryStream())
-            {
-                using (var tex = new System.IO.StreamWriter(mem))
-                {
-                    tex.Write(sb.ToString());
-                }
-
-                mem.TryGetBuffer(out BYTES content);
-
-                files[fileName] = content;
-            }
         }
         }
 
 
         #endregion
         #endregion