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(); VertexBuilder ConvertTo() where TvPP : struct, IVertexGeometry where TvMM : struct, IVertexMaterial where TvSS : struct, IVertexSkinning; // void SetGeometry(IVertexGeometry); // void SetMaterial(IVertexMaterial); // void SetSkinning(IVertexSkinning); } /// /// Represents an individual vertex object. /// /// /// The vertex fragment type with Position, Normal and Tangent. /// Valid types are: /// , /// , /// . /// /// /// The vertex fragment type with Colors and Texture Coordinates. /// Valid types are: /// , /// , /// , /// . /// . /// . /// /// /// The vertex fragment type with Skin Joint Weights. /// Valid types are: /// , /// , /// , /// , /// . /// [System.Diagnostics.DebuggerDisplay("Vertex 𝐏:{Position} {_GetDebugWarnings()}")] public partial struct VertexBuilder : IVertexBuilder where TvG : struct, IVertexGeometry where TvM : struct, IVertexMaterial where TvS : struct, IVertexSkinning { #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; Skinning = default; for (int i = 0; i < bindings.Length; ++i) { Skinning.SetJointBinding(i, bindings[i].Item1, bindings[i].Item2); } } 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, float)[] bindings) { Geometry = g; Material = default; Skinning = default; for (int i = 0; i < bindings.Length; ++i) { Skinning.SetJointBinding(i, bindings[i].Item1, bindings[i].Item2); } } public static implicit operator VertexBuilder((TvG, TvM, TvS) tuple) { return new VertexBuilder(tuple.Item1, tuple.Item2, tuple.Item3); } public static implicit operator VertexBuilder((TvG, TvM) tuple) { return new VertexBuilder(tuple.Item1, tuple.Item2); } public static implicit operator VertexBuilder((TvG, TvS) tuple) { return new VertexBuilder(tuple.Item1, tuple.Item2); } public static implicit operator VertexBuilder(TvG g) { return new VertexBuilder(g); } public static VertexBuilder Create(Vector3 position) { var v = default(VertexBuilder); v.Geometry.SetPosition(position); return v; } public static VertexBuilder Create(Vector3 position,Vector3 normal) { var v = default(VertexBuilder); v.Geometry.SetPosition(position); v.Geometry.SetNormal(normal); return v; } public static VertexBuilder Create(Vector3 position, Vector3 normal, Vector4 tangent) { var v = default(VertexBuilder); v.Geometry.SetPosition(position); v.Geometry.SetNormal(normal); v.Geometry.SetTangent(tangent); return v; } #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 WithGeometry(Vector3 position) { var v = this; v.Geometry.SetPosition(position); return v; } public VertexBuilder WithGeometry(Vector3 position, Vector3 normal) { var v = this; v.Geometry.SetPosition(position); v.Geometry.SetNormal(normal); return v; } public VertexBuilder 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 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 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 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 WithSkinning(params (int, float)[] bindings) { var v = this; int i = 0; while (i < bindings.Length) { v.Skinning.SetJointBinding(i, bindings[i].Item1, bindings[i].Item2); ++i; } while (i < bindings.Length) { v.Skinning.SetJointBinding(i, 0, 0); ++i; } return v; } public void Validate() { Geometry.Validate(); Material.Validate(); Skinning.Validate(); } public VertexBuilder ConvertTo() where TvPP : struct, IVertexGeometry where TvMM : struct, IVertexMaterial where TvSS : struct, IVertexSkinning { var p = Geometry.ConvertTo(); var m = Material.ConvertTo(); var s = Skinning.ConvertTo(); return new VertexBuilder(p, m, s); } public static MeshBuilder CreateCompatibleMesh(string name = null) { return new MeshBuilder(name); } public static MeshBuilder CreateCompatibleMesh(string name = null) { return new MeshBuilder(name); } private String _GetDebugWarnings() { var sb = new StringBuilder(); if (Geometry.TryGetNormal(out Vector3 n)) { if (!n.IsValidNormal()) 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._IsReal() | !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._IsReal()) sb.Append($" ❌𝐔𝐕{i}:{uv}"); } for (int i = 0; i < Skinning.MaxBindings; ++i) { var jw = Skinning.GetJointBinding(i); if (!jw.Weight._IsReal() || jw.Weight < 0 || jw.Joint < 0) sb.Append($" ❌𝐉𝐖{i} {jw.Joint}:{jw.Weight}"); } return sb.ToString(); } IVertexGeometry IVertexBuilder.GetGeometry() { return this.Geometry; } IVertexMaterial IVertexBuilder.GetMaterial() { return this.Material; } IVertexSkinning IVertexBuilder.GetSkinning() { return this.Skinning; } #endregion } }