@expofp/renderer 0.0.0-experimental.cf063fc

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 (280) hide show
  1. package/README.md +145 -0
  2. package/dist/Renderer.d.ts +102 -0
  3. package/dist/Renderer.js +96 -0
  4. package/dist/controls/CameraControls.d.ts +108 -0
  5. package/dist/controls/CameraControls.js +203 -0
  6. package/dist/controls/Controls.d.ts +53 -0
  7. package/dist/controls/Controls.js +54 -0
  8. package/dist/controls/camera-api.d.ts +226 -0
  9. package/dist/controls/camera-api.js +179 -0
  10. package/dist/controls/gestures.d.ts +71 -0
  11. package/dist/controls/gestures.js +98 -0
  12. package/dist/controls/handlers/DoubleTapZoom.d.ts +23 -0
  13. package/dist/controls/handlers/DoubleTapZoom.js +82 -0
  14. package/dist/controls/handlers/Inertia.d.ts +60 -0
  15. package/dist/controls/handlers/Inertia.js +222 -0
  16. package/dist/controls/handlers/Pan.d.ts +23 -0
  17. package/dist/controls/handlers/Pan.js +212 -0
  18. package/dist/controls/handlers/Pitch.d.ts +19 -0
  19. package/dist/controls/handlers/Pitch.js +200 -0
  20. package/dist/controls/handlers/Roll.d.ts +30 -0
  21. package/dist/controls/handlers/Roll.js +196 -0
  22. package/dist/controls/handlers/Zoom.d.ts +28 -0
  23. package/dist/controls/handlers/Zoom.js +34 -0
  24. package/dist/controls/hooks.d.ts +136 -0
  25. package/dist/controls/hooks.js +200 -0
  26. package/dist/controls/index.d.ts +9 -0
  27. package/dist/controls/index.js +7 -0
  28. package/dist/controls/zoom-to.d.ts +89 -0
  29. package/dist/controls/zoom-to.js +91 -0
  30. package/dist/core/InstanceUniforms.d.ts +108 -0
  31. package/dist/core/InstanceUniforms.js +298 -0
  32. package/dist/core/SquareDataTexture.d.ts +277 -0
  33. package/dist/core/SquareDataTexture.js +476 -0
  34. package/dist/core/batch/BatchedMesh.d.ts +74 -0
  35. package/dist/core/batch/BatchedMesh.js +155 -0
  36. package/dist/core/instanced/FrustumCulling.d.ts +141 -0
  37. package/dist/core/instanced/FrustumCulling.js +246 -0
  38. package/dist/core/instanced/InstancedMesh.d.ts +302 -0
  39. package/dist/core/instanced/InstancedMesh.js +497 -0
  40. package/dist/core/instanced/Instances.d.ts +119 -0
  41. package/dist/core/instanced/Instances.js +230 -0
  42. package/dist/core/instanced/Raycasting.d.ts +118 -0
  43. package/dist/core/instanced/Raycasting.js +134 -0
  44. package/dist/core/instanced/instanced-material.d.ts +77 -0
  45. package/dist/core/instanced/instanced-material.js +228 -0
  46. package/dist/core/lines/BatchedLines.d.ts +137 -0
  47. package/dist/core/lines/BatchedLines.js +215 -0
  48. package/dist/core/lines/FrustumCullingLines.d.ts +44 -0
  49. package/dist/core/lines/FrustumCullingLines.js +85 -0
  50. package/dist/core/lines/RaycastingLines.d.ts +45 -0
  51. package/dist/core/lines/RaycastingLines.js +91 -0
  52. package/dist/core/lines/lines-material.d.ts +47 -0
  53. package/dist/core/lines/lines-material.js +124 -0
  54. package/dist/core/shader-source.d.ts +70 -0
  55. package/dist/core/shader-source.js +110 -0
  56. package/dist/core/sprites/BatchedSprites.d.ts +115 -0
  57. package/dist/core/sprites/BatchedSprites.js +173 -0
  58. package/dist/core/sprites/RaycastingSprites.d.ts +41 -0
  59. package/dist/core/sprites/RaycastingSprites.js +71 -0
  60. package/dist/core/sprites/sprite-material.d.ts +59 -0
  61. package/dist/core/sprites/sprite-material.js +192 -0
  62. package/dist/core/text/BatchedText.d.ts +233 -0
  63. package/dist/core/text/BatchedText.js +473 -0
  64. package/dist/core/text/MemberTexture.d.ts +90 -0
  65. package/dist/core/text/MemberTexture.js +289 -0
  66. package/dist/core/text/Text.d.ts +88 -0
  67. package/dist/core/text/Text.js +230 -0
  68. package/dist/core/text/batched-text-material.d.ts +56 -0
  69. package/dist/core/text/batched-text-material.js +123 -0
  70. package/dist/core/text/glyph-packing.d.ts +17 -0
  71. package/dist/core/text/glyph-packing.js +61 -0
  72. package/dist/core/typed-array.d.ts +16 -0
  73. package/dist/core/typed-array.js +20 -0
  74. package/dist/debug/components/DebugPanelProvider.d.ts +20 -0
  75. package/dist/debug/components/DebugPanelProvider.js +50 -0
  76. package/dist/debug/components/DebugTools.d.ts +22 -0
  77. package/dist/debug/components/DebugTools.js +28 -0
  78. package/dist/debug/components/Gui.d.ts +22 -0
  79. package/dist/debug/components/Gui.js +42 -0
  80. package/dist/debug/components/MemoryInfo.d.ts +22 -0
  81. package/dist/debug/components/MemoryInfo.js +42 -0
  82. package/dist/debug/components/Panel.d.ts +31 -0
  83. package/dist/debug/components/Panel.js +104 -0
  84. package/dist/debug/components/Stats.d.ts +9 -0
  85. package/dist/debug/components/Stats.js +24 -0
  86. package/dist/debug/debug-chunk.d.ts +26 -0
  87. package/dist/debug/debug-chunk.js +32 -0
  88. package/dist/debug/debug-context.d.ts +41 -0
  89. package/dist/debug/debug-context.js +59 -0
  90. package/dist/debug/index.d.ts +41 -0
  91. package/dist/debug/index.js +43 -0
  92. package/dist/events/LayoutDriver.d.ts +36 -0
  93. package/dist/events/LayoutDriver.js +192 -0
  94. package/dist/events/PointerMissed.d.ts +23 -0
  95. package/dist/events/PointerMissed.js +58 -0
  96. package/dist/events/def-culling.d.ts +46 -0
  97. package/dist/events/def-culling.js +69 -0
  98. package/dist/events/layout-targets.d.ts +151 -0
  99. package/dist/events/layout-targets.js +397 -0
  100. package/dist/events/placement/box.d.ts +59 -0
  101. package/dist/events/placement/box.js +96 -0
  102. package/dist/events/placement/grid.d.ts +161 -0
  103. package/dist/events/placement/grid.js +235 -0
  104. package/dist/events/placement/index.d.ts +2 -0
  105. package/dist/events/placement/index.js +1 -0
  106. package/dist/events/placement/pass.d.ts +70 -0
  107. package/dist/events/placement/pass.js +617 -0
  108. package/dist/events/pointer.d.ts +194 -0
  109. package/dist/events/pointer.js +356 -0
  110. package/dist/external/ExternalCanvas.d.ts +56 -0
  111. package/dist/external/ExternalCanvas.js +177 -0
  112. package/dist/external/external-camera.d.ts +18 -0
  113. package/dist/external/external-camera.js +103 -0
  114. package/dist/external/external-events.d.ts +14 -0
  115. package/dist/external/external-events.js +33 -0
  116. package/dist/index.d.ts +13 -0
  117. package/dist/index.js +14 -0
  118. package/dist/objects/Background.d.ts +31 -0
  119. package/dist/objects/Background.js +37 -0
  120. package/dist/objects/containers/SlotContainer.d.ts +312 -0
  121. package/dist/objects/containers/SlotContainer.js +311 -0
  122. package/dist/objects/containers/hooks.d.ts +61 -0
  123. package/dist/objects/containers/hooks.js +196 -0
  124. package/dist/objects/containers/index.d.ts +6 -0
  125. package/dist/objects/containers/index.js +4 -0
  126. package/dist/objects/containers/keys.d.ts +10 -0
  127. package/dist/objects/containers/keys.js +18 -0
  128. package/dist/objects/containers/mesh-writes.d.ts +106 -0
  129. package/dist/objects/containers/mesh-writes.js +97 -0
  130. package/dist/objects/containers/props.d.ts +33 -0
  131. package/dist/objects/containers/props.js +1 -0
  132. package/dist/objects/images/ImageInstance.d.ts +29 -0
  133. package/dist/objects/images/ImageInstance.js +152 -0
  134. package/dist/objects/images/Images.d.ts +49 -0
  135. package/dist/objects/images/Images.js +394 -0
  136. package/dist/objects/images/atlas-packer.d.ts +129 -0
  137. package/dist/objects/images/atlas-packer.js +287 -0
  138. package/dist/objects/images/image-container.d.ts +74 -0
  139. package/dist/objects/images/image-container.js +100 -0
  140. package/dist/objects/images/index.d.ts +2 -0
  141. package/dist/objects/images/index.js +1 -0
  142. package/dist/objects/images/pack-sources.d.ts +190 -0
  143. package/dist/objects/images/pack-sources.js +272 -0
  144. package/dist/objects/images/texture-budget.d.ts +120 -0
  145. package/dist/objects/images/texture-budget.js +215 -0
  146. package/dist/objects/images/worker/atlas-worker.d.ts +56 -0
  147. package/dist/objects/images/worker/atlas-worker.js +123 -0
  148. package/dist/objects/images/worker/client.d.ts +62 -0
  149. package/dist/objects/images/worker/client.js +249 -0
  150. package/dist/objects/images/worker/index.d.ts +10 -0
  151. package/dist/objects/images/worker/index.js +1 -0
  152. package/dist/objects/layer/Layer.d.ts +28 -0
  153. package/dist/objects/layer/Layer.js +134 -0
  154. package/dist/objects/layer/index.d.ts +2 -0
  155. package/dist/objects/layer/index.js +1 -0
  156. package/dist/objects/layer/layer-context.d.ts +74 -0
  157. package/dist/objects/layer/layer-context.js +82 -0
  158. package/dist/objects/layer/mount-scheduler.d.ts +131 -0
  159. package/dist/objects/layer/mount-scheduler.js +289 -0
  160. package/dist/objects/layer/visibility-gui.d.ts +19 -0
  161. package/dist/objects/layer/visibility-gui.js +93 -0
  162. package/dist/objects/lighting/Lighting.d.ts +92 -0
  163. package/dist/objects/lighting/Lighting.js +384 -0
  164. package/dist/objects/lighting/OcclusionPasses.d.ts +23 -0
  165. package/dist/objects/lighting/OcclusionPasses.js +271 -0
  166. package/dist/objects/lighting/index.d.ts +11 -0
  167. package/dist/objects/lighting/index.js +10 -0
  168. package/dist/objects/lighting/lighting-gui.d.ts +24 -0
  169. package/dist/objects/lighting/lighting-gui.js +114 -0
  170. package/dist/objects/lighting/occluder.d.ts +34 -0
  171. package/dist/objects/lighting/occluder.js +62 -0
  172. package/dist/objects/lighting/occlusion-targets.d.ts +143 -0
  173. package/dist/objects/lighting/occlusion-targets.js +276 -0
  174. package/dist/objects/lines/LineInstance.d.ts +21 -0
  175. package/dist/objects/lines/LineInstance.js +73 -0
  176. package/dist/objects/lines/Lines.d.ts +17 -0
  177. package/dist/objects/lines/Lines.js +31 -0
  178. package/dist/objects/lines/index.d.ts +2 -0
  179. package/dist/objects/lines/index.js +1 -0
  180. package/dist/objects/lines/line-container.d.ts +35 -0
  181. package/dist/objects/lines/line-container.js +40 -0
  182. package/dist/objects/materials/ColorMaterial.d.ts +92 -0
  183. package/dist/objects/materials/ColorMaterial.js +124 -0
  184. package/dist/objects/materials/LineMaterial.d.ts +44 -0
  185. package/dist/objects/materials/LineMaterial.js +74 -0
  186. package/dist/objects/materials/ModelMaterial.d.ts +53 -0
  187. package/dist/objects/materials/ModelMaterial.js +111 -0
  188. package/dist/objects/materials/TextureMaterial.d.ts +33 -0
  189. package/dist/objects/materials/TextureMaterial.js +48 -0
  190. package/dist/objects/materials/effects/ao/ambient-occlusion-pass.d.ts +77 -0
  191. package/dist/objects/materials/effects/ao/ambient-occlusion-pass.js +296 -0
  192. package/dist/objects/materials/effects/ao/ambient-occlusion-patch.d.ts +29 -0
  193. package/dist/objects/materials/effects/ao/ambient-occlusion-patch.js +115 -0
  194. package/dist/objects/materials/effects/ao/blur-pass.d.ts +61 -0
  195. package/dist/objects/materials/effects/ao/blur-pass.js +101 -0
  196. package/dist/objects/materials/effects/ao/index.d.ts +129 -0
  197. package/dist/objects/materials/effects/ao/index.js +72 -0
  198. package/dist/objects/materials/effects/color-dim.d.ts +115 -0
  199. package/dist/objects/materials/effects/color-dim.js +206 -0
  200. package/dist/objects/materials/effects/contact-shadow.d.ts +100 -0
  201. package/dist/objects/materials/effects/contact-shadow.js +167 -0
  202. package/dist/objects/materials/effects/effects-context.d.ts +53 -0
  203. package/dist/objects/materials/effects/effects-context.js +24 -0
  204. package/dist/objects/materials/shared.d.ts +24 -0
  205. package/dist/objects/materials/shared.js +72 -0
  206. package/dist/objects/models/ModelInstance.d.ts +22 -0
  207. package/dist/objects/models/ModelInstance.js +33 -0
  208. package/dist/objects/models/Models.d.ts +22 -0
  209. package/dist/objects/models/Models.js +186 -0
  210. package/dist/objects/models/gltf-cache.d.ts +17 -0
  211. package/dist/objects/models/gltf-cache.js +50 -0
  212. package/dist/objects/models/index.d.ts +2 -0
  213. package/dist/objects/models/index.js +1 -0
  214. package/dist/objects/models/model-asset.d.ts +48 -0
  215. package/dist/objects/models/model-asset.js +77 -0
  216. package/dist/objects/models/model-container.d.ts +123 -0
  217. package/dist/objects/models/model-container.js +207 -0
  218. package/dist/objects/shapes/ShapeInstance.d.ts +26 -0
  219. package/dist/objects/shapes/ShapeInstance.js +39 -0
  220. package/dist/objects/shapes/Shapes.d.ts +21 -0
  221. package/dist/objects/shapes/Shapes.js +131 -0
  222. package/dist/objects/shapes/index.d.ts +2 -0
  223. package/dist/objects/shapes/index.js +1 -0
  224. package/dist/objects/shapes/shape-container.d.ts +141 -0
  225. package/dist/objects/shapes/shape-container.js +242 -0
  226. package/dist/objects/shapes/shape-geometry.d.ts +27 -0
  227. package/dist/objects/shapes/shape-geometry.js +94 -0
  228. package/dist/objects/text/TextInstance.d.ts +22 -0
  229. package/dist/objects/text/TextInstance.js +95 -0
  230. package/dist/objects/text/Texts.d.ts +30 -0
  231. package/dist/objects/text/Texts.js +43 -0
  232. package/dist/objects/text/index.d.ts +2 -0
  233. package/dist/objects/text/index.js +1 -0
  234. package/dist/objects/text/text-container.d.ts +121 -0
  235. package/dist/objects/text/text-container.js +229 -0
  236. package/dist/objects/text/text-layout.d.ts +92 -0
  237. package/dist/objects/text/text-layout.js +180 -0
  238. package/dist/space/Camera.d.ts +103 -0
  239. package/dist/space/Camera.js +321 -0
  240. package/dist/space/Scene.d.ts +47 -0
  241. package/dist/space/Scene.js +127 -0
  242. package/dist/space/Space.d.ts +325 -0
  243. package/dist/space/Space.js +359 -0
  244. package/dist/space/VisibleRect.d.ts +45 -0
  245. package/dist/space/VisibleRect.js +129 -0
  246. package/dist/space/camera-handle.d.ts +67 -0
  247. package/dist/space/camera-handle.js +63 -0
  248. package/dist/space/camera-kind.d.ts +26 -0
  249. package/dist/space/camera-kind.js +30 -0
  250. package/dist/space/canvas-size.d.ts +24 -0
  251. package/dist/space/canvas-size.js +20 -0
  252. package/dist/space/clipping.d.ts +69 -0
  253. package/dist/space/clipping.js +130 -0
  254. package/dist/space/layout-measure.d.ts +67 -0
  255. package/dist/space/layout-measure.js +175 -0
  256. package/dist/space/viewport.d.ts +112 -0
  257. package/dist/space/viewport.js +67 -0
  258. package/dist/types/defs.d.ts +234 -0
  259. package/dist/types/defs.js +1 -0
  260. package/dist/types/events.d.ts +198 -0
  261. package/dist/types/events.js +1 -0
  262. package/dist/types/guards.d.ts +21 -0
  263. package/dist/types/guards.js +52 -0
  264. package/dist/update/index.d.ts +3 -0
  265. package/dist/update/index.js +2 -0
  266. package/dist/update/slot-writers.d.ts +30 -0
  267. package/dist/update/slot-writers.js +76 -0
  268. package/dist/update/store.d.ts +41 -0
  269. package/dist/update/store.js +104 -0
  270. package/dist/utils/arrays.d.ts +13 -0
  271. package/dist/utils/arrays.js +20 -0
  272. package/dist/utils/colors.d.ts +19 -0
  273. package/dist/utils/colors.js +27 -0
  274. package/dist/utils/hot-state.d.ts +41 -0
  275. package/dist/utils/hot-state.js +37 -0
  276. package/dist/utils/logging.d.ts +29 -0
  277. package/dist/utils/logging.js +55 -0
  278. package/dist/utils/math.d.ts +52 -0
  279. package/dist/utils/math.js +76 -0
  280. package/package.json +79 -0
@@ -0,0 +1,230 @@
1
+ /**
2
+ * What one instance's entry holds. Ordered so a free instance can never read as visible, which is
3
+ * what lets the draw test be one comparison against {@link InstanceState.Visible} rather than a
4
+ * liveness check and a visibility check that have to agree.
5
+ */
6
+ var InstanceState;
7
+ (function (InstanceState) {
8
+ /** Deleted, or never handed out — free to hand out again. */
9
+ InstanceState[InstanceState["Free"] = 0] = "Free";
10
+ /** Live, but not drawn. */
11
+ InstanceState[InstanceState["Hidden"] = 1] = "Hidden";
12
+ /** Live and drawn. */
13
+ InstanceState[InstanceState["Visible"] = 2] = "Visible";
14
+ })(InstanceState || (InstanceState = {}));
15
+ /**
16
+ * The instance allocator: which instances are live, which are visible, which ids are free to hand
17
+ * out again, and how far the live range extends.
18
+ *
19
+ * Ported from three.ez's instanced-mesh — `feature/Instances.ts` for the lifecycle, the availability
20
+ * accessors from `InstancedMesh2.ts`, and `setInstancesArrayCount` from `feature/Capacity.ts`. The
21
+ * `InstancedEntity` object layer and the BVH bookkeeping woven through all three are dropped, so an
22
+ * instance is just an id.
23
+ *
24
+ * Upstream reaches these through prototype augmentation on `InstancedMesh2`; here they are a store
25
+ * the mesh holds, so frustum culling and raycasting can read availability without reaching into the
26
+ * mesh at all.
27
+ */
28
+ export class Instances {
29
+ /**
30
+ * What each instance holds, one entry each — so its length is the capacity, and there is no second
31
+ * count to keep in step with it. Never sparse; see {@link InstanceState}.
32
+ * @see `InstancedMesh2.availabilityArray` upstream, a pair of booleans per instance. One value
33
+ * cannot express "hidden and free" — which nothing wants, since the only path back to live is
34
+ * {@link addInstance}, and it hands the id to a different instance.
35
+ */
36
+ instanceStates;
37
+ /** Ids freed by {@link removeInstances}, handed back out newest first. */
38
+ freeIds = [];
39
+ onResize;
40
+ _activeInstancesCount = 0;
41
+ _addedInstancesCount = 0;
42
+ /**
43
+ * @param capacity - How many instances the stores start out holding.
44
+ * @param onResize - Grows everything the owner keeps per instance, keeping what is written.
45
+ * Called only when adding would overflow what the stores hold.
46
+ */
47
+ constructor(capacity, onResize) {
48
+ this.onResize = onResize;
49
+ this.instanceStates = new Array(capacity).fill(InstanceState.Free);
50
+ }
51
+ /**
52
+ * The number of instances the stores currently hold. Derived rather than tracked, so it cannot
53
+ * fall out of step with the array it describes.
54
+ */
55
+ get capacity() {
56
+ return this.instanceStates.length;
57
+ }
58
+ /** The number of active instances. */
59
+ get instancesCount() {
60
+ return this._activeInstancesCount;
61
+ }
62
+ /**
63
+ * One past the highest live id — the bound every per-instance sweep iterates to. Larger than
64
+ * {@link instancesCount} whenever a removal left a hole, since only trailing dead instances pull
65
+ * it back in.
66
+ *
67
+ * **Pulled back on removal**, unlike the batched text and line classes, whose equivalent is a
68
+ * pure high-water mark. Both bound a sweep; only this one shrinks. It can afford to because the
69
+ * textures here are sized by {@link capacity} instead, which only ever grows.
70
+ * @see `InstancedMesh2._instancesArrayCount` upstream, which this renames: that name reads as a
71
+ * count of instances, which is exactly what it is not.
72
+ */
73
+ get addedInstancesCount() {
74
+ return this._addedInstancesCount;
75
+ }
76
+ /**
77
+ * Adds `count` instances, reusing removed ids first, and reports each new id through `onCreation`
78
+ * so the caller can capture it. New instances start active and visible.
79
+ * @param count - How many to add.
80
+ * @param onCreation - Called with each new instance's id.
81
+ */
82
+ addInstances(count, onCreation) {
83
+ // Refill the holes `removeInstances` left before allocating anything new.
84
+ const freeIds = this.freeIds;
85
+ if (freeIds.length > 0) {
86
+ let maxId = -1;
87
+ // Taken off the tail, so the ids freed most recently are the first ones handed back out.
88
+ const freeIdsUsed = Math.min(freeIds.length, count);
89
+ const freeIdsEnd = freeIds.length - freeIdsUsed;
90
+ for (let i = freeIds.length - 1; i >= freeIdsEnd; i--) {
91
+ const id = freeIds[i];
92
+ if (id > maxId)
93
+ maxId = id;
94
+ this.addInstance(id, onCreation);
95
+ }
96
+ // Drop what was taken, and charge it against what still has to be allocated.
97
+ freeIds.length -= freeIdsUsed;
98
+ count -= freeIdsUsed;
99
+ // A removal may have pulled the bound in below an id just reused, so push it back out.
100
+ this._addedInstancesCount = Math.max(maxId + 1, this._addedInstancesCount);
101
+ }
102
+ // Whatever the free list could not cover extends the live range, growing the stores if needed.
103
+ const start = this._addedInstancesCount;
104
+ const end = start + count;
105
+ this.setAddedInstancesCount(end);
106
+ // Everything past the old bound is untouched, so it needs no reuse check.
107
+ for (let i = start; i < end; i++) {
108
+ this.addInstance(i, onCreation);
109
+ }
110
+ }
111
+ /**
112
+ * Removes instances by id, freeing them for reuse.
113
+ * @param ids - The instances to remove.
114
+ */
115
+ removeInstances(...ids) {
116
+ // Free each live id and hand it to the list. Whatever visibility it held goes with it — the
117
+ // id's next tenant gets a fresh one from `addInstance`.
118
+ const freeIds = this.freeIds;
119
+ for (const id of ids) {
120
+ // Anything already dead or past the live range is skipped, so removing twice counts once.
121
+ if (id < this._addedInstancesCount && this.getActiveAt(id)) {
122
+ this.instanceStates[id] = InstanceState.Free;
123
+ freeIds.push(id);
124
+ this._activeInstancesCount--;
125
+ }
126
+ }
127
+ // Pull the live range back past any instances the removal left trailing and dead, so every later
128
+ // sweep stops sooner. Holes below the last live id stay put for the free list to refill.
129
+ for (let i = this._addedInstancesCount - 1; i >= 0; i--) {
130
+ if (this.getActiveAt(i))
131
+ break;
132
+ this._addedInstancesCount--;
133
+ }
134
+ }
135
+ /**
136
+ * Whether an instance draws — live, and not hidden. The test every per-instance sweep applies.
137
+ * @param id - The index of the instance.
138
+ * @returns Whether it is visible.
139
+ * @see `InstancedMesh2.getVisibilityAt` and `getActiveAndVisibilityAt` upstream, which are one
140
+ * predicate here: an instance cannot be visible without being live.
141
+ */
142
+ getVisibleAt(id) {
143
+ return this.instanceStates[id] === InstanceState.Visible;
144
+ }
145
+ /**
146
+ * Shows or hides an instance. A freed id stays freed: liveness and visibility are one value, so
147
+ * writing visibility here would otherwise hand a dead instance back to the draw list.
148
+ * @param id - The index of the instance.
149
+ * @param visible - Whether it should be visible.
150
+ */
151
+ setVisibleAt(id, visible) {
152
+ if (this.instanceStates[id] === InstanceState.Free)
153
+ return;
154
+ this.instanceStates[id] = visible ? InstanceState.Visible : InstanceState.Hidden;
155
+ }
156
+ /**
157
+ * Whether an instance is live — handed out and not yet removed, hidden or not. What the bounds
158
+ * sweep to, since a hidden instance still occupies space.
159
+ * @param id - The index of the instance.
160
+ * @returns Whether it is active (not deleted).
161
+ */
162
+ getActiveAt(id) {
163
+ return this.instanceStates[id] !== InstanceState.Free;
164
+ }
165
+ /**
166
+ * Adopts another store's instances, for cloning a mesh.
167
+ * @param source - The store to copy.
168
+ */
169
+ copyFrom(source) {
170
+ // Capacity comes across with the array, since that is where it is read from.
171
+ this._activeInstancesCount = source._activeInstancesCount;
172
+ this._addedInstancesCount = source._addedInstancesCount;
173
+ this.instanceStates = source.instanceStates.slice();
174
+ this.freeIds.length = 0;
175
+ this.freeIds.push(...source.freeIds);
176
+ }
177
+ /**
178
+ * Moves the live range's bound, growing every store when it would pass what they hold. Shrinking
179
+ * only moves the bound; the instances past it keep their data until something reuses them.
180
+ * @param count - One past the highest id the range should cover.
181
+ * @see `InstancedMesh2.setInstancesArrayCount` upstream, which is `@internal` there for the same
182
+ * reason it is private here: only {@link addInstances} has cause to move the bound.
183
+ */
184
+ setAddedInstancesCount(count) {
185
+ if (count < this._addedInstancesCount) {
186
+ this._addedInstancesCount = count;
187
+ return;
188
+ }
189
+ const capacity = this.capacity;
190
+ if (count > capacity) {
191
+ // Grown geometrically, to amortize repeated additions.
192
+ let newCapacity = capacity + (capacity >> 1) + 512;
193
+ while (newCapacity < count)
194
+ newCapacity += (newCapacity >> 1) + 512;
195
+ this.resize(newCapacity);
196
+ }
197
+ this._addedInstancesCount = count;
198
+ }
199
+ /**
200
+ * Adds one instance at an id: marks it live and visible, then hands the id to `onCreation` so the
201
+ * owner can reset what it holds and the caller can fill in the rest.
202
+ *
203
+ * One write, so a reused id cannot inherit the hidden state of whatever freed it — the id now
204
+ * belongs to a different instance.
205
+ * @param id - The instance.
206
+ * @param onCreation - Called with the id.
207
+ */
208
+ addInstance(id, onCreation) {
209
+ this._activeInstancesCount++;
210
+ this.instanceStates[id] = InstanceState.Visible;
211
+ onCreation?.(id);
212
+ }
213
+ /**
214
+ * Grows this store and everything the owner keeps per instance.
215
+ *
216
+ * Upstream's `resizeBuffers` grows the availability array itself; here the owner has its buffers
217
+ * and this has the instances, so each grows its own.
218
+ * @param newCapacity - The new capacity, always larger than the current one.
219
+ */
220
+ resize(newCapacity) {
221
+ // Growing the array is what raises {@link capacity}, which reads its length. Filled rather than
222
+ // left as holes for two reasons: `InstanceState.Free` is a value, so an unwritten entry would
223
+ // read as live rather than free, and a holey array falls back to a dictionary on the sweeps that
224
+ // read it every frame.
225
+ const previous = this.instanceStates.length;
226
+ this.instanceStates.length = newCapacity;
227
+ this.instanceStates.fill(InstanceState.Free, previous);
228
+ this.onResize(newCapacity);
229
+ }
230
+ }
@@ -0,0 +1,118 @@
1
+ import { type Intersection, Matrix4, Mesh, type Object3D, type Raycaster, Sphere } from 'three';
2
+ import { type DrawList } from './FrustumCulling';
3
+ import { type Instances } from './Instances';
4
+ /**
5
+ * What {@link Raycasting} reads off the mesh it tests, beyond what every mesh already has — the
6
+ * `geometry` each hit is tested against, the `material` without which nothing is testable, and the
7
+ * `matrixWorld` each instance is placed under.
8
+ */
9
+ export interface RaycastHost extends Mesh {
10
+ /** Bounds enclosing every instance, for the whole-batch early-out. */
11
+ boundingSphere: Sphere | null;
12
+ /** Whether each instance is frustum-culled, and so whether the draw list is worth trusting. */
13
+ perObjectFrustumCulled: boolean;
14
+ /** Fills {@link boundingSphere} when it has been invalidated. */
15
+ computeBoundingSphere(): void;
16
+ /**
17
+ * Reads an instance's transform.
18
+ * @param id - The instance.
19
+ * @param matrix - Target for the result.
20
+ * @returns The transform matrix.
21
+ */
22
+ getMatrixAt(id: number, matrix: Matrix4): Matrix4;
23
+ }
24
+ /**
25
+ * Per-instance picking: walks the instances that could be under the ray and reports a hit for each
26
+ * one it passes through.
27
+ *
28
+ * Ported from three.ez's instanced-mesh `feature/Raycasting.ts`. The BVH branch is dropped, so this
29
+ * is the linear sweep upstream falls back to.
30
+ *
31
+ * Hits are per instance *quad*: an image is picked anywhere inside its bounds, transparent pixels
32
+ * included, since the atlas region is sampled by the shader and not consulted here.
33
+ *
34
+ * **What a subclass changes** is {@link prepareInstance}: the scratch object one instance is tested
35
+ * through, and where it is placed. Everything around it — the early-out, which instances are
36
+ * candidates, the visibility test, and the relabeling — holds however they are placed, so a batch
37
+ * whose instances are not placed by a matrix inherits all of it.
38
+ *
39
+ * Departures from upstream:
40
+ *
41
+ * - **Everything stays in world space.** Upstream brings the ray into the mesh's space once instead
42
+ * of lifting each instance out of it, which sounds cheaper and is not: `Mesh.raycast` inverts its
43
+ * object's matrix and transforms the ray per call regardless, so the saving is one matrix multiply
44
+ * per candidate against composing the instance's placement here. What it costs is real — hits come
45
+ * back measured in the mesh's local units, and R3F sorts intersections from *every* object by
46
+ * `distance`, so an instanced mesh under a scaled ancestor would sort against the batched meshes
47
+ * as though it were nearer or further than it is. It also puts `near` and `far` in the wrong units,
48
+ * which upstream compensates for by dividing them. World space needs none of that, and lets a
49
+ * subclass whose per-instance test projects through the camera — a screen-space line test —
50
+ * inherit this method rather than replace it.
51
+ * - **Hits are relabeled in place.** Upstream collects into a scratch array and copies each entry
52
+ * over; this appends straight to the caller's array and rewrites the tail it added, which costs
53
+ * no second array.
54
+ * - **The draw list is passed in, and may be absent.** Upstream reads the mesh's index attribute,
55
+ * which always exists; a mesh here has no draw list until its first render, and sweeping every
56
+ * live instance is the honest answer then rather than finding nothing.
57
+ * - **No `objectIndex > instancesArrayCount` guard.** Upstream flags it as possibly unnecessary;
58
+ * it is, because both id sources here are bounded by the live range.
59
+ */
60
+ export declare class Raycasting {
61
+ /**
62
+ * Whether picking considers only what the last draw left inside the frustum.
63
+ *
64
+ * Upstream defaults this off and tests every live instance. On here because picking is pointer
65
+ * picking, and nothing off-screen can be under the pointer. A mesh with no draw list — one that
66
+ * has not been drawn since it was built or cloned — falls back to the full sweep.
67
+ */
68
+ private readonly raycastOnlyFrustum;
69
+ /**
70
+ * Tests a ray against every instance that could be under it, appending a hit for each one it
71
+ * passes through.
72
+ * @param host - The mesh being picked.
73
+ * @param instances - The mesh's instance allocator, which says what is live and visible.
74
+ * @param drawList - What the last draw culled to, or `null` before the first draw.
75
+ * @param raycaster - The caster, which is only read.
76
+ * @param intersects - Receives the hits.
77
+ */
78
+ raycast(host: RaycastHost, instances: Instances, drawList: DrawList | null, raycaster: Raycaster, intersects: Intersection[]): void;
79
+ /**
80
+ * Whether the ray comes near the mesh at all — the early-out that costs one test for a batch
81
+ * nowhere near the pointer.
82
+ * @param host - The mesh being picked.
83
+ * @param raycaster - The caster.
84
+ * @returns Whether anything in the mesh can be under the ray.
85
+ */
86
+ protected intersectsMesh(host: RaycastHost, raycaster: Raycaster): boolean;
87
+ /**
88
+ * Sweeps the candidate instances.
89
+ * @param host - The mesh being picked.
90
+ * @param instances - The mesh's instance allocator, which says what is live and visible.
91
+ * @param drawList - What the last draw culled to, or `null`.
92
+ * @param raycaster - The caster.
93
+ * @param intersects - Receives the hits.
94
+ */
95
+ protected raycastInstances(host: RaycastHost, instances: Instances, drawList: DrawList | null, raycaster: Raycaster, intersects: Intersection[]): void;
96
+ /**
97
+ * Places the scratch object one instance is tested through, and hands it back.
98
+ *
99
+ * The seam a subclass changes, because it is the only part of a sweep that knows how an instance
100
+ * is placed — here, the mesh's geometry moved onto the instance's transform, and that lifted into
101
+ * world space, where the ray is. A batch whose instances are not placed by a matrix answers with a
102
+ * scratch of its own.
103
+ * @param host - The mesh being picked.
104
+ * @param objectIndex - The instance to place it as.
105
+ * @returns The object to cast against, standing in for that instance.
106
+ */
107
+ protected prepareInstance(host: RaycastHost, objectIndex: number): Object3D;
108
+ /**
109
+ * Tests one instance, appending whatever the ray passes through.
110
+ * @param host - The mesh being picked.
111
+ * @param instances - The mesh's instance allocator, which says what is live and visible.
112
+ * @param objectIndex - The instance to test.
113
+ * @param raycaster - The caster.
114
+ * @param intersects - Receives the hits.
115
+ */
116
+ private checkObjectIntersection;
117
+ }
118
+ //# sourceMappingURL=Raycasting.d.ts.map
@@ -0,0 +1,134 @@
1
+ import { Matrix4, Mesh, Sphere } from 'three';
2
+ /**
3
+ * Per-instance picking: walks the instances that could be under the ray and reports a hit for each
4
+ * one it passes through.
5
+ *
6
+ * Ported from three.ez's instanced-mesh `feature/Raycasting.ts`. The BVH branch is dropped, so this
7
+ * is the linear sweep upstream falls back to.
8
+ *
9
+ * Hits are per instance *quad*: an image is picked anywhere inside its bounds, transparent pixels
10
+ * included, since the atlas region is sampled by the shader and not consulted here.
11
+ *
12
+ * **What a subclass changes** is {@link prepareInstance}: the scratch object one instance is tested
13
+ * through, and where it is placed. Everything around it — the early-out, which instances are
14
+ * candidates, the visibility test, and the relabeling — holds however they are placed, so a batch
15
+ * whose instances are not placed by a matrix inherits all of it.
16
+ *
17
+ * Departures from upstream:
18
+ *
19
+ * - **Everything stays in world space.** Upstream brings the ray into the mesh's space once instead
20
+ * of lifting each instance out of it, which sounds cheaper and is not: `Mesh.raycast` inverts its
21
+ * object's matrix and transforms the ray per call regardless, so the saving is one matrix multiply
22
+ * per candidate against composing the instance's placement here. What it costs is real — hits come
23
+ * back measured in the mesh's local units, and R3F sorts intersections from *every* object by
24
+ * `distance`, so an instanced mesh under a scaled ancestor would sort against the batched meshes
25
+ * as though it were nearer or further than it is. It also puts `near` and `far` in the wrong units,
26
+ * which upstream compensates for by dividing them. World space needs none of that, and lets a
27
+ * subclass whose per-instance test projects through the camera — a screen-space line test —
28
+ * inherit this method rather than replace it.
29
+ * - **Hits are relabeled in place.** Upstream collects into a scratch array and copies each entry
30
+ * over; this appends straight to the caller's array and rewrites the tail it added, which costs
31
+ * no second array.
32
+ * - **The draw list is passed in, and may be absent.** Upstream reads the mesh's index attribute,
33
+ * which always exists; a mesh here has no draw list until its first render, and sweeping every
34
+ * live instance is the honest answer then rather than finding nothing.
35
+ * - **No `objectIndex > instancesArrayCount` guard.** Upstream flags it as possibly unnecessary;
36
+ * it is, because both id sources here are bounded by the live range.
37
+ */
38
+ export class Raycasting {
39
+ /**
40
+ * Whether picking considers only what the last draw left inside the frustum.
41
+ *
42
+ * Upstream defaults this off and tests every live instance. On here because picking is pointer
43
+ * picking, and nothing off-screen can be under the pointer. A mesh with no draw list — one that
44
+ * has not been drawn since it was built or cloned — falls back to the full sweep.
45
+ */
46
+ raycastOnlyFrustum = true;
47
+ /**
48
+ * Tests a ray against every instance that could be under it, appending a hit for each one it
49
+ * passes through.
50
+ * @param host - The mesh being picked.
51
+ * @param instances - The mesh's instance allocator, which says what is live and visible.
52
+ * @param drawList - What the last draw culled to, or `null` before the first draw.
53
+ * @param raycaster - The caster, which is only read.
54
+ * @param intersects - Receives the hits.
55
+ */
56
+ raycast(host, instances, drawList, raycaster, intersects) {
57
+ if (!host.material || instances.addedInstancesCount === 0)
58
+ return;
59
+ if (!this.intersectsMesh(host, raycaster))
60
+ return;
61
+ this.raycastInstances(host, instances, drawList, raycaster, intersects);
62
+ }
63
+ /**
64
+ * Whether the ray comes near the mesh at all — the early-out that costs one test for a batch
65
+ * nowhere near the pointer.
66
+ * @param host - The mesh being picked.
67
+ * @param raycaster - The caster.
68
+ * @returns Whether anything in the mesh can be under the ray.
69
+ */
70
+ intersectsMesh(host, raycaster) {
71
+ if (host.boundingSphere === null)
72
+ host.computeBoundingSphere();
73
+ _sphere.copy(host.boundingSphere).applyMatrix4(host.matrixWorld);
74
+ return raycaster.ray.intersectsSphere(_sphere);
75
+ }
76
+ /**
77
+ * Sweeps the candidate instances.
78
+ * @param host - The mesh being picked.
79
+ * @param instances - The mesh's instance allocator, which says what is live and visible.
80
+ * @param drawList - What the last draw culled to, or `null`.
81
+ * @param raycaster - The caster.
82
+ * @param intersects - Receives the hits.
83
+ */
84
+ raycastInstances(host, instances, drawList, raycaster, intersects) {
85
+ // Consider only what the last draw left inside the frustum, when there is such a list to read.
86
+ const useDrawList = this.raycastOnlyFrustum && host.perObjectFrustumCulled && drawList !== null;
87
+ const checkCount = useDrawList ? drawList.count : instances.addedInstancesCount;
88
+ for (let i = 0; i < checkCount; i++) {
89
+ this.checkObjectIntersection(host, instances, useDrawList ? drawList.ids[i] : i, raycaster, intersects);
90
+ }
91
+ }
92
+ /**
93
+ * Places the scratch object one instance is tested through, and hands it back.
94
+ *
95
+ * The seam a subclass changes, because it is the only part of a sweep that knows how an instance
96
+ * is placed — here, the mesh's geometry moved onto the instance's transform, and that lifted into
97
+ * world space, where the ray is. A batch whose instances are not placed by a matrix answers with a
98
+ * scratch of its own.
99
+ * @param host - The mesh being picked.
100
+ * @param objectIndex - The instance to place it as.
101
+ * @returns The object to cast against, standing in for that instance.
102
+ */
103
+ prepareInstance(host, objectIndex) {
104
+ // One scratch mesh stands in for every instance; only its world matrix changes between tests.
105
+ _mesh.geometry = host.geometry;
106
+ _mesh.material = host.material;
107
+ _mesh.matrixWorld.multiplyMatrices(host.matrixWorld, host.getMatrixAt(objectIndex, _matrix));
108
+ return _mesh;
109
+ }
110
+ /**
111
+ * Tests one instance, appending whatever the ray passes through.
112
+ * @param host - The mesh being picked.
113
+ * @param instances - The mesh's instance allocator, which says what is live and visible.
114
+ * @param objectIndex - The instance to test.
115
+ * @param raycaster - The caster.
116
+ * @param intersects - Receives the hits.
117
+ */
118
+ checkObjectIntersection(host, instances, objectIndex, raycaster, intersects) {
119
+ if (!instances.getVisibleAt(objectIndex))
120
+ return;
121
+ const before = intersects.length;
122
+ this.prepareInstance(host, objectIndex).raycast(raycaster, intersects);
123
+ // The scratch named itself as the hit object; relabel the tail it just appended so the hits
124
+ // point back at this batch and name the instance that produced them.
125
+ for (let hit = before; hit < intersects.length; hit++) {
126
+ intersects[hit].object = host;
127
+ intersects[hit].instanceId = objectIndex;
128
+ }
129
+ }
130
+ }
131
+ // Scratch shared by every mesh's picking pass, each filled and consumed within one synchronous call.
132
+ const _mesh = new Mesh();
133
+ const _matrix = new Matrix4();
134
+ const _sphere = new Sphere();
@@ -0,0 +1,77 @@
1
+ import { type Material } from 'three';
2
+ import { type InstanceUniforms } from '../InstanceUniforms';
3
+ import { type SquareDataTexture } from '../SquareDataTexture';
4
+ /**
5
+ * Everything the shader side of instancing needs: the GLSL chunks that make texture-backed
6
+ * instancing draw, and the material wrap that points a compiling program at one mesh's textures.
7
+ *
8
+ * The chunks are ported from three.ez's instanced-mesh
9
+ * {@link https://github.com/agargaro/instanced-mesh/blob/master/src/shaders/ShaderChunk.ts | ShaderChunk}
10
+ * and its `chunks/*.glsl`; the wrap from `InstancedMesh2`'s `patchMaterial`, `unpatchMaterial`,
11
+ * `_onBeforeCompile` and `_customProgramCacheKey`, which upstream keeps as methods on the mesh.
12
+ * Nothing here holds state, so they are free functions — {@link patchInstancedMaterial} hands back
13
+ * its own undo rather than parking it on the caller.
14
+ *
15
+ * Skinning, morphing and LOD chunks are dropped. Two substantive changes.
16
+ *
17
+ * **Where the draw's instance id comes from.** Upstream reads it from a `uint` vertex attribute; here
18
+ * it is **fetched from a data texture by `gl_InstanceID`**, the way three's own `BatchedMesh` resolves
19
+ * `gl_DrawID` — so the mesh writes its cull list to a texture it owns and never touches the geometry
20
+ * it was handed, which is what lets several meshes draw one cached geometry.
21
+ *
22
+ * It stays a **float**, not `uint`: the per-instance uniform varyings carry no `flat` qualifier (see
23
+ * {@link SquareDataTexture}), and GLSL ES 3.00 forbids a non-flat integer varying — so the index that
24
+ * feeds those varyings has to be float too. `int( instanceIndex )` still addresses the data textures,
25
+ * exact for every index a Float32 can hold (2^24, far past any instance count).
26
+ *
27
+ * **How the GLSL reaches the shader.** Upstream appends its declarations to three's own
28
+ * `batching_pars_vertex` and `batching_vertex` chunks, which every *stock* material includes — and a
29
+ * material that includes neither, such as three's hand-written `LineMaterial` or a shader supplied by
30
+ * a glTF extension, then compiles reads of an `instanceIndex` nothing declared. Here everything but
31
+ * the color path is injected straight into the source around `main` (see `shader-source`), so the
32
+ * only thing left on three's chunks is what is genuinely a stock-material concern: the transform
33
+ * chunks that apply the instance matrix, and `<color_vertex>`, which is where `vColor` is seeded.
34
+ */
35
+ /** The per-instance textures a patched program fetches from. */
36
+ export interface InstancingTextures {
37
+ /** The draw list: the instance id each `gl_InstanceID` reads. */
38
+ indexTexture: SquareDataTexture;
39
+ /** Per-instance transforms, one `mat4` each, or `null` while none have been written. */
40
+ matricesTexture: SquareDataTexture | null;
41
+ /** Per-instance RGBA colors, or `null` while none have been written. */
42
+ colorsTexture: SquareDataTexture | null;
43
+ /** Per-instance uniforms, which generate their own GLSL. */
44
+ uniforms: InstanceUniforms;
45
+ }
46
+ /**
47
+ * Prepares three's global `ShaderChunk` for indirect instancing, once per process.
48
+ *
49
+ * Only what a *stock* material needs, because only a stock material has these chunks to begin with:
50
+ * the transform chunks that apply the instance matrix, widened to fire under the indirect define as
51
+ * well, and the color chunk substituted for `<color_vertex>`. Everything else an instanced draw
52
+ * needs is injected into the one shader being compiled — see the module docs. Nothing here changes
53
+ * another material's output: the widened branches are inert without `USE_INSTANCING_INDIRECT`, which
54
+ * only an instanced mesh sets on the material it is drawing with, and the added chunk is reached only
55
+ * through the substitution below.
56
+ */
57
+ export declare function patchInstancedShaderChunks(): void;
58
+ /**
59
+ * Wraps a material so the program it compiles reads one mesh's instancing textures.
60
+ *
61
+ * Wraps the material three handed the mesh rather than the mesh's own, because those differ: a scene
62
+ * with an `overrideMaterial` draws every object with that one instead, and an override that skipped
63
+ * the wrap would stack every instance on a single transform. Undoing it afterward is what makes
64
+ * wrapping a material the mesh does not own safe — three tracks whether the program it cached was
65
+ * built for an instanced draw and rebuilds when the next object disagrees, so the plain meshes
66
+ * sharing that override compile their own way.
67
+ *
68
+ * The one case this does not cover is two instanced meshes sharing a material: both are
69
+ * `isInstancedMesh`, so three sees nothing to disagree with and the second draws against the
70
+ * first's textures. Give each mesh its own material.
71
+ * @param material - The material about to draw.
72
+ * @param textures - The textures its program should fetch from, read at compile time so a texture
73
+ * added later is still picked up.
74
+ * @returns Restores the material exactly as it arrived. Call it once, after the draw.
75
+ */
76
+ export declare function patchInstancedMaterial(material: Material, textures: InstancingTextures): () => void;
77
+ //# sourceMappingURL=instanced-material.d.ts.map