@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,449 +0,0 @@
1
- import {
2
- alignUp4,
3
- getExtensionGPUResourceTracker,
4
- requireEngineDevice,
5
- type IEngine,
6
- } from '@haiyue/engine/extension-authoring';
7
- import { EngineError, EngineErrorCode } from '@haiyue/engine';
8
- import { ErrorDomain, ErrorRecovery } from '@haiyue/engine/core';
9
- import { Spine2DComponent } from './Spine2DComponent';
10
- import { SpineFloatBuilder } from './SpineFloatBuilder';
11
- import { resolveAtlasPageImageUrl, type AtlasRegion } from './SpineAtlasParser';
12
- import { type SpineDrawBatch } from './SpineVertexBuilder';
13
- import {
14
- createCamera2DGpu,
15
- createObject2DLayout,
16
- createTexture2DGpu,
17
- destroyCamera2DGpu,
18
- destroyTexture2DGpu,
19
- type Camera2DGpu,
20
- type Texture2DGpu,
21
- } from '../utils/render2dGpu';
22
- import spine2dWgsl from '../shaders/generated/2d-ui-spine2d.generated.wgsl';
23
-
24
- export interface SpineBufferDirtyRange {
25
- byteOffset: number;
26
- byteLength: number;
27
- }
28
-
29
- export interface AtlasPageGpu {
30
- image: HTMLImageElement;
31
- texture: GPUTexture;
32
- textureBindGroup: GPUBindGroup;
33
- width: number;
34
- height: number;
35
- }
36
-
37
- export interface SpineRuntimeGpu {
38
- pages: Map<string, AtlasPageGpu>;
39
- vertexBuffer: GPUBuffer;
40
- vertexBufferSize: number;
41
- debugVertexBuffer: GPUBuffer;
42
- debugVertexBufferSize: number;
43
- batches: SpineDrawBatch[];
44
- mergedDirtyRanges: SpineBufferDirtyRange[];
45
- mergedDirtyRangePool: SpineBufferDirtyRange[];
46
- allocationStats: { dirtyRangePoolMisses: number };
47
- }
48
-
49
- export interface SpineRuntimeGpuBuffers {
50
- vertexBuffer: GPUBuffer;
51
- vertexBufferSize: number;
52
- debugVertexBuffer: GPUBuffer;
53
- debugVertexBufferSize: number;
54
- }
55
-
56
- const SPINE_WGSL = spine2dWgsl;
57
-
58
- type SpinePipelineMode = 'normal' | 'additive' | 'line';
59
-
60
- export class Spine2DGpuRenderer {
61
- private engine: IEngine | null = null;
62
- private cameraGpu: Camera2DGpu | null = null;
63
- private textureGpu: Texture2DGpu | null = null;
64
- private objectLayoutGpu: GPUBindGroupLayout | null = null;
65
- private shaderModule: GPUShaderModule | null = null;
66
- private pipelineLayout: GPUPipelineLayout | null = null;
67
- private readonly pipelines = new Map<string, GPURenderPipeline>();
68
- private reverseZ = false;
69
- private sampleCount: 1 | 4 = 1;
70
- private readonly pendingBufferDestroys = new Set<GPUBuffer>();
71
-
72
- get cameraBuffer(): GPUBuffer {
73
- return this.requirePrepared().cameraGpu.buffer;
74
- }
75
-
76
- get objectLayout(): GPUBindGroupLayout {
77
- return this.requirePrepared().objectLayout;
78
- }
79
-
80
- prepare(engine: IEngine): void {
81
- if (this.engine === engine && this.cameraGpu && this.textureGpu && this.objectLayoutGpu) return;
82
- if (this.engine && this.engine !== engine) this.destroy();
83
- this.engine = engine;
84
- const device = requireEngineDevice(engine);
85
- this.cameraGpu = createCamera2DGpu(device, getExtensionGPUResourceTracker(engine));
86
- this.objectLayoutGpu = createObject2DLayout(device);
87
- this.textureGpu = createTexture2DGpu(device, 255, getExtensionGPUResourceTracker(engine));
88
- this.shaderModule = device.createShaderModule({ code: SPINE_WGSL });
89
- this.pipelineLayout = device.createPipelineLayout({
90
- bindGroupLayouts: [this.cameraGpu.layout, this.objectLayoutGpu, this.textureGpu.layout],
91
- });
92
- }
93
-
94
- destroy(): void {
95
- if (this.cameraGpu) destroyCamera2DGpu(this.cameraGpu);
96
- if (this.textureGpu) destroyTexture2DGpu(this.textureGpu);
97
- this.flushPendingBufferDestroys();
98
- this.cameraGpu = null;
99
- this.textureGpu = null;
100
- this.objectLayoutGpu = null;
101
- this.shaderModule = null;
102
- this.pipelineLayout = null;
103
- this.pipelines.clear();
104
- }
105
-
106
- setRenderView(reverseZ: boolean, sampleCount: 1 | 4): void {
107
- this.reverseZ = reverseZ;
108
- this.sampleCount = sampleCount;
109
- }
110
-
111
- createRuntimeBuffers(): SpineRuntimeGpuBuffers {
112
- const engine = this.requireEngine();
113
- const vertexBufferSize = 1024;
114
- const debugVertexBufferSize = 1024;
115
- const vertexBuffer = engine.device.createBuffer({
116
- size: vertexBufferSize,
117
- usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
118
- });
119
- const debugVertexBuffer = engine.device.createBuffer({
120
- size: debugVertexBufferSize,
121
- usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
122
- });
123
- getExtensionGPUResourceTracker(engine)?.trackBuffer(vertexBuffer, 'Spine2D.vertexBuffer', vertexBufferSize);
124
- getExtensionGPUResourceTracker(engine)?.trackBuffer(debugVertexBuffer, 'Spine2D.debugVertexBuffer', debugVertexBufferSize);
125
- return { vertexBuffer, vertexBufferSize, debugVertexBuffer, debugVertexBufferSize };
126
- }
127
-
128
- async loadAtlasPages(
129
- component: Spine2DComponent,
130
- atlas: Map<string, AtlasRegion>,
131
- ): Promise<Map<string, AtlasPageGpu>> {
132
- const engine = this.requireEngine();
133
- const textureGpu = this.requirePrepared().textureGpu;
134
- const pageNames = Array.from(new Set(Array.from(atlas.values()).map(region => region.page).filter(Boolean)));
135
- const pages = new Map<string, AtlasPageGpu>();
136
- const names = pageNames.length ? pageNames : [''];
137
- for (const pageName of names) {
138
- const imageUrl = resolveAtlasPageImageUrl({
139
- atlasUrl: component.atlasUrl,
140
- imageUrl: component.imageUrl,
141
- imageUrls: component.imageUrls,
142
- }, atlas, pageName);
143
- const image = await loadImage(imageUrl);
144
- const width = Math.max(1, image.naturalWidth || image.width);
145
- const height = Math.max(1, image.naturalHeight || image.height);
146
- const texture = engine.device.createTexture({
147
- size: [width, height],
148
- format: 'rgba8unorm',
149
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
150
- });
151
- getExtensionGPUResourceTracker(engine)?.trackTexture(texture, 'Spine2D.atlasTexture', width * height * 4);
152
- engine.device.queue.copyExternalImageToTexture({ source: image }, { texture }, [width, height]);
153
- const textureBindGroup = engine.device.createBindGroup({
154
- layout: textureGpu.layout,
155
- entries: [
156
- { binding: 0, resource: texture.createView() },
157
- { binding: 1, resource: textureGpu.sampler },
158
- ],
159
- });
160
- pages.set(pageName, { image, texture, textureBindGroup, width, height });
161
- }
162
- return pages;
163
- }
164
-
165
- writeVertices(runtime: SpineRuntimeGpu, vertices: SpineFloatBuilder, dirtyRanges: SpineBufferDirtyRange[]): void {
166
- const engine = this.requireEngine();
167
- if (vertices.byteLength > runtime.vertexBufferSize) {
168
- const nextSize = nextGpuBufferSize(vertices.byteLength, runtime.vertexBufferSize);
169
- const nextBuffer = engine.device.createBuffer({
170
- size: nextSize,
171
- usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
172
- });
173
- this.deferBufferDestroy(runtime.vertexBuffer);
174
- runtime.vertexBuffer = nextBuffer;
175
- runtime.vertexBufferSize = nextSize;
176
- getExtensionGPUResourceTracker(engine)?.trackBuffer(runtime.vertexBuffer, 'Spine2D.vertexBuffer', nextSize);
177
- engine.device.queue.writeBuffer(runtime.vertexBuffer, 0, vertices.data.buffer as ArrayBuffer, 0, vertices.byteLength);
178
- return;
179
- }
180
- this.writeDirtyRanges(runtime, runtime.vertexBuffer, vertices, dirtyRanges, runtime.mergedDirtyRanges);
181
- }
182
-
183
- writeDebugVertices(runtime: SpineRuntimeGpu, vertices: SpineFloatBuilder, dirtyRanges: SpineBufferDirtyRange[]): void {
184
- const engine = this.requireEngine();
185
- if (vertices.byteLength > runtime.debugVertexBufferSize) {
186
- const nextSize = nextGpuBufferSize(vertices.byteLength, runtime.debugVertexBufferSize);
187
- const nextBuffer = engine.device.createBuffer({
188
- size: nextSize,
189
- usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
190
- });
191
- this.deferBufferDestroy(runtime.debugVertexBuffer);
192
- runtime.debugVertexBuffer = nextBuffer;
193
- runtime.debugVertexBufferSize = nextSize;
194
- getExtensionGPUResourceTracker(engine)?.trackBuffer(runtime.debugVertexBuffer, 'Spine2D.debugVertexBuffer', nextSize);
195
- engine.device.queue.writeBuffer(runtime.debugVertexBuffer, 0, vertices.data.buffer as ArrayBuffer, 0, vertices.byteLength);
196
- return;
197
- }
198
- this.writeDirtyRanges(runtime, runtime.debugVertexBuffer, vertices, dirtyRanges, runtime.mergedDirtyRanges);
199
- }
200
-
201
- drawRuntime(
202
- pass: GPURenderPassEncoder,
203
- runtime: SpineRuntimeGpu,
204
- objectBindGroup: GPUBindGroup,
205
- debugVertexCount: number,
206
- ): void {
207
- const { cameraGpu, textureGpu } = this.requirePrepared();
208
- pass.setPipeline(this.getPipeline('normal'));
209
- pass.setBindGroup(0, cameraGpu.bindGroup);
210
- pass.setBindGroup(1, objectBindGroup);
211
- pass.setVertexBuffer(0, runtime.vertexBuffer);
212
- let currentBlend: 'normal' | 'additive' = 'normal';
213
- let currentPage = '';
214
- for (const batch of runtime.batches) {
215
- if (batch.blend !== currentBlend) {
216
- currentBlend = batch.blend;
217
- pass.setPipeline(this.getPipeline(currentBlend));
218
- pass.setBindGroup(0, cameraGpu.bindGroup);
219
- pass.setBindGroup(1, objectBindGroup);
220
- pass.setVertexBuffer(0, runtime.vertexBuffer);
221
- }
222
- if (batch.page !== currentPage) {
223
- currentPage = batch.page;
224
- pass.setBindGroup(2, runtime.pages.get(batch.page)?.textureBindGroup ?? textureGpu.fallbackBindGroup);
225
- }
226
- pass.draw(batch.vertexCount, 1, batch.firstVertex);
227
- }
228
- if (debugVertexCount > 0) {
229
- pass.setPipeline(this.getPipeline('line'));
230
- pass.setBindGroup(0, cameraGpu.bindGroup);
231
- pass.setBindGroup(1, objectBindGroup);
232
- pass.setBindGroup(2, textureGpu.fallbackBindGroup);
233
- pass.setVertexBuffer(0, runtime.debugVertexBuffer);
234
- pass.draw(debugVertexCount);
235
- }
236
- }
237
-
238
- destroyRuntime(runtime: SpineRuntimeGpu): void {
239
- const engine = this.requireEngine();
240
- getExtensionGPUResourceTracker(engine)?.untrackBuffer(runtime.vertexBuffer);
241
- getExtensionGPUResourceTracker(engine)?.untrackBuffer(runtime.debugVertexBuffer);
242
- runtime.vertexBuffer.destroy();
243
- runtime.debugVertexBuffer.destroy();
244
- for (const page of runtime.pages.values()) this.destroyAtlasPage(page);
245
- runtime.pages.clear();
246
- runtime.batches.length = 0;
247
- }
248
-
249
- private destroyAtlasPage(page: AtlasPageGpu): void {
250
- const engine = this.requireEngine();
251
- getExtensionGPUResourceTracker(engine)?.untrackTexture(page.texture);
252
- page.texture.destroy();
253
- }
254
-
255
- private getPipeline(blend: SpinePipelineMode): GPURenderPipeline {
256
- const key = `${blend}:${this.reverseZ ? 1 : 0}:${this.sampleCount}`;
257
- const cached = this.pipelines.get(key);
258
- if (cached) return cached;
259
- const engine = this.requireEngine();
260
- const prepared = this.requirePrepared();
261
- const pipeline = engine.device.createRenderPipeline({
262
- layout: prepared.pipelineLayout,
263
- vertex: {
264
- module: prepared.shaderModule,
265
- entryPoint: 'vs_main',
266
- buffers: [{
267
- arrayStride: 32,
268
- attributes: [
269
- { shaderLocation: 0, offset: 0, format: 'float32x2' },
270
- { shaderLocation: 1, offset: 8, format: 'float32x2' },
271
- { shaderLocation: 2, offset: 16, format: 'float32x4' },
272
- ],
273
- }],
274
- },
275
- fragment: {
276
- module: prepared.shaderModule,
277
- entryPoint: 'fs_main',
278
- targets: [{
279
- format: engine.format,
280
- blend: {
281
- color: blend === 'additive'
282
- ? { srcFactor: 'src-alpha', dstFactor: 'one', operation: 'add' }
283
- : { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
284
- alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
285
- },
286
- }],
287
- },
288
- primitive: { topology: blend === 'line' ? 'line-list' : 'triangle-list' },
289
- depthStencil: {
290
- format: engine.getDepthFormat(this.reverseZ),
291
- depthWriteEnabled: false,
292
- depthCompare: this.reverseZ ? 'greater-equal' : 'less-equal',
293
- },
294
- multisample: { count: this.sampleCount },
295
- });
296
- this.pipelines.set(key, pipeline);
297
- return pipeline;
298
- }
299
-
300
- private writeDirtyRanges(
301
- runtime: SpineRuntimeGpu,
302
- buffer: GPUBuffer,
303
- vertices: SpineFloatBuilder,
304
- dirtyRanges: SpineBufferDirtyRange[],
305
- mergedRanges: SpineBufferDirtyRange[],
306
- ): void {
307
- const engine = this.requireEngine();
308
- for (const range of mergeDirtyRanges(
309
- dirtyRanges,
310
- mergedRanges,
311
- runtime.mergedDirtyRangePool,
312
- runtime.allocationStats,
313
- )) {
314
- if (range.byteLength <= 0) continue;
315
- engine.device.queue.writeBuffer(
316
- buffer,
317
- range.byteOffset,
318
- vertices.data.buffer as ArrayBuffer,
319
- range.byteOffset,
320
- range.byteLength,
321
- );
322
- }
323
- }
324
-
325
- private deferBufferDestroy(buffer: GPUBuffer): void {
326
- const engine = this.requireEngine();
327
- this.pendingBufferDestroys.add(buffer);
328
- void engine.device.queue.onSubmittedWorkDone().finally(() => {
329
- if (!this.pendingBufferDestroys.delete(buffer)) return;
330
- getExtensionGPUResourceTracker(engine)?.untrackBuffer(buffer);
331
- buffer.destroy();
332
- });
333
- }
334
-
335
- private flushPendingBufferDestroys(): void {
336
- const engine = this.engine;
337
- for (const buffer of this.pendingBufferDestroys) {
338
- if (engine) getExtensionGPUResourceTracker(engine)?.untrackBuffer(buffer);
339
- buffer.destroy();
340
- }
341
- this.pendingBufferDestroys.clear();
342
- }
343
-
344
- private requireEngine(): IEngine & { device: GPUDevice } {
345
- if (!this.engine) throw spineRendererStateError();
346
- requireEngineDevice(this.engine);
347
- return this.engine as IEngine & { device: GPUDevice };
348
- }
349
-
350
- private requirePrepared(): {
351
- cameraGpu: Camera2DGpu;
352
- textureGpu: Texture2DGpu;
353
- objectLayout: GPUBindGroupLayout;
354
- shaderModule: GPUShaderModule;
355
- pipelineLayout: GPUPipelineLayout;
356
- } {
357
- if (
358
- !this.cameraGpu
359
- || !this.textureGpu
360
- || !this.objectLayoutGpu
361
- || !this.shaderModule
362
- || !this.pipelineLayout
363
- ) {
364
- throw spineRendererStateError();
365
- }
366
- return {
367
- cameraGpu: this.cameraGpu,
368
- textureGpu: this.textureGpu,
369
- objectLayout: this.objectLayoutGpu,
370
- shaderModule: this.shaderModule,
371
- pipelineLayout: this.pipelineLayout,
372
- };
373
- }
374
- }
375
-
376
- function nextGpuBufferSize(requiredBytes: number, currentBytes: number): number {
377
- const required = Math.max(4, alignUp4(requiredBytes));
378
- let next = Math.max(1024, currentBytes);
379
- while (next < required) next *= 2;
380
- return next;
381
- }
382
-
383
- function mergeDirtyRanges(
384
- ranges: SpineBufferDirtyRange[],
385
- out: SpineBufferDirtyRange[],
386
- pool: SpineBufferDirtyRange[],
387
- allocationStats: { dirtyRangePoolMisses: number },
388
- ): SpineBufferDirtyRange[] {
389
- if (ranges.length <= 1) return ranges;
390
- ranges.sort((a, b) => a.byteOffset - b.byteOffset);
391
- out.length = 0;
392
- for (const range of ranges) {
393
- const last = out[out.length - 1];
394
- if (!last) {
395
- pushMergedRange(out, pool, range.byteOffset, range.byteLength, allocationStats);
396
- continue;
397
- }
398
- const lastEnd = last.byteOffset + last.byteLength;
399
- if (range.byteOffset <= lastEnd) {
400
- last.byteLength = Math.max(lastEnd, range.byteOffset + range.byteLength) - last.byteOffset;
401
- } else {
402
- pushMergedRange(out, pool, range.byteOffset, range.byteLength, allocationStats);
403
- }
404
- }
405
- return out;
406
- }
407
-
408
- function pushMergedRange(
409
- out: SpineBufferDirtyRange[],
410
- pool: SpineBufferDirtyRange[],
411
- byteOffset: number,
412
- byteLength: number,
413
- allocationStats: { dirtyRangePoolMisses: number },
414
- ): void {
415
- const index = out.length;
416
- let range = pool[index];
417
- if (!range) {
418
- range = { byteOffset, byteLength };
419
- pool.push(range);
420
- allocationStats.dirtyRangePoolMisses++;
421
- } else {
422
- range.byteOffset = byteOffset;
423
- range.byteLength = byteLength;
424
- }
425
- out.push(range);
426
- }
427
-
428
- function loadImage(url: string): Promise<HTMLImageElement> {
429
- return new Promise((resolve, reject) => {
430
- const image = new Image();
431
- image.crossOrigin = 'anonymous';
432
- image.onload = () => resolve(image);
433
- image.onerror = () => reject(new EngineError(EngineErrorCode.AssetLoadFailed, `Failed to load Spine image: ${url}`, {
434
- domain: ErrorDomain.Component,
435
- recovery: ErrorRecovery.Retry,
436
- context: { url, resourceType: 'skeleton/spine-image' },
437
- path: 'spine.atlas.pages',
438
- }));
439
- image.src = url;
440
- });
441
- }
442
-
443
- function spineRendererStateError(): EngineError {
444
- return new EngineError(EngineErrorCode.RendererResourceNotReady, 'Spine2DGpuRenderer is not prepared.', {
445
- domain: ErrorDomain.Component,
446
- recovery: ErrorRecovery.TerminateRuntime,
447
- path: 'spine.renderer',
448
- });
449
- }
@@ -1,199 +0,0 @@
1
- import {
2
- beginRenderCommandPass,
3
- type IEngine,
4
- type RenderCommandContext,
5
- type RenderPipelineEntryOptions,
6
- } from '@haiyue/engine/extension-authoring';
7
- import { Entity, type World } from '@haiyue/engine/ecs';
8
- import { Spine2DComponent } from './Spine2DComponent';
9
- import { Spine2DGpuRenderer } from './Spine2DGpuRenderer';
10
- import { advanceSpineRuntime, buildSpineVertices, loadSpineRuntime, type SpineRuntime } from './Spine2DRuntime';
11
- import type { SpineAssetWorker } from './SpineAssetWorkerContract';
12
- import { RenderSystem2DBase, type RenderSystem2DBaseOptions } from '../utils/RenderSystem2DBase';
13
- import {
14
- writeObjectMatrixIfChanged,
15
- type Object2DGpu,
16
- } from '../utils/render2dGpu';
17
-
18
- export interface Spine2DRenderSystemOptions extends RenderSystem2DBaseOptions {
19
- assetWorker?: SpineAssetWorker | null;
20
- }
21
-
22
- interface EntityGpu {
23
- objectGpu: Object2DGpu;
24
- }
25
-
26
- export class Spine2DRenderSystem extends RenderSystem2DBase {
27
- private gpuRenderer = new Spine2DGpuRenderer();
28
- private runtimes = new Map<Spine2DComponent, SpineRuntime>();
29
- private entityGpu = new Map<number, EntityGpu>();
30
- private readonly liveComponents = new Set<Spine2DComponent>();
31
- private readonly pendingLoads = new Map<Spine2DComponent, { key: string; controller: AbortController }>();
32
- private readonly assetWorker: SpineAssetWorker | null;
33
- private disposed = false;
34
-
35
- get renderPipelineOptions(): RenderPipelineEntryOptions {
36
- return {
37
- pass: 'shared',
38
- loadOp: this.loadOp,
39
- recordMode: 'delta',
40
- sort: this.priority,
41
- };
42
- }
43
-
44
- constructor(
45
- engine: IEngine,
46
- cameraEntity: Entity,
47
- options: Spine2DRenderSystemOptions = {},
48
- ) {
49
- super({ all: [Spine2DComponent] }, engine, cameraEntity, options, 'Spine2DRenderSystem');
50
- this.assetWorker = options.assetWorker ?? null;
51
- }
52
-
53
- record(world: World, delta: number, context: RenderCommandContext): this {
54
- if (this.disabled || !this.engine.device) return this;
55
- this.gpuRenderer.prepare(this.engine);
56
- this.gpuRenderer.setRenderView(
57
- context.view?.reverseZ ?? this.engine.reverseZ,
58
- context.view?.sampleCount ?? this.engine.msaaSamples,
59
- );
60
- const liveEntities = this.beginLiveEntityTracking();
61
- this.liveComponents.clear();
62
- if (!this.writeCameraBuffer(this.engine.device.queue, this.gpuRenderer.cameraBuffer, context)) return this;
63
-
64
- const { passEncoder: pass, ownsPass } = beginRenderCommandPass(context);
65
-
66
- const entities = this.entitySet.get(world);
67
- if (entities) for (const entity of entities) {
68
- if (!this.isEntityRenderable(entity)) continue;
69
- const component = entity.getComponent(Spine2DComponent);
70
- if (!component || !component.jsonUrl) continue;
71
- this.liveComponents.add(component);
72
- this.ensureRuntime(component);
73
- const runtime = this.runtimes.get(component);
74
- if (!runtime || component.status !== 'loaded') continue;
75
- advanceSpineRuntime(component, delta);
76
- const {
77
- vertices,
78
- debugVertices,
79
- vertexDirtyRanges,
80
- debugDirtyRanges,
81
- verticesChanged,
82
- debugVerticesChanged,
83
- } = buildSpineVertices(component, runtime);
84
- if (vertices.length === 0) continue;
85
- if (verticesChanged) this.gpuRenderer.writeVertices(runtime, vertices, vertexDirtyRanges);
86
- const gpu = this.getEntityGpu(entity);
87
- this.markEntityLive(entity);
88
- const worldMatrix = this.getWorldMatrix2D(entity, context);
89
- writeObjectMatrixIfChanged(this.engine.device.queue, gpu.objectGpu, worldMatrix);
90
- if (debugVertices.length > 0) {
91
- if (debugVerticesChanged) this.gpuRenderer.writeDebugVertices(runtime, debugVertices, debugDirtyRanges);
92
- }
93
- this.gpuRenderer.drawRuntime(pass, runtime, gpu.objectGpu.bindGroup, debugVertices.length / 8);
94
- }
95
-
96
- if (ownsPass) pass.end();
97
- this.releaseEntityGpuEntriesNotIn(this.entityGpu, gpu => this.destroyEntityGpu(gpu), liveEntities);
98
- this.releaseRuntimesNotIn(this.liveComponents);
99
- return this;
100
- }
101
-
102
- override destroy(): this {
103
- this.disposed = true;
104
- for (const pending of this.pendingLoads.values()) pending.controller.abort('system-destroyed');
105
- this.pendingLoads.clear();
106
- this.releaseGpuResourcesForRecovery();
107
- return super.destroy();
108
- }
109
-
110
- protected releaseGpuResourcesForRecovery(): void {
111
- for (const pending of this.pendingLoads.values()) pending.controller.abort('device-lost');
112
- this.pendingLoads.clear();
113
- this.destroyEntityGpuEntries(this.entityGpu, gpu => this.destroyEntityGpu(gpu));
114
- for (const [component, runtime] of this.runtimes) {
115
- this.destroyRuntime(runtime);
116
- component.runtimeKey = '';
117
- component.loadingKey = '';
118
- }
119
- this.runtimes.clear();
120
- this.gpuRenderer.destroy();
121
- }
122
-
123
- protected override restoreGpuResourcesAfterRecovery(): void {
124
- this.gpuRenderer = new Spine2DGpuRenderer();
125
- this.disposed = false;
126
- }
127
-
128
- private getEntityGpu(entity: Entity): EntityGpu {
129
- return this.getOrCreateEntityGpu(this.entityGpu, entity, () => ({
130
- objectGpu: this.createObjectGpu(this.gpuRenderer.objectLayout),
131
- }));
132
- }
133
-
134
- private releaseRuntimesNotIn(liveComponents: ReadonlySet<Spine2DComponent>): void {
135
- for (const [component, pending] of this.pendingLoads) {
136
- if (liveComponents.has(component)) continue;
137
- pending.controller.abort('component-removed');
138
- this.pendingLoads.delete(component);
139
- component.loadingKey = '';
140
- }
141
- for (const [component, runtime] of this.runtimes) {
142
- if (!liveComponents.has(component)) {
143
- this.destroyRuntime(runtime);
144
- this.runtimes.delete(component);
145
- component.runtimeKey = '';
146
- }
147
- }
148
- }
149
-
150
- private destroyEntityGpu(gpu: EntityGpu): void {
151
- this.destroyObjectGpu(gpu.objectGpu);
152
- }
153
-
154
- private destroyRuntime(runtime: SpineRuntime): void {
155
- this.gpuRenderer.destroyRuntime(runtime);
156
- }
157
-
158
- private ensureRuntime(component: Spine2DComponent): void {
159
- const key = component.sourceKey;
160
- if (component.runtimeKey === key || component.loadingKey === key) return;
161
- const previousPending = this.pendingLoads.get(component);
162
- previousPending?.controller.abort('source-changed');
163
- this.pendingLoads.delete(component);
164
- const previous = this.runtimes.get(component);
165
- if (previous) {
166
- this.destroyRuntime(previous);
167
- this.runtimes.delete(component);
168
- component.runtimeKey = '';
169
- }
170
- component.status = 'loading';
171
- component.error = null;
172
- component.loadingKey = key;
173
- const controller = new AbortController();
174
- const pending = { key, controller };
175
- this.pendingLoads.set(component, pending);
176
- void loadSpineRuntime(this.gpuRenderer, component, { assetWorker: this.assetWorker, signal: controller.signal })
177
- .then((runtime) => {
178
- if (this.disposed || component.loadingKey !== key) {
179
- this.destroyRuntime(runtime);
180
- return;
181
- }
182
- this.runtimes.set(component, runtime);
183
- component.runtimeKey = key;
184
- component.status = 'loaded';
185
- component.elapsed = 0;
186
- })
187
- .catch((error) => {
188
- if (controller.signal.aborted) return;
189
- component.status = 'error';
190
- component.error = error instanceof Error ? error.message : String(error);
191
- console.warn(`[Spine2DRenderSystem] ${component.error}`);
192
- })
193
- .finally(() => {
194
- if (this.pendingLoads.get(component) === pending) this.pendingLoads.delete(component);
195
- if (component.loadingKey === key) component.loadingKey = '';
196
- });
197
- }
198
-
199
- }