// SPDX-FileCopyrightText: 2023 Unity Technologies and the glTFast authors // SPDX-License-Identifier: Apache-2.0 using System; namespace GLTFast.Schema { /// /// The topology type of primitives to render /// /// public enum DrawMode { /// Points Points = 0, /// Lines Lines = 1, /// Line loop LineLoop = 2, /// Line strip LineStrip = 3, /// Triangles Triangles = 4, /// Triangle strip TriangleStrip = 5, /// Triangle fan TriangleFan = 6 } /// [Serializable] public class MeshPrimitive : MeshPrimitiveBase { } /// /// Mesh primitive extensions type [Serializable] public class MeshPrimitiveBase : MeshPrimitiveBase where TExtensions : MeshPrimitiveExtensions { /// public TExtensions extensions; /// public override MeshPrimitiveExtensions Extensions => extensions; /// internal override void UnsetExtensions() { extensions = null; } } /// /// Geometry to be rendered with the given material. /// [Serializable] public abstract class MeshPrimitiveBase : ICloneable, IMaterialsVariantsSlot { /// /// A dictionary object, where each key corresponds to mesh attribute semantic /// and each value is the index of the accessor containing attribute's data. /// public Attributes attributes; /// /// The index of the accessor that contains mesh indices. /// When this is not defined, the primitives should be rendered without indices /// using `drawArrays()`. When defined, the accessor must contain indices: /// the `bufferView` referenced by the accessor must have a `target` equal /// to 34963 (ELEMENT_ARRAY_BUFFER); a `byteStride` that is tightly packed, /// i.e., 0 or the byte size of `componentType` in bytes; /// `componentType` must be 5121 (UNSIGNED_BYTE), 5123 (UNSIGNED_SHORT) /// or 5125 (UNSIGNED_INT), the latter is only allowed /// when `OES_element_index_uint` extension is used; `type` must be `\"SCALAR\"`. /// public int indices = -1; /// /// The index of the material to apply to this primitive when rendering. /// public int material = -1; /// /// The type of primitives to render. All valid values correspond to WebGL enums. /// public DrawMode mode = DrawMode.Triangles; /// /// An array of Morph Targets, each Morph Target is a dictionary mapping /// attributes to their deviations /// in the Morph Target (index of the accessor containing the attribute /// displacements' data). /// public MorphTarget[] targets; /// public abstract MeshPrimitiveExtensions Extensions { get; } /// public int GetMaterialIndex(int variantIndex) { var mapping = Extensions?.KHR_materials_variants; if (mapping != null && mapping.TryGetMaterialIndex(variantIndex, out var materialIndex)) { return materialIndex; } return material; } /// ` /// Sets to null. /// internal abstract void UnsetExtensions(); #if DRACO_IS_INSTALLED public bool IsDracoCompressed => Extensions!=null && Extensions.KHR_draco_mesh_compression != null; #endif /// /// Determines whether two object instances are equal. /// /// The object to compare with the current object. /// true if the specified object is equal to the current object; otherwise, false. // TODO: Remove upon next major release. This serves no purpose anymore except keeping the API intact. public override bool Equals(object obj) { // ReSharper disable once BaseObjectEqualsIsObjectEquals return base.Equals(obj); } /// /// Default hash function. /// /// A hash code for the current object. // TODO: Remove upon next major release. This serves no purpose anymore except keeping the API intact. public override int GetHashCode() { // ReSharper disable once BaseObjectGetHashCodeCallInGetHashCode return base.GetHashCode(); } /// /// Clones the object /// /// Member-wise clone public object Clone() { return MemberwiseClone(); } internal void GltfSerialize(JsonWriter writer) { writer.AddObject(); if (attributes != null) { writer.AddProperty("attributes"); attributes.GltfSerialize(writer); } if (indices >= 0) { writer.AddProperty("indices", indices); } if (material >= 0) { writer.AddProperty("material", material); } if (mode != DrawMode.Triangles) { writer.AddProperty("mode", (int)mode); } if (targets != null) { writer.AddArray("targets"); foreach (var target in targets) { target.GltfSerialize(writer); } writer.CloseArray(); } if (Extensions != null) { writer.AddProperty("extensions"); Extensions.GltfSerialize(writer); } writer.Close(); } } /// /// Mesh vertex attribute collection. Each property value is the index of /// the accessor containing attribute’s data. /// [Serializable] public class Attributes { // Names are identical to glTF specified property names, that's why // inconsistent names are ignored. // ReSharper disable InconsistentNaming /// Vertex position accessor index. public int POSITION = -1; /// Vertex normals accessor index. public int NORMAL = -1; /// Vertex tangents accessor index. public int TANGENT = -1; /// Texture coordinates accessor index. public int TEXCOORD_0 = -1; /// Texture coordinates accessor index (second UV set). public int TEXCOORD_1 = -1; /// Texture coordinates accessor index (third UV set). public int TEXCOORD_2 = -1; /// Texture coordinates accessor index (fourth UV set). public int TEXCOORD_3 = -1; /// Texture coordinates accessor index (fifth UV set). public int TEXCOORD_4 = -1; /// Texture coordinates accessor index (sixth UV set). public int TEXCOORD_5 = -1; /// Texture coordinates accessor index (seventh UV set). public int TEXCOORD_6 = -1; /// Texture coordinates accessor index (eighth UV set). public int TEXCOORD_7 = -1; /// Texture coordinates accessor index (ninth UV set). public int TEXCOORD_8 = -1; /// Vertex color accessor index. public int COLOR_0 = -1; /// Bone joints accessor index. public int JOINTS_0 = -1; /// Bone weights accessor index. public int WEIGHTS_0 = -1; // ReSharper restore InconsistentNaming /// /// Determines whether two object instances are equal. /// /// The object to compare with the current object. /// true if the specified object is equal to the current object; otherwise, false. // TODO: Remove upon next major release. This serves no purpose anymore except keeping the API intact. public override bool Equals(object obj) { // ReSharper disable once BaseObjectEqualsIsObjectEquals return base.Equals(obj); } /// /// Default hash function. /// /// A hash code for the current object. // TODO: Remove upon next major release. This serves no purpose anymore except keeping the API intact. public override int GetHashCode() { // ReSharper disable once BaseObjectGetHashCodeCallInGetHashCode return base.GetHashCode(); } /// /// Calculates the texture coordinate set quantity. /// /// Texture coordinate set quantity. public int GetTexCoordsCount() { if (TEXCOORD_0 < 0) return 0; if (TEXCOORD_1 < 0) return 1; if (TEXCOORD_2 < 0) return 2; if (TEXCOORD_3 < 0) return 3; if (TEXCOORD_4 < 0) return 4; if (TEXCOORD_5 < 0) return 5; if (TEXCOORD_6 < 0) return 6; if (TEXCOORD_7 < 0) return 7; return TEXCOORD_8 < 0 ? 8 : 9; } /// /// Tries to consolidate all `TEXCOORD_*` accessor fields into a single array. /// /// Resulting array of accessor indices. /// If true, the glTF has more UV sets than glTFast supports. /// True if there's one or more UV sets and the result is valid. False otherwise. public bool TryGetAllUVAccessors(out int[] uvAccessors, out bool limitExceeded) { if (TEXCOORD_0 >= 0) { var uvCount = GetTexCoordsCount(); uvAccessors = new int[uvCount]; uvAccessors[0] = TEXCOORD_0; if (TEXCOORD_1 >= 0) { uvAccessors[1] = TEXCOORD_1; } if (TEXCOORD_2 >= 0) { uvAccessors[2] = TEXCOORD_2; } if (TEXCOORD_3 >= 0) { uvAccessors[3] = TEXCOORD_3; } if (TEXCOORD_4 >= 0) { uvAccessors[4] = TEXCOORD_4; } if (TEXCOORD_5 >= 0) { uvAccessors[5] = TEXCOORD_5; } if (TEXCOORD_6 >= 0) { uvAccessors[6] = TEXCOORD_6; } if (TEXCOORD_7 >= 0) { uvAccessors[7] = TEXCOORD_7; } limitExceeded = TEXCOORD_8 >= 0; return true; } uvAccessors = null; limitExceeded = false; return false; } internal void GltfSerialize(JsonWriter writer) { writer.AddObject(); if (POSITION >= 0) writer.AddProperty("POSITION", POSITION); if (NORMAL >= 0) writer.AddProperty("NORMAL", NORMAL); if (TANGENT >= 0) writer.AddProperty("TANGENT", TANGENT); if (TEXCOORD_0 >= 0) writer.AddProperty("TEXCOORD_0", TEXCOORD_0); if (TEXCOORD_1 >= 0) writer.AddProperty("TEXCOORD_1", TEXCOORD_1); if (TEXCOORD_2 >= 0) writer.AddProperty("TEXCOORD_2", TEXCOORD_2); if (TEXCOORD_3 >= 0) writer.AddProperty("TEXCOORD_3", TEXCOORD_3); if (TEXCOORD_4 >= 0) writer.AddProperty("TEXCOORD_4", TEXCOORD_4); if (TEXCOORD_5 >= 0) writer.AddProperty("TEXCOORD_5", TEXCOORD_5); if (TEXCOORD_6 >= 0) writer.AddProperty("TEXCOORD_6", TEXCOORD_6); if (TEXCOORD_7 >= 0) writer.AddProperty("TEXCOORD_7", TEXCOORD_7); if (COLOR_0 >= 0) writer.AddProperty("COLOR_0", COLOR_0); if (JOINTS_0 >= 0) writer.AddProperty("JOINTS_0", JOINTS_0); if (WEIGHTS_0 >= 0) writer.AddProperty("WEIGHTS_0", WEIGHTS_0); writer.Close(); } } /// /// Mesh primitive extensions /// [Serializable] public class MeshPrimitiveExtensions { #if DRACO_IS_INSTALLED // ReSharper disable once InconsistentNaming public MeshPrimitiveDracoExtension KHR_draco_mesh_compression; #endif /// // ReSharper disable once InconsistentNaming public MaterialsVariantsMeshPrimitiveExtension KHR_materials_variants; internal void GltfSerialize(JsonWriter writer) { writer.AddObject(); #if DRACO_IS_INSTALLED if (KHR_draco_mesh_compression != null) { writer.AddProperty("KHR_draco_mesh_compression"); KHR_draco_mesh_compression.GltfSerialize(writer); } #endif if (KHR_materials_variants != null) { writer.AddProperty("KHR_materials_variants"); KHR_materials_variants.GltfSerialize(writer); } writer.Close(); } } #if DRACO_IS_INSTALLED [Serializable] public class MeshPrimitiveDracoExtension { public int bufferView; public Attributes attributes; internal void GltfSerialize(JsonWriter writer) { writer.AddObject(); writer.AddProperty("bufferView", bufferView); writer.AddProperty("attributes"); attributes.GltfSerialize(writer); writer.Close(); } } #endif /// /// Morph target (blend shape) /// [Serializable] public class MorphTarget { // Names are identical to glTF specified property names, that's why // inconsistent names are ignored. // ReSharper disable InconsistentNaming /// Vertex position deviation accessor index. public int POSITION = -1; /// Vertex normal deviation accessor index. public int NORMAL = -1; /// Vertex tangent deviation accessor index. public int TANGENT = -1; // ReSharper restore InconsistentNaming /// /// Determines whether two object instances are equal. /// /// The object to compare with the current object. /// true if the specified object is equal to the current object; otherwise, false. // TODO: Remove upon next major release. This serves no purpose anymore except keeping the API intact. public override bool Equals(object obj) { // ReSharper disable once BaseObjectEqualsIsObjectEquals return base.Equals(obj); } /// /// Default hash function. /// /// A hash code for the current object. // TODO: Remove upon next major release. This serves no purpose anymore except keeping the API intact. public override int GetHashCode() { // ReSharper disable once BaseObjectGetHashCodeCallInGetHashCode return base.GetHashCode(); } internal void GltfSerialize(JsonWriter writer) { if (POSITION >= 0) writer.AddProperty("POSITION", POSITION); if (NORMAL >= 0) writer.AddProperty("NORMAL", NORMAL); if (TANGENT >= 0) writer.AddProperty("TANGENT", TANGENT); } } }