Răsfoiți Sursa

added mesh builder support tool

Vicente Penades 6 ani în urmă
părinte
comite
0cc9af92b6

+ 7 - 0
glTF2Sharp.sln

@@ -20,6 +20,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "glTF2Sharp.Tests", "src\glT
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{D7D51F42-D08C-4DDA-88DA-AF008F10B644}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeshBuffers", "src\MeshBuffers\MeshBuffers.csproj", "{1C93D96E-19DD-443B-8818-AAB14FEDA35D}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -38,6 +40,10 @@ Global
 		{4FCBB910-67D4-4628-9B2B-F5F2C8D92257}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{4FCBB910-67D4-4628-9B2B-F5F2C8D92257}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{4FCBB910-67D4-4628-9B2B-F5F2C8D92257}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1C93D96E-19DD-443B-8818-AAB14FEDA35D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1C93D96E-19DD-443B-8818-AAB14FEDA35D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1C93D96E-19DD-443B-8818-AAB14FEDA35D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1C93D96E-19DD-443B-8818-AAB14FEDA35D}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -46,6 +52,7 @@ Global
 		{E15F8DCC-987D-4FA8-B7B0-1F0614DC93DD} = {D7D51F42-D08C-4DDA-88DA-AF008F10B644}
 		{B1DA4F42-AB6A-4021-9989-674B1394E8A2} = {072B725F-773F-4751-9616-E9778897C1D2}
 		{4FCBB910-67D4-4628-9B2B-F5F2C8D92257} = {0CBF510D-D836-40BA-95EC-E93FDBB90632}
+		{1C93D96E-19DD-443B-8818-AAB14FEDA35D} = {0CBF510D-D836-40BA-95EC-E93FDBB90632}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {1D7BBAD9-834C-4981-AC96-0AA5226FC43F}

+ 105 - 0
src/MeshBuffers/ListSegment.cs

@@ -0,0 +1,105 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MeshBuffers
+{
+    struct ListSegment<T> : IList<T>
+    {
+        public ListSegment(IList<T> source) : this(source,0,source.Count) { }
+
+        public ListSegment(IList<T> source, int offset, int count)
+        {
+            if (source == null) throw new ArgumentNullException(nameof(offset));
+            if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset));
+            if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
+            if (offset >= source.Count) throw new ArgumentOutOfRangeException(nameof(offset));
+            if (offset+count-1 >= source.Count) throw new ArgumentOutOfRangeException(nameof(count));
+
+            _Source = source;
+            _Offset = offset;
+            _Count = count;
+        }
+
+        private readonly IList<T> _Source;
+        private readonly int _Offset;
+        private int _Count;
+
+        public T this[int index]
+        {
+            get
+            {
+                if (index < 0) throw new ArgumentOutOfRangeException(nameof(index));
+                if (index >= _Count) throw new ArgumentOutOfRangeException(nameof(index));
+                return _Source[_Offset + index];
+            }
+            set
+            {
+                if (index < 0) throw new ArgumentOutOfRangeException(nameof(index));
+                if (index >= _Count) throw new ArgumentOutOfRangeException(nameof(index));
+                _Source[_Offset + index] = value;
+            }
+        }
+
+        public int Count => _Count;
+
+        public bool IsReadOnly => false;
+
+        public void Add(T item)
+        {
+            _Source.Insert(_Offset + _Count, item);
+            ++_Count;
+        }
+
+        public void Clear() { throw new NotImplementedException(); }
+
+        public bool Contains(T item) { throw new NotImplementedException(); }
+
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            for(int i=0; i < _Count; ++i)
+            {
+                array[i + arrayIndex] = _Source[i + _Offset];
+            }
+        }
+
+        public int IndexOf(T item)
+        {
+            for (int i = 0; i < _Count; ++i)
+            {
+                if (Object.Equals(item, _Source[i + _Offset])) return i;
+            }
+
+            return -1;
+        }
+
+        public void Insert(int index, T item)
+        {
+            if (index < 0) throw new ArgumentOutOfRangeException(nameof(index));
+            if (index >= _Count) throw new ArgumentOutOfRangeException(nameof(index));
+            _Source.Insert(index + _Offset, item);
+            ++_Count;
+        }
+
+        public bool Remove(T item) { throw new NotImplementedException(); }
+
+        public void RemoveAt(int index) { throw new NotImplementedException(); }
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            for (int i = 0; i < _Count; ++i)
+            {
+                yield return _Source[i + _Offset];
+            }
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            for (int i = 0; i < _Count; ++i)
+            {
+                yield return _Source[i + _Offset];
+            }
+        }
+    }
+}

+ 11 - 0
src/MeshBuffers/MeshBuffers.csproj

@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
+  </ItemGroup>
+
+</Project>

+ 60 - 0
src/MeshBuffers/MeshPrimitive.cs

@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MeshBuffers
+{
+    class VertexBufferView
+    {
+        private readonly VertexBuffer _Buffer;
+        private readonly int _Offset;
+        private readonly int _Count;
+    }
+
+    class IndexBufferView
+    {
+        private readonly List<int> _Buffer;
+        private readonly int _Offset;
+        private readonly int _Count;
+    }
+
+    class MeshPrimitive
+    {
+        VertexBufferView _Vertices;
+        List<VertexBufferView> _Morphs;
+        IndexBufferView _Indices;
+    }
+
+    /*
+    [TestFixture]
+    public class MeshBuilderTests
+    {
+        [Test]
+        public void CreateVertexBufferTest()
+        {
+            var vbdecl = new VertexDeclaration()
+                .WithVector3("POSITION")
+                .WithVector3("NORMAL");
+
+            Assert.AreEqual(6, vbdecl.Stride);            
+
+            var vertex1 = vbdecl.CreateVertex();
+            var vertex2 = vbdecl.CreateVertex();
+            var vertex3 = vbdecl.CreateVertex();
+
+            var vbuffer = new TriangleBufferBuilder(vbdecl);
+
+            vertex1.Position = new Vector3(1, 2, 3);
+            vertex1.Normal = Vector3.UnitX;
+            vertex2.Position = new Vector3(4, 2, 3);
+            vertex2.Normal = Vector3.UnitY;
+            vertex3.Position = new Vector3(1, 5, 3);
+            vertex3.Normal = Vector3.UnitZ;
+
+            vbuffer.AddTriangle(vertex1, vertex2, vertex3);
+            vbuffer.AddTriangle(vertex1, vertex2, vertex3);            
+
+        }
+
+    }*/
+}

+ 64 - 0
src/MeshBuffers/TriangleBufferBuilder.cs

@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MeshBuffers
+{
+    public class TriangleBufferBuilder
+    {
+        #region lifecycle
+
+        public TriangleBufferBuilder(VertexBuffer vbuffer)
+        {
+            _Vertices = vbuffer;
+        }
+
+        public TriangleBufferBuilder(VertexDeclaration declaration)
+        {
+            _Vertices = new VertexBuffer(declaration);
+        }
+
+        #endregion
+
+        #region data        
+
+        private readonly VertexBuffer _Vertices;
+
+        private readonly List<int> _Indices = new List<int>();
+
+        private readonly Dictionary<Vertex, int> _VertexMap = new Dictionary<Vertex, int>();
+
+        #endregion
+
+        #region properties
+
+        public VertexBuffer Vertices => _Vertices;
+
+        public IReadOnlyList<int> Indices => _Indices;
+
+        #endregion
+
+        #region API
+
+        private int UseVertex(Vertex v)
+        {
+            if (_VertexMap.TryGetValue(v, out int index)) return index;
+            index = _Vertices.Count;
+
+            _Vertices.Add(v);
+            v = _Vertices[index];
+            _VertexMap[v] = index;
+
+            return index;
+        }
+
+        public void AddTriangle(Vertex a, Vertex b, Vertex c)
+        {
+            _Indices.Add(UseVertex(a));
+            _Indices.Add(UseVertex(b));
+            _Indices.Add(UseVertex(c));
+        }
+
+        #endregion
+    }
+}

+ 69 - 0
src/MeshBuffers/Vertex.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Numerics;
+using System.Linq;
+
+namespace MeshBuffers
+{
+    using ROW = ListSegment<Single>;
+
+    public struct Vertex : IEquatable<Vertex>
+    {
+        #region constructor
+
+        internal Vertex(VertexDeclaration declaration)
+        {
+            _Declaration = declaration;
+            _Data = new ROW(new Single[_Declaration.Stride]);
+        }
+
+        internal Vertex(VertexDeclaration declaration, ROW data)
+        {
+            System.Diagnostics.Debug.Assert(declaration.Stride == data.Count);
+
+            _Declaration = declaration;
+            _Data = data;
+        }
+
+        #endregion
+
+        #region data
+
+        internal readonly VertexDeclaration _Declaration;
+        internal readonly ROW _Data;
+
+        public bool Equals(Vertex other) { return AreEqual(this, other); }
+
+        public static bool AreEqual(Vertex a, Vertex b)
+        {
+            VertexDeclaration.AreEqual(a._Declaration, b._Declaration);
+            return a._Data.SequenceEqual(b._Data);
+        }
+
+        public override int GetHashCode()
+        {
+            return _Declaration.GetHashCode() ^ _Data.Select(item => item.GetHashCode()).Aggregate((a, b) => (a * 17) ^ b);
+        }
+
+        #endregion
+
+        #region properties
+
+        public VertexDeclaration Declaration => _Declaration;
+
+        public Vector3 Position
+        {
+            get => _Declaration.GetPosition(_Data);
+            set => _Declaration.SetPosition(_Data, value);
+        }
+
+        public Vector3 Normal
+        {
+            get => _Declaration.GetNormal(_Data);
+            set => _Declaration.SetNormal(_Data, value);
+        }
+
+        #endregion
+    }
+}

+ 87 - 0
src/MeshBuffers/VertexBuffer.cs

@@ -0,0 +1,87 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using System.Text;
+
+namespace MeshBuffers
+{    
+    using ROW = ListSegment<Single>;    
+
+    public class VertexBuffer : IList<Vertex>
+    {
+        #region lifecycle
+
+        public VertexBuffer(VertexDeclaration declaration)
+        {
+            _Declaration = declaration;
+            _Stride = _Declaration.Stride;
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly VertexDeclaration _Declaration;
+
+        private readonly int _Stride;
+
+        private readonly List<Single> _Data = new List<float>();
+
+        #endregion
+
+        #region API
+
+        public VertexDeclaration Declaration => _Declaration;        
+
+        public int Count => _Data.Count / _Stride;
+
+        public bool IsReadOnly => throw new NotImplementedException();
+        
+        public Vertex this[int index]
+        {
+            get => new Vertex(_Declaration, new ROW(_Data, index * _Stride, _Stride));
+            set => throw new NotImplementedException();
+        }
+
+        public void Add(Vertex vertex)
+        {
+            if (!VertexDeclaration.AreEqual(vertex._Declaration, this._Declaration)) throw new ArgumentException(nameof(vertex));
+            if (vertex._Data.Count == _Stride) throw new ArgumentException(nameof(vertex));
+            _Data.AddRange(vertex._Data);
+        }
+
+        public int IndexOf(Vertex item) { throw new NotImplementedException(); }
+
+        public void Insert(int index, Vertex item) { throw new NotImplementedException(); }
+
+        public void RemoveAt(int index) { throw new NotImplementedException(); }
+
+        public void Clear() { _Data.Clear(); }
+
+        public bool Contains(Vertex item) { throw new NotImplementedException(); }
+
+        public void CopyTo(Vertex[] array, int arrayIndex)
+        {
+            for(int i=0; i < Count; ++i)
+            {
+                array[arrayIndex + i] = this[i];
+            }
+        }
+
+        public bool Remove(Vertex item) { throw new NotImplementedException(); }
+
+        public IEnumerator<Vertex> GetEnumerator()
+        {
+            for (int i = 0; i < Count; ++i) yield return this[i];
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            for (int i = 0; i < Count; ++i) yield return this[i];
+        }
+
+        #endregion
+    }
+}

+ 144 - 0
src/MeshBuffers/VertexDeclaration.cs

@@ -0,0 +1,144 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Numerics;
+
+namespace MeshBuffers
+{
+    using ROW = ListSegment<Single>;
+
+    struct _VertexElement
+    {
+        public _VertexElement(string attribute, int dim, int offset)
+        {
+            _Attribute = attribute;
+            _Dimensions = dim;
+            _Offset = offset;
+        }
+
+        internal readonly String _Attribute;
+        internal readonly int _Dimensions;
+        internal readonly int _Offset;
+    }
+
+    public class VertexDeclaration : IEquatable<VertexDeclaration>
+    {
+        #region lifecycle
+
+        public VertexDeclaration() { _Elements = new _VertexElement[0]; }
+
+        private VertexDeclaration(_VertexElement[] elements, _VertexElement extra)
+        {
+            _Elements = new _VertexElement[elements.Length + 1];
+            elements.CopyTo(_Elements, 0);
+            _Elements[_Elements.Length - 1] = extra;
+
+            _Stride = _Elements.Sum(item => item._Dimensions);
+
+            _HashCode = _Elements.Select(item => item.GetHashCode()).Aggregate((a, b) => (a * 17) ^ b);
+
+            _PositionV3 = _Offset("POSITION");
+            _NormalV3 = _Offset("NORMAL");
+        }
+
+        private int _Offset(string attribute)
+        {
+            var element = _Elements.FirstOrDefault(item => item._Attribute == attribute);
+            return element._Attribute == null ? -1 : element._Offset;
+        }
+
+        public VertexDeclaration WithSingle(string attribute)
+        {
+            var e = new _VertexElement(attribute, 1, Stride);
+
+            return new VertexDeclaration(_Elements, e);
+        }
+
+        public VertexDeclaration WithVector2(string attribute)
+        {
+            var e = new _VertexElement(attribute, 2, Stride);
+
+            return new VertexDeclaration(_Elements, e);
+        }
+
+        public VertexDeclaration WithVector3(string attribute)
+        {
+            var e = new _VertexElement(attribute, 3, Stride);
+
+            return new VertexDeclaration(_Elements, e);
+        }
+
+        public VertexDeclaration WithVector4(string attribute)
+        {
+            var e = new _VertexElement(attribute, 4, Stride);
+
+            return new VertexDeclaration(_Elements, e);
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly _VertexElement[] _Elements;
+        private readonly int _Stride;
+        private readonly int _HashCode;
+
+        private readonly int _PositionV3;
+        private readonly int _NormalV3;
+
+        public bool Equals(VertexDeclaration other) { return AreEqual(this, other); }
+
+        public static bool AreEqual(VertexDeclaration a, VertexDeclaration b)
+        {
+            if (Object.ReferenceEquals(a, b)) return true;
+            return Enumerable.SequenceEqual(a._Elements, b._Elements);
+        }
+
+        public override int GetHashCode() { return _HashCode; }
+
+        #endregion
+
+        #region API
+
+        public int Stride => _Stride;
+
+        public Vertex CreateVertex() { return new Vertex(this); }
+
+        internal Vector3 GetPosition(ROW vertex)
+        {
+            return new Vector3
+                (
+                vertex[_PositionV3 + 0],
+                vertex[_PositionV3 + 1],
+                vertex[_PositionV3 + 2]
+                );
+        }
+
+        internal void SetPosition(ROW vertex, Vector3 value)
+        {
+            vertex[_PositionV3 + 0] = value.X;
+            vertex[_PositionV3 + 1] = value.Y;
+            vertex[_PositionV3 + 2] = value.Z;
+        }
+
+        internal Vector3 GetNormal(ROW vertex)
+        {
+            return new Vector3
+                (
+                vertex[_NormalV3 + 0],
+                vertex[_NormalV3 + 1],
+                vertex[_NormalV3 + 2]
+                );
+        }
+
+        internal void SetNormal(ROW vertex, Vector3 value)
+        {
+            vertex[_NormalV3 + 0] = value.X;
+            vertex[_NormalV3 + 1] = value.Y;
+            vertex[_NormalV3 + 2] = value.Z;
+        }
+
+        #endregion
+    }
+}

+ 42 - 0
src/glTF2Sharp.Tests/MeshBuffers/VertexBuffer.cs

@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using System.Text;
+
+using NUnit.Framework;
+
+namespace MeshBuffers
+{
+    [TestFixture]
+    public class MeshBuffersTests
+    {
+        [Test]
+        public void CreateVertexBufferTest()
+        {
+            var vbdecl = new VertexDeclaration()
+                .WithVector3("POSITION")
+                .WithVector3("NORMAL");
+
+            Assert.AreEqual(6, vbdecl.Stride);            
+
+            var vertex1 = vbdecl.CreateVertex();
+            var vertex2 = vbdecl.CreateVertex();
+            var vertex3 = vbdecl.CreateVertex();
+
+            var vbuffer = new TriangleBufferBuilder(vbdecl);
+
+            vertex1.Position = new Vector3(1, 2, 3);
+            vertex1.Normal = Vector3.UnitX;
+            vertex2.Position = new Vector3(4, 2, 3);
+            vertex2.Normal = Vector3.UnitY;
+            vertex3.Position = new Vector3(1, 5, 3);
+            vertex3.Normal = Vector3.UnitZ;
+
+            vbuffer.AddTriangle(vertex1, vertex2, vertex3);
+            vbuffer.AddTriangle(vertex1, vertex2, vertex3);            
+
+        }
+
+    }
+}

+ 1 - 0
src/glTF2Sharp.Tests/glTF2Sharp.Tests.csproj

@@ -17,6 +17,7 @@
 
   <ItemGroup>
     <ProjectReference Include="..\glTF2Sharp.DOM\glTF2Sharp.DOM.csproj" />
+    <ProjectReference Include="..\MeshBuffers\MeshBuffers.csproj" />
   </ItemGroup>
 
 </Project>