@haiyue/extensions 0.1.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 (293) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/dist/animation/Animation2DComponent.d.ts +46 -0
  4. package/dist/animation/Animation2DExtensionRegistry.d.ts +27 -0
  5. package/dist/animation/Animation2DRenderSystem.d.ts +89 -0
  6. package/dist/animation/Animation2DRuntime.d.ts +99 -0
  7. package/dist/animation/Animation2DStateMachine.d.ts +13 -0
  8. package/dist/animation/Animation2DStateMachineComponent.d.ts +54 -0
  9. package/dist/animation/Animation2DStateMachineRuntime.d.ts +30 -0
  10. package/dist/animation/Animation2DStateMachineSystem.d.ts +14 -0
  11. package/dist/animation/Animation2DStateMachineVisualRuntime.d.ts +27 -0
  12. package/dist/animation/Animation2DSystem.d.ts +14 -0
  13. package/dist/animation/AnimationAssetLoader.d.ts +9 -0
  14. package/dist/animation/AnimationAudioClip.d.ts +26 -0
  15. package/dist/animation/AnimationPathTessellator.d.ts +52 -0
  16. package/dist/animation/AnimationTextRasterizer.d.ts +21 -0
  17. package/dist/animation/AnimationVisual2D.d.ts +68 -0
  18. package/dist/animation/HyaAnimation2DClipAdapter.d.ts +16 -0
  19. package/dist/animation/Particle2DDescriptorAdapter.d.ts +5 -0
  20. package/dist/animation/runtime/mixer/Action.d.ts +150 -0
  21. package/dist/animation/runtime/mixer/Mixer.d.ts +54 -0
  22. package/dist/animation/runtime/mixer/PoseBuffer.d.ts +23 -0
  23. package/dist/animation/runtime/mixer/Sampler.d.ts +17 -0
  24. package/dist/animation/runtime/mixer/Types.d.ts +101 -0
  25. package/dist/animation/runtime/mixer/index.d.ts +6 -0
  26. package/dist/animation-state-machine/AnimationStateMachine.d.ts +111 -0
  27. package/dist/animation-state-machine/AnimationStateMachineChannels.d.ts +23 -0
  28. package/dist/animation-state-machine/runtime/Animation2DStateMachineMixerAdapter.d.ts +51 -0
  29. package/dist/animation-state-machine/runtime/AnimationStateMachineBlendTreeWeights.d.ts +14 -0
  30. package/dist/animation-state-machine/runtime/AnimationStateMachineCompiler.d.ts +109 -0
  31. package/dist/animation-state-machine/runtime/AnimationStateMachineController.d.ts +103 -0
  32. package/dist/animation-state-machine/runtime/AnimationStateMachineMixerPort.d.ts +35 -0
  33. package/dist/animation-state-machine/runtime/index.d.ts +7 -0
  34. package/dist/animation.d.ts +15 -0
  35. package/dist/animation.js +1171 -0
  36. package/dist/animation3d/Animation3DAction.d.ts +46 -0
  37. package/dist/animation3d/Animation3DBinding.d.ts +85 -0
  38. package/dist/animation3d/Animation3DClip.d.ts +20 -0
  39. package/dist/animation3d/Animation3DError.d.ts +13 -0
  40. package/dist/animation3d/Animation3DMixer.d.ts +27 -0
  41. package/dist/animation3d/Animation3DPose.d.ts +40 -0
  42. package/dist/animation3d/Animation3DPoseBuffer.d.ts +24 -0
  43. package/dist/animation3d/Animation3DResource.d.ts +28 -0
  44. package/dist/animation3d/Animation3DStateMachine.d.ts +95 -0
  45. package/dist/animation3d/Animation3DStateMachineRuntime.d.ts +70 -0
  46. package/dist/animation3d/Animation3DTrack.d.ts +19 -0
  47. package/dist/animation3d/hya/HyaAnimation3DRuntime.d.ts +73 -0
  48. package/dist/animation3d/hya/HyaAnimation3DStateMachineRuntime.d.ts +65 -0
  49. package/dist/animation3d/hya/HyaAnimation3DTypes.d.ts +170 -0
  50. package/dist/animation3d/hya/index.d.ts +4 -0
  51. package/dist/animation3d/index.d.ts +14 -0
  52. package/dist/animation3d/runtime/integration/Animation3DStateMachineMixerAdapter.d.ts +81 -0
  53. package/dist/animation3d/runtime/integration/Animation3DStateMachineMixerIntegration.d.ts +39 -0
  54. package/dist/animation3d/runtime/integration/index.d.ts +2 -0
  55. package/dist/animation3d/runtime/mixer/Action.d.ts +150 -0
  56. package/dist/animation3d/runtime/mixer/Animation3DMixerRuntimeStore.d.ts +6 -0
  57. package/dist/animation3d/runtime/mixer/Mixer.d.ts +59 -0
  58. package/dist/animation3d/runtime/mixer/PoseBuffer.d.ts +1 -0
  59. package/dist/animation3d/runtime/mixer/TrackSampler.d.ts +24 -0
  60. package/dist/animation3d/runtime/mixer/index.d.ts +4 -0
  61. package/dist/animation3d/runtime/state-machine/Animation3DBlendTreeWeights.d.ts +1 -0
  62. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineCompiler.d.ts +1 -0
  63. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineController.d.ts +1 -0
  64. package/dist/animation3d/runtime/state-machine/Animation3DStateMachineMixerPort.d.ts +1 -0
  65. package/dist/animation3d/runtime/state-machine/index.d.ts +6 -0
  66. package/dist/animation3d.d.ts +5 -0
  67. package/dist/animation3d.js +1708 -0
  68. package/dist/benchmark.d.ts +30 -0
  69. package/dist/benchmark.js +119 -0
  70. package/dist/canvas-text/CanvasText2DRenderSystem.d.ts +24 -0
  71. package/dist/canvas-text/CanvasTextComponent.d.ts +18 -0
  72. package/dist/canvas-text.d.ts +4 -0
  73. package/dist/canvas-text.js +276 -0
  74. package/dist/chunks/2d-ui-animation-2d.generated-D4aHzFU2.js +4 -0
  75. package/dist/chunks/2d-ui-canvas-text-2d.generated-C0Eaej2m.js +4 -0
  76. package/dist/chunks/2d-ui-spine2d.generated-CUUi8xjl.js +4 -0
  77. package/dist/chunks/2d-ui-tilemap2d.generated-gebw4mX7.js +4 -0
  78. package/dist/chunks/Animation2DStateMachine-9IonguNa.js +3245 -0
  79. package/dist/chunks/AnimationStateMachineController-BIcAh-sT.js +1438 -0
  80. package/dist/chunks/GltfAnimation3DAdapter-Cu3rQQsW.js +2240 -0
  81. package/dist/chunks/GltfAnimationRuntime-CRHsLycN.js +631 -0
  82. package/dist/chunks/RenderSystem2DBase-DDT61dAu.js +227 -0
  83. package/dist/chunks/Spine2DRuntime-D9M9LAQR.js +3056 -0
  84. package/dist/chunks/SpineAssetParser-BSDmPge1.js +378 -0
  85. package/dist/chunks/gltfLoader-Dm22jLYB.js +2085 -0
  86. package/dist/chunks/pluginUtils-CvwroRMd.js +33 -0
  87. package/dist/experimental-gltf-worker.d.ts +4 -0
  88. package/dist/experimental-gltf-worker.js +138 -0
  89. package/dist/experimental-spine-worker.d.ts +4 -0
  90. package/dist/experimental-spine-worker.js +110 -0
  91. package/dist/gltf/GltfAccessorReader.d.ts +7 -0
  92. package/dist/gltf/GltfAnimation3DAdapter.d.ts +47 -0
  93. package/dist/gltf/GltfAnimationRuntime.d.ts +10 -0
  94. package/dist/gltf/GltfAssetWorkerClient.d.ts +20 -0
  95. package/dist/gltf/GltfCompatibilityReport.d.ts +70 -0
  96. package/dist/gltf/GltfConservativeBounds.d.ts +18 -0
  97. package/dist/gltf/GltfDracoDecoder.d.ts +4 -0
  98. package/dist/gltf/GltfExtensionAdapter.d.ts +54 -0
  99. package/dist/gltf/GltfLoaderContract.d.ts +249 -0
  100. package/dist/gltf/GltfLoaderErrors.d.ts +4 -0
  101. package/dist/gltf/GltfMaterialDescriptor.d.ts +23 -0
  102. package/dist/gltf/GltfMaterialEncoder.d.ts +20 -0
  103. package/dist/gltf/GltfMaterialLoader.d.ts +6 -0
  104. package/dist/gltf/GltfModelComponent.d.ts +72 -0
  105. package/dist/gltf/GltfModelSystem.d.ts +37 -0
  106. package/dist/gltf/GltfPlugin.d.ts +6 -0
  107. package/dist/gltf/GltfSchema.d.ts +225 -0
  108. package/dist/gltf/GltfUvSemanticPlanner.d.ts +33 -0
  109. package/dist/gltf/gltfLoader.d.ts +9 -0
  110. package/dist/gltf-animation3d.d.ts +3 -0
  111. package/dist/gltf-animation3d.js +8 -0
  112. package/dist/gltf-worker-runtime.d.ts +7 -0
  113. package/dist/gltf-worker-runtime.js +6981 -0
  114. package/dist/gltf.d.ts +12 -0
  115. package/dist/gltf.js +517 -0
  116. package/dist/grid/Grid2DComponent.d.ts +25 -0
  117. package/dist/grid.d.ts +2 -0
  118. package/dist/grid.js +56 -0
  119. package/dist/hya-state-machine.d.ts +7 -0
  120. package/dist/hya-state-machine.js +2934 -0
  121. package/dist/index.d.ts +2 -0
  122. package/dist/index.js +7 -0
  123. package/dist/internal/2d-ui-shader-artifact.js +870 -0
  124. package/dist/plugins/pluginUtils.d.ts +20 -0
  125. package/dist/plugins.d.ts +6 -0
  126. package/dist/shaders/generated/2d-ui-artifact.generated.d.ts +658 -0
  127. package/dist/spine/Spine2DComponent.d.ts +116 -0
  128. package/dist/spine/Spine2DGpuRenderer.d.ts +65 -0
  129. package/dist/spine/Spine2DRenderSystem.d.ts +27 -0
  130. package/dist/spine/Spine2DRuntime.d.ts +103 -0
  131. package/dist/spine/SpineAnimationBoneTimelines.d.ts +8 -0
  132. package/dist/spine/SpineAssetParser.d.ts +18 -0
  133. package/dist/spine/SpineAssetWorkerClient.d.ts +19 -0
  134. package/dist/spine/SpineAssetWorkerContract.d.ts +6 -0
  135. package/dist/spine/SpineAtlasParser.d.ts +21 -0
  136. package/dist/spine/SpineFloatBuilder.d.ts +15 -0
  137. package/dist/spine/SpinePathConstraintSolver.d.ts +32 -0
  138. package/dist/spine/SpinePlugin.d.ts +8 -0
  139. package/dist/spine/SpineSkeletonRuntime.d.ts +185 -0
  140. package/dist/spine/SpineSlotAnimation.d.ts +17 -0
  141. package/dist/spine/SpineTimelineRuntime.d.ts +25 -0
  142. package/dist/spine/SpineVertexBuilder.d.ts +61 -0
  143. package/dist/spine.d.ts +7 -0
  144. package/dist/spine.js +578 -0
  145. package/dist/tilemap/Tilemap2DComponent.d.ts +110 -0
  146. package/dist/tilemap/Tilemap2DRenderSystem.d.ts +11 -0
  147. package/dist/tilemap/Tilemap2DRenderer.d.ts +24 -0
  148. package/dist/tilemap/TilemapPlugin.d.ts +8 -0
  149. package/dist/tilemap.d.ts +6 -0
  150. package/dist/tilemap.js +535 -0
  151. package/dist/tween/Tween2DComponent.d.ts +70 -0
  152. package/dist/tween/Tween2DSystem.d.ts +12 -0
  153. package/dist/tween.d.ts +4 -0
  154. package/dist/tween.js +138 -0
  155. package/dist/utils/RenderSystem2DBase.d.ts +42 -0
  156. package/dist/utils/arrayAccess.d.ts +4 -0
  157. package/dist/utils/camera2d.d.ts +12 -0
  158. package/dist/utils/render2dGpu.d.ts +32 -0
  159. package/package.json +124 -0
  160. package/src/animation/Animation2DComponent.ts +135 -0
  161. package/src/animation/Animation2DExtensionRegistry.ts +52 -0
  162. package/src/animation/Animation2DRenderSystem.ts +1026 -0
  163. package/src/animation/Animation2DRuntime.ts +1326 -0
  164. package/src/animation/Animation2DStateMachine.ts +39 -0
  165. package/src/animation/Animation2DStateMachineComponent.ts +228 -0
  166. package/src/animation/Animation2DStateMachineRuntime.ts +141 -0
  167. package/src/animation/Animation2DStateMachineSystem.ts +60 -0
  168. package/src/animation/Animation2DStateMachineVisualRuntime.ts +282 -0
  169. package/src/animation/Animation2DSystem.ts +72 -0
  170. package/src/animation/AnimationAssetLoader.ts +84 -0
  171. package/src/animation/AnimationAudioClip.ts +140 -0
  172. package/src/animation/AnimationPathTessellator.ts +691 -0
  173. package/src/animation/AnimationTextRasterizer.ts +340 -0
  174. package/src/animation/AnimationVisual2D.ts +153 -0
  175. package/src/animation/HyaAnimation2DClipAdapter.ts +845 -0
  176. package/src/animation/Particle2DDescriptorAdapter.ts +35 -0
  177. package/src/animation/runtime/mixer/Action.ts +876 -0
  178. package/src/animation/runtime/mixer/Mixer.ts +505 -0
  179. package/src/animation/runtime/mixer/PoseBuffer.ts +105 -0
  180. package/src/animation/runtime/mixer/Sampler.ts +252 -0
  181. package/src/animation/runtime/mixer/Types.ts +138 -0
  182. package/src/animation/runtime/mixer/index.ts +31 -0
  183. package/src/animation-state-machine/AnimationStateMachine.ts +146 -0
  184. package/src/animation-state-machine/AnimationStateMachineChannels.ts +116 -0
  185. package/src/animation-state-machine/runtime/Animation2DStateMachineMixerAdapter.ts +197 -0
  186. package/src/animation-state-machine/runtime/AnimationStateMachineBlendTreeWeights.ts +503 -0
  187. package/src/animation-state-machine/runtime/AnimationStateMachineCompiler.ts +763 -0
  188. package/src/animation-state-machine/runtime/AnimationStateMachineController.ts +987 -0
  189. package/src/animation-state-machine/runtime/AnimationStateMachineMixerPort.ts +54 -0
  190. package/src/animation-state-machine/runtime/index.ts +47 -0
  191. package/src/animation.ts +33 -0
  192. package/src/animation3d/Animation3DAction.ts +73 -0
  193. package/src/animation3d/Animation3DBinding.ts +116 -0
  194. package/src/animation3d/Animation3DClip.ts +22 -0
  195. package/src/animation3d/Animation3DError.ts +34 -0
  196. package/src/animation3d/Animation3DMixer.ts +82 -0
  197. package/src/animation3d/Animation3DPose.ts +100 -0
  198. package/src/animation3d/Animation3DPoseBuffer.ts +85 -0
  199. package/src/animation3d/Animation3DResource.ts +49 -0
  200. package/src/animation3d/Animation3DStateMachine.ts +126 -0
  201. package/src/animation3d/Animation3DStateMachineRuntime.ts +191 -0
  202. package/src/animation3d/Animation3DTrack.ts +29 -0
  203. package/src/animation3d/hya/HyaAnimation3DRuntime.ts +756 -0
  204. package/src/animation3d/hya/HyaAnimation3DStateMachineRuntime.ts +618 -0
  205. package/src/animation3d/hya/HyaAnimation3DTypes.ts +168 -0
  206. package/src/animation3d/hya/index.ts +10 -0
  207. package/src/animation3d/index.ts +76 -0
  208. package/src/animation3d/runtime/integration/Animation3DStateMachineMixerAdapter.ts +325 -0
  209. package/src/animation3d/runtime/integration/Animation3DStateMachineMixerIntegration.ts +158 -0
  210. package/src/animation3d/runtime/integration/index.ts +9 -0
  211. package/src/animation3d/runtime/mixer/Action.ts +833 -0
  212. package/src/animation3d/runtime/mixer/Animation3DMixerRuntimeStore.ts +26 -0
  213. package/src/animation3d/runtime/mixer/Mixer.ts +562 -0
  214. package/src/animation3d/runtime/mixer/PoseBuffer.ts +1 -0
  215. package/src/animation3d/runtime/mixer/TrackSampler.ts +399 -0
  216. package/src/animation3d/runtime/mixer/index.ts +8 -0
  217. package/src/animation3d/runtime/state-machine/Animation3DBlendTreeWeights.ts +4 -0
  218. package/src/animation3d/runtime/state-machine/Animation3DStateMachineCompiler.ts +1 -0
  219. package/src/animation3d/runtime/state-machine/Animation3DStateMachineController.ts +1 -0
  220. package/src/animation3d/runtime/state-machine/Animation3DStateMachineMixerPort.ts +1 -0
  221. package/src/animation3d/runtime/state-machine/index.ts +45 -0
  222. package/src/animation3d.ts +5 -0
  223. package/src/benchmark.ts +168 -0
  224. package/src/canvas-text/CanvasText2DRenderSystem.ts +292 -0
  225. package/src/canvas-text/CanvasTextComponent.ts +47 -0
  226. package/src/canvas-text.ts +4 -0
  227. package/src/experimental-gltf-worker.ts +18 -0
  228. package/src/experimental-spine-worker.ts +9 -0
  229. package/src/gltf/GltfAccessorReader.ts +271 -0
  230. package/src/gltf/GltfAnimation3DAdapter.ts +680 -0
  231. package/src/gltf/GltfAnimationRuntime.ts +392 -0
  232. package/src/gltf/GltfAssetWorkerClient.ts +136 -0
  233. package/src/gltf/GltfCompatibilityReport.ts +214 -0
  234. package/src/gltf/GltfConservativeBounds.ts +219 -0
  235. package/src/gltf/GltfDracoDecoder.ts +251 -0
  236. package/src/gltf/GltfExtensionAdapter.ts +340 -0
  237. package/src/gltf/GltfLoaderContract.ts +333 -0
  238. package/src/gltf/GltfLoaderErrors.ts +59 -0
  239. package/src/gltf/GltfMaterialDescriptor.ts +134 -0
  240. package/src/gltf/GltfMaterialEncoder.ts +173 -0
  241. package/src/gltf/GltfMaterialLoader.ts +293 -0
  242. package/src/gltf/GltfModelComponent.ts +115 -0
  243. package/src/gltf/GltfModelSystem.ts +208 -0
  244. package/src/gltf/GltfPlugin.ts +84 -0
  245. package/src/gltf/GltfSchema.ts +229 -0
  246. package/src/gltf/GltfUvSemanticPlanner.ts +166 -0
  247. package/src/gltf/gltfLoader.ts +910 -0
  248. package/src/gltf-animation3d.ts +10 -0
  249. package/src/gltf-worker-runtime.ts +10 -0
  250. package/src/gltf.ts +56 -0
  251. package/src/grid/Grid2DComponent.ts +69 -0
  252. package/src/grid.ts +2 -0
  253. package/src/hya-state-machine.ts +19 -0
  254. package/src/index.ts +2 -0
  255. package/src/plugins/pluginUtils.ts +50 -0
  256. package/src/plugins.ts +6 -0
  257. package/src/shaders/generated/2d-ui-animation-2d.generated.wgsl +242 -0
  258. package/src/shaders/generated/2d-ui-artifact.generated.ts +867 -0
  259. package/src/shaders/generated/2d-ui-canvas-text-2d.generated.wgsl +38 -0
  260. package/src/shaders/generated/2d-ui-spine2d.generated.wgsl +41 -0
  261. package/src/shaders/generated/2d-ui-tilemap2d.generated.wgsl +36 -0
  262. package/src/spine/Spine2DComponent.ts +168 -0
  263. package/src/spine/Spine2DGpuRenderer.ts +449 -0
  264. package/src/spine/Spine2DRenderSystem.ts +199 -0
  265. package/src/spine/Spine2DRuntime.ts +1529 -0
  266. package/src/spine/SpineAnimationBoneTimelines.ts +30 -0
  267. package/src/spine/SpineAssetParser.ts +20 -0
  268. package/src/spine/SpineAssetWorkerClient.ts +112 -0
  269. package/src/spine/SpineAssetWorkerContract.ts +4 -0
  270. package/src/spine/SpineAtlasParser.ts +127 -0
  271. package/src/spine/SpineFloatBuilder.ts +66 -0
  272. package/src/spine/SpinePathConstraintSolver.ts +582 -0
  273. package/src/spine/SpinePlugin.ts +76 -0
  274. package/src/spine/SpineSkeletonRuntime.ts +521 -0
  275. package/src/spine/SpineSlotAnimation.ts +195 -0
  276. package/src/spine/SpineTimelineRuntime.ts +453 -0
  277. package/src/spine/SpineVertexBuilder.ts +686 -0
  278. package/src/spine.ts +7 -0
  279. package/src/tilemap/Tilemap2DComponent.ts +232 -0
  280. package/src/tilemap/Tilemap2DRenderSystem.ts +58 -0
  281. package/src/tilemap/Tilemap2DRenderer.ts +289 -0
  282. package/src/tilemap/TilemapPlugin.ts +75 -0
  283. package/src/tilemap.ts +6 -0
  284. package/src/tween/Tween2DComponent.ts +83 -0
  285. package/src/tween/Tween2DSystem.ts +78 -0
  286. package/src/tween.ts +4 -0
  287. package/src/types/earcut.d.ts +7 -0
  288. package/src/types/wgsl.d.ts +4 -0
  289. package/src/utils/RenderSystem2DBase.ts +164 -0
  290. package/src/utils/arrayAccess.ts +17 -0
  291. package/src/utils/camera2d.ts +68 -0
  292. package/src/utils/render2dGpu.ts +132 -0
  293. package/test/fixtures/gltf/animation-characterization.gltf +344 -0
@@ -0,0 +1,686 @@
1
+ import { Spine2DComponent } from './Spine2DComponent';
2
+ import { SpineFloatBuilder } from './SpineFloatBuilder';
3
+ import type { AtlasRegion } from './SpineAtlasParser';
4
+ import type { BonePose, RegionAttachment, SlotData, SpineData } from './SpineSkeletonRuntime';
5
+ import { requiredItemAt, requiredNumberAt } from '../utils/arrayAccess';
6
+
7
+ export interface SpineDrawBatch {
8
+ blend: 'normal' | 'additive';
9
+ page: string;
10
+ firstVertex: number;
11
+ vertexCount: number;
12
+ }
13
+
14
+ interface SpineVertex {
15
+ x: number;
16
+ y: number;
17
+ u: number;
18
+ v: number;
19
+ color: [number, number, number, number];
20
+ }
21
+
22
+ export interface SpineSlotGeometryCache {
23
+ key: string;
24
+ signature: number;
25
+ debugSignature: number;
26
+ vertices: Float32Array;
27
+ vertexLength: number;
28
+ vertexCapacity: number;
29
+ debugVertices: Float32Array;
30
+ debugVertexLength: number;
31
+ debugVertexCapacity: number;
32
+ batch: Omit<SpineDrawBatch, 'firstVertex'>;
33
+ vertexOffset: number;
34
+ debugVertexOffset: number;
35
+ }
36
+
37
+ export interface SpineVertexRuntime {
38
+ data: SpineData;
39
+ pages: Map<string, { width: number; height: number }>;
40
+ vertexBuilder: SpineFloatBuilder;
41
+ debugVertexBuilder: SpineFloatBuilder;
42
+ meshPointBuilder: SpineFloatBuilder;
43
+ batches: SpineDrawBatch[];
44
+ batchPool: SpineDrawBatch[];
45
+ allocationStats?: { batchPoolMisses: number };
46
+ vertexColorScratch: [number, number, number, number];
47
+ }
48
+
49
+ export const HASH_OFFSET = 2166136261;
50
+ const HASH_PRIME = 16777619;
51
+
52
+ export function createEmptySlotCache(key: string): SpineSlotGeometryCache {
53
+ return {
54
+ key,
55
+ signature: 0,
56
+ debugSignature: 0,
57
+ vertices: new Float32Array(0),
58
+ vertexLength: 0,
59
+ vertexCapacity: 0,
60
+ debugVertices: new Float32Array(0),
61
+ debugVertexLength: 0,
62
+ debugVertexCapacity: 0,
63
+ batch: { blend: 'normal', page: '', vertexCount: 0 },
64
+ vertexOffset: -1,
65
+ debugVertexOffset: -1,
66
+ };
67
+ }
68
+
69
+ export function copyBuilderData(builder: SpineFloatBuilder, target: Float32Array): Float32Array {
70
+ let output = target;
71
+ if (output.length < builder.length) {
72
+ output = new Float32Array(builder.length);
73
+ }
74
+ for (let index = 0; index < builder.length; index++) output[index] = builder.data[index] ?? 0;
75
+ return output;
76
+ }
77
+
78
+ export function hasInvalidOffsets(entries: SpineSlotGeometryCache[]): boolean {
79
+ let vertexOffset = 0;
80
+ let debugOffset = 0;
81
+ for (const entry of entries) {
82
+ if (entry.vertexOffset !== vertexOffset || entry.debugVertexOffset !== debugOffset) return true;
83
+ vertexOffset += entry.vertexCapacity;
84
+ debugOffset += entry.debugVertexLength;
85
+ }
86
+ return false;
87
+ }
88
+
89
+ export function rebuildCachedGeometryLayout(runtime: SpineVertexRuntime, entries: SpineSlotGeometryCache[]): void {
90
+ const vertices = runtime.vertexBuilder;
91
+ const debugVertices = runtime.debugVertexBuilder;
92
+ vertices.clear();
93
+ debugVertices.clear();
94
+ for (const entry of entries) {
95
+ entry.vertexOffset = vertices.length;
96
+ entry.debugVertexOffset = debugVertices.length;
97
+ if (entry.vertexLength > 0) {
98
+ vertices.reserveLength(vertices.length + entry.vertexCapacity);
99
+ for (let index = 0; index < entry.vertexLength; index++) {
100
+ vertices.data[entry.vertexOffset + index] = entry.vertices[index] ?? 0;
101
+ }
102
+ } else if (entry.vertexCapacity > 0) {
103
+ vertices.reserveLength(vertices.length + entry.vertexCapacity);
104
+ }
105
+ if (entry.debugVertexLength > 0) {
106
+ debugVertices.reserveLength(debugVertices.length + entry.debugVertexLength);
107
+ for (let index = 0; index < entry.debugVertexLength; index++) {
108
+ debugVertices.data[entry.debugVertexOffset + index] = entry.debugVertices[index] ?? 0;
109
+ }
110
+ }
111
+ }
112
+ }
113
+
114
+ export function rebuildCachedDrawBatches(runtime: SpineVertexRuntime, entries: SpineSlotGeometryCache[]): void {
115
+ const batches = runtime.batches;
116
+ batches.length = 0;
117
+ for (const entry of entries) {
118
+ if (entry.vertexLength <= 0 || entry.batch.vertexCount <= 0) continue;
119
+ appendBatch(
120
+ batches,
121
+ runtime.batchPool,
122
+ runtime.allocationStats,
123
+ entry.batch.blend,
124
+ entry.batch.page,
125
+ entry.vertexOffset / 8,
126
+ entry.batch.vertexCount,
127
+ );
128
+ }
129
+ }
130
+
131
+ export function getSlotOrderHash(entries: SpineSlotGeometryCache[]): number {
132
+ let hash = HASH_OFFSET;
133
+ for (const entry of entries) {
134
+ hash = hashString(hash, entry.key);
135
+ hash = hashInt(hash, entry.vertexCapacity);
136
+ hash = hashInt(hash, entry.debugVertexLength);
137
+ }
138
+ return hash;
139
+ }
140
+
141
+ export function getSlotBuildSignature(
142
+ slot: SlotData,
143
+ attachmentName: string,
144
+ attachment: RegionAttachment,
145
+ regionName: string,
146
+ region: AtlasRegion,
147
+ bone: BonePose,
148
+ poses: Map<string, BonePose>,
149
+ slotColor: [number, number, number, number] | undefined,
150
+ clip: { endSlot?: string; polygon: Array<[number, number]> } | null,
151
+ component: Spine2DComponent,
152
+ ): number {
153
+ let hash = HASH_OFFSET;
154
+ hash = hashString(hash, slot.name);
155
+ hash = hashString(hash, attachmentName);
156
+ hash = hashString(hash, attachment.type ?? '');
157
+ hash = hashString(hash, regionName);
158
+ hash = hashString(hash, region.page);
159
+ hash = hashString(hash, normalizeBlend(slot.blend));
160
+ hash = hashInt(hash, quantizeSignatureNumber(component.scale));
161
+ hash = hashColor(hash, slotColor);
162
+ hash = hashClip(hash, clip);
163
+ return attachment.type === 'mesh' ? hashAllPoses(hash, poses) : hashPose(hash, bone);
164
+ }
165
+
166
+ export function getDebugBonesSignature(scale: number, poses: Map<string, BonePose>): number {
167
+ let hash = hashString(HASH_OFFSET, 'debugBones');
168
+ hash = hashInt(hash, quantizeSignatureNumber(scale));
169
+ return hashAllPoses(hash, poses);
170
+ }
171
+
172
+ export function hashInt(hash: number, value: number): number {
173
+ let input = value | 0;
174
+ for (let i = 0; i < 4; i++) {
175
+ hash ^= input & 0xff;
176
+ hash = Math.imul(hash, HASH_PRIME) >>> 0;
177
+ input >>= 8;
178
+ }
179
+ return hash;
180
+ }
181
+
182
+ export function normalizeBlend(blend: string): 'normal' | 'additive' {
183
+ return blend === 'additive' ? 'additive' : 'normal';
184
+ }
185
+
186
+ export function computeClipPolygon(bone: BonePose, attachment: RegionAttachment, scale: number): Array<[number, number]> {
187
+ const vertices = attachment.vertices ?? [];
188
+ const polygon: Array<[number, number]> = [];
189
+ for (let i = 0; i < vertices.length - 1; i += 2) {
190
+ polygon.push(transformBonePoint(
191
+ bone,
192
+ requiredNumberAt(vertices, i, 'clip attachment vertices'),
193
+ requiredNumberAt(vertices, i + 1, 'clip attachment vertices'),
194
+ scale,
195
+ ));
196
+ }
197
+ return signedPolygonArea(polygon) < 0 ? polygon.slice().reverse() : polygon;
198
+ }
199
+
200
+ export function replaceClippedRange(floats: SpineFloatBuilder, start: number, polygon: Array<[number, number]>, clipped: SpineFloatBuilder): void {
201
+ if (polygon.length < 3 || start >= floats.length) return;
202
+ clipped.clear();
203
+ for (let i = start; i < floats.length; i += 24) {
204
+ const triangle: SpineVertex[] = [
205
+ readVertex(floats, i),
206
+ readVertex(floats, i + 8),
207
+ readVertex(floats, i + 16),
208
+ ];
209
+ const clippedPolygon = clipVertexPolygon(triangle, polygon);
210
+ for (let vertex = 1; vertex < clippedPolygon.length - 1; vertex++) {
211
+ writeVertex(clipped, requiredItemAt(clippedPolygon, 0, 'clipped polygon'));
212
+ writeVertex(clipped, requiredItemAt(clippedPolygon, vertex, 'clipped polygon'));
213
+ writeVertex(clipped, requiredItemAt(clippedPolygon, vertex + 1, 'clipped polygon'));
214
+ }
215
+ }
216
+ floats.truncate(start);
217
+ floats.appendArray(clipped.data, clipped.length);
218
+ }
219
+
220
+ export function appendRegionVertices(
221
+ out: SpineFloatBuilder,
222
+ component: Spine2DComponent,
223
+ runtime: SpineVertexRuntime,
224
+ bone: BonePose,
225
+ slotColor: [number, number, number, number] | undefined,
226
+ attachment: RegionAttachment,
227
+ region: AtlasRegion,
228
+ ): void {
229
+ const w = attachment.width || region.originalWidth || region.width;
230
+ const h = attachment.height || region.originalHeight || region.height;
231
+ const sx = attachment.scaleX ?? 1;
232
+ const sy = attachment.scaleY ?? 1;
233
+ const rad = (attachment.rotation ?? 0) * Math.PI / 180;
234
+ const cos = Math.cos(rad);
235
+ const sin = Math.sin(rad);
236
+ const halfW = w * 0.5;
237
+ const halfH = h * 0.5;
238
+ const tx = attachment.x ?? 0;
239
+ const ty = attachment.y ?? 0;
240
+ const scale = component.scale;
241
+ const x0 = -halfW * sx; const y0 = -halfH * sy;
242
+ const x1 = halfW * sx; const y1 = halfH * sy;
243
+ const rx0 = x0 * cos - y0 * sin + tx; const ry0 = x0 * sin + y0 * cos + ty;
244
+ const rx1 = x1 * cos - y0 * sin + tx; const ry1 = x1 * sin + y0 * cos + ty;
245
+ const rx2 = x1 * cos - y1 * sin + tx; const ry2 = x1 * sin + y1 * cos + ty;
246
+ const rx3 = x0 * cos - y1 * sin + tx; const ry3 = x0 * sin + y1 * cos + ty;
247
+ const px0 = (bone.a * rx0 + bone.b * ry0 + bone.worldX) * scale;
248
+ const py0 = (bone.c * rx0 + bone.d * ry0 + bone.worldY) * scale;
249
+ const px1 = (bone.a * rx1 + bone.b * ry1 + bone.worldX) * scale;
250
+ const py1 = (bone.c * rx1 + bone.d * ry1 + bone.worldY) * scale;
251
+ const px2 = (bone.a * rx2 + bone.b * ry2 + bone.worldX) * scale;
252
+ const py2 = (bone.c * rx2 + bone.d * ry2 + bone.worldY) * scale;
253
+ const px3 = (bone.a * rx3 + bone.b * ry3 + bone.worldX) * scale;
254
+ const py3 = (bone.c * rx3 + bone.d * ry3 + bone.worldY) * scale;
255
+ const page = runtime.pages.get(region.page);
256
+ const pageWidth = page?.width ?? 1;
257
+ const pageHeight = page?.height ?? 1;
258
+ const packedWidth = region.rotate === 90 ? region.height : region.width;
259
+ const packedHeight = region.rotate === 90 ? region.width : region.height;
260
+ const u0 = region.x / pageWidth; const v0 = region.y / pageHeight;
261
+ const u1 = (region.x + packedWidth) / pageWidth; const v1 = (region.y + packedHeight) / pageHeight;
262
+ const color = multiplyColor(slotColor, attachment.color, runtime.vertexColorScratch);
263
+ if (region.rotate === 90) {
264
+ pushVertex(out, px0, py0, u1, v1, color); pushVertex(out, px1, py1, u1, v0, color);
265
+ pushVertex(out, px2, py2, u0, v0, color); pushVertex(out, px0, py0, u1, v1, color);
266
+ pushVertex(out, px2, py2, u0, v0, color); pushVertex(out, px3, py3, u0, v1, color);
267
+ } else {
268
+ pushVertex(out, px0, py0, u0, v1, color); pushVertex(out, px1, py1, u1, v1, color);
269
+ pushVertex(out, px2, py2, u1, v0, color); pushVertex(out, px0, py0, u0, v1, color);
270
+ pushVertex(out, px2, py2, u1, v0, color); pushVertex(out, px3, py3, u0, v0, color);
271
+ }
272
+ }
273
+
274
+ export function appendMeshVertices(
275
+ out: SpineFloatBuilder,
276
+ component: Spine2DComponent,
277
+ runtime: SpineVertexRuntime,
278
+ data: SpineData,
279
+ poses: Map<string, BonePose>,
280
+ bone: BonePose,
281
+ slotColor: [number, number, number, number] | undefined,
282
+ attachment: RegionAttachment,
283
+ region: AtlasRegion,
284
+ ): void {
285
+ const points = computeMeshPoints(data, poses, bone, attachment, component.scale, runtime.meshPointBuilder);
286
+ const triangles = attachment.triangles ?? [];
287
+ const color = multiplyColor(slotColor, attachment.color, runtime.vertexColorScratch);
288
+ for (let i = 0; i < triangles.length - 2; i += 3) {
289
+ const a = triangles[i] ?? -1;
290
+ const b = triangles[i + 1] ?? -1;
291
+ const c = triangles[i + 2] ?? -1;
292
+ if (!hasMeshPoint(points, a) || !hasMeshPoint(points, b) || !hasMeshPoint(points, c)) continue;
293
+ appendMeshVertex(out, points, region, runtime, attachment, a, color);
294
+ appendMeshVertex(out, points, region, runtime, attachment, b, color);
295
+ appendMeshVertex(out, points, region, runtime, attachment, c, color);
296
+ }
297
+ }
298
+
299
+ export function appendMeshWireframe(
300
+ out: SpineFloatBuilder,
301
+ component: Spine2DComponent,
302
+ runtime: SpineVertexRuntime,
303
+ data: SpineData,
304
+ poses: Map<string, BonePose>,
305
+ bone: BonePose,
306
+ attachment: RegionAttachment,
307
+ ): void {
308
+ const points = computeMeshPoints(data, poses, bone, attachment, component.scale, runtime.meshPointBuilder);
309
+ const triangles = attachment.triangles ?? [];
310
+ const seen = new Set<string>();
311
+ for (let i = 0; i < triangles.length - 2; i += 3) {
312
+ appendMeshDebugEdge(out, points, triangles[i] ?? -1, triangles[i + 1] ?? -1, seen, [0.3, 0.85, 1, 0.8]);
313
+ appendMeshDebugEdge(out, points, triangles[i + 1] ?? -1, triangles[i + 2] ?? -1, seen, [0.3, 0.85, 1, 0.8]);
314
+ appendMeshDebugEdge(out, points, triangles[i + 2] ?? -1, triangles[i] ?? -1, seen, [0.3, 0.85, 1, 0.8]);
315
+ }
316
+ }
317
+
318
+ export function appendRegionWireframe(
319
+ out: SpineFloatBuilder,
320
+ component: Spine2DComponent,
321
+ bone: BonePose,
322
+ attachment: RegionAttachment,
323
+ region: AtlasRegion,
324
+ ): void {
325
+ const w = attachment.width || region.originalWidth || region.width;
326
+ const h = attachment.height || region.originalHeight || region.height;
327
+ const sx = attachment.scaleX ?? 1;
328
+ const sy = attachment.scaleY ?? 1;
329
+ const rad = (attachment.rotation ?? 0) * Math.PI / 180;
330
+ const cos = Math.cos(rad);
331
+ const sin = Math.sin(rad);
332
+ const localCorners: Array<[number, number]> = [
333
+ [-w / 2, -h / 2],
334
+ [w / 2, -h / 2],
335
+ [w / 2, h / 2],
336
+ [-w / 2, h / 2],
337
+ ];
338
+ const points = localCorners.map(([x, y]) => {
339
+ const lx = x * sx;
340
+ const ly = y * sy;
341
+ const rx = lx * cos - ly * sin + (attachment.x ?? 0);
342
+ const ry = lx * sin + ly * cos + (attachment.y ?? 0);
343
+ return transformBonePoint(bone, rx, ry, component.scale);
344
+ });
345
+ const seen = new Set<string>();
346
+ appendDebugEdge(out, points, 0, 1, seen, [0.3, 0.85, 1, 0.8]);
347
+ appendDebugEdge(out, points, 1, 2, seen, [0.3, 0.85, 1, 0.8]);
348
+ appendDebugEdge(out, points, 2, 3, seen, [0.3, 0.85, 1, 0.8]);
349
+ appendDebugEdge(out, points, 3, 0, seen, [0.3, 0.85, 1, 0.8]);
350
+ }
351
+
352
+ export function appendBoneDebug(out: SpineFloatBuilder, data: SpineData, poses: Map<string, BonePose>, scale: number): void {
353
+ for (const boneData of data.bones) {
354
+ const bone = poses.get(boneData.name);
355
+ if (!bone) continue;
356
+ const start: [number, number] = [bone.worldX * scale, bone.worldY * scale];
357
+ const end = boneData.length > 0
358
+ ? [(bone.worldX + bone.a * boneData.length) * scale, (bone.worldY + bone.c * boneData.length) * scale] as [number, number]
359
+ : boneData.parent && poses.get(boneData.parent)
360
+ ? [poses.get(boneData.parent)!.worldX * scale, poses.get(boneData.parent)!.worldY * scale] as [number, number]
361
+ : start;
362
+ appendDebugLine(out, start, end, [1, 0.85, 0.25, 0.95]);
363
+ const joint = 3 / Math.max(0.001, scale);
364
+ appendDebugLine(out, transformBonePoint(bone, -joint, 0, scale), transformBonePoint(bone, joint, 0, scale), [1, 0.35, 0.3, 0.95]);
365
+ appendDebugLine(out, transformBonePoint(bone, 0, -joint, scale), transformBonePoint(bone, 0, joint, scale), [1, 0.35, 0.3, 0.95]);
366
+ }
367
+ }
368
+
369
+ function hashPose(hash: number, pose: BonePose): number {
370
+ hash = hashInt(hash, quantizeSignatureNumber(pose.a));
371
+ hash = hashInt(hash, quantizeSignatureNumber(pose.b));
372
+ hash = hashInt(hash, quantizeSignatureNumber(pose.c));
373
+ hash = hashInt(hash, quantizeSignatureNumber(pose.d));
374
+ hash = hashInt(hash, quantizeSignatureNumber(pose.worldX));
375
+ hash = hashInt(hash, quantizeSignatureNumber(pose.worldY));
376
+ return hash;
377
+ }
378
+
379
+ function hashAllPoses(hash: number, poses: Map<string, BonePose>): number {
380
+ for (const [name, pose] of poses) {
381
+ hash = hashString(hash, name);
382
+ hash = hashPose(hash, pose);
383
+ }
384
+ return hash;
385
+ }
386
+
387
+ function hashColor(hash: number, color: [number, number, number, number] | undefined): number {
388
+ if (!color) return hashInt(hash, 0);
389
+ hash = hashInt(hash, 1);
390
+ hash = hashInt(hash, quantizeSignatureNumber(color[0]));
391
+ hash = hashInt(hash, quantizeSignatureNumber(color[1]));
392
+ hash = hashInt(hash, quantizeSignatureNumber(color[2]));
393
+ return hashInt(hash, quantizeSignatureNumber(color[3]));
394
+ }
395
+
396
+ function hashClip(hash: number, clip: { endSlot?: string; polygon: Array<[number, number]> } | null): number {
397
+ if (!clip) return hashInt(hash, 0);
398
+ hash = hashInt(hash, 1);
399
+ hash = hashString(hash, clip.endSlot ?? '');
400
+ for (const point of clip.polygon) {
401
+ hash = hashInt(hash, quantizeSignatureNumber(point[0]));
402
+ hash = hashInt(hash, quantizeSignatureNumber(point[1]));
403
+ }
404
+ return hash;
405
+ }
406
+
407
+ function quantizeSignatureNumber(value: number): number {
408
+ return Math.round(value * 10000);
409
+ }
410
+
411
+ function hashString(hash: number, value: string): number {
412
+ for (let i = 0; i < value.length; i++) hash = hashInt(hash, value.charCodeAt(i));
413
+ return hash;
414
+ }
415
+
416
+ function appendBatch(
417
+ batches: SpineDrawBatch[],
418
+ pool: SpineDrawBatch[],
419
+ runtimeAllocationStats: { batchPoolMisses: number } | undefined,
420
+ blend: 'normal' | 'additive',
421
+ page: string,
422
+ firstVertex: number,
423
+ vertexCount: number,
424
+ ): void {
425
+ const last = batches[batches.length - 1];
426
+ if (last && last.blend === blend && last.page === page && last.firstVertex + last.vertexCount === firstVertex) {
427
+ last.vertexCount += vertexCount;
428
+ return;
429
+ }
430
+ const index = batches.length;
431
+ let batch = pool[index];
432
+ if (!batch) {
433
+ batch = { blend, page, firstVertex, vertexCount };
434
+ pool.push(batch);
435
+ if (runtimeAllocationStats) runtimeAllocationStats.batchPoolMisses++;
436
+ } else {
437
+ batch.blend = blend;
438
+ batch.page = page;
439
+ batch.firstVertex = firstVertex;
440
+ batch.vertexCount = vertexCount;
441
+ }
442
+ batches.push(batch);
443
+ }
444
+
445
+ function transformBonePoint(bone: BonePose, x: number, y: number, scale: number): [number, number] {
446
+ return [
447
+ (bone.a * x + bone.b * y + bone.worldX) * scale,
448
+ (bone.c * x + bone.d * y + bone.worldY) * scale,
449
+ ];
450
+ }
451
+
452
+ function computeMeshPoints(
453
+ data: SpineData,
454
+ poses: Map<string, BonePose>,
455
+ slotBone: BonePose,
456
+ attachment: RegionAttachment,
457
+ scale: number,
458
+ out: SpineFloatBuilder,
459
+ ): SpineFloatBuilder {
460
+ const vertices = attachment.vertices ?? [];
461
+ const vertexCount = Math.floor((attachment.uvs?.length ?? 0) / 2);
462
+ out.clear();
463
+ if (vertices.length === vertexCount * 2) {
464
+ for (let i = 0; i < vertices.length; i += 2) {
465
+ const x = vertices[i] ?? 0;
466
+ const y = vertices[i + 1] ?? 0;
467
+ out.push(
468
+ (slotBone.a * x + slotBone.b * y + slotBone.worldX) * scale,
469
+ (slotBone.c * x + slotBone.d * y + slotBone.worldY) * scale,
470
+ );
471
+ }
472
+ return out;
473
+ }
474
+
475
+ let offset = 0;
476
+ for (let vertex = 0; vertex < vertexCount && offset < vertices.length; vertex++) {
477
+ const boneCount = vertices[offset++] ?? 0;
478
+ let x = 0;
479
+ let y = 0;
480
+ for (let influence = 0; influence < boneCount; influence++) {
481
+ const boneIndex = vertices[offset++] ?? -1;
482
+ const vx = vertices[offset++] ?? 0;
483
+ const vy = vertices[offset++] ?? 0;
484
+ const weight = vertices[offset++] ?? 0;
485
+ const boneName = data.bones[boneIndex]?.name;
486
+ const bone = boneName ? poses.get(boneName) : null;
487
+ if (!bone) continue;
488
+ x += (bone.a * vx + bone.b * vy + bone.worldX) * weight;
489
+ y += (bone.c * vx + bone.d * vy + bone.worldY) * weight;
490
+ }
491
+ out.push(x * scale, y * scale);
492
+ }
493
+ return out;
494
+ }
495
+
496
+ function hasMeshPoint(points: SpineFloatBuilder, vertexIndex: number): boolean {
497
+ return vertexIndex >= 0 && vertexIndex * 2 + 1 < points.length;
498
+ }
499
+
500
+ function appendMeshVertex(
501
+ out: SpineFloatBuilder,
502
+ points: SpineFloatBuilder,
503
+ region: AtlasRegion,
504
+ runtime: SpineVertexRuntime,
505
+ attachment: RegionAttachment,
506
+ vertexIndex: number,
507
+ color: [number, number, number, number],
508
+ ): void {
509
+ const rawU = attachment.uvs?.[vertexIndex * 2] ?? 0;
510
+ const rawV = attachment.uvs?.[vertexIndex * 2 + 1] ?? 0;
511
+ const page = runtime.pages.get(region.page);
512
+ const textureWidth = page?.width ?? 1;
513
+ const textureHeight = page?.height ?? 1;
514
+ let u: number;
515
+ let v: number;
516
+ if (region.rotate === 90) {
517
+ const baseU = region.x / textureWidth - (region.originalHeight - region.offsetY - region.height) / textureWidth;
518
+ const baseV = region.y / textureHeight - (region.originalWidth - region.offsetX - region.width) / textureHeight;
519
+ u = baseU + rawV * region.originalHeight / textureWidth;
520
+ v = baseV + (1 - rawU) * region.originalWidth / textureHeight;
521
+ } else if (region.rotate === 180) {
522
+ const baseU = region.x / textureWidth - (region.originalWidth - region.offsetX - region.width) / textureWidth;
523
+ const baseV = region.y / textureHeight - region.offsetY / textureHeight;
524
+ u = baseU + (1 - rawU) * region.originalWidth / textureWidth;
525
+ v = baseV + (1 - rawV) * region.originalHeight / textureHeight;
526
+ } else if (region.rotate === 270) {
527
+ const baseU = region.x / textureWidth - region.offsetY / textureWidth;
528
+ const baseV = region.y / textureHeight - region.offsetX / textureHeight;
529
+ u = baseU + (1 - rawV) * region.originalHeight / textureWidth;
530
+ v = baseV + rawU * region.originalWidth / textureHeight;
531
+ } else {
532
+ const baseU = region.x / textureWidth - region.offsetX / textureWidth;
533
+ const baseV = region.y / textureHeight - (region.originalHeight - region.offsetY - region.height) / textureHeight;
534
+ u = baseU + rawU * region.originalWidth / textureWidth;
535
+ v = baseV + rawV * region.originalHeight / textureHeight;
536
+ }
537
+ const pointOffset = vertexIndex * 2;
538
+ pushVertex(out, points.get(pointOffset), points.get(pointOffset + 1), u, v, color);
539
+ }
540
+
541
+ function appendDebugEdge(
542
+ out: SpineFloatBuilder,
543
+ points: Array<[number, number]>,
544
+ a: number,
545
+ b: number,
546
+ seen: Set<string>,
547
+ color: [number, number, number, number],
548
+ ): void {
549
+ if (!points[a] || !points[b]) return;
550
+ const key = a < b ? `${a}:${b}` : `${b}:${a}`;
551
+ if (seen.has(key)) return;
552
+ seen.add(key);
553
+ appendDebugLine(out, points[a], points[b], color);
554
+ }
555
+
556
+ function appendMeshDebugEdge(
557
+ out: SpineFloatBuilder,
558
+ points: SpineFloatBuilder,
559
+ a: number,
560
+ b: number,
561
+ seen: Set<string>,
562
+ color: [number, number, number, number],
563
+ ): void {
564
+ if (!hasMeshPoint(points, a) || !hasMeshPoint(points, b)) return;
565
+ const key = a < b ? `${a}:${b}` : `${b}:${a}`;
566
+ if (seen.has(key)) return;
567
+ seen.add(key);
568
+ const aOffset = a * 2;
569
+ const bOffset = b * 2;
570
+ out.push(
571
+ points.get(aOffset),
572
+ points.get(aOffset + 1),
573
+ 0,
574
+ 0,
575
+ ...color,
576
+ points.get(bOffset),
577
+ points.get(bOffset + 1),
578
+ 0,
579
+ 0,
580
+ ...color,
581
+ );
582
+ }
583
+
584
+ function appendDebugLine(out: SpineFloatBuilder, a: [number, number], b: [number, number], color: [number, number, number, number]): void {
585
+ out.push(a[0], a[1], 0, 0, ...color, b[0], b[1], 0, 0, ...color);
586
+ }
587
+
588
+ function multiplyColor(
589
+ a: [number, number, number, number] | undefined,
590
+ b: [number, number, number, number] | undefined,
591
+ out: [number, number, number, number],
592
+ ): [number, number, number, number] {
593
+ out[0] = (a?.[0] ?? 1) * (b?.[0] ?? 1);
594
+ out[1] = (a?.[1] ?? 1) * (b?.[1] ?? 1);
595
+ out[2] = (a?.[2] ?? 1) * (b?.[2] ?? 1);
596
+ out[3] = (a?.[3] ?? 1) * (b?.[3] ?? 1);
597
+ return out;
598
+ }
599
+
600
+ function pushVertex(
601
+ out: SpineFloatBuilder,
602
+ x: number,
603
+ y: number,
604
+ u: number,
605
+ v: number,
606
+ color: [number, number, number, number],
607
+ ): void {
608
+ out.push8(x, y, u, v, color[0], color[1], color[2], color[3]);
609
+ }
610
+
611
+ function signedPolygonArea(polygon: Array<[number, number]>): number {
612
+ let area = 0;
613
+ for (let i = 0; i < polygon.length; i++) {
614
+ const a = requiredItemAt(polygon, i, 'clip polygon');
615
+ const b = requiredItemAt(polygon, (i + 1) % polygon.length, 'clip polygon');
616
+ area += a[0] * b[1] - b[0] * a[1];
617
+ }
618
+ return area * 0.5;
619
+ }
620
+
621
+ function clipVertexPolygon(vertices: SpineVertex[], clipPolygon: Array<[number, number]>): SpineVertex[] {
622
+ let output = vertices;
623
+ for (let i = 0; i < clipPolygon.length; i++) {
624
+ const a = requiredItemAt(clipPolygon, i, 'clip polygon');
625
+ const b = requiredItemAt(clipPolygon, (i + 1) % clipPolygon.length, 'clip polygon');
626
+ const input = output;
627
+ output = [];
628
+ if (input.length === 0) break;
629
+ let previous = requiredItemAt(input, input.length - 1, 'clip input polygon');
630
+ let previousInside = isInsideClipEdge(previous, a, b);
631
+ for (const current of input) {
632
+ const currentInside = isInsideClipEdge(current, a, b);
633
+ if (currentInside !== previousInside) output.push(intersectClipEdge(previous, current, a, b));
634
+ if (currentInside) output.push(current);
635
+ previous = current;
636
+ previousInside = currentInside;
637
+ }
638
+ }
639
+ return output;
640
+ }
641
+
642
+ function isInsideClipEdge(vertex: SpineVertex, a: [number, number], b: [number, number]): boolean {
643
+ return (b[0] - a[0]) * (vertex.y - a[1]) - (b[1] - a[1]) * (vertex.x - a[0]) >= -0.0001;
644
+ }
645
+
646
+ function intersectClipEdge(start: SpineVertex, end: SpineVertex, a: [number, number], b: [number, number]): SpineVertex {
647
+ const dx = end.x - start.x;
648
+ const dy = end.y - start.y;
649
+ const edgeX = b[0] - a[0];
650
+ const edgeY = b[1] - a[1];
651
+ const denominator = edgeX * dy - edgeY * dx;
652
+ const t = Math.abs(denominator) < 0.000001
653
+ ? 0
654
+ : (edgeY * (start.x - a[0]) - edgeX * (start.y - a[1])) / denominator;
655
+ const clamped = Math.max(0, Math.min(1, t));
656
+ return lerpVertex(start, end, clamped);
657
+ }
658
+
659
+ function lerpVertex(start: SpineVertex, end: SpineVertex, t: number): SpineVertex {
660
+ return {
661
+ x: start.x + (end.x - start.x) * t,
662
+ y: start.y + (end.y - start.y) * t,
663
+ u: start.u + (end.u - start.u) * t,
664
+ v: start.v + (end.v - start.v) * t,
665
+ color: [
666
+ start.color[0] + (end.color[0] - start.color[0]) * t,
667
+ start.color[1] + (end.color[1] - start.color[1]) * t,
668
+ start.color[2] + (end.color[2] - start.color[2]) * t,
669
+ start.color[3] + (end.color[3] - start.color[3]) * t,
670
+ ],
671
+ };
672
+ }
673
+
674
+ function readVertex(floats: SpineFloatBuilder, index: number): SpineVertex {
675
+ return {
676
+ x: floats.get(index),
677
+ y: floats.get(index + 1),
678
+ u: floats.get(index + 2),
679
+ v: floats.get(index + 3),
680
+ color: [floats.get(index + 4), floats.get(index + 5), floats.get(index + 6), floats.get(index + 7)],
681
+ };
682
+ }
683
+
684
+ function writeVertex(out: SpineFloatBuilder, vertex: SpineVertex): void {
685
+ out.push(vertex.x, vertex.y, vertex.u, vertex.v, ...vertex.color);
686
+ }
package/src/spine.ts ADDED
@@ -0,0 +1,7 @@
1
+ export { Spine2DComponent } from './spine/Spine2DComponent';
2
+ export type { Spine2DComponentOptions, Spine2DStatus } from './spine/Spine2DComponent';
3
+ export { Spine2DRenderSystem } from './spine/Spine2DRenderSystem';
4
+ export type { Spine2DRenderSystemOptions } from './spine/Spine2DRenderSystem';
5
+ export type { SpineAssetWorker } from './spine/SpineAssetWorkerContract';
6
+ export { createSpinePlugin } from './spine/SpinePlugin';
7
+ export type { SpinePluginOptions } from './spine/SpinePlugin';