فهرست منبع

Some more refactoring...

Vicente Penades 7 سال پیش
والد
کامیت
27092910d3

+ 40 - 8
README.md

@@ -1,8 +1,40 @@
-# glTF2Sharp
-
-glTF2Sharp is NetStandard 2.0, C# library designed to parse and create [Khronos Group glTF2](https://github.com/KhronosGroup/glTF) files.
-
-The current status of the library is preview alpha, but, for some cases it is probably fully usable.
-
-In particular, Loading ans saving both *.gltf* and binary *.glb* files is already fully supported.
-
+# glTF2Sharp
+
+glTF2Sharp is NetStandard 2.0, C# library designed to parse and create [Khronos Group glTF2](https://github.com/KhronosGroup/glTF) files.
+
+The current status of the library is preview alpha, but, for some cases it is probably fully usable.
+
+### Features
+
+- [x] glTF2 code API generated from Schema.
+- [x] Reading and writing *.gltf* files.
+- [x] Reading and writing *.glb* files.
+- [x] Logical Data Access.
+- [x] Visual Tree Access.
+- [x] Vertex and Index buffer decoding.
+- [ ] gltf.Extra field ; *Help Neeed*
+- [ ] Scene Evaluation.
+- [ ] Mesh Building utilities.
+- [ ] Animation utilities.
+- [ ] Material utilities
+
+### Supported Extensions
+
+- [x] [KHR_materials_pbrSpecularGlossiness](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness)
+- [x] [KHR_materials_unlit](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit)
+- [ ] [KHR_draco_mesh_compression](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression)
+  - Depends on [Google's Draco Project](https://github.com/google/draco) which is C++ ; *Help Needed*
+- [ ] [KHR_lights_punctual](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual)
+- [ ] [KHR_techniques_webgl](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_techniques_webgl)
+- [ ] [KHR_texture_transform](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_transform)
+- [ ] [MSFT_texture_dds](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds)
+- [ ] [MSFT_lod](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod)
+  - When this extension is used, the model's visual tree needs to be abstracted, which requires an extensive API rework.
+- [ ] [MSFT_packing_normalRoughnessMetallic](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_normalRoughnessMetallic)
+- [ ] [MSFT_packing_occlusionRoughnessMetallic](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_occlusionRoughnessMetallic)
+- [ ] [AGI_articulations](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/AGI_articulations)
+- [ ] [AGI_stk_metadata](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/AGI_stk_metadata)
+- [ ] [EXT_lights_image_based](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_lights_image_based)
+- [ ] [EXT_texture_webp](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_webp)
+- [ ] [ADOBE_materials_thin_transparency](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/ADOBE_materials_thin_transparency)
+

+ 1 - 1
src/glTF2Sharp.DOM/Debug/DebugViews.cs

@@ -50,7 +50,7 @@ namespace glTF2Sharp.Debug
         public Schema2.Accessor[] Accessors => _Value.Accessors.ToArray();
     }
 
-    [System.Diagnostics.DebuggerDisplay(" {_Value._target} Bytes:{_Value.Buffer1.Count}")]
+    [System.Diagnostics.DebuggerDisplay("{_Value.Count}")]
     internal sealed class _MemoryAccessorDebugView<T>
         where T:unmanaged
     {

+ 12 - 0
src/glTF2Sharp.DOM/Memory/Accessors.cs

@@ -142,6 +142,9 @@ namespace glTF2Sharp.Memory
     }
 
 
+    /// <summary>
+    /// Wraps a collection of Scalar values and exposes it as a collection of Vector4 values
+    /// </summary>
     struct _MapScalarToVector4 : IAccessor<Vector4>
     {
         public _MapScalarToVector4(ScalarAccessor source)
@@ -168,6 +171,9 @@ namespace glTF2Sharp.Memory
         public (Vector4, Vector4) GetBounds() { return AccessorsUtils.GetBounds(this); }
     }
 
+    /// <summary>
+    /// Wraps a collection of Vector2 values and exposes it as a collection of Vector4 values
+    /// </summary>
     struct _MapVector2ToVector4 : IAccessor<Vector4>
     {
         public _MapVector2ToVector4(Vector2Accessor source)
@@ -194,6 +200,9 @@ namespace glTF2Sharp.Memory
         public (Vector4, Vector4) GetBounds() { return AccessorsUtils.GetBounds(this); }
     }
 
+    /// <summary>
+    /// Wraps a collection of Vector3 values and exposes it as a collection of Vector4 values
+    /// </summary>
     struct _MapVector3ToVector4 : IAccessor<Vector4>
     {
         public _MapVector3ToVector4(Vector3Accessor source)
@@ -220,6 +229,9 @@ namespace glTF2Sharp.Memory
         public (Vector4, Vector4) GetBounds() { return AccessorsUtils.GetBounds(this); }
     }
 
+    /// <summary>
+    /// Wraps a collection of Quaternion values and exposes it as a collection of Vector4 values
+    /// </summary>
     struct _MapQuaternionToVector4 : IAccessor<Vector4>
     {
         public _MapQuaternionToVector4(QuaternionAccessor source)

+ 18 - 0
src/glTF2Sharp.DOM/Memory/FloatingAccessors.cs

@@ -185,6 +185,9 @@ namespace glTF2Sharp.Memory
         #endregion
     }
 
+    /// <summary>
+    /// Wraps an encoded byte array and exposes it as a collection of Single Scalar values
+    /// </summary>
     [System.Diagnostics.DebuggerTypeProxy(typeof(Debug._MemoryAccessorDebugView<Single>))]
     public struct ScalarAccessor : IAccessor<Single>
     {
@@ -231,6 +234,9 @@ namespace glTF2Sharp.Memory
         #endregion
     }
 
+    /// <summary>
+    /// Wraps an encoded byte array and exposes it as a collection of Vector2 values
+    /// </summary
     [System.Diagnostics.DebuggerTypeProxy(typeof(Debug._MemoryAccessorDebugView<Vector2>))]
     public struct Vector2Accessor : IAccessor<Vector2>
     {
@@ -287,6 +293,9 @@ namespace glTF2Sharp.Memory
         #endregion
     }
 
+    /// <summary>
+    /// Wraps an encoded byte array and exposes it as a collection of Vector3 values
+    /// </summary
     [System.Diagnostics.DebuggerTypeProxy(typeof(Debug._MemoryAccessorDebugView<Vector3>))]
     public struct Vector3Accessor: IAccessor<Vector3>
     {
@@ -344,6 +353,9 @@ namespace glTF2Sharp.Memory
         #endregion
     }
 
+    /// <summary>
+    /// Wraps an encoded byte array and exposes it as a collection of Vector4 values
+    /// </summary
     [System.Diagnostics.DebuggerTypeProxy(typeof(Debug._MemoryAccessorDebugView<Vector4>))]
     public struct Vector4Accessor: IAccessor<Vector4>
     {
@@ -402,6 +414,9 @@ namespace glTF2Sharp.Memory
         #endregion
     }
 
+    /// <summary>
+    /// Wraps an encoded byte array and exposes it as a collection of Quaternion values
+    /// </summary
     [System.Diagnostics.DebuggerTypeProxy(typeof(Debug._MemoryAccessorDebugView<Quaternion>))]
     public struct QuaternionAccessor : IAccessor<Quaternion>
     {
@@ -460,6 +475,9 @@ namespace glTF2Sharp.Memory
         #endregion
     }
 
+    /// <summary>
+    /// Wraps an encoded byte array and exposes it as a collection of Matrix4x4 values
+    /// </summary
     [System.Diagnostics.DebuggerTypeProxy(typeof(Debug._MemoryAccessorDebugView<Matrix4x4>))]
     public struct Matrix4x4Accessor : IAccessor<Matrix4x4>
     {

+ 2 - 2
src/glTF2Sharp.DOM/Memory/IntegerAccessor.cs

@@ -10,8 +10,8 @@ namespace glTF2Sharp.Memory
     using ENCODING = Schema2.IndexType;
 
     /// <summary>
-    /// Helper structure to access any Byte array as an array of Integers/>
-    /// </summary>
+    /// Wraps an encoded byte array and exposes it as a collection of UInt32 indices
+    /// </summary
     [System.Diagnostics.DebuggerTypeProxy(typeof(Debug._MemoryAccessorDebugView<UInt32>))]
     public struct IntegerAccessor : IAccessor<UInt32>
     {

+ 21 - 15
src/glTF2Sharp.DOM/Schema2/gltf.Accessors.cs

@@ -10,7 +10,7 @@ namespace glTF2Sharp.Schema2
 
     // https://github.com/KhronosGroup/glTF/issues/827#issuecomment-277537204
 
-    [System.Diagnostics.DebuggerDisplay("Accessor[{LogicalIndex}] BufferView[{Buffer.LogicalIndex}][{ByteOffset}...] => {Dimension}_{Packing}[{_count}]")]
+    [System.Diagnostics.DebuggerDisplay("Accessor[{LogicalIndex}] BufferView[{Buffer.LogicalIndex}][{ByteOffset}...] => 0 => {Dimensions}x{Encoding}x{Normalized} => [{Count}]")]
     public partial class Accessor
     {
         #region debug
@@ -67,9 +67,9 @@ namespace glTF2Sharp.Schema2
 
         #endregion
 
-        #region API
+        #region Data Buffer API
 
-        internal void SetData(BufferView buffer, int byteOffset, ComponentType encoding, ElementType dimensions, int count)
+        internal void SetData(BufferView buffer, int byteOffset, ElementType dimensions, ComponentType encoding, Boolean normalized, int count)
         {
             Guard.NotNull(buffer, nameof(buffer));
             Guard.MustShareLogicalParent(this, buffer, nameof(buffer));
@@ -78,12 +78,13 @@ namespace glTF2Sharp.Schema2
             Guard.MustBeGreaterThan(count, 0, nameof(count));
 
             this._bufferView = buffer.LogicalIndex;
-            this._componentType = encoding;
-            this._normalized = false;
-            this._type = dimensions;
             this._byteOffset = byteOffset;
             this._count = count;
 
+            this._type = dimensions;
+            this._componentType = encoding;
+            this._normalized = normalized.AsNullable(false);            
+
             _UpdateBounds();
         }
 
@@ -108,12 +109,13 @@ namespace glTF2Sharp.Schema2
             Guard.MustBeGreaterThan(count, 0, nameof(count));
 
             this._bufferView = buffer.LogicalIndex;
-            this._componentType = encoding.ToComponent();
-            this._type = ElementType.SCALAR;
-            this._normalized = null;
             this._byteOffset = byteOffset;
             this._count = count;
 
+            this._type = ElementType.SCALAR;
+            this._componentType = encoding.ToComponent();            
+            this._normalized = null;            
+
             _UpdateBounds();
         }
 
@@ -130,7 +132,7 @@ namespace glTF2Sharp.Schema2
 
         #region Vertex Buffer API
 
-        public void SetVertexData(BufferView buffer, int byteOffset, ComponentType encoding, ElementType dimensions, bool normalized, int count)
+        public void SetVertexData(BufferView buffer, int byteOffset, ElementType dimensions, ComponentType encoding, Boolean normalized, int count)
         {
             Guard.NotNull(buffer,nameof(buffer));
             Guard.MustShareLogicalParent(this, buffer, nameof(buffer));
@@ -140,12 +142,13 @@ namespace glTF2Sharp.Schema2
             Guard.MustBeGreaterThan(count, 0, nameof(count));
 
             this._bufferView = buffer.LogicalIndex;
-            this._componentType = encoding;
-            this._normalized = normalized.AsNullable(false);
-            this._type = dimensions;
             this._byteOffset = byteOffset;
             this._count = count;
 
+            this._type = dimensions;
+            this._componentType = encoding;
+            this._normalized = normalized.AsNullable(false);
+
             _UpdateBounds();
         }
 
@@ -280,9 +283,12 @@ namespace glTF2Sharp.Schema2
 
     public partial class ModelRoot
     {
-        public Accessor CreateAccessor()
+        public Accessor CreateAccessor(string name = null)
         {
-            var accessor = new Accessor();
+            var accessor = new Accessor
+            {
+                Name = name
+            };
 
             _accessors.Add(accessor);
 

+ 6 - 3
src/glTF2Sharp.DOM/Schema2/gltf.Animations.cs

@@ -22,7 +22,7 @@ namespace glTF2Sharp.Schema2
 
         #region properties
 
-        public int LogicalIndex => this.LogicalParent.Animations.IndexOfReference(this);
+        public int LogicalIndex => this.LogicalParent.LogicalAnimations.IndexOfReference(this);
 
         internal IReadOnlyList<AnimationSampler> _Samplers => _samplers;
 
@@ -193,9 +193,12 @@ namespace glTF2Sharp.Schema2
 
     public partial class ModelRoot
     {
-        public Animation CreateAnimation()
+        public Animation CreateAnimation(string name = null)
         {
-            var anim = new Animation();
+            var anim = new Animation
+            {
+                Name = name
+            };
 
             _animations.Add(anim);
 

+ 6 - 6
src/glTF2Sharp.DOM/Schema2/gltf.Asset.cs

@@ -15,7 +15,8 @@ namespace glTF2Sharp.Schema2
             {
                 _generator = "glTF2Sharp",
                 _copyright = copyright,
-                _version = MAXVERSION.ToString()
+                _version = MAXVERSION.ToString(),
+                _minVersion = MINVERSION.ToString()
             };
         }
 
@@ -24,15 +25,14 @@ namespace glTF2Sharp.Schema2
         #region properties
 
         private static readonly Version ZEROVERSION = new Version(0, 0);
-
         private static readonly Version MINVERSION = new Version(2, 0);
         private static readonly Version MAXVERSION = new Version(2, 0);
 
-        public string Copyright { get => _copyright; set => _copyright = value; }
-        public string Generator { get => _generator; set => _generator = value; }
+        public string Copyright { get => _copyright; set => _copyright = value.AsEmptyNullable(); }
+        public string Generator { get => _generator; set => _generator = value.AsEmptyNullable(); }
 
-        public Version Version { get => Version.TryParse(_version, out Version ver) ? ver : ZEROVERSION; }
-        public Version MinVersion { get => Version.TryParse(_minVersion, out Version ver) ? ver : ZEROVERSION; }
+        public Version Version      => Version.TryParse(   _version, out Version ver) ? ver : ZEROVERSION;
+        public Version MinVersion   => Version.TryParse(_minVersion, out Version ver) ? ver : ZEROVERSION;
 
         #endregion
 

+ 15 - 0
src/glTF2Sharp.DOM/Schema2/gltf.Camera.cs

@@ -25,4 +25,19 @@ namespace glTF2Sharp.Schema2
 
         #endregion        
     }
+
+    public partial class ModelRoot
+    {
+        public Camera CreateCamera(string name = null)
+        {
+            var camera = new Camera
+            {
+                Name = name
+            };
+
+            _cameras.Add(camera);
+
+            return camera;
+        }
+    }
 }

+ 14 - 2
src/glTF2Sharp.DOM/Schema2/gltf.Extensions.cs

@@ -8,14 +8,24 @@ namespace glTF2Sharp.Schema2
 
     static class ExtensionsFactory
     {
+        #region supported extensions must be registered here
+
         static ExtensionsFactory()
         {
             RegisterExtension("KHR_materials_pbrSpecularGlossiness", () => new MaterialPBRSpecularGlossiness_KHR());
             RegisterExtension("KHR_materials_unlit", () => new MaterialUnlit_KHR());
-        }
+        }        
+
+        #endregion
+
+        #region data
 
         private static readonly Dictionary<string, Func<JsonSerializable>> _Extensions = new Dictionary<string, Func<JsonSerializable>>();
 
+        #endregion
+
+        #region API
+
         public static IEnumerable<string> SupportedExtensions => _Extensions.Keys;
 
         public static void RegisterExtension(string persistentName, Func<JsonSerializable> activator)
@@ -23,11 +33,13 @@ namespace glTF2Sharp.Schema2
             _Extensions[persistentName] = activator;
         }
 
-        public static JsonSerializable Create(string key)
+        internal static JsonSerializable Create(string key)
         {
             if (!_Extensions.TryGetValue(key, out Func<JsonSerializable> activator)) return null;
 
             return activator.Invoke();
         }
+
+        #endregion
     }
 }

+ 2 - 2
src/glTF2Sharp.DOM/Schema2/gltf.Materials.cs

@@ -50,7 +50,7 @@ namespace glTF2Sharp.Schema2
 
         #region properties
 
-        public int LogicalIndex => this.LogicalParent._LogicalMaterials.IndexOfReference(this);
+        public int LogicalIndex => this.LogicalParent.LogicalMaterials.IndexOfReference(this);
 
         public AlphaMode Alpha
         {
@@ -178,7 +178,7 @@ namespace glTF2Sharp.Schema2
 
         public String Semantic => _Semantic;
 
-        public Texture Texture => _TextureInfoGetter?.Invoke(false) == null ? null : _Material.LogicalParent._LogicalTextures[_TextureInfoGetter(false)._LogicalTextureIndex];
+        public Texture Texture => _TextureInfoGetter?.Invoke(false) == null ? null : _Material.LogicalParent.LogicalTextures[_TextureInfoGetter(false)._LogicalTextureIndex];
 
         public int Set => _TextureInfoGetter?.Invoke(false) == null ? 0 : _TextureInfoGetter(false).TextureSet;
 

+ 1 - 1
src/glTF2Sharp.DOM/Schema2/gltf.MeshPrimitive.cs

@@ -33,7 +33,7 @@ namespace glTF2Sharp.Schema2
 
         public Material Material
         {
-            get => this._material.HasValue ? LogicalParent.LogicalParent._LogicalMaterials[this._material.Value] : null;
+            get => this._material.HasValue ? LogicalParent.LogicalParent.LogicalMaterials[this._material.Value] : null;
             set
             {
                 if (value != null) Guard.MustShareLogicalParent(LogicalParent.LogicalParent, value, nameof(value));

+ 19 - 12
src/glTF2Sharp.DOM/Schema2/gltf.Root.cs

@@ -47,27 +47,34 @@ namespace glTF2Sharp.Schema2
 
         public IEnumerable<String> ExtensionsRequired           => _extensionsRequired;
 
-        public IEnumerable<String> IncompatibleExtensions       => _extensionsRequired.Except(ExtensionsFactory.SupportedExtensions);
-        
-        internal IReadOnlyList<Material>    _LogicalMaterials   => _materials;
-        internal IReadOnlyList<Texture>     _LogicalTextures    => _textures;
-        internal IReadOnlyList<Sampler>     _LogicalSamplers    => _samplers;
-        internal IReadOnlyList<Image>       _LogicalImages      => _images;
+        public IEnumerable<String> IncompatibleExtensions       => _extensionsRequired.Except(ExtensionsFactory.SupportedExtensions).ToList();
 
-        public IReadOnlyList<Mesh>          LogicalMeshes       => _meshes;
-        public IReadOnlyList<Skin>          LogicalSkins        => _skins;
-        public IReadOnlyList<Camera>        LogicalCameras      => _cameras;
+        #endregion
+
+        #region Logical resouces
+
+        public IReadOnlyList<Material>      LogicalMaterials    => _materials;
+        public IReadOnlyList<Texture>       LogicalTextures     => _textures;
+        public IReadOnlyList<Sampler>       LogicalSamplers     => _samplers;
+        public IReadOnlyList<Image>         LogicalImages       => _images;
 
         public IReadOnlyList<Buffer>        LogicalBuffers      => _buffers;
         public IReadOnlyList<BufferView>    LogicalBufferViews  => _bufferViews;
         public IReadOnlyList<Accessor>      LogicalAccessors    => _accessors;
 
-        public IReadOnlyList<Node>          LogicalNodes        => _nodes;
+        public IReadOnlyList<Mesh>          LogicalMeshes       => _meshes;
+        public IReadOnlyList<Skin>          LogicalSkins        => _skins;
+        public IReadOnlyList<Camera>        LogicalCameras      => _cameras;        
 
+        public IReadOnlyList<Node>          LogicalNodes        => _nodes;
         public IReadOnlyList<Scene>         LogicalScenes       => _scenes;
-        public IReadOnlyList<Animation>     Animations          => _animations;
+        public IReadOnlyList<Animation>     LogicalAnimations   => _animations;
+
+        #endregion
+
+        #region Visual Tree
 
-        public Scene                        DefaultScene        => _scenes.Count == 0 ? null : _scenes[_scene ?? 0];
+        public Scene DefaultScene => _scenes.Count == 0 ? null : _scenes[_scene ?? 0];
 
         #endregion
 

+ 10 - 1
src/glTF2Sharp.DOM/Schema2/gltf.Scene.cs

@@ -158,11 +158,16 @@ namespace glTF2Sharp.Schema2
 
         public Node AddNode(string name)
         {
-            return this.LogicalParent._AddLogicalNode(this._children);
+            var node = this.LogicalParent._AddLogicalNode(this._children);
+            node.Name = name;
+            return node;
         }
 
         public void AddNode(Node node)
         {
+            Guard.NotNull(node,nameof(node));
+            Guard.MustShareLogicalParent(this, node, nameof(node));
+
             var idx = this.LogicalParent._UseLogicaNode(node);
 
             this._children.Add(idx);
@@ -185,6 +190,8 @@ namespace glTF2Sharp.Schema2
 
         public static IEnumerable<Node> GetNodesUsingMesh(Mesh mesh)
         {
+            if (mesh == null) return Enumerable.Empty<Node>();
+
             var meshIdx = mesh.LogicalIndex;
 
             return mesh.LogicalParent
@@ -194,6 +201,8 @@ namespace glTF2Sharp.Schema2
 
         public static IEnumerable<Node> GetNodesUsingSkin(Skin skin)
         {
+            if (skin == null) return Enumerable.Empty<Node>();
+
             var meshIdx = skin.LogicalIndex;
 
             return skin.LogicalParent

+ 5 - 5
src/glTF2Sharp.DOM/Schema2/gltf.Textures.cs

@@ -59,17 +59,17 @@ namespace glTF2Sharp.Schema2
     {
         #region properties
 
-        public int LogicalIndex => this.LogicalParent._LogicalTextures.IndexOfReference(this);
+        public int LogicalIndex => this.LogicalParent.LogicalTextures.IndexOfReference(this);
 
         public Sampler Sampler
         {
-            get => _sampler.HasValue ? LogicalParent._LogicalSamplers[_sampler.Value] : null;
+            get => _sampler.HasValue ? LogicalParent.LogicalSamplers[_sampler.Value] : null;
             set => _sampler = value == null ? null : (int?)LogicalParent._UseLogicalSampler(value);
         }
 
         public Image Source
         {
-            get => _source.HasValue ? LogicalParent._LogicalImages[_source.Value] : null;
+            get => _source.HasValue ? LogicalParent.LogicalImages[_source.Value] : null;
             set => _source = value == null ? null : (int?)LogicalParent._UseLogicalImage(value);
         }
 
@@ -95,7 +95,7 @@ namespace glTF2Sharp.Schema2
 
         #region properties
 
-        public int LogicalIndex => this.LogicalParent._LogicalSamplers.IndexOfReference(this);
+        public int LogicalIndex => this.LogicalParent.LogicalSamplers.IndexOfReference(this);
 
         public TextureInterpolationMode MagFilter => _magFilter ?? TextureInterpolationMode.LINEAR;
 
@@ -132,7 +132,7 @@ namespace glTF2Sharp.Schema2
 
         #region properties
 
-        public int LogicalIndex => this.LogicalParent._LogicalImages.IndexOfReference(this);
+        public int LogicalIndex => this.LogicalParent.LogicalImages.IndexOfReference(this);
 
         public bool IsPng => string.IsNullOrWhiteSpace(_mimeType) ? false : _mimeType.Contains("png");
         public bool IsJpeg => string.IsNullOrWhiteSpace(_mimeType) ? false : _mimeType.Contains("jpg") | _mimeType.Contains("jpeg");

+ 15 - 0
src/glTF2Sharp.DOM/_Extensions.cs

@@ -199,6 +199,21 @@ namespace glTF2Sharp
             return value;
         }
 
+        internal static String AsNullable(this string value)
+        {
+            return string.IsNullOrEmpty(value) ? null : value;
+        }
+
+        internal static String AsEmptyNullable(this string value)
+        {
+            return string.IsNullOrWhiteSpace(value) ? null : value;
+        }
+
+        internal static String AsName(this string name)
+        {
+            return string.IsNullOrWhiteSpace(name) ? null : name;
+        }        
+
         #endregion
 
         #region vertex & index accessors

+ 1 - 1
src/glTF2Sharp.Tests/Schema2/CreateModelTests.cs

@@ -45,7 +45,7 @@ namespace glTF2Sharp.Schema2
             var indicesView =   root.CreateBufferView(indices, null, null, null, BufferMode.ELEMENT_ARRAY_BUFFER);
 
             var positionsAccessor = root.CreateAccessor();
-            positionsAccessor.SetVertexData(positionsView, 0, ComponentType.FLOAT, ElementType.VEC3, false, 3);
+            positionsAccessor.SetVertexData(positionsView, 0, ElementType.VEC3, ComponentType.FLOAT, false, 3);
 
             var indicesAccessor = root.CreateAccessor();
             indicesAccessor.SetIndexData(indicesView, 0, IndexType.UNSIGNED_INT, 3);

+ 6 - 1
src/glTF2Sharp.sln

@@ -7,7 +7,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "glTF2Sharp.CodeGen", "glTF2
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "glTF2Sharp.DOM", "glTF2Sharp.DOM\glTF2Sharp.DOM.csproj", "{FEC1B7D4-36F7-45C4-8F33-EB210C3127D4}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "glTF2Sharp.Tests", "glTF2Sharp.Tests\glTF2Sharp.Tests.csproj", "{A2F7458A-6646-4BC9-8042-375E25CB2396}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "glTF2Sharp.Tests", "glTF2Sharp.Tests\glTF2Sharp.Tests.csproj", "{A2F7458A-6646-4BC9-8042-375E25CB2396}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{29566B60-311D-42A0-9E8D-C48DECDD587F}"
+	ProjectSection(SolutionItems) = preProject
+		..\README.md = ..\README.md
+	EndProjectSection
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution