Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
d49ffeb42This file is pinned to the selected release. Download the original to open it in your design tool.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using SharpGLTF.Geometry.VertexTypes;
namespace SharpGLTF.Geometry
{
public interface IPrimitiveMorphTargetReader
{
/// <summary>
/// Gets the collection of vertex indices that have morph target deltas.
/// </summary>
/// <returns>A collection of vertex indices.</returns>
IReadOnlyCollection<int> GetTargetIndices();
/// <summary>
/// Gets the vertex for the given <paramref name="vertexIndex"/> morphed by the current morph target (if any).
/// </summary>
/// <param name="vertexIndex">The index of the vertex.</param>
/// <returns>If the given index has a morphed vertex, it will return it, else ir will return the base vertex.</returns>
IVertexGeometry GetVertex(int vertexIndex);
/// <summary>
/// Gets the <see cref="VertexGeometryDelta"/> of a given vertex for a given morph target.
/// </summary>
/// <param name="vertexIndex">The index of the vertex.</param>
/// <returns>A Vertex delta (Morphed vertex minus base vertex).</returns>
VertexGeometryDelta GetVertexDelta(int vertexIndex);
}
sealed class PrimitiveMorphTargetBuilder<TvG> : IPrimitiveMorphTargetReader
where TvG : struct, IVertexGeometry
{
#region lifecycle
internal PrimitiveMorphTargetBuilder(Func<int, TvG> baseVertexFunc)
{
this._BaseVertexFunc = baseVertexFunc;
this._MorphVertices = new Dictionary<int, TvG>();
}
internal PrimitiveMorphTargetBuilder(Func<int, TvG> baseVertexFunc, PrimitiveMorphTargetBuilder<TvG> other)
{
this._BaseVertexFunc = baseVertexFunc;
this._MorphVertices = new Dictionary<int, TvG>(other._MorphVertices);
}
#endregion
#region data
private readonly Func<int, TvG> _BaseVertexFunc;
private readonly Dictionary<int, TvG> _MorphVertices;
#endregion
#region API
public IReadOnlyCollection<int> GetTargetIndices()
{
return _MorphVertices.Keys;
}
public VertexGeometryDelta GetVertexDelta(int vertexIndex)
{
if (_MorphVertices.TryGetValue(vertexIndex, out TvG value))
{
return value.Subtract(_BaseVertexFunc(vertexIndex));
}
return default;
}
public void SetVertexDelta(int vertexIndex, VertexGeometryDelta value)
{
if (object.Equals(value, default(VertexGeometryDelta)))
{
_RemoveVertex(vertexIndex);
return;
}
var vertex = _BaseVertexFunc(vertexIndex);
vertex.Add(value);
_SetVertex(vertexIndex, vertex);
}
IVertexGeometry IPrimitiveMorphTargetReader.GetVertex(int vertexIndex)
{
return _MorphVertices.TryGetValue(vertexIndex, out TvG value) ? value : _BaseVertexFunc(vertexIndex);
}
public TvG GetVertex(int vertexIndex)
{
return _MorphVertices.TryGetValue(vertexIndex, out TvG value) ? value : _BaseVertexFunc(vertexIndex);
}
public void SetVertex(int vertexIndex, TvG value)
{
if (object.Equals(value, _BaseVertexFunc(vertexIndex)))
{
_RemoveVertex(vertexIndex);
return;
}
_SetVertex(vertexIndex, value);
}
private void _SetVertex(int vertexIndex, TvG value)
{
_MorphVertices[vertexIndex] = value;
}
private void _RemoveVertex(int vertexIndex)
{
_MorphVertices.Remove(vertexIndex);
}
#endregion
#region internals
internal void TransformVertices(Func<TvG, TvG> vertexFunc)
{
foreach (var vidx in _MorphVertices.Keys)
{
var g = GetVertex(vidx);
g = vertexFunc(g);
SetVertex(vidx, g);
}
}
internal void SetMorphTargets(IPrimitiveMorphTargetReader other, IReadOnlyDictionary<int, int> vertexMap, Func<IVertexGeometry, TvG> vertexFunc)
{
Guard.NotNull(vertexFunc, nameof(vertexFunc));
var indices = other.GetTargetIndices();
foreach (var srcVidx in indices)
{
var g = vertexFunc(other.GetVertex(srcVidx));
var dstVidx = srcVidx;
if (vertexMap != null)
{
if (!vertexMap.TryGetValue(srcVidx, out dstVidx)) dstVidx = -1;
}
if (dstVidx >= 0) this.SetVertex(dstVidx, g);
}
}
#endregion
}
public interface IMorphTargetBuilder
{
IReadOnlyCollection<Vector3> Positions { get; }
IReadOnlyCollection<IVertexGeometry> Vertices { get; }
IReadOnlyList<IVertexGeometry> GetVertices(Vector3 position);
void SetVertex(IVertexGeometry meshVertex, IVertexGeometry morphVertex);
void SetVertexDelta(Vector3 key, VertexGeometryDelta delta);
void SetVertexDelta(IVertexGeometry meshVertex, VertexGeometryDelta delta);
}
/// <summary>
/// Utility class to edit the Morph targets of a mesh.
/// </summary>
public sealed class MorphTargetBuilder<TMaterial, TvG, TvS, TvM> : IMorphTargetBuilder
where TvG : struct, IVertexGeometry
where TvM : struct, IVertexMaterial
where TvS : struct, IVertexSkinning
{
#region lifecycle
internal MorphTargetBuilder(MeshBuilder<TMaterial, TvG, TvM, TvS> mesh, int morphTargetIndex)
{
_Mesh = mesh;
_MorphTargetIndex = morphTargetIndex;
foreach (var prim in _Mesh.Primitives)
{
for (int vidx = 0; vidx < prim.Vertices.Count; ++vidx)
{
var key = prim.Vertices[vidx].Geometry;
if (!_Vertices.TryGetValue(key, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
{
_Vertices[key] = val = new List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)>();
}
val.Add((prim, vidx));
if (!_Positions.TryGetValue(key.GetPosition(), out List<TvG> geos))
{
_Positions[key.GetPosition()] = geos = new List<TvG>();
}
geos.Add(key);
}
}
}
#endregion
#region data
private readonly MeshBuilder<TMaterial, TvG, TvM, TvS> _Mesh;
private readonly int _MorphTargetIndex;
private readonly Dictionary<TvG, List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)>> _Vertices = new Dictionary<TvG, List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)>>();
private readonly Dictionary<Vector3, List<TvG>> _Positions = new Dictionary<Vector3, List<TvG>>();
#endregion
#region properties
public IReadOnlyCollection<Vector3> Positions => _Positions.Keys;
public IReadOnlyCollection<TvG> Vertices => _Vertices.Keys;
IReadOnlyCollection<IVertexGeometry> IMorphTargetBuilder.Vertices => (IReadOnlyList<IVertexGeometry>)(IReadOnlyCollection<TvG>)_Vertices.Keys;
#endregion
#region API
public IReadOnlyList<TvG> GetVertices(Vector3 position)
{
return _Positions.TryGetValue(position, out List<TvG> geos) ? (IReadOnlyList<TvG>)geos : Array.Empty<TvG>();
}
IReadOnlyList<IVertexGeometry> IMorphTargetBuilder.GetVertices(Vector3 position)
{
return _Positions.TryGetValue(position, out List<TvG> geos) ? (IReadOnlyList<IVertexGeometry>)geos : Array.Empty<IVertexGeometry>();
}
public void SetVertexDelta(Vector3 key, VertexGeometryDelta delta)
{
if (_Positions.TryGetValue(key, out List<TvG> geos))
{
foreach (var g in geos) SetVertexDelta(g, delta);
}
}
public void SetVertex(TvG meshVertex, TvG morphVertex)
{
if (_Vertices.TryGetValue(meshVertex, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
{
foreach (var entry in val)
{
entry.Item1
._UseMorphTarget(_MorphTargetIndex)
.SetVertex(entry.Item2, morphVertex);
}
}
}
void IMorphTargetBuilder.SetVertex(IVertexGeometry meshVertex, IVertexGeometry morphVertex)
{
SetVertex(meshVertex.ConvertToGeometry<TvG>(), morphVertex.ConvertToGeometry<TvG>());
}
public void SetVertexDelta(TvG meshVertex, VertexGeometryDelta delta)
{
if (_Vertices.TryGetValue(meshVertex, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
{
foreach (var entry in val)
{
entry.Item1
._UseMorphTarget(_MorphTargetIndex)
.SetVertexDelta(entry.Item2, delta);
}
}
}
void IMorphTargetBuilder.SetVertexDelta(IVertexGeometry meshVertex, VertexGeometryDelta delta)
{
SetVertexDelta(meshVertex.ConvertToGeometry<TvG>(), delta);
}
#endregion
}
}