@deck.gl/extensions 8.9.0-alpha.5 → 8.9.0-beta.1

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 (201) hide show
  1. package/dist/dist.dev.js +3688 -14538
  2. package/dist/es5/brushing/brushing.js +0 -8
  3. package/dist/es5/brushing/brushing.js.map +1 -1
  4. package/dist/es5/clip/clip.js +5 -5
  5. package/dist/es5/clip/clip.js.map +1 -1
  6. package/dist/es5/collide/collide-effect.js +285 -0
  7. package/dist/es5/collide/collide-effect.js.map +1 -0
  8. package/dist/es5/collide/collide-pass.js +80 -0
  9. package/dist/es5/collide/collide-pass.js.map +1 -0
  10. package/dist/es5/collide/collide.js +116 -0
  11. package/dist/es5/collide/collide.js.map +1 -0
  12. package/dist/es5/collide/shader-module.js +39 -0
  13. package/dist/es5/collide/shader-module.js.map +1 -0
  14. package/dist/es5/common/projection-utils.js +164 -0
  15. package/dist/es5/common/projection-utils.js.map +1 -0
  16. package/dist/es5/data-filter/shader-module.js +1 -0
  17. package/dist/es5/data-filter/shader-module.js.map +1 -1
  18. package/dist/es5/fill-style/fill-style.js +16 -125
  19. package/dist/es5/fill-style/fill-style.js.map +1 -1
  20. package/dist/es5/fill-style/shaders.glsl.js +6 -8
  21. package/dist/es5/fill-style/shaders.glsl.js.map +1 -1
  22. package/dist/es5/fp64/project64.glsl.js +1 -1
  23. package/dist/es5/index.js +16 -0
  24. package/dist/es5/index.js.map +1 -1
  25. package/dist/es5/mask/mask-effect.js +280 -0
  26. package/dist/es5/mask/mask-effect.js.map +1 -0
  27. package/dist/es5/mask/mask-pass.js +106 -0
  28. package/dist/es5/mask/mask-pass.js.map +1 -0
  29. package/dist/es5/mask/mask.js +17 -4
  30. package/dist/es5/mask/mask.js.map +1 -1
  31. package/dist/es5/mask/shader-module.js +1 -1
  32. package/dist/es5/mask/shader-module.js.map +1 -1
  33. package/dist/es5/mask/utils.js +136 -0
  34. package/dist/es5/mask/utils.js.map +1 -0
  35. package/dist/es5/path-style/shaders.glsl.js +1 -1
  36. package/dist/es5/terrain/height-map-builder.js +116 -0
  37. package/dist/es5/terrain/height-map-builder.js.map +1 -0
  38. package/dist/es5/terrain/shader-module.js +84 -0
  39. package/dist/es5/terrain/shader-module.js.map +1 -0
  40. package/dist/es5/terrain/terrain-cover.js +259 -0
  41. package/dist/es5/terrain/terrain-cover.js.map +1 -0
  42. package/dist/es5/terrain/terrain-effect.js +337 -0
  43. package/dist/es5/terrain/terrain-effect.js.map +1 -0
  44. package/dist/es5/terrain/terrain-pass.js +122 -0
  45. package/dist/es5/terrain/terrain-pass.js.map +1 -0
  46. package/dist/es5/terrain/terrain-picking-pass.js +130 -0
  47. package/dist/es5/terrain/terrain-picking-pass.js.map +1 -0
  48. package/dist/es5/terrain/terrain.js +101 -0
  49. package/dist/es5/terrain/terrain.js.map +1 -0
  50. package/dist/es5/terrain/utils.js +32 -0
  51. package/dist/es5/terrain/utils.js.map +1 -0
  52. package/dist/es5/utils/debug.js +71 -0
  53. package/dist/es5/utils/debug.js.map +1 -0
  54. package/dist/esm/brushing/brushing.js +0 -7
  55. package/dist/esm/brushing/brushing.js.map +1 -1
  56. package/dist/esm/clip/clip.js +5 -4
  57. package/dist/esm/clip/clip.js.map +1 -1
  58. package/dist/esm/collide/collide-effect.js +250 -0
  59. package/dist/esm/collide/collide-effect.js.map +1 -0
  60. package/dist/esm/collide/collide-pass.js +30 -0
  61. package/dist/esm/collide/collide-pass.js.map +1 -0
  62. package/dist/esm/collide/collide.js +78 -0
  63. package/dist/esm/collide/collide.js.map +1 -0
  64. package/dist/esm/collide/shader-module.js +32 -0
  65. package/dist/esm/collide/shader-module.js.map +1 -0
  66. package/dist/esm/common/projection-utils.js +130 -0
  67. package/dist/esm/common/projection-utils.js.map +1 -0
  68. package/dist/esm/data-filter/shader-module.js +1 -0
  69. package/dist/esm/data-filter/shader-module.js.map +1 -1
  70. package/dist/esm/fill-style/fill-style.js +20 -72
  71. package/dist/esm/fill-style/fill-style.js.map +1 -1
  72. package/dist/esm/fill-style/shaders.glsl.js +5 -7
  73. package/dist/esm/fill-style/shaders.glsl.js.map +1 -1
  74. package/dist/esm/fp64/project64.glsl.js +1 -1
  75. package/dist/esm/index.js +2 -0
  76. package/dist/esm/index.js.map +1 -1
  77. package/dist/esm/mask/mask-effect.js +233 -0
  78. package/dist/esm/mask/mask-effect.js.map +1 -0
  79. package/dist/esm/mask/mask-pass.js +62 -0
  80. package/dist/esm/mask/mask-pass.js.map +1 -0
  81. package/dist/esm/mask/mask.js +14 -3
  82. package/dist/esm/mask/mask.js.map +1 -1
  83. package/dist/esm/mask/shader-module.js +1 -1
  84. package/dist/esm/mask/shader-module.js.map +1 -1
  85. package/dist/esm/mask/utils.js +109 -0
  86. package/dist/esm/mask/utils.js.map +1 -0
  87. package/dist/esm/path-style/shaders.glsl.js +1 -1
  88. package/dist/esm/terrain/height-map-builder.js +92 -0
  89. package/dist/esm/terrain/height-map-builder.js.map +1 -0
  90. package/dist/esm/terrain/shader-module.js +73 -0
  91. package/dist/esm/terrain/shader-module.js.map +1 -0
  92. package/dist/esm/terrain/terrain-cover.js +219 -0
  93. package/dist/esm/terrain/terrain-cover.js.map +1 -0
  94. package/dist/esm/terrain/terrain-effect.js +231 -0
  95. package/dist/esm/terrain/terrain-effect.js.map +1 -0
  96. package/dist/esm/terrain/terrain-pass.js +69 -0
  97. package/dist/esm/terrain/terrain-pass.js.map +1 -0
  98. package/dist/esm/terrain/terrain-picking-pass.js +75 -0
  99. package/dist/esm/terrain/terrain-picking-pass.js.map +1 -0
  100. package/dist/esm/terrain/terrain.js +62 -0
  101. package/dist/esm/terrain/terrain.js.map +1 -0
  102. package/dist/esm/terrain/utils.js +21 -0
  103. package/dist/esm/terrain/utils.js.map +1 -0
  104. package/dist/esm/utils/debug.js +61 -0
  105. package/dist/esm/utils/debug.js.map +1 -0
  106. package/dist.min.js +1359 -1
  107. package/package.json +6 -4
  108. package/src/brushing/brushing.ts +0 -11
  109. package/src/clip/clip.ts +6 -5
  110. package/src/collide/collide-effect.ts +257 -0
  111. package/src/collide/collide-pass.ts +35 -0
  112. package/src/collide/collide.ts +79 -0
  113. package/src/collide/shader-module.ts +113 -0
  114. package/src/common/projection-utils.ts +187 -0
  115. package/src/data-filter/shader-module.ts +6 -0
  116. package/src/fill-style/fill-style.ts +15 -53
  117. package/src/fill-style/shaders.glsl.ts +6 -7
  118. package/src/index.ts +4 -0
  119. package/src/mask/mask-effect.ts +255 -0
  120. package/src/mask/mask-pass.ts +67 -0
  121. package/src/mask/mask.ts +17 -7
  122. package/src/mask/shader-module.ts +7 -1
  123. package/src/mask/utils.ts +148 -0
  124. package/src/terrain/height-map-builder.ts +120 -0
  125. package/src/terrain/shader-module.ts +161 -0
  126. package/src/terrain/terrain-cover.ts +225 -0
  127. package/src/terrain/terrain-effect.ts +223 -0
  128. package/src/terrain/terrain-pass.ts +86 -0
  129. package/src/terrain/terrain-picking-pass.ts +87 -0
  130. package/src/terrain/terrain.ts +74 -0
  131. package/src/terrain/utils.ts +29 -0
  132. package/src/utils/debug.ts +59 -0
  133. package/typed/brushing/brushing.d.ts +0 -1
  134. package/typed/brushing/brushing.d.ts.map +1 -1
  135. package/typed/brushing/brushing.js +83 -0
  136. package/typed/brushing/shader-module.js +116 -0
  137. package/typed/clip/clip.d.ts +1 -1
  138. package/typed/clip/clip.d.ts.map +1 -1
  139. package/typed/clip/clip.js +114 -0
  140. package/typed/collide/collide-effect.d.ts +28 -0
  141. package/typed/collide/collide-effect.d.ts.map +1 -0
  142. package/typed/collide/collide-pass.d.ts +14 -0
  143. package/typed/collide/collide-pass.d.ts.map +1 -0
  144. package/typed/collide/collide.d.ts +41 -0
  145. package/typed/collide/collide.d.ts.map +1 -0
  146. package/typed/collide/shader-module.d.ts +4 -0
  147. package/typed/collide/shader-module.d.ts.map +1 -0
  148. package/typed/common/projection-utils.d.ts +27 -0
  149. package/typed/common/projection-utils.d.ts.map +1 -0
  150. package/typed/data-filter/aggregator.js +98 -0
  151. package/typed/data-filter/data-filter.js +159 -0
  152. package/typed/data-filter/shader-module.d.ts.map +1 -1
  153. package/typed/data-filter/shader-module.js +152 -0
  154. package/typed/fill-style/fill-style.d.ts +14 -5
  155. package/typed/fill-style/fill-style.d.ts.map +1 -1
  156. package/typed/fill-style/fill-style.js +152 -0
  157. package/typed/fill-style/shaders.glsl.d.ts.map +1 -1
  158. package/typed/fill-style/shaders.glsl.js +95 -0
  159. package/typed/fp64/fp64.js +34 -0
  160. package/typed/fp64/project64.glsl.js +100 -0
  161. package/typed/fp64/project64.js +50 -0
  162. package/typed/index.d.ts +4 -0
  163. package/typed/index.d.ts.map +1 -1
  164. package/typed/index.js +9 -0
  165. package/typed/mask/mask-effect.d.ts +42 -0
  166. package/typed/mask/mask-effect.d.ts.map +1 -0
  167. package/typed/mask/mask-pass.d.ts +19 -0
  168. package/typed/mask/mask-pass.d.ts.map +1 -0
  169. package/typed/mask/mask.d.ts +9 -3
  170. package/typed/mask/mask.d.ts.map +1 -1
  171. package/typed/mask/mask.js +48 -0
  172. package/typed/mask/shader-module.d.ts.map +1 -1
  173. package/typed/mask/shader-module.js +73 -0
  174. package/typed/mask/utils.d.ts +13 -0
  175. package/typed/mask/utils.d.ts.map +1 -0
  176. package/typed/path-style/path-style.js +107 -0
  177. package/typed/path-style/shaders.glsl.js +93 -0
  178. package/typed/terrain/height-map-builder.d.ts +38 -0
  179. package/typed/terrain/height-map-builder.d.ts.map +1 -0
  180. package/typed/terrain/height-map.d.ts +27 -0
  181. package/typed/terrain/height-map.d.ts.map +1 -0
  182. package/typed/terrain/shader-module-offset.d.ts +4 -0
  183. package/typed/terrain/shader-module-offset.d.ts.map +1 -0
  184. package/typed/terrain/shader-module-source.d.ts +4 -0
  185. package/typed/terrain/shader-module-source.d.ts.map +1 -0
  186. package/typed/terrain/shader-module.d.ts +31 -0
  187. package/typed/terrain/shader-module.d.ts.map +1 -0
  188. package/typed/terrain/terrain-cover.d.ts +46 -0
  189. package/typed/terrain/terrain-cover.d.ts.map +1 -0
  190. package/typed/terrain/terrain-effect.d.ts +29 -0
  191. package/typed/terrain/terrain-effect.d.ts.map +1 -0
  192. package/typed/terrain/terrain-pass.d.ts +11 -0
  193. package/typed/terrain/terrain-pass.d.ts.map +1 -0
  194. package/typed/terrain/terrain-picking-pass.d.ts +19 -0
  195. package/typed/terrain/terrain-picking-pass.d.ts.map +1 -0
  196. package/typed/terrain/terrain.d.ts +21 -0
  197. package/typed/terrain/terrain.d.ts.map +1 -0
  198. package/typed/terrain/utils.d.ts +5 -0
  199. package/typed/terrain/utils.d.ts.map +1 -0
  200. package/typed/utils/debug.d.ts +6 -0
  201. package/typed/utils/debug.d.ts.map +1 -0
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@deck.gl/extensions",
3
3
  "description": "Plug-and-play functionalities for deck.gl layers",
4
4
  "license": "MIT",
5
- "version": "8.9.0-alpha.5",
5
+ "version": "8.9.0-beta.1",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
@@ -26,8 +26,8 @@
26
26
  ],
27
27
  "sideEffects": false,
28
28
  "scripts": {
29
- "build-bundle": "webpack --config ../../scripts/bundle.config.js",
30
- "prepublishOnly": "npm run build-bundle && npm run build-bundle -- --env.dev"
29
+ "build-bundle": "ocular-bundle ./bundle.ts",
30
+ "prepublishOnly": "npm run build-bundle && npm run build-bundle -- --env=dev"
31
31
  },
32
32
  "dependencies": {
33
33
  "@luma.gl/shadertools": "^8.5.16"
@@ -36,7 +36,9 @@
36
36
  "@deck.gl/core": "^8.0.0",
37
37
  "@luma.gl/constants": "^8.0.0",
38
38
  "@luma.gl/core": "^8.0.0",
39
+ "@math.gl/core": "^3.6.2",
40
+ "@math.gl/web-mercator": "^3.6.2",
39
41
  "gl-matrix": "^3.0.0"
40
42
  },
41
- "gitHead": "36330f8ca588055b11ed8032dc68ced641cb258b"
43
+ "gitHead": "47223d1ea084c3f9b0c9f0f9736682850bb5db85"
42
44
  }
@@ -70,11 +70,6 @@ export default class BrushingExtension extends LayerExtension {
70
70
  brushingTargets: {
71
71
  size: 2,
72
72
  accessor: 'getBrushingTarget',
73
- // Hack: extension's defaultProps is not merged with the layer's defaultProps,
74
- // So we can't use the standard accessor when the prop is undefined
75
- // TODO - move to an option
76
- // eslint-disable-next-line @typescript-eslint/unbound-method
77
- update: this.props.getBrushingTarget ? undefined : extension.useConstantTargetPositions,
78
73
  shaderAttributes: {
79
74
  brushingTargets: {
80
75
  divisor: 0
@@ -111,10 +106,4 @@ export default class BrushingExtension extends LayerExtension {
111
106
  });
112
107
  }
113
108
  }
114
-
115
- useConstantTargetPositions(attribute) {
116
- attribute.constant = true;
117
- attribute.value = new Float32Array(2);
118
- return;
119
- }
120
109
  }
package/src/clip/clip.ts CHANGED
@@ -23,7 +23,8 @@ import {LayerExtension, _ShaderModule as ShaderModule} from '@deck.gl/core';
23
23
  import type {Layer} from '@deck.gl/core';
24
24
 
25
25
  const defaultProps = {
26
- clipBounds: [0, 0, 1, 1]
26
+ clipBounds: [0, 0, 1, 1],
27
+ clipByInstance: undefined
27
28
  };
28
29
 
29
30
  export type ClipExtensionProps = {
@@ -107,8 +108,8 @@ export default class ClipExtension extends LayerExtension {
107
108
  // @ts-expect-error attributeManager is always defined for primitive layers
108
109
  let clipByInstance = 'instancePositions' in this.getAttributeManager().attributes;
109
110
  // Users can override by setting the `clipByInstance` prop
110
- if ('clipByInstance' in this.props) {
111
- clipByInstance = this.props.clipByInstance as boolean;
111
+ if (this.props.clipByInstance !== undefined) {
112
+ clipByInstance = Boolean(this.props.clipByInstance);
112
113
  }
113
114
  this.state.clipByInstance = clipByInstance;
114
115
 
@@ -124,8 +125,8 @@ export default class ClipExtension extends LayerExtension {
124
125
  }
125
126
 
126
127
  /* eslint-disable camelcase */
127
- draw(this: Layer<ClipExtensionProps>, {uniforms}: any): void {
128
- const {clipBounds = defaultProps.clipBounds} = this.props;
128
+ draw(this: Layer<Required<ClipExtensionProps>>, {uniforms}: any): void {
129
+ const {clipBounds} = this.props;
129
130
  if (this.state.clipByInstance) {
130
131
  uniforms.clip_bounds = clipBounds;
131
132
  } else {
@@ -0,0 +1,257 @@
1
+ import {Framebuffer, Renderbuffer, Texture2D, cssToDeviceRatio} from '@luma.gl/core';
2
+ import {equals} from '@math.gl/core';
3
+ import {_deepEqual as deepEqual} from '@deck.gl/core';
4
+ import type {Effect, Layer, PreRenderOptions, Viewport} from '@deck.gl/core';
5
+ import CollidePass from './collide-pass';
6
+ import MaskEffect, {MaskPreRenderStats} from '../mask/mask-effect';
7
+ // import {debugFBO} from '../utils/debug';
8
+
9
+ type CollideExtensionProps = {
10
+ collideTestProps?: {};
11
+ collideGroup: string;
12
+ };
13
+
14
+ // Factor by which to downscale Collide FBO relative to canvas
15
+ const DOWNSCALE = 2;
16
+
17
+ type RenderInfo = {
18
+ collideGroup: string;
19
+ layers: Layer<CollideExtensionProps>[];
20
+ layerBounds: ([number[], number[]] | null)[];
21
+ };
22
+
23
+ // Class to manage collide effect
24
+ export default class CollideEffect implements Effect {
25
+ id = 'collide-effect';
26
+ props = null;
27
+ useInPicking = true;
28
+ order = 1;
29
+
30
+ private channels: Record<string, RenderInfo> = {};
31
+ private collidePass?: CollidePass;
32
+ private collideFBOs: Record<string, Framebuffer> = {};
33
+ private dummyCollideMap?: Texture2D;
34
+ private lastViewport?: Viewport;
35
+
36
+ preRender(
37
+ gl: WebGLRenderingContext,
38
+ {
39
+ effects: allEffects,
40
+ layers,
41
+ layerFilter,
42
+ viewports,
43
+ onViewportActive,
44
+ views,
45
+ pass,
46
+ preRenderStats = {}
47
+ }: PreRenderOptions
48
+ ): void {
49
+ if (!this.dummyCollideMap) {
50
+ this.dummyCollideMap = new Texture2D(gl, {width: 1, height: 1});
51
+ }
52
+
53
+ if (pass.startsWith('picking')) {
54
+ // Do not update on picking pass
55
+ return;
56
+ }
57
+
58
+ const collideLayers = layers.filter(
59
+ // @ts-ignore
60
+ ({props: {visible, collideEnabled}}) => visible && collideEnabled
61
+ ) as Layer<CollideExtensionProps>[];
62
+ if (collideLayers.length === 0) {
63
+ this.channels = {};
64
+ return;
65
+ }
66
+
67
+ if (!this.collidePass) {
68
+ this.collidePass = new CollidePass(gl, {id: 'default-collide'});
69
+ }
70
+
71
+ // Detect if mask has rendered. TODO: better dependency system for Effects
72
+ const effects = allEffects?.filter(e => e.constructor === MaskEffect);
73
+ const maskEffectRendered = (preRenderStats['mask-effect'] as MaskPreRenderStats)?.didRender;
74
+
75
+ // Collect layers to render
76
+ const channels = this._groupByCollideGroup(gl, collideLayers);
77
+
78
+ const viewport = viewports[0];
79
+ const viewportChanged =
80
+ !this.lastViewport || !this.lastViewport.equals(viewport) || maskEffectRendered;
81
+
82
+ // Resize framebuffers to match canvas
83
+ for (const collideGroup in channels) {
84
+ const collideFBO = this.collideFBOs[collideGroup];
85
+ const renderInfo = channels[collideGroup];
86
+ collideFBO.resize({
87
+ width: gl.canvas.width / DOWNSCALE,
88
+ height: gl.canvas.height / DOWNSCALE
89
+ });
90
+ this._render(renderInfo, {
91
+ effects,
92
+ layerFilter,
93
+ onViewportActive,
94
+ views,
95
+ viewport,
96
+ viewportChanged
97
+ });
98
+ }
99
+
100
+ // debugFBO(this.collideFBOs[Object.keys(channels)[0]], {minimap: true});
101
+ }
102
+
103
+ private _render(
104
+ renderInfo: RenderInfo,
105
+ {
106
+ effects,
107
+ layerFilter,
108
+ onViewportActive,
109
+ views,
110
+ viewport,
111
+ viewportChanged
112
+ }: {
113
+ effects: PreRenderOptions['effects'];
114
+ layerFilter: PreRenderOptions['layerFilter'];
115
+ onViewportActive: PreRenderOptions['onViewportActive'];
116
+ views: PreRenderOptions['views'];
117
+ viewport: Viewport;
118
+ viewportChanged: boolean;
119
+ }
120
+ ) {
121
+ const {collideGroup} = renderInfo;
122
+ const oldRenderInfo = this.channels[collideGroup];
123
+ if (!oldRenderInfo) {
124
+ return;
125
+ }
126
+
127
+ const needsRender =
128
+ viewportChanged ||
129
+ // If render info is new
130
+ renderInfo === oldRenderInfo ||
131
+ // If sublayers have changed
132
+ !deepEqual(oldRenderInfo.layers, renderInfo.layers, 0) ||
133
+ // If a sublayer's bounds have been updated
134
+ renderInfo.layerBounds.some((b, i) => !equals(b, oldRenderInfo.layerBounds[i]));
135
+
136
+ this.channels[collideGroup] = renderInfo;
137
+
138
+ if (needsRender) {
139
+ this.lastViewport = viewport;
140
+ const collideFBO = this.collideFBOs[collideGroup];
141
+
142
+ // Rerender collide FBO
143
+ this.collidePass!.renderCollideMap(collideFBO, {
144
+ pass: 'collide',
145
+ layers: renderInfo.layers,
146
+ effects,
147
+ layerFilter,
148
+ viewports: viewport ? [viewport] : [],
149
+ onViewportActive,
150
+ views,
151
+ moduleParameters: {
152
+ // To avoid feedback loop forming between Framebuffer and active Texture.
153
+ dummyCollideMap: this.dummyCollideMap,
154
+ devicePixelRatio: cssToDeviceRatio(collideFBO.gl) / DOWNSCALE
155
+ }
156
+ });
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Group layers by collideGroup
162
+ * Returns a map from collideGroup to render info
163
+ */
164
+ private _groupByCollideGroup(
165
+ gl: WebGLRenderingContext,
166
+ collideLayers: Layer<CollideExtensionProps>[]
167
+ ): Record<string, RenderInfo> {
168
+ const channelMap = {};
169
+ for (const layer of collideLayers) {
170
+ const {collideGroup} = layer.props;
171
+ let channelInfo = channelMap[collideGroup];
172
+ if (!channelInfo) {
173
+ channelInfo = {
174
+ collideGroup,
175
+ layers: [],
176
+ layerBounds: []
177
+ };
178
+ channelMap[collideGroup] = channelInfo;
179
+ }
180
+ channelInfo.layers.push(layer);
181
+ channelInfo.layerBounds.push(layer.getBounds());
182
+ }
183
+
184
+ // Create any new passes and remove any old ones
185
+ for (const collideGroup of Object.keys(channelMap)) {
186
+ if (!this.collideFBOs[collideGroup]) {
187
+ this.createFBO(gl, collideGroup);
188
+ }
189
+ if (!this.channels[collideGroup]) {
190
+ this.channels[collideGroup] = channelMap[collideGroup];
191
+ }
192
+ }
193
+ for (const collideGroup of Object.keys(this.collideFBOs)) {
194
+ if (!channelMap[collideGroup]) {
195
+ this.destroyFBO(collideGroup);
196
+ }
197
+ }
198
+
199
+ return channelMap;
200
+ }
201
+
202
+ getModuleParameters(layer: Layer): {
203
+ collideFBO: Framebuffer;
204
+ dummyCollideMap: Texture2D;
205
+ } {
206
+ const {collideGroup} = (layer as Layer<CollideExtensionProps>).props;
207
+ const {collideFBOs, dummyCollideMap} = this;
208
+ return {collideFBO: collideFBOs[collideGroup], dummyCollideMap};
209
+ }
210
+
211
+ cleanup(): void {
212
+ if (this.dummyCollideMap) {
213
+ this.dummyCollideMap.delete();
214
+ this.dummyCollideMap = undefined;
215
+ }
216
+ this.channels = {};
217
+ for (const collideGroup of Object.keys(this.collideFBOs)) {
218
+ this.destroyFBO(collideGroup);
219
+ }
220
+ this.collideFBOs = {};
221
+ this.lastViewport = undefined;
222
+ }
223
+
224
+ createFBO(gl: WebGLRenderingContext, collideGroup: string) {
225
+ const {width, height} = gl.canvas;
226
+ const collideMap = new Texture2D(gl, {
227
+ width,
228
+ height,
229
+ parameters: {
230
+ [gl.TEXTURE_MIN_FILTER]: gl.NEAREST,
231
+ [gl.TEXTURE_MAG_FILTER]: gl.NEAREST,
232
+ [gl.TEXTURE_WRAP_S]: gl.CLAMP_TO_EDGE,
233
+ [gl.TEXTURE_WRAP_T]: gl.CLAMP_TO_EDGE
234
+ }
235
+ });
236
+
237
+ const depthBuffer = new Renderbuffer(gl, {format: gl.DEPTH_COMPONENT16, width, height});
238
+ this.collideFBOs[collideGroup] = new Framebuffer(gl, {
239
+ id: `Collide-${collideGroup}`,
240
+ width,
241
+ height,
242
+ attachments: {
243
+ [gl.COLOR_ATTACHMENT0]: collideMap,
244
+ [gl.DEPTH_ATTACHMENT]: depthBuffer
245
+ }
246
+ });
247
+ }
248
+
249
+ destroyFBO(collideGroup: string) {
250
+ const fbo = this.collideFBOs[collideGroup];
251
+ for (const attachment of Object.values(fbo.attachments as Texture2D[])) {
252
+ attachment.delete();
253
+ }
254
+ fbo.delete();
255
+ delete this.collideFBOs[collideGroup];
256
+ }
257
+ }
@@ -0,0 +1,35 @@
1
+ import {Framebuffer, withParameters} from '@luma.gl/core';
2
+ import {_LayersPass as LayersPass, LayersPassRenderOptions} from '@deck.gl/core';
3
+
4
+ type CollidePassRenderOptions = LayersPassRenderOptions & {};
5
+
6
+ export default class CollidePass extends LayersPass {
7
+ renderCollideMap(target: Framebuffer, options: CollidePassRenderOptions) {
8
+ const gl = this.gl;
9
+
10
+ const padding = 1;
11
+
12
+ return withParameters(
13
+ gl,
14
+ {
15
+ scissorTest: true,
16
+ scissor: [padding, padding, target.width - 2 * padding, target.height - 2 * padding],
17
+ clearColor: [0, 0, 0, 0],
18
+ blend: false,
19
+ depthTest: true,
20
+ depthRange: [0, 1]
21
+ },
22
+ () => this.render({...options, target, pass: 'collide'})
23
+ );
24
+ }
25
+
26
+ getModuleParameters() {
27
+ // Draw picking colors into collide FBO
28
+ return {
29
+ drawToCollideMap: true,
30
+ pickingActive: 1,
31
+ pickingAttribute: false,
32
+ lightSources: {}
33
+ };
34
+ }
35
+ }
@@ -0,0 +1,79 @@
1
+ import {Accessor, Layer, LayerContext, LayerExtension} from '@deck.gl/core';
2
+ import collide from './shader-module';
3
+ import CollideEffect from './collide-effect';
4
+
5
+ const defaultProps = {
6
+ getCollidePriority: {type: 'accessor', value: 0},
7
+ collideEnabled: true,
8
+ collideGroup: {type: 'string', value: 'default'},
9
+ collideTestProps: {}
10
+ };
11
+
12
+ export type CollideExtensionProps<DataT = any> = {
13
+ /**
14
+ * Accessor for collision priority. Must return a number in the range -1000 -> 1000. Features with higher values are shown preferentially.
15
+ */
16
+ getCollidePriority?: Accessor<DataT, number>;
17
+
18
+ /**
19
+ * Enable/disable collisions. If collisions are disabled, all objects are rendered.
20
+ * @default true
21
+ */
22
+ collideEnabled: boolean;
23
+
24
+ /**
25
+ * Collision group this layer belongs to. If it is not set, the 'default' collision group is used
26
+ */
27
+ collideGroup?: string;
28
+
29
+ /**
30
+ * Props to override when rendering collision map
31
+ */
32
+ collideTestProps?: {};
33
+ };
34
+
35
+ /** Allows layers to hide overlapping objects. */
36
+ export default class CollideExtension extends LayerExtension {
37
+ static defaultProps = defaultProps;
38
+ static extensionName = 'CollideExtension';
39
+
40
+ getShaders(this: Layer<CollideExtensionProps>): any {
41
+ return {modules: [collide]};
42
+ }
43
+
44
+ /* eslint-disable camelcase */
45
+ draw(this: Layer<CollideExtensionProps>, {uniforms, context, moduleParameters}: any) {
46
+ const {collideEnabled} = this.props;
47
+ const {collideFBO, drawToCollideMap} = moduleParameters;
48
+ const enabled = collideEnabled && Boolean(collideFBO);
49
+ uniforms.collide_enabled = enabled;
50
+
51
+ if (drawToCollideMap) {
52
+ // Override any props with those defined in collideTestProps
53
+ // @ts-ignore
54
+ this.props = this.clone(this.props.collideTestProps).props;
55
+ }
56
+ }
57
+
58
+ initializeState(this: Layer<CollideExtensionProps>, context: LayerContext, extension: this) {
59
+ if (this.getAttributeManager() === null) {
60
+ return;
61
+ }
62
+ this.context.deck?._addDefaultEffect(new CollideEffect());
63
+ const attributeManager = this.getAttributeManager();
64
+ attributeManager!.add({
65
+ collidePriorities: {
66
+ size: 1,
67
+ accessor: 'getCollidePriority',
68
+ shaderAttributes: {
69
+ collidePriorities: {divisor: 0},
70
+ instanceCollidePriorities: {divisor: 1}
71
+ }
72
+ }
73
+ });
74
+ }
75
+
76
+ getNeedsPickingBuffer(this: Layer<CollideExtensionProps>): boolean {
77
+ return this.props.collideEnabled;
78
+ }
79
+ }
@@ -0,0 +1,113 @@
1
+ import {Framebuffer, Texture2D} from '@luma.gl/core';
2
+ import {project} from '@deck.gl/core';
3
+ import type {_ShaderModule as ShaderModule} from '@deck.gl/core';
4
+
5
+ const vs = `
6
+ #ifdef NON_INSTANCED_MODEL
7
+ attribute float collidePriorities;
8
+ #else
9
+ attribute float instanceCollidePriorities;
10
+ #endif
11
+
12
+ uniform sampler2D collide_texture;
13
+ uniform bool collide_sort;
14
+ uniform bool collide_enabled;
15
+
16
+ vec2 collide_getCoords(vec4 position) {
17
+ vec4 collide_clipspace = project_common_position_to_clipspace(position);
18
+ return (1.0 + collide_clipspace.xy / collide_clipspace.w) / 2.0;
19
+ }
20
+
21
+ float collide_match(vec2 tex, vec3 pickingColor) {
22
+ vec4 collide_pickingColor = texture2D(collide_texture, tex);
23
+ float delta = dot(abs(collide_pickingColor.rgb - pickingColor), vec3(1.0));
24
+ float e = 0.001;
25
+ return step(delta, e);
26
+ }
27
+
28
+ float collide_isVisible(vec2 texCoords, vec3 pickingColor) {
29
+ if (!collide_enabled) {
30
+ return 1.0;
31
+ }
32
+
33
+ // Visibility test, sample area of 5x5 pixels in order to fade in/out.
34
+ // Due to the locality, the lookups will be cached
35
+ // This reduces the flicker present when objects are shown/hidden
36
+ const int N = 2;
37
+ float accumulator = 0.0;
38
+ vec2 step = vec2(1.0 / project_uViewportSize);
39
+
40
+ const float floatN = float(N);
41
+ vec2 delta = -floatN * step;
42
+ for(int i = -N; i <= N; i++) {
43
+ delta.x = -step.x * floatN;
44
+ for(int j = -N; j <= N; j++) {
45
+ accumulator += collide_match(texCoords + delta, pickingColor);
46
+ delta.x += step.x;
47
+ }
48
+ delta.y += step.y;
49
+ }
50
+
51
+ float W = 2.0 * floatN + 1.0;
52
+ return pow(accumulator / (W * W), 2.2);
53
+ }
54
+ `;
55
+
56
+ const inject = {
57
+ 'vs:#decl': `
58
+ float collide_fade = 1.0;
59
+ `,
60
+ 'vs:DECKGL_FILTER_GL_POSITION': `
61
+ if (collide_sort) {
62
+ #ifdef NON_INSTANCED_MODEL
63
+ float collidePriority = collidePriorities;
64
+ #else
65
+ float collidePriority = instanceCollidePriorities;
66
+ #endif
67
+ position.z = -0.001 * collidePriority * position.w; // Support range -1000 -> 1000
68
+ }
69
+
70
+ if (collide_enabled) {
71
+ vec4 collide_common_position = project_position(vec4(geometry.worldPosition, 1.0));
72
+ vec2 collide_texCoords = collide_getCoords(collide_common_position);
73
+ collide_fade = collide_isVisible(collide_texCoords, geometry.pickingColor / 255.0);
74
+ if (collide_fade < 0.0001) {
75
+ position = vec4(0.);
76
+ }
77
+ }
78
+ `,
79
+ 'vs:DECKGL_FILTER_COLOR': `
80
+ color.a *= collide_fade;
81
+ `
82
+ };
83
+
84
+ type CollideModuleSettings = {
85
+ collideFBO?: Framebuffer;
86
+ drawToCollideMap?: boolean;
87
+ dummyCollideMap?: Texture2D;
88
+ };
89
+
90
+ /* eslint-disable camelcase */
91
+ type CollideUniforms = {collide_sort?: boolean; collide_texture?: Framebuffer | Texture2D};
92
+
93
+ const getCollideUniforms = (
94
+ opts: CollideModuleSettings | {},
95
+ uniforms: Record<string, any>
96
+ ): CollideUniforms => {
97
+ if (!opts || !('dummyCollideMap' in opts)) {
98
+ return {};
99
+ }
100
+ const {collideFBO, drawToCollideMap, dummyCollideMap} = opts;
101
+ return {
102
+ collide_sort: Boolean(drawToCollideMap),
103
+ collide_texture: !drawToCollideMap && collideFBO ? collideFBO : dummyCollideMap
104
+ };
105
+ };
106
+
107
+ export default {
108
+ name: 'collide',
109
+ dependencies: [project],
110
+ vs,
111
+ inject,
112
+ getUniforms: getCollideUniforms
113
+ } as ShaderModule;