@haiyue/extensions 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/README.md +25 -0
  2. package/dist/animation/Animation2DComponent.d.ts +18 -0
  3. package/dist/animation/Animation2DExtensionRegistry.d.ts +7 -0
  4. package/dist/animation/Animation2DRenderSystem.d.ts +6 -0
  5. package/dist/animation/Animation2DRuntime.d.ts +6 -2
  6. package/dist/animation/AnimationTextRasterizer.d.ts +4 -0
  7. package/dist/animation/AnimationVisual2D.d.ts +58 -2
  8. package/dist/animation/interaction/InteractionRuntime.d.ts +83 -0
  9. package/dist/animation/interaction/runtime-types.d.ts +257 -0
  10. package/dist/animation.d.ts +3 -1
  11. package/dist/animation.js +551 -59
  12. package/dist/animation3d.js +1 -1
  13. package/dist/canvas-text.js +1 -1
  14. package/dist/chunks/2d-ui-animation-2d.generated-FpziAeGJ.js +4 -0
  15. package/dist/chunks/2d-ui-indexed-sprite.generated-DmKR0CC3.js +4 -0
  16. package/dist/chunks/Animation2DStateMachine-BHcA6Cu3.js +18212 -0
  17. package/dist/chunks/{AnimationStateMachineController-BIcAh-sT.js → AnimationStateMachineController-4sKaqh9E.js} +2 -2
  18. package/dist/chunks/AnimationVisual2D-8y3qp0_U.js +230 -0
  19. package/dist/chunks/{RenderSystem2DBase-DDT61dAu.js → RenderSystem2DBase-CF2s00vg.js} +2 -2
  20. package/dist/controls/VirtualJoystickControls.d.ts +46 -0
  21. package/dist/controls/contracts.d.ts +91 -0
  22. package/dist/controls.d.ts +2 -0
  23. package/dist/controls.js +358 -0
  24. package/dist/deformable-animation/runtime/DeformableMesh2DRuntimeExtension.d.ts +11 -0
  25. package/dist/deformable-animation/runtime/DeformableMesh2DSampler.d.ts +11 -0
  26. package/dist/deformable-animation.d.ts +5 -0
  27. package/dist/deformable-animation.js +316 -0
  28. package/dist/experimental-indexed-sprite.d.ts +5 -0
  29. package/dist/experimental-indexed-sprite.js +482 -0
  30. package/dist/gltf-worker-runtime.js +9 -9
  31. package/dist/hya-state-machine.js +3 -2
  32. package/dist/index.js +1 -1
  33. package/dist/indexed-sprite/AtlasLayout.d.ts +2 -0
  34. package/dist/indexed-sprite/IndexedSpriteRenderer.d.ts +23 -0
  35. package/dist/indexed-sprite/contracts.d.ts +89 -0
  36. package/dist/internal/2d-ui-shader-artifact.js +232 -23
  37. package/dist/ray-tracing/acceleration/bvh.d.ts +37 -0
  38. package/dist/ray-tracing/acceleration/index.d.ts +6 -0
  39. package/dist/ray-tracing/acceleration/pack.d.ts +152 -0
  40. package/dist/ray-tracing/acceleration/query.d.ts +4 -0
  41. package/dist/ray-tracing/acceleration/runtime.d.ts +30 -0
  42. package/dist/ray-tracing/acceleration/tlas.d.ts +4 -0
  43. package/dist/ray-tracing/acceleration/types.d.ts +165 -0
  44. package/dist/ray-tracing/denoise/index.d.ts +3 -0
  45. package/dist/ray-tracing/denoise/layout.d.ts +9 -0
  46. package/dist/ray-tracing/denoise/runtime.d.ts +23 -0
  47. package/dist/ray-tracing/denoise/types.d.ts +28 -0
  48. package/dist/ray-tracing/hybrid/contract.d.ts +2 -0
  49. package/dist/ray-tracing/hybrid/index.d.ts +5 -0
  50. package/dist/ray-tracing/hybrid/layout.d.ts +17 -0
  51. package/dist/ray-tracing/hybrid/plan.d.ts +2 -0
  52. package/dist/ray-tracing/hybrid/runtime.d.ts +31 -0
  53. package/dist/ray-tracing/hybrid/shaders/hybrid-artifact.generated.d.ts +625 -0
  54. package/dist/ray-tracing/hybrid/types.d.ts +144 -0
  55. package/dist/ray-tracing/lifecycle/device-recovery.d.ts +31 -0
  56. package/dist/ray-tracing/lifecycle/index.d.ts +2 -0
  57. package/dist/ray-tracing/lifecycle/types.d.ts +37 -0
  58. package/dist/ray-tracing/material/index.d.ts +2 -0
  59. package/dist/ray-tracing/material/pack.d.ts +5 -0
  60. package/dist/ray-tracing/material/types.d.ts +63 -0
  61. package/dist/ray-tracing/reference/index.d.ts +122 -0
  62. package/dist/ray-tracing/renderer/index.d.ts +7 -0
  63. package/dist/ray-tracing/renderer/layout.d.ts +20 -0
  64. package/dist/ray-tracing/renderer/plan.d.ts +2 -0
  65. package/dist/ray-tracing/renderer/reference.d.ts +17 -0
  66. package/dist/ray-tracing/renderer/runtime.d.ts +39 -0
  67. package/dist/ray-tracing/renderer/scene.d.ts +4 -0
  68. package/dist/ray-tracing/renderer/types.d.ts +115 -0
  69. package/dist/ray-tracing/sampling/index.d.ts +8 -0
  70. package/dist/ray-tracing/sampling/layout.d.ts +12 -0
  71. package/dist/ray-tracing/sampling/plan.d.ts +5 -0
  72. package/dist/ray-tracing/sampling/revision.d.ts +15 -0
  73. package/dist/ray-tracing/sampling/runtime.d.ts +44 -0
  74. package/dist/ray-tracing/sampling/sequence.d.ts +2 -0
  75. package/dist/ray-tracing/sampling/types.d.ts +96 -0
  76. package/dist/ray-tracing/scene/index.d.ts +41 -0
  77. package/dist/ray-tracing/traversal/index.d.ts +4 -0
  78. package/dist/ray-tracing/traversal/layout.d.ts +16 -0
  79. package/dist/ray-tracing/traversal/plan.d.ts +2 -0
  80. package/dist/ray-tracing/traversal/runtime.d.ts +25 -0
  81. package/dist/ray-tracing/traversal/types.d.ts +79 -0
  82. package/dist/ray-tracing/worker/client.d.ts +25 -0
  83. package/dist/ray-tracing/worker/index.d.ts +5 -0
  84. package/dist/ray-tracing/worker/runtime.d.ts +11 -0
  85. package/dist/ray-tracing/worker/serialization.d.ts +16 -0
  86. package/dist/ray-tracing/worker/source.d.ts +1 -0
  87. package/dist/ray-tracing/worker/types.d.ts +91 -0
  88. package/dist/ray-tracing.d.ts +17 -0
  89. package/dist/ray-tracing.js +7666 -0
  90. package/dist/spine.js +1 -1
  91. package/dist/tilemap.js +1 -1
  92. package/package.json +26 -23
  93. package/dist/animation/Animation2DStateMachineVisualRuntime.d.ts +0 -27
  94. package/dist/animation/Particle2DDescriptorAdapter.d.ts +0 -5
  95. package/dist/animation3d/Animation3DResource.d.ts +0 -28
  96. package/dist/animation3d/hya/HyaAnimation3DStateMachineRuntime.d.ts +0 -65
  97. package/dist/animation3d/hya/index.d.ts +0 -4
  98. package/dist/animation3d/runtime/integration/Animation3DStateMachineMixerAdapter.d.ts +0 -81
  99. package/dist/animation3d/runtime/integration/Animation3DStateMachineMixerIntegration.d.ts +0 -39
  100. package/dist/animation3d/runtime/integration/index.d.ts +0 -2
  101. package/dist/animation3d/runtime/mixer/Action.d.ts +0 -150
  102. package/dist/animation3d/runtime/mixer/Animation3DMixerRuntimeStore.d.ts +0 -6
  103. package/dist/animation3d/runtime/mixer/Mixer.d.ts +0 -59
  104. package/dist/animation3d/runtime/mixer/PoseBuffer.d.ts +0 -1
  105. package/dist/animation3d/runtime/mixer/TrackSampler.d.ts +0 -24
  106. package/dist/animation3d/runtime/mixer/index.d.ts +0 -4
  107. package/dist/animation3d/runtime/state-machine/Animation3DBlendTreeWeights.d.ts +0 -1
  108. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineCompiler.d.ts +0 -1
  109. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineController.d.ts +0 -1
  110. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineMixerPort.d.ts +0 -1
  111. package/dist/animation3d/runtime/state-machine/index.d.ts +0 -6
  112. package/dist/benchmark.d.ts +0 -30
  113. package/dist/chunks/2d-ui-animation-2d.generated-D4aHzFU2.js +0 -4
  114. package/dist/chunks/Animation2DStateMachine-9IonguNa.js +0 -3245
  115. package/dist/gltf/GltfAccessorReader.d.ts +0 -7
  116. package/dist/gltf/GltfDracoDecoder.d.ts +0 -4
  117. package/dist/gltf/GltfLoaderErrors.d.ts +0 -4
  118. package/dist/gltf/GltfMaterialDescriptor.d.ts +0 -23
  119. package/dist/gltf/GltfMaterialLoader.d.ts +0 -6
  120. package/dist/gltf-worker-runtime.d.ts +0 -7
  121. package/dist/plugins/pluginUtils.d.ts +0 -20
  122. package/dist/plugins.d.ts +0 -6
  123. package/dist/shaders/generated/2d-ui-artifact.generated.d.ts +0 -658
  124. package/dist/spine/Spine2DGpuRenderer.d.ts +0 -65
  125. package/dist/spine/Spine2DRuntime.d.ts +0 -103
  126. package/dist/spine/SpineAnimationBoneTimelines.d.ts +0 -8
  127. package/dist/spine/SpineFloatBuilder.d.ts +0 -15
  128. package/dist/spine/SpinePathConstraintSolver.d.ts +0 -32
  129. package/dist/spine/SpineSkeletonRuntime.d.ts +0 -185
  130. package/dist/spine/SpineSlotAnimation.d.ts +0 -17
  131. package/dist/spine/SpineTimelineRuntime.d.ts +0 -25
  132. package/dist/spine/SpineVertexBuilder.d.ts +0 -61
  133. package/dist/tilemap/Tilemap2DRenderer.d.ts +0 -24
  134. package/dist/utils/arrayAccess.d.ts +0 -4
  135. package/dist/utils/camera2d.d.ts +0 -12
  136. package/src/animation/Animation2DComponent.ts +0 -135
  137. package/src/animation/Animation2DExtensionRegistry.ts +0 -52
  138. package/src/animation/Animation2DRenderSystem.ts +0 -1026
  139. package/src/animation/Animation2DRuntime.ts +0 -1326
  140. package/src/animation/Animation2DStateMachine.ts +0 -39
  141. package/src/animation/Animation2DStateMachineComponent.ts +0 -228
  142. package/src/animation/Animation2DStateMachineRuntime.ts +0 -141
  143. package/src/animation/Animation2DStateMachineSystem.ts +0 -60
  144. package/src/animation/Animation2DStateMachineVisualRuntime.ts +0 -282
  145. package/src/animation/Animation2DSystem.ts +0 -72
  146. package/src/animation/AnimationAssetLoader.ts +0 -84
  147. package/src/animation/AnimationAudioClip.ts +0 -140
  148. package/src/animation/AnimationPathTessellator.ts +0 -691
  149. package/src/animation/AnimationTextRasterizer.ts +0 -340
  150. package/src/animation/AnimationVisual2D.ts +0 -153
  151. package/src/animation/HyaAnimation2DClipAdapter.ts +0 -845
  152. package/src/animation/Particle2DDescriptorAdapter.ts +0 -35
  153. package/src/animation/runtime/mixer/Action.ts +0 -876
  154. package/src/animation/runtime/mixer/Mixer.ts +0 -505
  155. package/src/animation/runtime/mixer/PoseBuffer.ts +0 -105
  156. package/src/animation/runtime/mixer/Sampler.ts +0 -252
  157. package/src/animation/runtime/mixer/Types.ts +0 -138
  158. package/src/animation/runtime/mixer/index.ts +0 -31
  159. package/src/animation-state-machine/AnimationStateMachine.ts +0 -146
  160. package/src/animation-state-machine/AnimationStateMachineChannels.ts +0 -116
  161. package/src/animation-state-machine/runtime/Animation2DStateMachineMixerAdapter.ts +0 -197
  162. package/src/animation-state-machine/runtime/AnimationStateMachineBlendTreeWeights.ts +0 -503
  163. package/src/animation-state-machine/runtime/AnimationStateMachineCompiler.ts +0 -763
  164. package/src/animation-state-machine/runtime/AnimationStateMachineController.ts +0 -987
  165. package/src/animation-state-machine/runtime/AnimationStateMachineMixerPort.ts +0 -54
  166. package/src/animation-state-machine/runtime/index.ts +0 -47
  167. package/src/animation.ts +0 -33
  168. package/src/animation3d/Animation3DAction.ts +0 -73
  169. package/src/animation3d/Animation3DBinding.ts +0 -116
  170. package/src/animation3d/Animation3DClip.ts +0 -22
  171. package/src/animation3d/Animation3DError.ts +0 -34
  172. package/src/animation3d/Animation3DMixer.ts +0 -82
  173. package/src/animation3d/Animation3DPose.ts +0 -100
  174. package/src/animation3d/Animation3DPoseBuffer.ts +0 -85
  175. package/src/animation3d/Animation3DResource.ts +0 -49
  176. package/src/animation3d/Animation3DStateMachine.ts +0 -126
  177. package/src/animation3d/Animation3DStateMachineRuntime.ts +0 -191
  178. package/src/animation3d/Animation3DTrack.ts +0 -29
  179. package/src/animation3d/hya/HyaAnimation3DRuntime.ts +0 -756
  180. package/src/animation3d/hya/HyaAnimation3DStateMachineRuntime.ts +0 -618
  181. package/src/animation3d/hya/HyaAnimation3DTypes.ts +0 -168
  182. package/src/animation3d/hya/index.ts +0 -10
  183. package/src/animation3d/index.ts +0 -76
  184. package/src/animation3d/runtime/integration/Animation3DStateMachineMixerAdapter.ts +0 -325
  185. package/src/animation3d/runtime/integration/Animation3DStateMachineMixerIntegration.ts +0 -158
  186. package/src/animation3d/runtime/integration/index.ts +0 -9
  187. package/src/animation3d/runtime/mixer/Action.ts +0 -833
  188. package/src/animation3d/runtime/mixer/Animation3DMixerRuntimeStore.ts +0 -26
  189. package/src/animation3d/runtime/mixer/Mixer.ts +0 -562
  190. package/src/animation3d/runtime/mixer/PoseBuffer.ts +0 -1
  191. package/src/animation3d/runtime/mixer/TrackSampler.ts +0 -399
  192. package/src/animation3d/runtime/mixer/index.ts +0 -8
  193. package/src/animation3d/runtime/state-machine/Animation3DBlendTreeWeights.ts +0 -4
  194. package/src/animation3d/runtime/state-machine/Animation3DStateMachineCompiler.ts +0 -1
  195. package/src/animation3d/runtime/state-machine/Animation3DStateMachineController.ts +0 -1
  196. package/src/animation3d/runtime/state-machine/Animation3DStateMachineMixerPort.ts +0 -1
  197. package/src/animation3d/runtime/state-machine/index.ts +0 -45
  198. package/src/animation3d.ts +0 -5
  199. package/src/benchmark.ts +0 -168
  200. package/src/canvas-text/CanvasText2DRenderSystem.ts +0 -292
  201. package/src/canvas-text/CanvasTextComponent.ts +0 -47
  202. package/src/canvas-text.ts +0 -4
  203. package/src/experimental-gltf-worker.ts +0 -18
  204. package/src/experimental-spine-worker.ts +0 -9
  205. package/src/gltf/GltfAccessorReader.ts +0 -271
  206. package/src/gltf/GltfAnimation3DAdapter.ts +0 -680
  207. package/src/gltf/GltfAnimationRuntime.ts +0 -392
  208. package/src/gltf/GltfAssetWorkerClient.ts +0 -136
  209. package/src/gltf/GltfCompatibilityReport.ts +0 -214
  210. package/src/gltf/GltfConservativeBounds.ts +0 -219
  211. package/src/gltf/GltfDracoDecoder.ts +0 -251
  212. package/src/gltf/GltfExtensionAdapter.ts +0 -340
  213. package/src/gltf/GltfLoaderContract.ts +0 -333
  214. package/src/gltf/GltfLoaderErrors.ts +0 -59
  215. package/src/gltf/GltfMaterialDescriptor.ts +0 -134
  216. package/src/gltf/GltfMaterialEncoder.ts +0 -173
  217. package/src/gltf/GltfMaterialLoader.ts +0 -293
  218. package/src/gltf/GltfModelComponent.ts +0 -115
  219. package/src/gltf/GltfModelSystem.ts +0 -208
  220. package/src/gltf/GltfPlugin.ts +0 -84
  221. package/src/gltf/GltfSchema.ts +0 -229
  222. package/src/gltf/GltfUvSemanticPlanner.ts +0 -166
  223. package/src/gltf/gltfLoader.ts +0 -910
  224. package/src/gltf-animation3d.ts +0 -10
  225. package/src/gltf-worker-runtime.ts +0 -10
  226. package/src/gltf.ts +0 -56
  227. package/src/grid/Grid2DComponent.ts +0 -69
  228. package/src/grid.ts +0 -2
  229. package/src/hya-state-machine.ts +0 -19
  230. package/src/index.ts +0 -2
  231. package/src/plugins/pluginUtils.ts +0 -50
  232. package/src/plugins.ts +0 -6
  233. package/src/shaders/generated/2d-ui-animation-2d.generated.wgsl +0 -242
  234. package/src/shaders/generated/2d-ui-artifact.generated.ts +0 -867
  235. package/src/shaders/generated/2d-ui-canvas-text-2d.generated.wgsl +0 -38
  236. package/src/shaders/generated/2d-ui-spine2d.generated.wgsl +0 -41
  237. package/src/shaders/generated/2d-ui-tilemap2d.generated.wgsl +0 -36
  238. package/src/spine/Spine2DComponent.ts +0 -168
  239. package/src/spine/Spine2DGpuRenderer.ts +0 -449
  240. package/src/spine/Spine2DRenderSystem.ts +0 -199
  241. package/src/spine/Spine2DRuntime.ts +0 -1529
  242. package/src/spine/SpineAnimationBoneTimelines.ts +0 -30
  243. package/src/spine/SpineAssetParser.ts +0 -20
  244. package/src/spine/SpineAssetWorkerClient.ts +0 -112
  245. package/src/spine/SpineAssetWorkerContract.ts +0 -4
  246. package/src/spine/SpineAtlasParser.ts +0 -127
  247. package/src/spine/SpineFloatBuilder.ts +0 -66
  248. package/src/spine/SpinePathConstraintSolver.ts +0 -582
  249. package/src/spine/SpinePlugin.ts +0 -76
  250. package/src/spine/SpineSkeletonRuntime.ts +0 -521
  251. package/src/spine/SpineSlotAnimation.ts +0 -195
  252. package/src/spine/SpineTimelineRuntime.ts +0 -453
  253. package/src/spine/SpineVertexBuilder.ts +0 -686
  254. package/src/spine.ts +0 -7
  255. package/src/tilemap/Tilemap2DComponent.ts +0 -232
  256. package/src/tilemap/Tilemap2DRenderSystem.ts +0 -58
  257. package/src/tilemap/Tilemap2DRenderer.ts +0 -289
  258. package/src/tilemap/TilemapPlugin.ts +0 -75
  259. package/src/tilemap.ts +0 -6
  260. package/src/tween/Tween2DComponent.ts +0 -83
  261. package/src/tween/Tween2DSystem.ts +0 -78
  262. package/src/tween.ts +0 -4
  263. package/src/types/earcut.d.ts +0 -7
  264. package/src/types/wgsl.d.ts +0 -4
  265. package/src/utils/RenderSystem2DBase.ts +0 -164
  266. package/src/utils/arrayAccess.ts +0 -17
  267. package/src/utils/camera2d.ts +0 -68
  268. package/src/utils/render2dGpu.ts +0 -132
  269. package/test/fixtures/gltf/animation-characterization.gltf +0 -344
@@ -1,214 +0,0 @@
1
- import type { Geometry3D } from '@haiyue/engine';
2
- import type { GltfAccessor, GltfAsset, GltfPrimitive } from './GltfSchema';
3
- import type { GltfUvSemanticPlan } from './GltfUvSemanticPlanner';
4
-
5
- export type GltfCompatibilityStatus = 'compatible' | 'degraded';
6
- export type GltfTextureMipmapSource = 'generated-full-chain' | 'source-provided' | 'unavailable';
7
- export type GltfPrimitiveBoundsSupport = 'static' | 'accessor-conservative' | 'fail-open';
8
-
9
- export interface GltfCompatibilityExtensionEntry {
10
- readonly extension: string;
11
- readonly required: boolean;
12
- readonly support: 'supported' | 'partial' | 'unsupported';
13
- readonly disposition: 'supported' | 'partial' | 'ignored';
14
- readonly note: string;
15
- }
16
-
17
- export interface GltfTextureCompatibilityEntry {
18
- readonly textureIndex: number;
19
- readonly imageIndex: number | null;
20
- readonly mipmapSource: GltfTextureMipmapSource;
21
- readonly path: string;
22
- readonly note: string;
23
- }
24
-
25
- export interface GltfPrimitiveBoundsCompatibilityEntry {
26
- readonly meshIndex: number;
27
- readonly primitiveIndex: number;
28
- readonly support: GltfPrimitiveBoundsSupport;
29
- readonly path: string;
30
- readonly reason: string | null;
31
- }
32
-
33
- export interface GltfPrimitiveUvSemanticCompatibilityEntry {
34
- readonly meshIndex: number;
35
- readonly primitiveIndex: number;
36
- readonly capacity: number;
37
- readonly availableSemantics: readonly string[];
38
- readonly referencedSemantics: readonly string[];
39
- readonly mappings: readonly Readonly<{ semantic: string; set: number; channel: 0 | 1 }>[];
40
- readonly path: string;
41
- }
42
-
43
- export interface GltfCompatibilityPerformanceSummary {
44
- /** Fetch, parse, decode, and entity/material instantiation on the loading thread. */
45
- readonly loadMs: number;
46
- /** Unique decoded geometry ArrayBuffer storage retained by the loaded model. */
47
- readonly decodedGeometryBytes: number;
48
- }
49
-
50
- export interface GltfCompatibilityIssue {
51
- readonly category: 'extension' | 'texture-mipmap' | 'bounds' | 'uv-semantic';
52
- readonly path: string;
53
- readonly code: string;
54
- readonly message: string;
55
- }
56
-
57
- export interface GltfCompatibilityReport {
58
- readonly status: GltfCompatibilityStatus;
59
- readonly extensions: readonly GltfCompatibilityExtensionEntry[];
60
- readonly textures: readonly GltfTextureCompatibilityEntry[];
61
- readonly bounds: readonly GltfPrimitiveBoundsCompatibilityEntry[];
62
- readonly uvSemantics: readonly GltfPrimitiveUvSemanticCompatibilityEntry[];
63
- readonly performance: GltfCompatibilityPerformanceSummary;
64
- readonly issues: readonly GltfCompatibilityIssue[];
65
- }
66
-
67
- export interface GltfPrimitiveCompatibilityInput {
68
- readonly meshIndex: number;
69
- readonly primitiveIndex: number;
70
- readonly primitive: GltfPrimitive;
71
- readonly geometry: Geometry3D;
72
- readonly skinRequested: boolean;
73
- readonly uvSemanticPlan: GltfUvSemanticPlan;
74
- }
75
-
76
- export function createGltfCompatibilityReport(
77
- gltf: GltfAsset,
78
- extensions: readonly GltfCompatibilityExtensionEntry[],
79
- primitives: readonly GltfPrimitiveCompatibilityInput[],
80
- performance: GltfCompatibilityPerformanceSummary,
81
- ): GltfCompatibilityReport {
82
- const extensionEntries = extensions.map(entry => Object.freeze({ ...entry }));
83
- const textures = createTextureEntries(gltf);
84
- const bounds = primitives.map(input => createBoundsEntry(gltf, input));
85
- const uvSemantics = primitives.map(input => Object.freeze({
86
- meshIndex: input.meshIndex,
87
- primitiveIndex: input.primitiveIndex,
88
- capacity: input.uvSemanticPlan.capacity,
89
- availableSemantics: Object.freeze([...input.uvSemanticPlan.availableSemantics]),
90
- referencedSemantics: Object.freeze([...input.uvSemanticPlan.referencedSemantics]),
91
- mappings: Object.freeze(input.uvSemanticPlan.mappings.map(mapping => Object.freeze({ ...mapping }))),
92
- path: input.uvSemanticPlan.path,
93
- }));
94
- const issues: GltfCompatibilityIssue[] = [];
95
-
96
- for (const entry of extensionEntries) {
97
- if (entry.support === 'supported') continue;
98
- issues.push(Object.freeze({
99
- category: 'extension',
100
- path: `gltf.extensionsUsed[${Math.max(0, (gltf.extensionsUsed ?? []).indexOf(entry.extension))}]`,
101
- code: entry.support === 'partial' ? 'GLTF_EXTENSION_PARTIAL' : 'GLTF_EXTENSION_UNSUPPORTED',
102
- message: entry.note,
103
- }));
104
- }
105
- for (const entry of textures) {
106
- if (entry.mipmapSource !== 'unavailable') continue;
107
- issues.push(Object.freeze({
108
- category: 'texture-mipmap',
109
- path: entry.path,
110
- code: 'GLTF_TEXTURE_MIPMAP_UNAVAILABLE',
111
- message: entry.note,
112
- }));
113
- }
114
- for (const entry of bounds) {
115
- if (entry.support !== 'fail-open') continue;
116
- issues.push(Object.freeze({
117
- category: 'bounds',
118
- path: entry.path,
119
- code: 'GLTF_BOUNDS_FAIL_OPEN',
120
- message: entry.reason ?? 'Dynamic bounds cannot be proven; frustum culling remains disabled.',
121
- }));
122
- }
123
-
124
- return Object.freeze({
125
- status: issues.length === 0 ? 'compatible' : 'degraded',
126
- extensions: Object.freeze(extensionEntries),
127
- textures: Object.freeze(textures),
128
- bounds: Object.freeze(bounds),
129
- uvSemantics: Object.freeze(uvSemantics),
130
- performance: Object.freeze({ ...performance }),
131
- issues: Object.freeze(issues),
132
- });
133
- }
134
-
135
- function createTextureEntries(gltf: GltfAsset): GltfTextureCompatibilityEntry[] {
136
- return (gltf.textures ?? []).map((texture, textureIndex) => {
137
- const basisuSource = texture.extensions?.KHR_texture_basisu?.source;
138
- const imageIndex = basisuSource ?? texture.source;
139
- const image = imageIndex === undefined ? undefined : gltf.images?.[imageIndex];
140
- const path = `gltf.textures[${textureIndex}]`;
141
- if (imageIndex === undefined || !image) {
142
- return Object.freeze({
143
- textureIndex,
144
- imageIndex: imageIndex ?? null,
145
- mipmapSource: 'unavailable' as const,
146
- path,
147
- note: 'Texture has no resolvable image source, so a mipmap contract cannot be established.',
148
- });
149
- }
150
- const compressed = basisuSource !== undefined || image.mimeType === 'image/ktx2';
151
- return Object.freeze({
152
- textureIndex,
153
- imageIndex,
154
- mipmapSource: compressed ? 'source-provided' as const : 'generated-full-chain' as const,
155
- path,
156
- note: compressed
157
- ? 'KTX2/Basis texture uses the source-provided mip chain.'
158
- : 'Ordinary image receives a generated full mip chain when loaded by PBR.',
159
- });
160
- });
161
- }
162
-
163
- function createBoundsEntry(
164
- gltf: GltfAsset,
165
- input: GltfPrimitiveCompatibilityInput,
166
- ): GltfPrimitiveBoundsCompatibilityEntry {
167
- const path = `gltf.meshes[${input.meshIndex}].primitives[${input.primitiveIndex}]`;
168
- const dynamic = input.skinRequested || (input.primitive.targets?.length ?? 0) > 0;
169
- if (!dynamic) {
170
- return Object.freeze({ meshIndex: input.meshIndex, primitiveIndex: input.primitiveIndex, support: 'static', path, reason: null });
171
- }
172
- const reason = getBoundsEvidenceFailure(gltf, input);
173
- if (reason) {
174
- return Object.freeze({ meshIndex: input.meshIndex, primitiveIndex: input.primitiveIndex, support: 'fail-open', path, reason });
175
- }
176
- return Object.freeze({
177
- meshIndex: input.meshIndex,
178
- primitiveIndex: input.primitiveIndex,
179
- support: 'accessor-conservative',
180
- path,
181
- reason: null,
182
- });
183
- }
184
-
185
- function getBoundsEvidenceFailure(gltf: GltfAsset, input: GltfPrimitiveCompatibilityInput): string | null {
186
- const positionIndex = input.primitive.attributes.POSITION;
187
- if (positionIndex === undefined || !hasVec3Bounds(gltf.accessors?.[positionIndex])) {
188
- return 'Base POSITION accessor is missing a valid finite min/max pair.';
189
- }
190
- for (const [targetIndex, target] of (input.primitive.targets ?? []).entries()) {
191
- if (target.POSITION === undefined) continue;
192
- if (!hasVec3Bounds(gltf.accessors?.[target.POSITION])) {
193
- return `Morph target ${targetIndex} POSITION accessor is missing a valid finite min/max pair.`;
194
- }
195
- }
196
- if (input.skinRequested && !input.geometry.skinning) {
197
- return 'Skin was requested but a runtime skin contract could not be created for this primitive.';
198
- }
199
- if (!input.geometry.localBounds) {
200
- return 'Dynamic local bounds are unavailable for the current morph/skin state.';
201
- }
202
- return null;
203
- }
204
-
205
- function hasVec3Bounds(accessor: GltfAccessor | undefined): boolean {
206
- if (!accessor || accessor.type !== 'VEC3' || accessor.min?.length !== 3 || accessor.max?.length !== 3) return false;
207
- const min = accessor.min;
208
- const max = accessor.max;
209
- return [...min, ...max].every(Number.isFinite)
210
- && min.every((value, axis) => {
211
- const maximum = max[axis];
212
- return maximum !== undefined && value <= maximum;
213
- });
214
- }
@@ -1,219 +0,0 @@
1
- import type { Geometry3DLocalBounds } from '@haiyue/engine/geometry';
2
- import type { GltfAccessor, GltfAsset, GltfPrimitive } from './GltfSchema';
3
-
4
- interface Bounds3 {
5
- readonly min: readonly [number, number, number];
6
- readonly max: readonly [number, number, number];
7
- }
8
-
9
- interface JointUsage {
10
- readonly joints: Set<number>;
11
- readonly includeSource: boolean;
12
- }
13
-
14
- /**
15
- * Keeps the accessor evidence needed to derive conservative bounds for the
16
- * current morph weights and skin matrices. Missing evidence returns null so
17
- * Render3D keeps its fail-open culling behavior.
18
- */
19
- export class GltfConservativeBounds {
20
- private _current: Bounds3 | null;
21
- private _skinUsageCache: {
22
- jointCount: number;
23
- joints: Float32Array | undefined;
24
- weights: Float32Array | undefined;
25
- usage: JointUsage | null;
26
- } | null = null;
27
-
28
- private constructor(
29
- private readonly _base: Bounds3,
30
- private readonly _positionTargets: readonly (Bounds3 | null)[],
31
- ) {
32
- this._current = _base;
33
- }
34
-
35
- static fromPrimitive(gltf: GltfAsset, primitive: GltfPrimitive): GltfConservativeBounds | null {
36
- const positionAccessorIndex = primitive.attributes.POSITION;
37
- if (positionAccessorIndex === undefined) return null;
38
- const base = readVec3Bounds(gltf.accessors?.[positionAccessorIndex]);
39
- if (!base) return null;
40
- const positionTargets = (primitive.targets ?? []).map(target => {
41
- if (target.POSITION === undefined) return ZERO_BOUNDS;
42
- return readVec3Bounds(gltf.accessors?.[target.POSITION]);
43
- });
44
- return new GltfConservativeBounds(base, positionTargets);
45
- }
46
-
47
- updateMorphWeights(weights: ArrayLike<number>): Geometry3DLocalBounds | null {
48
- const min: [number, number, number] = [...this._base.min];
49
- const max: [number, number, number] = [...this._base.max];
50
- for (let targetIndex = 0; targetIndex < this._positionTargets.length; targetIndex++) {
51
- const weight = weights[targetIndex] ?? 0;
52
- if (!Number.isFinite(weight)) {
53
- this._current = null;
54
- return null;
55
- }
56
- if (weight === 0) continue;
57
- const target = this._positionTargets[targetIndex];
58
- if (!target) {
59
- this._current = null;
60
- return null;
61
- }
62
- for (let axis = 0; axis < 3; axis++) {
63
- const targetMin = target.min[axis];
64
- const targetMax = target.max[axis];
65
- const currentMin = min[axis];
66
- const currentMax = max[axis];
67
- if (targetMin === undefined || targetMax === undefined || currentMin === undefined || currentMax === undefined) {
68
- this._current = null;
69
- return null;
70
- }
71
- const a = targetMin * weight;
72
- const b = targetMax * weight;
73
- min[axis] = currentMin + Math.min(a, b);
74
- max[axis] = currentMax + Math.max(a, b);
75
- }
76
- }
77
- this._current = { min, max };
78
- return boundsToSphere(this._current);
79
- }
80
-
81
- getSourceBounds(): Geometry3DLocalBounds | null {
82
- return this._current ? boundsToSphere(this._current) : null;
83
- }
84
-
85
- getSkinnedBounds(
86
- jointMatrices: Float32Array,
87
- joints?: Float32Array,
88
- weights?: Float32Array,
89
- ): Geometry3DLocalBounds | null {
90
- if (!this._current || jointMatrices.length === 0 || jointMatrices.length % 16 !== 0) return null;
91
- const min: [number, number, number] = [Infinity, Infinity, Infinity];
92
- const max: [number, number, number] = [-Infinity, -Infinity, -Infinity];
93
- const jointCount = jointMatrices.length / 16;
94
- let usage: JointUsage | null;
95
- if (this._skinUsageCache
96
- && this._skinUsageCache.jointCount === jointCount
97
- && this._skinUsageCache.joints === joints
98
- && this._skinUsageCache.weights === weights) {
99
- usage = this._skinUsageCache.usage;
100
- } else {
101
- usage = collectJointUsage(jointCount, joints, weights);
102
- this._skinUsageCache = { jointCount, joints, weights, usage };
103
- }
104
- if (!usage) return null;
105
- if (usage.includeSource) includeBounds(min, max, this._current);
106
- for (const jointIndex of usage.joints) {
107
- if (!includeTransformedBounds(min, max, this._current, jointMatrices, jointIndex * 16)) return null;
108
- }
109
- return boundsToSphere({ min, max });
110
- }
111
- }
112
-
113
- function collectJointUsage(
114
- jointCount: number,
115
- joints: Float32Array | undefined,
116
- weights: Float32Array | undefined,
117
- ): JointUsage | null {
118
- if (!joints || !weights || joints.length !== weights.length || joints.length % 4 !== 0) {
119
- return { joints: new Set(Array.from({ length: jointCount }, (_, index) => index)), includeSource: true };
120
- }
121
- const used = new Set<number>();
122
- let includeSource = false;
123
- for (let vertexOffset = 0; vertexOffset < joints.length; vertexOffset += 4) {
124
- let weightSum = 0;
125
- for (let influence = 0; influence < 4; influence++) {
126
- const offset = vertexOffset + influence;
127
- const weight = weights[offset];
128
- const joint = joints[offset];
129
- if (weight === undefined || joint === undefined
130
- || !Number.isFinite(weight) || !Number.isInteger(joint) || joint < 0 || joint >= jointCount) return null;
131
- if (weight <= 0) continue;
132
- used.add(joint);
133
- weightSum += weight;
134
- }
135
- if (weightSum <= 0) includeSource = true;
136
- }
137
- if (used.size === 0) includeSource = true;
138
- return { joints: used, includeSource };
139
- }
140
-
141
- function readVec3Bounds(accessor: GltfAccessor | undefined): Bounds3 | null {
142
- if (!accessor || accessor.type !== 'VEC3') return null;
143
- const min = accessor.min;
144
- const max = accessor.max;
145
- if (!min || !max || min.length !== 3 || max.length !== 3) return null;
146
- if (![...min, ...max].every(Number.isFinite)) return null;
147
- const [minX, minY, minZ] = min;
148
- const [maxX, maxY, maxZ] = max;
149
- if (minX === undefined || minY === undefined || minZ === undefined
150
- || maxX === undefined || maxY === undefined || maxZ === undefined) return null;
151
- if (minX > maxX || minY > maxY || minZ > maxZ) return null;
152
- return {
153
- min: [minX, minY, minZ],
154
- max: [maxX, maxY, maxZ],
155
- };
156
- }
157
-
158
- function includeTransformedBounds(
159
- outMin: [number, number, number],
160
- outMax: [number, number, number],
161
- bounds: Bounds3,
162
- matrix: Float32Array,
163
- offset: number,
164
- ): boolean {
165
- if (offset < 0 || offset + 15 >= matrix.length) return false;
166
- for (let corner = 0; corner < 8; corner++) {
167
- const x = corner & 1 ? bounds.max[0] : bounds.min[0];
168
- const y = corner & 2 ? bounds.max[1] : bounds.min[1];
169
- const z = corner & 4 ? bounds.max[2] : bounds.min[2];
170
- const tx = (matrix[offset] ?? NaN) * x + (matrix[offset + 4] ?? NaN) * y + (matrix[offset + 8] ?? NaN) * z + (matrix[offset + 12] ?? NaN);
171
- const ty = (matrix[offset + 1] ?? NaN) * x + (matrix[offset + 5] ?? NaN) * y + (matrix[offset + 9] ?? NaN) * z + (matrix[offset + 13] ?? NaN);
172
- const tz = (matrix[offset + 2] ?? NaN) * x + (matrix[offset + 6] ?? NaN) * y + (matrix[offset + 10] ?? NaN) * z + (matrix[offset + 14] ?? NaN);
173
- if (![tx, ty, tz].every(Number.isFinite)) return false;
174
- outMin[0] = Math.min(outMin[0], tx);
175
- outMin[1] = Math.min(outMin[1], ty);
176
- outMin[2] = Math.min(outMin[2], tz);
177
- outMax[0] = Math.max(outMax[0], tx);
178
- outMax[1] = Math.max(outMax[1], ty);
179
- outMax[2] = Math.max(outMax[2], tz);
180
- }
181
- return true;
182
- }
183
-
184
- function includeBounds(
185
- outMin: [number, number, number],
186
- outMax: [number, number, number],
187
- bounds: Bounds3,
188
- ): void {
189
- for (let axis = 0; axis < 3; axis++) {
190
- const currentMin = outMin[axis];
191
- const currentMax = outMax[axis];
192
- const boundsMin = bounds.min[axis];
193
- const boundsMax = bounds.max[axis];
194
- if (currentMin === undefined || currentMax === undefined || boundsMin === undefined || boundsMax === undefined) continue;
195
- outMin[axis] = Math.min(currentMin, boundsMin);
196
- outMax[axis] = Math.max(currentMax, boundsMax);
197
- }
198
- }
199
-
200
- function boundsToSphere(bounds: Bounds3): Geometry3DLocalBounds {
201
- const center: [number, number, number] = [
202
- (bounds.min[0] + bounds.max[0]) * 0.5,
203
- (bounds.min[1] + bounds.max[1]) * 0.5,
204
- (bounds.min[2] + bounds.max[2]) * 0.5,
205
- ];
206
- return {
207
- center,
208
- radius: Math.hypot(
209
- bounds.max[0] - center[0],
210
- bounds.max[1] - center[1],
211
- bounds.max[2] - center[2],
212
- ),
213
- };
214
- }
215
-
216
- const ZERO_BOUNDS: Bounds3 = Object.freeze({
217
- min: Object.freeze([0, 0, 0] as [number, number, number]),
218
- max: Object.freeze([0, 0, 0] as [number, number, number]),
219
- });
@@ -1,251 +0,0 @@
1
- import { parseTextureCoordinateSemantic } from './GltfUvSemanticPlanner';
2
- import type { GltfAsset, GltfDracoMeshCompression } from './GltfSchema';
3
- import type {
4
- DracoDecoder,
5
- DracoDecoderConfig,
6
- DracoDecoderFactory,
7
- DracoDecoderModule,
8
- DracoMesh,
9
- DracoPrimitiveGeometry,
10
- LoadGltfOptions,
11
- } from './GltfLoaderContract';
12
- import { gltfDataError, throwIfGltfLoadAborted } from './GltfLoaderErrors';
13
-
14
- const DEFAULT_DRACO_DECODER_SCRIPT_URL = 'draco_decoder_gltf_nodejs.js';
15
- const FALLBACK_DRACO_DECODER_SCRIPT_URL = '../node_modules/draco3dgltf/draco_decoder_gltf_nodejs.js';
16
-
17
- let sharedDecoderPromise: Promise<DracoDecoderModule> | null = null;
18
- const sharedScriptPromises = new Map<string, Promise<DracoDecoderFactory>>();
19
-
20
- /** Resolves and decodes one KHR_draco_mesh_compression primitive. */
21
- export async function decodeDracoPrimitive(
22
- gltf: GltfAsset,
23
- buffers: ArrayBuffer[],
24
- extension: GltfDracoMeshCompression,
25
- options: LoadGltfOptions,
26
- ): Promise<DracoPrimitiveGeometry> {
27
- throwIfGltfLoadAborted(options.signal);
28
- const view = gltf.bufferViews?.[extension.bufferView];
29
- if (!view) throw gltfDataError(`Missing Draco bufferView ${extension.bufferView}.`);
30
- const source = buffers[view.buffer];
31
- if (!source) throw gltfDataError(`Missing Draco buffer ${view.buffer}.`);
32
-
33
- const module = await resolveDracoDecoder(options);
34
- throwIfGltfLoadAborted(options.signal);
35
- const decoder = new module.Decoder();
36
- const decoderBuffer = new module.DecoderBuffer();
37
- const mesh = new module.Mesh();
38
- const bytes = new Uint8Array(source, view.byteOffset ?? 0, view.byteLength);
39
- decoderBuffer.Init(bytes, bytes.byteLength);
40
-
41
- try {
42
- const status = decoder.DecodeBufferToMesh(decoderBuffer, mesh);
43
- throwIfGltfLoadAborted(options.signal);
44
- if (!status.ok()) throw gltfDataError(`Draco decode failed: ${status.error_msg()}`);
45
- const positions = readFloatAttribute(module, decoder, mesh, extension, 'POSITION', 3);
46
- if (!positions) throw gltfDataError('Draco primitive is missing POSITION attribute.');
47
- const normals = readFloatAttribute(module, decoder, mesh, extension, 'NORMAL', 3);
48
- const textureCoordinates = Object.keys(extension.attributes)
49
- .map(semantic => ({ semantic, set: parseTextureCoordinateSemantic(semantic) }))
50
- .filter((entry): entry is { semantic: string; set: number } => entry.set !== null)
51
- .sort((a, b) => a.set - b.set)
52
- .map(entry => {
53
- const data = readFloatAttribute(module, decoder, mesh, extension, entry.semantic, 2);
54
- if (!data) throw gltfDataError(`Draco primitive is missing ${entry.semantic}.`);
55
- return { set: entry.set, data };
56
- });
57
- const joints = readUnsignedAttribute(module, decoder, mesh, extension, 'JOINTS_0', 4);
58
- const weights = readFloatAttribute(module, decoder, mesh, extension, 'WEIGHTS_0', 4);
59
- const indices = readIndices(module, decoder, mesh);
60
- throwIfGltfLoadAborted(options.signal);
61
- return {
62
- positions,
63
- ...(normals === null ? {} : { normals }),
64
- textureCoordinates,
65
- ...(joints === null ? {} : { joints }),
66
- ...(weights === null ? {} : { weights }),
67
- indices,
68
- };
69
- } finally {
70
- module.destroy(mesh);
71
- module.destroy(decoderBuffer);
72
- module.destroy(decoder);
73
- }
74
- }
75
-
76
- async function resolveDracoDecoder(options: LoadGltfOptions): Promise<DracoDecoderModule> {
77
- throwIfGltfLoadAborted(options.signal);
78
- const provided = options.dracoDecoder;
79
- if (provided) {
80
- const module = typeof provided === 'function'
81
- ? await provided(options.dracoDecoderConfig)
82
- : await provided;
83
- throwIfGltfLoadAborted(options.signal);
84
- return module;
85
- }
86
- if (!sharedDecoderPromise) sharedDecoderPromise = loadDefaultDecoder(options.dracoDecoderConfig);
87
- const module = await sharedDecoderPromise;
88
- throwIfGltfLoadAborted(options.signal);
89
- return module;
90
- }
91
-
92
- async function loadDefaultDecoder(config: DracoDecoderConfig | undefined): Promise<DracoDecoderModule> {
93
- let factory: DracoDecoderFactory;
94
- if (config?.scriptUrl) {
95
- factory = await loadDecoderFactory(config.scriptUrl);
96
- } else {
97
- try {
98
- factory = await loadDecoderFactory(DEFAULT_DRACO_DECODER_SCRIPT_URL);
99
- } catch {
100
- factory = await loadDecoderFactory(FALLBACK_DRACO_DECODER_SCRIPT_URL);
101
- }
102
- }
103
- return factory(config);
104
- }
105
-
106
- function loadDecoderFactory(scriptUrl: string): Promise<DracoDecoderFactory> {
107
- const existing = getGlobalDecoderFactory();
108
- if (existing) return Promise.resolve(existing);
109
- const existingPromise = sharedScriptPromises.get(scriptUrl);
110
- if (existingPromise) return existingPromise;
111
- const promise = new Promise<DracoDecoderFactory>((resolve, reject) => {
112
- if (typeof document === 'undefined') {
113
- const workerScope = globalThis as typeof globalThis & { postMessage?: unknown; location?: unknown };
114
- if (typeof workerScope.postMessage !== 'function' || workerScope.location === undefined) {
115
- reject(gltfDataError('Draco decoder is not available. Provide LoadGltfOptions.dracoDecoder in non-browser environments.'));
116
- return;
117
- }
118
- void loadWorkerDecoderFactory(scriptUrl).then(resolve, reject);
119
- return;
120
- }
121
- const script = document.createElement('script');
122
- script.async = true;
123
- script.src = scriptUrl;
124
- script.onload = () => {
125
- const factory = getGlobalDecoderFactory();
126
- if (factory) resolve(factory);
127
- else reject(gltfDataError(`Draco decoder script loaded without DracoDecoderModule: ${scriptUrl}`, { url: scriptUrl }));
128
- };
129
- script.onerror = () => reject(gltfDataError(`Failed to load Draco decoder script: ${scriptUrl}`, { url: scriptUrl }));
130
- document.head.appendChild(script);
131
- });
132
- sharedScriptPromises.set(scriptUrl, promise);
133
- promise.catch(() => sharedScriptPromises.delete(scriptUrl));
134
- return promise;
135
- }
136
-
137
- async function loadWorkerDecoderFactory(scriptUrl: string): Promise<DracoDecoderFactory> {
138
- const response = await fetch(scriptUrl);
139
- if (!response.ok) {
140
- throw gltfDataError(
141
- `Failed to load Draco decoder script: ${scriptUrl}`,
142
- { url: scriptUrl, status: response.status },
143
- );
144
- }
145
- const source = await response.text();
146
- const factory = new Function(
147
- `${source}\nreturn typeof DracoDecoderModule === "function" ? DracoDecoderModule : null;\n//# sourceURL=${scriptUrl}`,
148
- )() as unknown;
149
- if (typeof factory !== 'function') {
150
- throw gltfDataError(`Draco decoder script loaded without DracoDecoderModule: ${scriptUrl}`, { url: scriptUrl });
151
- }
152
- return factory as DracoDecoderFactory;
153
- }
154
-
155
- function getGlobalDecoderFactory(): DracoDecoderFactory | null {
156
- const globalScope = globalThis as typeof globalThis & { DracoDecoderModule?: DracoDecoderFactory };
157
- return typeof globalScope.DracoDecoderModule === 'function' ? globalScope.DracoDecoderModule : null;
158
- }
159
-
160
- function readUnsignedAttribute(
161
- module: DracoDecoderModule,
162
- decoder: DracoDecoder,
163
- mesh: DracoMesh,
164
- extension: GltfDracoMeshCompression,
165
- semantic: string,
166
- expectedSize: number,
167
- ): Uint16Array | Uint32Array | null {
168
- const uniqueId = extension.attributes[semantic];
169
- if (uniqueId === undefined) return null;
170
- const attribute = decoder.GetAttributeByUniqueId(mesh, uniqueId);
171
- if (!attribute) throw gltfDataError(`Draco primitive is missing attribute ${semantic} with unique id ${uniqueId}.`);
172
- const pointCount = mesh.num_points();
173
- const decode = <T extends Uint16Array | Uint32Array>(
174
- ArrayType: { new(length: number): T },
175
- ValuesType: (new () => import('./GltfLoaderContract').DracoDecoderArray) | undefined,
176
- read: ((mesh: DracoMesh, attribute: import('./GltfLoaderContract').DracoPointAttribute, out: import('./GltfLoaderContract').DracoDecoderArray) => boolean) | undefined,
177
- ): T | null => {
178
- if (!ValuesType || !read) return null;
179
- const values = new ValuesType();
180
- try {
181
- if (!read.call(decoder, mesh, attribute, values)) throw gltfDataError(`Failed to decode Draco attribute ${semantic}.`);
182
- if (values.size() < pointCount * expectedSize) {
183
- throw gltfDataError(`Draco attribute ${semantic} returned ${values.size()} values, expected at least ${pointCount * expectedSize}.`);
184
- }
185
- const out = new ArrayType(pointCount * expectedSize);
186
- for (let i = 0; i < out.length; i++) out[i] = values.GetValue(i);
187
- return out;
188
- } finally {
189
- module.destroy(values);
190
- }
191
- };
192
- const u16 = decode(Uint16Array, module.DracoUInt16Array, decoder.GetAttributeUInt16ForAllPoints);
193
- if (u16) return u16;
194
- const u32 = decode(Uint32Array, module.DracoUInt32Array, decoder.GetAttributeUInt32ForAllPoints);
195
- if (u32) return u32;
196
- const values = readFloatAttribute(module, decoder, mesh, extension, semantic, expectedSize);
197
- if (!values) return null;
198
- const out = new Uint16Array(values.length);
199
- for (let i = 0; i < values.length; i++) out[i] = Math.max(0, Math.round(requiredFiniteValue(values, i, `Draco ${semantic}`)));
200
- return out;
201
- }
202
-
203
- function readFloatAttribute(
204
- module: DracoDecoderModule,
205
- decoder: DracoDecoder,
206
- mesh: DracoMesh,
207
- extension: GltfDracoMeshCompression,
208
- semantic: string,
209
- expectedSize: number,
210
- ): Float32Array | null {
211
- const uniqueId = extension.attributes[semantic];
212
- if (uniqueId === undefined) return null;
213
- const attribute = decoder.GetAttributeByUniqueId(mesh, uniqueId);
214
- if (!attribute) throw gltfDataError(`Draco primitive is missing attribute ${semantic} with unique id ${uniqueId}.`);
215
- const values = new module.DracoFloat32Array();
216
- try {
217
- if (!decoder.GetAttributeFloatForAllPoints(mesh, attribute, values)) throw gltfDataError(`Failed to decode Draco attribute ${semantic}.`);
218
- const pointCount = mesh.num_points();
219
- if (values.size() < pointCount * expectedSize) {
220
- throw gltfDataError(`Draco attribute ${semantic} returned ${values.size()} values, expected at least ${pointCount * expectedSize}.`);
221
- }
222
- const out = new Float32Array(pointCount * expectedSize);
223
- for (let i = 0; i < out.length; i++) out[i] = values.GetValue(i);
224
- return out;
225
- } finally {
226
- module.destroy(values);
227
- }
228
- }
229
-
230
- function readIndices(module: DracoDecoderModule, decoder: DracoDecoder, mesh: DracoMesh): Uint16Array | Uint32Array {
231
- const faceCount = mesh.num_faces();
232
- const indices = mesh.num_points() > 65535 ? new Uint32Array(faceCount * 3) : new Uint16Array(faceCount * 3);
233
- const face = new module.DracoInt32Array();
234
- try {
235
- for (let faceIndex = 0; faceIndex < faceCount; faceIndex++) {
236
- if (!decoder.GetFaceFromMesh(mesh, faceIndex, face)) throw gltfDataError(`Failed to decode Draco face ${faceIndex}.`);
237
- indices[faceIndex * 3] = face.GetValue(0);
238
- indices[faceIndex * 3 + 1] = face.GetValue(1);
239
- indices[faceIndex * 3 + 2] = face.GetValue(2);
240
- }
241
- return indices;
242
- } finally {
243
- module.destroy(face);
244
- }
245
- }
246
-
247
- function requiredFiniteValue(values: ArrayLike<number>, index: number, label: string): number {
248
- const value = values[index];
249
- if (value === undefined || !Number.isFinite(value)) throw gltfDataError(`${label} is missing a finite value at index ${index}.`);
250
- return value;
251
- }