| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Microsoft.Xna.Framework.Graphics;
- using SharpGLTF.Schema2;
- namespace SharpGLTF.Runtime
- {
- /// <summary>
- /// Helper class used to import a glTF model into MonoGame
- /// </summary>
- class LoaderContext
- {
- #region lifecycle
- public LoaderContext(GraphicsDevice device)
- {
- _Device = device;
- _MatFactory = new MaterialFactory(device, _Disposables);
- }
- #endregion
- #region data
- private GraphicsDevice _Device;
- private readonly GraphicsResourceTracker _Disposables = new GraphicsResourceTracker();
- private readonly MaterialFactory _MatFactory;
- private readonly Dictionary<Mesh, ModelMesh> _StaticMeshes = new Dictionary<Mesh, ModelMesh>();
- private readonly Dictionary<Mesh, ModelMesh> _SkinnedMeshes = new Dictionary<Mesh, ModelMesh>();
-
- #endregion
- #region properties
- public IReadOnlyList<GraphicsResource> Disposables => _Disposables.Disposables;
- #endregion
- #region Mesh API
- private static IEnumerable<Schema2.MeshPrimitive> GetValidPrimitives(Schema2.Mesh srcMesh)
- {
- foreach (var srcPrim in srcMesh.Primitives)
- {
- var ppp = srcPrim.GetVertexAccessor("POSITION");
- if (ppp.Count < 3) continue;
- if (srcPrim.DrawPrimitiveType == Schema2.PrimitiveType.POINTS) continue;
- if (srcPrim.DrawPrimitiveType == Schema2.PrimitiveType.LINES) continue;
- if (srcPrim.DrawPrimitiveType == Schema2.PrimitiveType.LINE_LOOP) continue;
- if (srcPrim.DrawPrimitiveType == Schema2.PrimitiveType.LINE_STRIP) continue;
- yield return srcPrim;
- }
- }
- public ModelMesh CreateMesh(Schema2.Mesh srcMesh, int maxBones = 72)
- {
- if (_Device == null) throw new InvalidOperationException();
- var srcPrims = GetValidPrimitives(srcMesh).ToList();
- var dstMesh = new ModelMesh(_Device, Enumerable.Range(0, srcPrims.Count).Select(item => new ModelMeshPart()).ToList());
- dstMesh.Name = srcMesh.Name;
- dstMesh.BoundingSphere = srcMesh.CreateBoundingSphere();
- var srcNormals = new MeshNormalsFallback(srcMesh);
- var idx = 0;
- foreach (var srcPrim in srcPrims)
- {
- CreateMeshPart(dstMesh.MeshParts[idx++], srcPrim, srcNormals, maxBones);
- }
- return dstMesh;
- }
- private void CreateMeshPart(ModelMeshPart dstPart, MeshPrimitive srcPart, MeshNormalsFallback normalsFunc, int maxBones)
- {
- var doubleSided = srcPart.Material?.DoubleSided ?? false;
- var srcGeometry = new MeshPrimitiveReader(srcPart, doubleSided, normalsFunc);
- var eff = srcGeometry.IsSkinned ? _MatFactory.UseSkinnedEffect(srcPart.Material) : _MatFactory.UseStaticEffect(srcPart.Material);
- dstPart.Effect = eff;
- var vb = srcGeometry.IsSkinned ? CreateVertexBuffer(srcGeometry.ToXnaSkinned()) : CreateVertexBuffer(srcGeometry.ToXnaStatic());
- dstPart.VertexBuffer = vb;
- dstPart.NumVertices = srcGeometry.VertexCount;
- dstPart.VertexOffset = 0;
- dstPart.IndexBuffer = CreateIndexBuffer(srcGeometry.TriangleIndices);
- dstPart.PrimitiveCount = srcGeometry.TriangleIndices.Length;
- dstPart.StartIndex = 0;
- }
-
- #endregion
- #region resources API
- private VertexBuffer CreateVertexBuffer<T>(T[] dstVertices) where T:struct, IVertexType
- {
- var vb = new VertexBuffer(_Device, typeof(T), dstVertices.Length, BufferUsage.None);
- _Disposables.AddDisposable(vb);
- vb.SetData(dstVertices);
- return vb;
- }
- private IndexBuffer CreateIndexBuffer(IEnumerable<(int, int, int)> triangles)
- {
- var sequence32 = triangles
- .SelectMany(item => new[] { (UInt32)item.Item3, (UInt32)item.Item2, (UInt32)item.Item1 })
- .ToArray();
- var max = sequence32.Max();
- if (max > 65535)
- {
- var indices = new IndexBuffer(_Device, typeof(UInt32), sequence32.Length, BufferUsage.None);
- _Disposables.AddDisposable(indices);
- indices.SetData(sequence32);
- return indices;
- }
- else
- {
- var sequence16 = sequence32.Select(item => (UInt16)item).ToArray();
- var indices = new IndexBuffer(_Device, typeof(UInt16), sequence16.Length, BufferUsage.None);
- _Disposables.AddDisposable(indices);
- indices.SetData(sequence16);
- return indices;
- }
- }
- #endregion
- }
- }
|