@bitefoundry/retrieviewer 0.0.3 → 0.0.4

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 (254) hide show
  1. package/ASSET-PROVENANCE.md +6 -0
  2. package/ASSETS-LICENSE.md +2 -1
  3. package/ATTRIBUTION.md +6 -1
  4. package/COMFORT-ART.md +65 -0
  5. package/DESKTOP-PLATFORMS.md +6 -1
  6. package/PLUGIN.md +13 -10
  7. package/PREREQUISITES.md +95 -0
  8. package/PUPPY-MEMORY.md +102 -1
  9. package/README.ko.md +110 -0
  10. package/README.md +117 -59
  11. package/RELEASING.md +23 -12
  12. package/THIRD-PARTY-NOTICES.md +5 -3
  13. package/braille.mjs +35 -9
  14. package/examples/live.mjs +2 -2
  15. package/integrations/linux-overlay/overlay.py +2 -2
  16. package/integrations/macos-overlay/overlay.jxa +8 -6
  17. package/integrations/opencode/runtime.mjs +4 -4
  18. package/integrations/opencode/tui.tsx +1 -1
  19. package/integrations/windows-overlay/Overlay.cs +4 -4
  20. package/integrations/windows-overlay/protocol.mjs +11 -7
  21. package/package.json +34 -13
  22. package/puppy-comfort-sprites.mjs +25 -0
  23. package/puppy-companion-comfort-q5.bin.gz +0 -0
  24. package/puppy-companion-comfort.json +77 -0
  25. package/puppy-companion-life.mjs +49 -16
  26. package/puppy-companion-objects.mjs +12 -0
  27. package/puppy-frame-predictive.mjs +15 -9
  28. package/puppy-frame-store.mjs +2 -2
  29. package/puppy-paper-world.mjs +14 -0
  30. package/puppy-paper.mjs +65 -14
  31. package/retrieviewer-plugin.d.mts +1 -1
  32. package/retrieviewer-plugin.mjs +1 -1
  33. package/retrieviewer.d.mts +10 -4
  34. package/retrieviewer.mjs +20 -14
  35. package/locomotion-core.mjs +0 -21
  36. package/locomotion-puppy.animal +0 -0
  37. package/vendor/procedural-animals/package.json +0 -40
  38. package/vendor/procedural-animals/src/animal.js +0 -146
  39. package/vendor/procedural-animals/src/bake.js +0 -51
  40. package/vendor/procedural-animals/src/build.js +0 -81
  41. package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
  42. package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
  43. package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
  44. package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
  45. package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
  46. package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
  47. package/vendor/procedural-animals/src/core/build/seams.js +0 -183
  48. package/vendor/procedural-animals/src/core/build/warp.js +0 -112
  49. package/vendor/procedural-animals/src/core/build/weights.js +0 -393
  50. package/vendor/procedural-animals/src/core/math/vec.js +0 -81
  51. package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
  52. package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
  53. package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
  54. package/vendor/procedural-animals/src/core/motion/common.js +0 -158
  55. package/vendor/procedural-animals/src/core/motion/index.js +0 -22
  56. package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
  57. package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
  58. package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
  59. package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
  60. package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
  61. package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
  62. package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
  63. package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
  64. package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
  65. package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
  66. package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
  67. package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
  68. package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
  69. package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
  70. package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
  71. package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
  72. package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
  73. package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
  74. package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
  75. package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
  76. package/vendor/procedural-animals/src/index.d.ts +0 -98
  77. package/vendor/procedural-animals/src/index.js +0 -29
  78. package/vendor/procedural-animals/src/registry.js +0 -48
  79. package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
  80. package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
  81. package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
  82. package/vendor/procedural-animals/src/species/bear/index.js +0 -139
  83. package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
  84. package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
  85. package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
  86. package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
  87. package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
  88. package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
  89. package/vendor/procedural-animals/src/species/boar/index.js +0 -110
  90. package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
  91. package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
  92. package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
  93. package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
  94. package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
  95. package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
  96. package/vendor/procedural-animals/src/species/cat/index.js +0 -211
  97. package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
  98. package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
  99. package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
  100. package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
  101. package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
  102. package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
  103. package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
  104. package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
  105. package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
  106. package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
  107. package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
  108. package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
  109. package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
  110. package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
  111. package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
  112. package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
  113. package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
  114. package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
  115. package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
  116. package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
  117. package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
  118. package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
  119. package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
  120. package/vendor/procedural-animals/src/species/cow/index.js +0 -118
  121. package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
  122. package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
  123. package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
  124. package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
  125. package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
  126. package/vendor/procedural-animals/src/species/crow/index.js +0 -70
  127. package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
  128. package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
  129. package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
  130. package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
  131. package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
  132. package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
  133. package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
  134. package/vendor/procedural-animals/src/species/deer/index.js +0 -106
  135. package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
  136. package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
  137. package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
  138. package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
  139. package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
  140. package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
  141. package/vendor/procedural-animals/src/species/dog/index.js +0 -144
  142. package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
  143. package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
  144. package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
  145. package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
  146. package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
  147. package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
  148. package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
  149. package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
  150. package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
  151. package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
  152. package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
  153. package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
  154. package/vendor/procedural-animals/src/species/fish/index.js +0 -88
  155. package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
  156. package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
  157. package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
  158. package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
  159. package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
  160. package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
  161. package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
  162. package/vendor/procedural-animals/src/species/fox/index.js +0 -120
  163. package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
  164. package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
  165. package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
  166. package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
  167. package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
  168. package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
  169. package/vendor/procedural-animals/src/species/frog/index.js +0 -97
  170. package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
  171. package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
  172. package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
  173. package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
  174. package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
  175. package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
  176. package/vendor/procedural-animals/src/species/goat/index.js +0 -149
  177. package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
  178. package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
  179. package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
  180. package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
  181. package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
  182. package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
  183. package/vendor/procedural-animals/src/species/horse/index.js +0 -80
  184. package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
  185. package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
  186. package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
  187. package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
  188. package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
  189. package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
  190. package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
  191. package/vendor/procedural-animals/src/species/lion/index.js +0 -111
  192. package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
  193. package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
  194. package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
  195. package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
  196. package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
  197. package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
  198. package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
  199. package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
  200. package/vendor/procedural-animals/src/species/pig/index.js +0 -161
  201. package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
  202. package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
  203. package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
  204. package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
  205. package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
  206. package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
  207. package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
  208. package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
  209. package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
  210. package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
  211. package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
  212. package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
  213. package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
  214. package/vendor/procedural-animals/src/species/rat/index.js +0 -111
  215. package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
  216. package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
  217. package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
  218. package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
  219. package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
  220. package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
  221. package/vendor/procedural-animals/src/species/shark/index.js +0 -104
  222. package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
  223. package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
  224. package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
  225. package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
  226. package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
  227. package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
  228. package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
  229. package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
  230. package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
  231. package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
  232. package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
  233. package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
  234. package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
  235. package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
  236. package/vendor/procedural-animals/src/species/snake/index.js +0 -73
  237. package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
  238. package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
  239. package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
  240. package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
  241. package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
  242. package/vendor/procedural-animals/src/species/spider/index.js +0 -78
  243. package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
  244. package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
  245. package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
  246. package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
  247. package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
  248. package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
  249. package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
  250. package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
  251. package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
  252. package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
  253. package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
  254. package/vendor/procedural-animals/src/worker.js +0 -29
@@ -1,189 +0,0 @@
1
- // Flight-feather cards: real feather geometry (primaries, secondaries, rectrices and their coverts)
2
- // appended to the base surface. Each card is a thin two-sided vane (top and bottom layer, rachis
3
- // down the middle, asymmetric outer / inner vane, rounded or emarginated tip, curved rachis) rigidly
4
- // skinned to its own feather bone, so the engine can fan, fold, twist and splay every feather while
5
- // the base draw call renders it (one draw, shadows and the crowd tier included). Material id 10
6
- // (vane) is shaded in core/render/coatMaterial.js from surf = [gloss, iridescence, across, along]:
7
- // across -1 (outer vane edge) .. 0 (rachis) .. 1 (inner vane edge), along 0 (root) .. 1 (tip).
8
- // colour(kind, i, side, t, c, layer) -> { rgb, gloss, irid, bar? }: bar { rgb, period (m) } draws bars
9
- // across the vane in the shader (patternColor = [rgb, -bar count]; opt-in, e.g. barred poultry).
10
- //
11
- // Species usage (surfaces hook, see core/build/pipeline.js):
12
- // surfaces: (ctx) => featherCards({ ...ctx, wing: motion.wing, feathers: motion.feathers,
13
- // tail: motion.tail, colour: (kind, i, side, t, c) => ({ rgb, gloss, irid }) })
14
- import { featherJoints, DEG } from '../rig/bird.js';
15
- import { MAT } from './coatKit.js';
16
-
17
- const V = (x, y, z) => [x, y, z];
18
- const addS = (a, b, k) => [a[0] + b[0] * k, a[1] + b[1] * k, a[2] + b[2] * k];
19
- const cross = (a, b) => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
20
- const norm = (a) => { const l = Math.hypot(a[0], a[1], a[2]) || 1; return [a[0] / l, a[1] / l, a[2] / l]; };
21
- const mirror = (p) => [-p[0], p[1], p[2]];
22
-
23
- // vane half-widths at t (0 root .. 1 tip): [outer, inner] (also used by the bird engine's ground checks)
24
- // (f.base0: the vane's width at the root as a fraction of its full width, default 0.3)
25
- export function vaneWidth(f, t, w) {
26
- const b0 = f.base0 ?? 0.3;
27
- const base = b0 + (1 - b0) * smooth(0.0, 0.16, t);
28
- const tr = f.tipRound;
29
- let tip = 1;
30
- if (t > 1 - tr) { const x = (t - (1 - tr)) / tr; tip = Math.sqrt(Math.max(0, 1 - x * x)); }
31
- let wo = w * f.outer * base * tip, wi = w * (1 - f.outer) * base * tip;
32
- if (f.emarg > 0) {
33
- // emarginated primaries: both vanes step in beyond the notch, leaving a narrow "finger"
34
- const k = smooth(0.5, 0.64, t) * f.emarg;
35
- wi *= 1 - 0.62 * k; wo *= 1 - 0.3 * k;
36
- }
37
- return [wo, Math.max(wi, 0.0006)];
38
- }
39
- function smooth(a, b, x) { const t = Math.min(1, Math.max(0, (x - a) / (b - a))); return t * t * (3 - 2 * t); }
40
-
41
- /**
42
- * @param ctx { rig, params, Q, wing, feathers, tail, colour, thickness? }
43
- * @returns surfaces block { nV, pos, nrm, index, skinIndex, skinWeight, comb, tint, pattern, mark, furLen, patternColor, surf }
44
- */
45
- export function featherCards(ctx) {
46
- const { rig, Q, wing, feathers, tail } = ctx;
47
- const colour = ctx.colour || (() => ({ rgb: [0.02, 0.02, 0.02], gloss: 0.5, irid: 0 }));
48
- // the bind layout (the rig built the joints from the same call)
49
- const Jl = {};
50
- for (const k of ['shoulderL', 'tailBase', 'tailTip']) Jl[k] = rig.J[k];
51
- const lay = featherJoints(Jl, wing, feathers, tail);
52
- const res = Q?.res ?? 1;
53
- const nA = res <= 1.35 ? 9 : res <= 2.1 ? 6 : res <= 3.1 ? 4 : 3;
54
- const th = ctx.thickness ?? 0.0005;
55
- const coverts = res < 4 || ctx.crowdCoverts;
56
- const P = [], N = [], C = [], T = [], S = [], SI = [], I = [], X = [];
57
- const PCL = []; // vane bars: [vertex, rgb, -count]
58
- const cov = lay.F.coverts;
59
-
60
- const card = (bone, side, fr, f, opts) => {
61
- const b = rig.BONE[bone];
62
- if (!b) throw new Error('featherCards: missing bone ' + bone);
63
- const s = side;
64
- const m = (p) => (s > 0 ? p : mirror(p));
65
- const L = f.len * (opts.lenK || 1), W = f.width * (opts.widthK || 1);
66
- const A = m(V(fr.axis.x, fr.axis.y, fr.axis.z)), Nn = m(V(fr.normal.x, fr.normal.y, fr.normal.z));
67
- // inner vane side (+across): s * (N x A)
68
- const Tv = norm(cross(Nn, A)).map((x) => x * s);
69
- const root0 = m(V(fr.root.x, fr.root.y, fr.root.z));
70
- const root = addS(addS(root0, Nn, opts.lift || 0), A, opts.shift || 0);
71
- const fo = opts.shape ? { ...f, ...opts.shape } : f;
72
- // vane arch: the edges sit this fraction of the half-width below the rachis (feather spec `arch`,
73
- // default 0.12; a flatter vane lets overlapping neighbours stack on smaller lift steps)
74
- const arch = fo.arch ?? 0.12;
75
- const v0 = P.length / 3;
76
- const ts = [];
77
- for (let j = 0; j <= nA; j++) { const u = j / nA; ts.push(0.5 - 0.5 * Math.cos(Math.PI * u)); }
78
- const pt = (t, c) => {
79
- const [wo, wi] = vaneWidth(fo, t, W);
80
- const w = c < 0 ? wo : wi;
81
- if (fo.arc) {
82
- // rachis bent along a circular arc of total angle `arc` (rad) toward the inner vane, length
83
- // kept (long display feathers: a rooster's sickles); the vane width turns with the rachis
84
- const a = fo.arc * t, R = L / fo.arc, ca = Math.cos(a), sa = Math.sin(a);
85
- let p = addS(root, A, R * sa);
86
- p = addS(p, Tv, R * (1 - ca));
87
- p = addS(p, A, -sa * c * w);
88
- p = addS(p, Tv, ca * c * w);
89
- return addS(p, Nn, -fo.droop * L * t * t - Math.abs(c) * w * arch);
90
- }
91
- // curved rachis (toward the inner vane, drooping), vanes slightly convex (edges lower)
92
- const along = t * L, curve = fo.curve * L * t * t, droop = fo.droop * L * t * t;
93
- let p = addS(root, A, along);
94
- p = addS(p, Tv, curve + c * w);
95
- p = addS(p, Nn, -droop - Math.abs(c) * w * arch);
96
- return p;
97
- };
98
- const cols = [-1, 0, 1];
99
- for (const layer of [1, -1]) {
100
- for (let j = 0; j <= nA; j++) {
101
- const t = ts[j];
102
- for (const c of cols) {
103
- const p = addS(pt(t, c), Nn, layer * th * 0.5 * (1 - 0.6 * t));
104
- // surface tangents for the normal
105
- const e = 1e-3;
106
- const pa = pt(Math.min(1, t + e), c), pb = pt(Math.max(0, t - e), c);
107
- const pc = pt(t, Math.min(1, c + 0.05)), pd = pt(t, Math.max(-1, c - 0.05));
108
- const dt = [pa[0] - pb[0], pa[1] - pb[1], pa[2] - pb[2]], dc = [pc[0] - pd[0], pc[1] - pd[1], pc[2] - pd[2]];
109
- let n = norm(cross(dt, dc));
110
- const sgn = (n[0] * Nn[0] + n[1] * Nn[1] + n[2] * Nn[2]) < 0 ? -1 : 1;
111
- n = n.map((x) => x * sgn * layer);
112
- if (!Number.isFinite(n[0])) n = Nn.map((x) => x * layer);
113
- P.push(...p); N.push(...n);
114
- C.push(...norm(dt));
115
- const col = colour(opts.kind, f.i, s, t, c, layer);
116
- T.push(col.rgb[0], col.rgb[1], col.rgb[2], MAT.VANE);
117
- // opt-in bars across the vane (colour() returns bar: { rgb, period (m) }): shader-drawn
118
- if (col.bar) PCL.push([P.length / 3 - 1, col.bar.rgb, -L / col.bar.period]);
119
- S.push(col.gloss ?? 0.5, col.irid ?? 0, c, t);
120
- const wv = vaneWidth(fo, t, W);
121
- X.push(c * (c < 0 ? wv[0] : wv[1]) * s);
122
- SI.push(b.index, 0, 0, 0);
123
- }
124
- }
125
- const base = v0 + (layer > 0 ? 0 : (nA + 1) * 3);
126
- for (let j = 0; j < nA; j++) {
127
- for (let k = 0; k < 2; k++) {
128
- const a = base + j * 3 + k, bq = a + 1, c2 = a + 3, d = a + 4;
129
- // top layer faces +N; the bottom layer is wound the other way
130
- if ((layer > 0) === (s > 0)) I.push(a, c2, bq, bq, c2, d);
131
- else I.push(a, bq, c2, bq, d, c2);
132
- }
133
- }
134
- }
135
- // winding sanity: flip this card's triangles if their geometric normal disagrees with the layer normal
136
- fixWinding(P, N, I, v0);
137
- };
138
-
139
- // per-feather covert overrides (spec field `cov`: { lift, shift, lenK, widthK, shape }, merged over
140
- // the defaults below; opt-in: a species can restack its coverts, e.g. reverse their overlap order;
141
- // `cov: { skip: true }` drops the covert card, e.g. where the species sculpts the coverts as skin)
142
- const covOpts = (f, o) => (f.cov ? { ...o, ...f.cov, shape: { ...o.shape, ...(f.cov.shape || {}) } } : o);
143
- const wEH = lay.frames;
144
- for (const side of [1, -1]) {
145
- const S2 = side > 0 ? 'L' : 'R';
146
- for (const fr of wEH.pri) {
147
- const f = fr.f;
148
- card(`pri${f.i + 1}${S2}`, side, fr, f, { kind: 'primary' });
149
- if (coverts && !f.cov?.skip) card(`pri${f.i + 1}${S2}`, side, fr, f, covOpts(f, { kind: 'primaryCovert', lenK: cov.primary * (1 - 0.25 * f.i / Math.max(1, f.n - 1)), widthK: 1.05, lift: 0.0022, shift: -0.004, shape: { emarg: 0, tipRound: 0.6, outer: 0.45, curve: 0.02 } }));
150
- }
151
- for (const fr of wEH.sec) {
152
- const f = fr.f;
153
- card(`sec${f.i + 1}${S2}`, side, fr, f, { kind: 'secondary' });
154
- if (coverts && !f.cov?.skip) card(`sec${f.i + 1}${S2}`, side, fr, f, covOpts(f, { kind: 'secondaryCovert', lenK: cov.secondary, widthK: 1.15, lift: 0.0028, shift: -0.006, shape: { tipRound: 0.65, outer: 0.45, curve: 0.02 } }));
155
- }
156
- for (const fr of wEH.rec) {
157
- const f = fr.f;
158
- card(`rec${f.i + 1}${S2}`, side, fr, f, { kind: 'rectrix' });
159
- if (coverts && f.i < 4 && !f.cov?.skip) card(`rec${f.i + 1}${S2}`, side, fr, f, covOpts(f, { kind: 'tailCovert', lenK: cov.tail * (1 - 0.1 * f.i), widthK: 1.2, lift: 0.0025, shift: -0.012, shape: { tipRound: 0.7, outer: 0.5 } }));
160
- }
161
- }
162
- const nV = P.length / 3;
163
- const out = {
164
- nV,
165
- pos: Float32Array.from(P), nrm: Float32Array.from(N), index: Uint32Array.from(I),
166
- skinIndex: Uint16Array.from(SI), skinWeight: new Float32Array(nV * 4),
167
- comb: Float32Array.from(C), tint: Float32Array.from(T), surf: Float32Array.from(S),
168
- pattern: Float32Array.from(X), mark: new Float32Array(nV).fill(1), furLen: new Float32Array(nV),
169
- patternColor: new Float32Array(nV * 4),
170
- };
171
- for (const [v, rgb, n] of PCL) out.patternColor.set([rgb[0], rgb[1], rgb[2], n], v * 4);
172
- for (let v = 0; v < nV; v++) out.skinWeight[v * 4] = 1;
173
- return out;
174
- }
175
-
176
- function fixWinding(P, N, I, v0) {
177
- // triangles are appended per card; check the first triangle referencing v0's range
178
- for (let t = 0; t < I.length; t += 3) {
179
- const a = I[t], b = I[t + 1], c = I[t + 2];
180
- if (a < v0) continue;
181
- const e1 = [P[b * 3] - P[a * 3], P[b * 3 + 1] - P[a * 3 + 1], P[b * 3 + 2] - P[a * 3 + 2]];
182
- const e2 = [P[c * 3] - P[a * 3], P[c * 3 + 1] - P[a * 3 + 1], P[c * 3 + 2] - P[a * 3 + 2]];
183
- const g = cross(e1, e2);
184
- const d = g[0] * N[a * 3] + g[1] * N[a * 3 + 1] + g[2] * N[a * 3 + 2];
185
- if (d < 0) { I[t + 1] = c; I[t + 2] = b; }
186
- }
187
- }
188
-
189
- export { DEG };
@@ -1,85 +0,0 @@
1
- // Knife-thin fin edges below the mesh cell size.
2
- //
3
- // A fin slab (SDFModel.fin) meshes with a rim no thinner than ~2 cells (thinner slabs alias into
4
- // holes), so at 1 cm cells a shark's fins end in 2 cm rounded, rubbery edges. A fin primitive tagged
5
- // `sharpen: { edge, band, rim }` has its meshed surface squeezed toward its mid-plane near its free
6
- // outline: every vertex whose nearest fin slab is that primitive has its distance from the plane
7
- // scaled by `edge` (e.g. 0.15) at the outline, easing back to 1 at `band` mesh cells (of the vertex's
8
- // region, so every quality tier) inside it; the rounded rim beyond the outline is drawn in toward it
9
- // by `rim` (0.4: to 0.4 of its width), so the squeezed edge runs straight instead of following the
10
- // cells' sampling of the round cap. Where the fin grows out of the body (the field of the non-fin
11
- // primitives within ~1.5-4 cells of the vertex) nothing moves, so the root fillet keeps its shape.
12
- // Same vertex count; the field's analytic normals are carried through the squeeze (inverse transpose
13
- // of its Jacobian), so the shading stays as smooth as the field's. Opt-in: no tagged primitive, no
14
- // change.
15
- import { SDFModel, T_FIN, polySD } from '../sdf/sdf.js';
16
-
17
- const smooth = (a, b, x) => { const t = Math.min(1, Math.max(0, (x - a) / (b - a))); return t * t * (3 - 2 * t); };
18
- const dsmooth = (a, b, x) => { if (x <= a || x >= b) return 0; const t = (x - a) / (b - a); return (6 * t * (1 - t)) / (b - a); };
19
-
20
- /** @returns the number of vertices moved */
21
- export function sharpenFinEdges({ pos, nrm, lists, nV, regionOf }, hOfRegion) {
22
- let n = 0;
23
- for (let v = 0; v < nV; v++) {
24
- const L = lists[v];
25
- if (!L) continue;
26
- const h = hOfRegion[regionOf[v]];
27
- let fin = null, best = Infinity;
28
- const x = pos[v * 3], y = pos[v * 3 + 1], z = pos[v * 3 + 2];
29
- for (const pr of L) {
30
- if (pr.type !== T_FIN || !pr.sharpen || pr.carve) continue;
31
- const d = Math.abs(SDFModel.dist(pr, x, y, z));
32
- if (d < best) { best = d; fin = pr; }
33
- }
34
- if (!fin) continue;
35
- const P = fin.P, S = fin.sharpen, e = S.edge, B = S.band * h, c = S.rim ?? 1;
36
- const dx = x - P[0], dy = y - P[1], dz = z - P[2];
37
- const pu = dx * P[3] + dy * P[4] + dz * P[5], pv = dx * P[6] + dy * P[7] + dz * P[8];
38
- const pn = dx * P[9] + dy * P[10] + dz * P[11];
39
- // depth inside the outline (< 0 on the rounded rim beyond it)
40
- const din = -polySD(P, pu, pv);
41
- if (din >= B) continue;
42
- // the body around the root: the field of every non-fin primitive near the vertex
43
- const rest = L.filter((pr) => pr.type !== T_FIN && !pr.carve);
44
- const dBody = rest.length ? SDFModel.evalList(rest, x, y, z) : 1e9;
45
- const wr = smooth(1.5 * h, 4 * h, dBody);
46
- if (wr < 1e-3) continue;
47
- // squeeze factor s(din) = 1 - wr (1 - k(din)), k = e + (1 - e) smooth(0, B, din)
48
- const s = 1 - wr * (1 - e) * (1 - smooth(0, B, din));
49
- const ds = wr * (1 - e) * dsmooth(0, B, din);
50
- // in-plane gradient of din (unit, pointing into the fin)
51
- const eps = 0.25 * h;
52
- let gu = -(polySD(P, pu + eps, pv) - polySD(P, pu - eps, pv)) / (2 * eps);
53
- let gv = -(polySD(P, pu, pv + eps) - polySD(P, pu, pv - eps)) / (2 * eps);
54
- const gl = Math.hypot(gu, gv) || 1;
55
- gu /= gl; gv /= gl;
56
- const gx = P[3] * gu + P[6] * gv, gy = P[4] * gu + P[7] * gv, gz = P[5] * gu + P[8] * gv;
57
- // the rim beyond the outline drawn in toward it (to c of its width)
58
- const pull = din < 0 ? (1 - c) * -din * wr : 0;
59
- const off = pn * (s - 1);
60
- pos[v * 3] += P[9] * off + gx * pull; pos[v * 3 + 1] += P[10] * off + gy * pull; pos[v * 3 + 2] += P[11] * off + gz * pull;
61
- // normal: J = I + nf a^T (a = (s - 1) nf + pn ds g) -> J^-T n0 = n0 - a (nf . n0) / s; the rim pull
62
- // scales along g by c' = 1 - (1 - c) wr -> divide the g component by c'
63
- let nx = nrm[v * 3], ny = nrm[v * 3 + 1], nz = nrm[v * 3 + 2];
64
- const fn = (nx * P[9] + ny * P[10] + nz * P[11]) / s;
65
- const ax = (s - 1) * P[9] + pn * ds * gx, ay = (s - 1) * P[10] + pn * ds * gy, az = (s - 1) * P[11] + pn * ds * gz;
66
- nx -= ax * fn; ny -= ay * fn; nz -= az * fn;
67
- if (din < 0 && c < 1) {
68
- const cc = 1 - (1 - c) * wr, gn = (nx * gx + ny * gy + nz * gz) * (1 / cc - 1);
69
- nx += gx * gn; ny += gy * gn; nz += gz * gn;
70
- }
71
- // at the knife edge itself the faces above and below meet: a vertex there (on the field's rounded
72
- // cap, close to the mid-plane) takes the edge's in-plane normal; otherwise vertices a hair above and
73
- // below the plane along the rim would alternate up / down normals (stripes across the edge)
74
- const q = Math.abs(pn) / Math.max(1e-9, P[12]);
75
- const fq = smooth(0.15, 0.7, q);
76
- if (fq < 1) {
77
- const nfc = (nx * P[9] + ny * P[10] + nz * P[11]) * (1 - fq);
78
- nx -= P[9] * nfc; ny -= P[10] * nfc; nz -= P[11] * nfc;
79
- }
80
- const l = Math.hypot(nx, ny, nz) || 1;
81
- nrm[v * 3] = nx / l; nrm[v * 3 + 1] = ny / l; nrm[v * 3 + 2] = nz / l;
82
- n++;
83
- }
84
- return n;
85
- }
@@ -1,115 +0,0 @@
1
- // Fur-length slope limit (shorten only), applied by the pipeline to every coat.
2
- //
3
- // The coat shells are offset copies of the skin at hair height x (0..1) x furLen, so where the hair
4
- // length jumps from one vertex to the next the shells stand up as a wall: a round pad with a hard
5
- // rim (a cheek switched from 5 to 11 mm across a plane), an eye sunk in a ring of long fur, a strand
6
- // pattern smeared into a smooth plate over the steep triangles. Real hair changes length gradually
7
- // and lies over the shorter hair around it, so the coat surface has no cliffs.
8
- //
9
- // The limit: hair may grow no faster than `slope` metres of hair per metre of skin above the hair
10
- // around it, U(v) = min(L(v), min_u U(u) + s(v) |p_u - p_v|) over the furred, hairy vertices of the
11
- // same surface (a Dijkstra sweep from the shortest hair outward: exact, one pass). Long hair may rise
12
- // proportionally faster, s(v) = slope x max(1, L(v) / free): every boundary then bevels over at most
13
- // ~free / slope of skin whatever the hair length, so manes, ruffs, forelocks and fleeces keep
14
- // standing off (their edge is beveled, not flattened) while a face loses its walls.
15
- //
16
- // Species control (optional):
17
- // species.render.furSlope slope for hair up to `furSlopeFree` long (default 1); false / 0: off
18
- // species.render.furSlopeFree hair length (m) above which the allowed slope grows (default 0.025)
19
- // coat().furSlope per-vertex slope (Float32Array) replacing the default at that vertex;
20
- // Infinity (or <= 0) leaves that vertex's hair as painted (a crest meant
21
- // to stand up as a wall)
22
- // Bare vertices (no hair, or a material without shells) neither limit nor get limited: fur may meet a
23
- // lid margin, the nose leather or a hoof at full length.
24
-
25
- export const FUR_SLOPE_DEFAULTS = { slope: 1.0, free: 0.025 };
26
-
27
- const HAIRY = (m) => m === 0 || m === 4 || m === 8 || m === 9; // materials that grow shells (coatMaterial.js hairy())
28
-
29
- /**
30
- * Shortens furLen in place so that no hair rises faster than the slope above its neighbours.
31
- * @param {Float32Array} furLen per-vertex hair length (m), modified in place
32
- * @param {Float32Array} pos per-vertex positions (reference space)
33
- * @param {Uint32Array} index triangle indices
34
- * @param {number} nV vertex count (vertices >= nV are ignored)
35
- * @param {Float32Array} tint per-vertex rgba, a = material id
36
- * @param {object} o { slope, free, perVertex }
37
- * @returns {{ shortened: number, maxCut: number }} vertices shortened by more than 0.1 mm, the largest cut (m)
38
- */
39
- export function limitFurSlope(furLen, pos, index, nV, tint, { slope = FUR_SLOPE_DEFAULTS.slope, free = FUR_SLOPE_DEFAULTS.free, perVertex = null } = {}) {
40
- const res = { shortened: 0, maxCut: 0 };
41
- if (!furLen || !(slope > 0) || !(free > 0)) return res;
42
- const L0 = Float32Array.from(furLen.subarray(0, nV));
43
- const active = new Uint8Array(nV);
44
- let any = false;
45
- for (let v = 0; v < nV; v++) {
46
- if (L0[v] > 0 && HAIRY(Math.round(tint[v * 4 + 3]))) { active[v] = 1; any = true; }
47
- }
48
- if (!any) return res;
49
- // the allowed slope of each vertex's hair (0 = unlimited)
50
- const sOf = new Float32Array(nV);
51
- for (let v = 0; v < nV; v++) {
52
- if (!active[v]) continue;
53
- let s = perVertex ? perVertex[v] : slope;
54
- if (perVertex && !(s > 0)) s = Infinity; // a species' explicit "leave as painted"
55
- sOf[v] = Number.isFinite(s) ? s * Math.max(1, L0[v] / free) : 0;
56
- }
57
- // adjacency (CSR) over the active vertices
58
- const deg = new Uint32Array(nV + 1);
59
- for (let i = 0; i < index.length; i += 3) {
60
- for (let e = 0; e < 3; e++) {
61
- const u = index[i + e], v = index[i + ((e + 1) % 3)];
62
- if (u < nV && v < nV && active[u] && active[v]) { deg[u + 1]++; deg[v + 1]++; }
63
- }
64
- }
65
- for (let v = 0; v < nV; v++) deg[v + 1] += deg[v];
66
- const adj = new Uint32Array(deg[nV]), fill = deg.slice(0, nV);
67
- for (let i = 0; i < index.length; i += 3) {
68
- for (let e = 0; e < 3; e++) {
69
- const u = index[i + e], v = index[i + ((e + 1) % 3)];
70
- if (u < nV && v < nV && active[u] && active[v]) { adj[fill[u]++] = v; adj[fill[v]++] = u; }
71
- }
72
- }
73
- // Dijkstra: settle vertices in increasing (limited) length; a settled vertex bounds its neighbours
74
- const U = furLen;
75
- let hk = new Float64Array(4096), hv = new Int32Array(4096), n = 0;
76
- const push = (k, v) => {
77
- if (n === hk.length) { const k2 = new Float64Array(n * 2); k2.set(hk); hk = k2; const v2 = new Int32Array(n * 2); v2.set(hv); hv = v2; }
78
- let i = n++;
79
- while (i > 0) { const p = (i - 1) >> 1; if (hk[p] <= k) break; hk[i] = hk[p]; hv[i] = hv[p]; i = p; }
80
- hk[i] = k; hv[i] = v;
81
- };
82
- const pop = () => {
83
- const top = hv[0], k = hk[--n], v = hv[n];
84
- let i = 0;
85
- for (;;) {
86
- const l = 2 * i + 1;
87
- if (l >= n) break;
88
- const r = l + 1, m = r < n && hk[r] < hk[l] ? r : l;
89
- if (hk[m] >= k) break;
90
- hk[i] = hk[m]; hv[i] = hv[m]; i = m;
91
- }
92
- hk[i] = k; hv[i] = v;
93
- return top;
94
- };
95
- const done = new Uint8Array(nV);
96
- for (let v = 0; v < nV; v++) if (active[v]) push(U[v], v);
97
- while (n) {
98
- const v = pop();
99
- if (done[v]) continue;
100
- done[v] = 1;
101
- const Uv = U[v], px = pos[v * 3], py = pos[v * 3 + 1], pz = pos[v * 3 + 2];
102
- for (let k = deg[v]; k < deg[v + 1]; k++) {
103
- const u = adj[k];
104
- if (done[u] || sOf[u] === 0) continue;
105
- const cand = Uv + sOf[u] * Math.hypot(pos[u * 3] - px, pos[u * 3 + 1] - py, pos[u * 3 + 2] - pz);
106
- if (cand < U[u]) { U[u] = cand; push(cand, u); }
107
- }
108
- }
109
- for (let v = 0; v < nV; v++) {
110
- const cut = L0[v] - U[v];
111
- if (cut > 0.0001) res.shortened++;
112
- if (cut > res.maxCut) res.maxCut = cut;
113
- }
114
- return res;
115
- }
@@ -1,67 +0,0 @@
1
- // Meshing stage: turns a species' SDF sculpt into surface pieces ("regions").
2
- //
3
- // A species describes its regions as jobs (each job can run in its own worker):
4
- // { name, part, bmin, bmax, h, F?, clip?(x,y,z), patches?: [{ c, R, B, h }], rigidBone? }
5
- // part: which primitives to mesh (primitives carry part: 'body' | 'jaw' | ...)
6
- // h: cell size in metres (quality tiers multiply it)
7
- // clip: keep only cells whose centre passes (used for overlapping regions that cross-fade)
8
- // patches: balls re-meshed at a finer cell size (eyelid margins); the region itself is clipped
9
- // to exclude the inner ball and the two cross-fade in a thin shell
10
- // rigidBone: the whole region follows one bone (a separately meshed jaw)
11
- import { meshSDF } from '../sdf/mesher.js';
12
-
13
- export function meshRegion(model, R) {
14
- const prims = model.forPart(R.part || 'body');
15
- if (!prims.length) throw new Error(`region ${R.name}: no primitives in part ${R.part}`);
16
- const d2 = (x, y, z, c) => (x - c[0]) * (x - c[0]) + (y - c[1]) * (y - c[1]) + (z - c[2]) * (z - c[2]);
17
- const patches = R.patches || [];
18
- const baseClip = R.clip || null;
19
- // The region stops one of its own cells inside the patch's inner radius: its cut is as ragged as its
20
- // cells, and a cut that pokes past the middle of the cross-fade band (a cell wider than the band B) left
21
- // a slit there that neither surface covered; one cell further in, the cut lies where the patch shows
22
- // alone and the region's fade is ~0 (drawn nowhere).
23
- const clip = patches.length
24
- ? (x, y, z) => (!baseClip || baseClip(x, y, z)) && patches.every((p) => d2(x, y, z, p.c) > Math.max(0, p.R - p.B - R.h) ** 2)
25
- : baseClip;
26
- const parts = [meshSDF(prims, R.bmin, R.bmax, R.h, R.F || 6, null, clip)];
27
- for (const p of patches) {
28
- const rOut = p.R + p.B, pad = rOut + 3 * p.h;
29
- parts.push(meshSDF(prims, [p.c[0] - pad, p.c[1] - pad, p.c[2] - pad], [p.c[0] + pad, p.c[1] + pad, p.c[2] + pad], p.h, 4, null, (x, y, z) => d2(x, y, z, p.c) < rOut * rOut && (!baseClip || baseClip(x, y, z))));
30
- }
31
- const m = parts.length > 1 ? mergeMeshes(parts) : { ...parts[0], patch: null };
32
- return serialiseLists({ name: R.name, ...m });
33
- }
34
-
35
- export function mergeMeshes(meshes) {
36
- let n = 0, ni = 0;
37
- for (const m of meshes) { n += m.count; ni += m.indices.length; }
38
- const positions = new Float32Array(n * 3), normals = new Float32Array(n * 3), indices = new Uint32Array(ni), patch = new Uint8Array(n);
39
- const lists = new Array(n);
40
- let v0 = 0, i0 = 0;
41
- meshes.forEach((m, k) => {
42
- positions.set(m.positions, v0 * 3);
43
- normals.set(m.normals, v0 * 3);
44
- for (let i = 0; i < m.indices.length; i++) indices[i0 + i] = m.indices[i] + v0;
45
- for (let i = 0; i < m.count; i++) { lists[v0 + i] = m.lists[i]; patch[v0 + i] = k > 0 ? 1 : 0; }
46
- v0 += m.count; i0 += m.indices.length;
47
- });
48
- return { positions, normals, indices, lists, count: n, patch };
49
- }
50
-
51
- // replace per-vertex primitive lists by ids so a region can cross a worker boundary
52
- function serialiseLists(p) {
53
- const uniq = new Map();
54
- const listIndex = new Uint32Array(p.count);
55
- const listIds = [];
56
- for (let v = 0; v < p.count; v++) {
57
- const l = p.lists[v];
58
- let k = uniq.get(l);
59
- if (k === undefined) { k = listIds.length; uniq.set(l, k); listIds.push(Int16Array.from(l.map((q) => q.id))); }
60
- listIndex[v] = k;
61
- }
62
- return { name: p.name, positions: p.positions, normals: p.normals, indices: p.indices, count: p.count, listIndex, listIds, patch: p.patch || null };
63
- }
64
-
65
- export function regionTransferables(parts) {
66
- return parts.flatMap((p) => [p.positions.buffer, p.normals.buffer, p.indices.buffer, p.listIndex.buffer]);
67
- }