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.Text;
using System.Numerics;
using SharpGLTF.Geometry.VertexTypes;
namespace SharpGLTF.Geometry
{
public interface IVertexBuilder
{
IVertexGeometry GetGeometry();
IVertexMaterial GetMaterial();
IVertexSkinning GetSkinning();
/// <summary>
/// Applies a <see cref="IVertexGeometry"/> set to this <see cref="VertexBuilder{TvG, TvM, TvS}"/>
/// Remember we're working with struct types; <see href="https://blogs.msdn.microsoft.com/abhinaba/2005/10/05/c-structs-and-interface/"/>
/// </summary>
/// <param name="geometry">A <see cref="IVertexGeometry"/> set.</param>
void SetGeometry(IVertexGeometry geometry);
/// <summary>
/// Applies a <see cref="IVertexMaterial"/> set to this <see cref="VertexBuilder{TvG, TvM, TvS}"/>
/// Remember we're working with struct types; <see href="https://blogs.msdn.microsoft.com/abhinaba/2005/10/05/c-structs-and-interface/"/>
/// </summary>
/// <param name="material">A <see cref="IVertexMaterial"/> set.</param>
void SetMaterial(IVertexMaterial material);
/// <summary>
/// Applies a <see cref="IVertexSkinning"/> set to this <see cref="VertexBuilder{TvG, TvM, TvS}"/>
/// Remember we're working with struct types; <see href="https://blogs.msdn.microsoft.com/abhinaba/2005/10/05/c-structs-and-interface/"/>
/// </summary>
/// <param name="skinning">A <see cref="IVertexSkinning"/> set.</param>
void SetSkinning(IVertexSkinning skinning);
}
/// <summary>
/// Represents an individual vertex object.
/// </summary>
/// <typeparam name="TvG">
/// The vertex fragment type with Position, Normal and Tangent.
/// Valid types are:
/// <see cref="VertexPosition"/>,
/// <see cref="VertexPositionNormal"/>,
/// <see cref="VertexPositionNormalTangent"/>.
/// </typeparam>
/// <typeparam name="TvM">
/// The vertex fragment type with Colors and Texture Coordinates.
/// Valid types are:
/// <see cref="VertexEmpty"/>,
/// <see cref="VertexColor1"/>,
/// <see cref="VertexTexture1"/>,
/// <see cref="VertexColor1Texture1"/>.
/// <see cref="VertexColor1Texture2"/>.
/// <see cref="VertexColor2Texture2"/>.
/// </typeparam>
/// <typeparam name="TvS">
/// The vertex fragment type with Skin Joint Weights.
/// Valid types are:
/// <see cref="VertexEmpty"/>,
/// <see cref="VertexJoints4"/>,
/// <see cref="VertexJoints8"/>.
/// </typeparam>
[System.Diagnostics.DebuggerDisplay("{_GetDebuggerDisplay(),nq}")]
public partial struct VertexBuilder<TvG, TvM, TvS> : IVertexBuilder
where TvG : struct, IVertexGeometry
where TvM : struct, IVertexMaterial
where TvS : struct, IVertexSkinning
{
#region debug
internal string _GetDebuggerDisplay()
{
var txt = "Vertex";
txt += " " + _GetDebuggerDisplayTextFrom(Geometry);
txt += " " + _GetDebuggerDisplayTextFrom(Material);
txt += " " + _GetDebuggerDisplayTextFrom(Skinning);
return txt;
}
private static string _GetDebuggerDisplayTextFrom(Object o)
{
if (o is VertexEmpty) return string.Empty;
var bindings = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance;
var method = o.GetType().GetMethod("_GetDebuggerDisplay", bindings);
if (method == null) return string.Empty;
return method.Invoke(o, Array.Empty<Object>()) as string;
}
private String _GetDebugWarnings()
{
var sb = new StringBuilder();
if (Geometry.TryGetNormal(out Vector3 n))
{
if (!n.IsNormalized()) sb.Append($" ❌𝚴:{n}");
}
if (Geometry.TryGetTangent(out Vector4 t))
{
if (!t.IsValidTangent()) sb.Append($" ❌𝚻:{t}");
}
for (int i = 0; i < Material.MaxColors; ++i)
{
var c = Material.GetColor(i);
if (!c._IsFinite() | !c.IsInRange(Vector4.Zero, Vector4.One)) sb.Append($" ❌𝐂{i}:{c}");
}
for (int i = 0; i < Material.MaxTextCoords; ++i)
{
var uv = Material.GetTexCoord(i);
if (!uv._IsFinite()) sb.Append($" ❌𝐔𝐕{i}:{uv}");
}
for (int i = 0; i < Skinning.MaxBindings; ++i)
{
var jw = Skinning.GetJointBinding(i);
if (!jw.Weight._IsFinite() || jw.Weight < 0 || jw.Index < 0) sb.Append($" ❌𝐉𝐖{i} {jw.Index}:{jw.Weight}");
}
return sb.ToString();
}
#endregion
#region constructors
public VertexBuilder(TvG g, TvM m, TvS s)
{
Geometry = g;
Material = m;
Skinning = s;
}
public VertexBuilder(TvG g, TvM m, params (int, float)[] bindings)
{
Geometry = g;
Material = m;
var sparse = Transforms.SparseWeight8.Create(bindings);
Skinning = default;
Skinning.SetWeights(sparse);
}
public VertexBuilder(TvG g, TvM m, Transforms.SparseWeight8 bindings)
{
Geometry = g;
Material = m;
Skinning = default;
Skinning.SetWeights(bindings);
}
public VertexBuilder(TvG g, TvM m)
{
Geometry = g;
Material = m;
Skinning = default;
}
public VertexBuilder(TvG g, TvS s)
{
Geometry = g;
Material = default;
Skinning = s;
}
public VertexBuilder(TvG g)
{
Geometry = g;
Material = default;
Skinning = default;
}
public VertexBuilder(TvG g, params (int Index, float Weight)[] bindings)
{
Geometry = g;
Material = default;
var sparse = Transforms.SparseWeight8.Create(bindings);
Skinning = default;
Skinning.SetWeights(sparse);
}
public VertexBuilder(TvG g, Transforms.SparseWeight8 bindings)
{
Geometry = g;
Material = default;
Skinning = default;
Skinning.SetWeights(bindings);
}
public static implicit operator VertexBuilder<TvG, TvM, TvS>((TvG Geo, TvM Mat, TvS Skin) tuple)
{
return new VertexBuilder<TvG, TvM, TvS>(tuple.Geo, tuple.Mat, tuple.Skin);
}
public static implicit operator VertexBuilder<TvG, TvM, TvS>((TvG Geo, TvM Mat) tuple)
{
return new VertexBuilder<TvG, TvM, TvS>(tuple.Geo, tuple.Mat);
}
public static implicit operator VertexBuilder<TvG, TvM, TvS>((TvG Geo, TvS Skin) tuple)
{
return new VertexBuilder<TvG, TvM, TvS>(tuple.Geo, tuple.Skin);
}
public static implicit operator VertexBuilder<TvG, TvM, TvS>(TvG g)
{
return new VertexBuilder<TvG, TvM, TvS>(g);
}
#pragma warning disable CA1000 // Do not declare static members on generic types
public static VertexBuilder<TvG, TvM, TvS> Create(Vector3 position)
{
var v = default(VertexBuilder<TvG, TvM, TvS>);
v.Geometry.SetPosition(position);
return v;
}
public static VertexBuilder<TvG, TvM, TvS> Create(Vector3 position, Vector3 normal)
{
var v = default(VertexBuilder<TvG, TvM, TvS>);
v.Geometry.SetPosition(position);
v.Geometry.SetNormal(normal);
return v;
}
public static VertexBuilder<TvG, TvM, TvS> Create(Vector3 position, Vector3 normal, Vector4 tangent)
{
var v = default(VertexBuilder<TvG, TvM, TvS>);
v.Geometry.SetPosition(position);
v.Geometry.SetNormal(normal);
v.Geometry.SetTangent(tangent);
return v;
}
public static VertexBuilder<TvG, TvM, TvS> CreateFrom(IVertexBuilder src)
{
if (src is VertexBuilder<TvG, TvM, TvS> srcTyped) return srcTyped;
Guard.NotNull(src, nameof(src));
var dst = default(VertexBuilder<TvG, TvM, TvS>);
dst.Geometry = src.GetGeometry().ConvertToGeometry<TvG>();
dst.Material = src.GetMaterial().ConvertToMaterial<TvM>();
dst.Skinning = src.GetSkinning().ConvertToSkinning<TvS>();
return dst;
}
#pragma warning restore CA1000 // Do not declare static members on generic types
#endregion
#region data
public TvG Geometry;
public TvM Material;
public TvS Skinning;
#endregion
#region properties
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
public Vector3 Position
{
get => Geometry.GetPosition();
set => Geometry.SetPosition(value);
}
#endregion
#region API
public VertexBuilder<TvG, TvM, TvS> WithGeometry(Vector3 position)
{
var v = this;
v.Geometry.SetPosition(position);
return v;
}
public VertexBuilder<TvG, TvM, TvS> WithGeometry(Vector3 position, Vector3 normal)
{
var v = this;
v.Geometry.SetPosition(position);
v.Geometry.SetNormal(normal);
return v;
}
public VertexBuilder<TvG, TvM, TvS> WithGeometry(Vector3 position, Vector3 normal, Vector4 tangent)
{
var v = this;
v.Geometry.SetPosition(position);
v.Geometry.SetNormal(normal);
v.Geometry.SetTangent(tangent);
return v;
}
public VertexBuilder<TvG, TvM, TvS> WithMaterial(params Vector2[] uvs)
{
var v = this;
for (int i = 0; i < uvs.Length; ++i) v.Material.SetTexCoord(i, uvs[i]);
return v;
}
public VertexBuilder<TvG, TvM, TvS> WithMaterial(Vector4 color0, params Vector2[] uvs)
{
var v = this;
v.Material.SetColor(0, color0);
for (int i = 0; i < uvs.Length; ++i) v.Material.SetTexCoord(i, uvs[i]);
return v;
}
public VertexBuilder<TvG, TvM, TvS> WithMaterial(Vector4 color0, Vector4 color1, params Vector2[] uvs)
{
var v = this;
v.Material.SetColor(0, color0);
v.Material.SetColor(1, color1);
for (int i = 0; i < uvs.Length; ++i) v.Material.SetTexCoord(i, uvs[i]);
return v;
}
public VertexBuilder<TvG, TvM, TvS> WithSkinning(params (int Index, float Weight)[] bindings)
{
var v = this;
int i = 0;
while (i < bindings.Length)
{
v.Skinning.SetJointBinding(i, bindings[i].Index, bindings[i].Weight);
++i;
}
while (i < bindings.Length)
{
v.Skinning.SetJointBinding(i, 0, 0);
++i;
}
return v;
}
public VertexBuilder<TvG, TvM, TvS> TransformedBy(in Matrix4x4 transform)
{
var clone = this;
clone.Geometry.ApplyTransform(transform);
return clone;
}
public void Validate()
{
Geometry.Validate();
Material.Validate();
Skinning.Validate();
}
#pragma warning disable CA1000 // Do not declare static members on generic types
public static MeshBuilder<TMaterial, TvG, TvM, TvS> CreateCompatibleMesh<TMaterial>(string name = null)
{
return new MeshBuilder<TMaterial, TvG, TvM, TvS>(name);
}
public static MeshBuilder<TvG, TvM, TvS> CreateCompatibleMesh(string name = null)
{
return new MeshBuilder<TvG, TvM, TvS>(name);
}
#pragma warning restore CA1000 // Do not declare static members on generic types
IVertexGeometry IVertexBuilder.GetGeometry() { return this.Geometry; }
IVertexMaterial IVertexBuilder.GetMaterial() { return this.Material; }
IVertexSkinning IVertexBuilder.GetSkinning() { return this.Skinning; }
void IVertexBuilder.SetGeometry(IVertexGeometry geometry)
{
Guard.NotNull(geometry, nameof(geometry));
this.Geometry = geometry.ConvertToGeometry<TvG>();
}
void IVertexBuilder.SetMaterial(IVertexMaterial material)
{
Guard.NotNull(material, nameof(material));
this.Material = material.ConvertToMaterial<TvM>();
}
void IVertexBuilder.SetSkinning(IVertexSkinning skinning)
{
Guard.NotNull(skinning, nameof(skinning));
this.Skinning = skinning.ConvertToSkinning<TvS>();
}
#endregion
}
struct VertexBuilder : IVertexBuilder
{
#region constructor
public VertexBuilder(IVertexGeometry g)
{
this.Geometry = g;
this.Material = null;
this.Skinning = null;
}
public VertexBuilder(IVertexGeometry g, IVertexMaterial m, IVertexSkinning s)
{
this.Geometry = g;
this.Material = m;
this.Skinning = s;
}
#endregion
#region data
public IVertexGeometry Geometry;
public IVertexMaterial Material;
public IVertexSkinning Skinning;
#endregion
#region API
public IVertexGeometry GetGeometry() { return Geometry; }
public IVertexMaterial GetMaterial() { return Material; }
public IVertexSkinning GetSkinning() { return Skinning; }
public void SetGeometry(IVertexGeometry geometry) { this.Geometry = geometry; }
public void SetMaterial(IVertexMaterial material) { this.Material = material; }
public void SetSkinning(IVertexSkinning skinning) { this.Skinning = skinning; }
public IVertexBuilder ConvertToType(Type vertexType)
{
var v = (IVertexBuilder)Activator.CreateInstance(vertexType);
v.SetGeometry(Geometry);
v.SetMaterial(Material);
v.SetSkinning(Skinning);
return v;
}
#endregion
}
}