Ext.InstanceFeatures.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. using SharpGLTF.Validation;
  2. using System.Collections.Generic;
  3. namespace SharpGLTF.Schema2
  4. {
  5. public partial class MeshExtInstanceFeatures
  6. {
  7. private Node _node;
  8. internal MeshExtInstanceFeatures(Node node)
  9. {
  10. _node = node;
  11. _featureIds = new List<MeshExtInstanceFeatureID>();
  12. }
  13. public List<MeshExtInstanceFeatureID> FeatureIds
  14. {
  15. get
  16. {
  17. return _featureIds;
  18. }
  19. set
  20. {
  21. _featureIds = value;
  22. }
  23. }
  24. protected override void OnValidateReferences(ValidationContext validate)
  25. {
  26. var extInstanceFeatures = _node.GetExtension<MeshExtInstanceFeatures>();
  27. validate.NotNull(nameof(extInstanceFeatures), extInstanceFeatures);
  28. var extMeshGpInstancing = _node.GetExtension<MeshGpuInstancing>();
  29. validate.NotNull(nameof(extMeshGpInstancing), extMeshGpInstancing);
  30. foreach (var instanceFeatureId in FeatureIds)
  31. {
  32. if (instanceFeatureId.Attribute.HasValue)
  33. {
  34. var expectedVertexAttribute = $"_FEATURE_ID_{instanceFeatureId.Attribute}";
  35. var gpuInstancing = _node.GetGpuInstancing();
  36. var featureIdAccessors = gpuInstancing.GetAccessor(expectedVertexAttribute);
  37. Guard.NotNull(featureIdAccessors, expectedVertexAttribute);
  38. }
  39. if (instanceFeatureId.PropertyTable.HasValue)
  40. {
  41. var metadataExtension = _node.LogicalParent.GetExtension<EXTStructuralMetadataRoot>();
  42. Guard.NotNull(metadataExtension, nameof(metadataExtension), "EXT_Structural_Metadata extension is not found.");
  43. Guard.NotNull(metadataExtension.PropertyTables[instanceFeatureId.PropertyTable.Value], nameof(instanceFeatureId.PropertyTable), $"Property table index {instanceFeatureId.PropertyTable.Value} does not exist");
  44. }
  45. }
  46. base.OnValidateReferences(validate);
  47. }
  48. protected override void OnValidateContent(ValidationContext validate)
  49. {
  50. var extInstanceFeatures = _node.GetExtension<MeshExtInstanceFeatures>();
  51. validate.NotNull(nameof(FeatureIds), extInstanceFeatures.FeatureIds);
  52. validate.IsTrue(nameof(FeatureIds), extInstanceFeatures.FeatureIds.Count > 0, "Instance FeatureIds has items");
  53. foreach (var instanceFeatureId in FeatureIds)
  54. {
  55. Guard.MustBeGreaterThanOrEqualTo((int)instanceFeatureId.FeatureCount, 1, nameof(instanceFeatureId.FeatureCount));
  56. if (instanceFeatureId.NullFeatureId.HasValue)
  57. {
  58. Guard.MustBeGreaterThanOrEqualTo((int)instanceFeatureId.NullFeatureId, 0, nameof(instanceFeatureId.NullFeatureId));
  59. }
  60. if (instanceFeatureId.Label != null)
  61. {
  62. var regex = "^[a-zA-Z_][a-zA-Z0-9_]*$";
  63. Guard.IsTrue(System.Text.RegularExpressions.Regex.IsMatch(instanceFeatureId.Label, regex), nameof(instanceFeatureId.Label));
  64. }
  65. if (instanceFeatureId.Attribute.HasValue)
  66. {
  67. Guard.MustBeGreaterThanOrEqualTo((int)instanceFeatureId.Attribute, 0, nameof(instanceFeatureId.Attribute));
  68. }
  69. if (instanceFeatureId.PropertyTable.HasValue)
  70. {
  71. Guard.MustBeGreaterThanOrEqualTo((int)instanceFeatureId.PropertyTable, 0, nameof(instanceFeatureId.PropertyTable));
  72. }
  73. }
  74. base.OnValidateContent(validate);
  75. }
  76. }
  77. public partial class MeshExtInstanceFeatureID
  78. {
  79. public MeshExtInstanceFeatureID()
  80. {
  81. }
  82. public MeshExtInstanceFeatureID(int featureCount, int? attribute = null, int? propertyTable = null, string label = null, int? nullFeatureId = null)
  83. {
  84. _featureCount = featureCount;
  85. _attribute = attribute;
  86. _label = label;
  87. _propertyTable = propertyTable;
  88. _nullFeatureId = nullFeatureId;
  89. }
  90. /// <summary>
  91. /// The number of unique features in the attribute
  92. /// </summary>
  93. public int FeatureCount { get => _featureCount; }
  94. /// <summary>
  95. /// An attribute containing feature IDs. When this is omitted, then the feature IDs are assigned to the GPU instances by their index.
  96. /// </summary>
  97. public int? Attribute { get => _attribute; }
  98. /// <summary>
  99. /// A label assigned to this feature ID set
  100. /// </summary>
  101. public string Label { get => _label; }
  102. /// <summary>
  103. /// The index of the property table containing per-feature property values. Only applicable when using the `EXT_structural_metadata` extension.
  104. /// </summary>
  105. public int? PropertyTable { get => _propertyTable; }
  106. /// <summary>
  107. /// A value that indicates that no feature is associated with this instance
  108. /// </summary>
  109. public int? NullFeatureId { get => _nullFeatureId; }
  110. }
  111. public static class ExtInstanceFeatures
  112. {
  113. /// <summary>
  114. /// Set the instance feature ids for this node.
  115. /// </summary>
  116. /// <param name="node"></param>
  117. /// <param name="instanceFeatureIds"></param>
  118. public static void SetFeatureIds(this Node node, List<MeshExtInstanceFeatureID> instanceFeatureIds)
  119. {
  120. if (instanceFeatureIds == null) { node.RemoveExtensions<MeshExtInstanceFeatures>(); return; }
  121. Guard.NotNullOrEmpty(instanceFeatureIds, nameof(instanceFeatureIds));
  122. var extMeshGpInstancing = node.GetExtension<MeshGpuInstancing>();
  123. Guard.NotNull(extMeshGpInstancing, nameof(extMeshGpInstancing));
  124. var ext = node.UseExtension<MeshExtInstanceFeatures>();
  125. ext.FeatureIds = instanceFeatureIds;
  126. }
  127. }
  128. }