@deck.gl/extensions 8.9.0-beta.2 → 8.9.0-beta.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 (109) hide show
  1. package/dist/dist.dev.js +281 -460
  2. package/dist/es5/{collide/collide-effect.js → collision-filter/collision-filter-effect.js} +79 -72
  3. package/dist/es5/collision-filter/collision-filter-effect.js.map +1 -0
  4. package/dist/es5/{collide/collide-pass.js → collision-filter/collision-filter-pass.js} +13 -13
  5. package/dist/es5/collision-filter/collision-filter-pass.js.map +1 -0
  6. package/dist/es5/{collide/collide.js → collision-filter/collision-filter.js} +30 -30
  7. package/dist/es5/collision-filter/collision-filter.js.map +1 -0
  8. package/dist/es5/collision-filter/shader-module.js +39 -0
  9. package/dist/es5/collision-filter/shader-module.js.map +1 -0
  10. package/dist/es5/data-filter/data-filter.js +1 -1
  11. package/dist/es5/data-filter/data-filter.js.map +1 -1
  12. package/dist/es5/index.js +4 -4
  13. package/dist/es5/index.js.map +1 -1
  14. package/dist/es5/mask/mask-effect.js +17 -8
  15. package/dist/es5/mask/mask-effect.js.map +1 -1
  16. package/dist/es5/terrain/height-map-builder.js +1 -1
  17. package/dist/es5/terrain/height-map-builder.js.map +1 -1
  18. package/dist/es5/terrain/shader-module.js.map +1 -1
  19. package/dist/es5/terrain/terrain-cover.js +1 -1
  20. package/dist/es5/terrain/terrain-cover.js.map +1 -1
  21. package/dist/es5/terrain/terrain-effect.js +5 -5
  22. package/dist/es5/terrain/terrain-effect.js.map +1 -1
  23. package/dist/es5/terrain/terrain.js +7 -7
  24. package/dist/es5/terrain/terrain.js.map +1 -1
  25. package/dist/es5/{common → utils}/projection-utils.js +3 -1
  26. package/dist/es5/utils/projection-utils.js.map +1 -0
  27. package/dist/esm/{collide/collide-effect.js → collision-filter/collision-filter-effect.js} +69 -64
  28. package/dist/esm/collision-filter/collision-filter-effect.js.map +1 -0
  29. package/dist/esm/{collide/collide-pass.js → collision-filter/collision-filter-pass.js} +5 -5
  30. package/dist/esm/collision-filter/collision-filter-pass.js.map +1 -0
  31. package/dist/esm/collision-filter/collision-filter.js +78 -0
  32. package/dist/esm/collision-filter/collision-filter.js.map +1 -0
  33. package/dist/esm/collision-filter/shader-module.js +32 -0
  34. package/dist/esm/collision-filter/shader-module.js.map +1 -0
  35. package/dist/esm/data-filter/data-filter.js +1 -1
  36. package/dist/esm/data-filter/data-filter.js.map +1 -1
  37. package/dist/esm/index.js +2 -2
  38. package/dist/esm/index.js.map +1 -1
  39. package/dist/esm/mask/mask-effect.js +14 -8
  40. package/dist/esm/mask/mask-effect.js.map +1 -1
  41. package/dist/esm/terrain/height-map-builder.js +1 -1
  42. package/dist/esm/terrain/height-map-builder.js.map +1 -1
  43. package/dist/esm/terrain/shader-module.js.map +1 -1
  44. package/dist/esm/terrain/terrain-cover.js +1 -1
  45. package/dist/esm/terrain/terrain-cover.js.map +1 -1
  46. package/dist/esm/terrain/terrain-effect.js +5 -5
  47. package/dist/esm/terrain/terrain-effect.js.map +1 -1
  48. package/dist/esm/terrain/terrain.js +7 -7
  49. package/dist/esm/terrain/terrain.js.map +1 -1
  50. package/dist/esm/{common → utils}/projection-utils.js +3 -1
  51. package/dist/esm/utils/projection-utils.js.map +1 -0
  52. package/dist.min.js +59 -62
  53. package/package.json +2 -2
  54. package/src/{collide/collide-effect.ts → collision-filter/collision-filter-effect.ts} +81 -78
  55. package/src/{collide/collide-pass.ts → collision-filter/collision-filter-pass.ts} +6 -6
  56. package/src/collision-filter/collision-filter.ts +83 -0
  57. package/src/collision-filter/shader-module.ts +113 -0
  58. package/src/data-filter/data-filter.ts +1 -1
  59. package/src/index.ts +3 -3
  60. package/src/mask/mask-effect.ts +32 -13
  61. package/src/terrain/height-map-builder.ts +2 -2
  62. package/src/terrain/shader-module.ts +4 -1
  63. package/src/terrain/terrain-cover.ts +2 -2
  64. package/src/terrain/terrain-effect.ts +5 -5
  65. package/src/terrain/terrain.ts +10 -10
  66. package/src/{common → utils}/projection-utils.ts +4 -2
  67. package/typed/collision-filter/collision-filter-effect.d.ts +28 -0
  68. package/typed/collision-filter/collision-filter-effect.d.ts.map +1 -0
  69. package/typed/collision-filter/collision-filter-pass.d.ts +14 -0
  70. package/typed/collision-filter/collision-filter-pass.d.ts.map +1 -0
  71. package/typed/collision-filter/collision-filter.d.ts +41 -0
  72. package/typed/collision-filter/collision-filter.d.ts.map +1 -0
  73. package/typed/collision-filter/shader-module.d.ts +4 -0
  74. package/typed/collision-filter/shader-module.d.ts.map +1 -0
  75. package/typed/data-filter/data-filter.d.ts +1 -1
  76. package/typed/index.d.ts +3 -3
  77. package/typed/index.d.ts.map +1 -1
  78. package/typed/mask/mask-effect.d.ts +2 -2
  79. package/typed/mask/mask-effect.d.ts.map +1 -1
  80. package/typed/terrain/height-map-builder.d.ts +2 -2
  81. package/typed/terrain/height-map-builder.d.ts.map +1 -1
  82. package/typed/terrain/shader-module.d.ts +1 -1
  83. package/typed/terrain/shader-module.d.ts.map +1 -1
  84. package/typed/terrain/terrain-cover.d.ts +2 -2
  85. package/typed/terrain/terrain-cover.d.ts.map +1 -1
  86. package/typed/terrain/terrain.d.ts +2 -2
  87. package/typed/terrain/terrain.d.ts.map +1 -1
  88. package/typed/utils/projection-utils.d.ts +27 -0
  89. package/typed/utils/projection-utils.d.ts.map +1 -0
  90. package/dist/es5/collide/collide-effect.js.map +0 -1
  91. package/dist/es5/collide/collide-pass.js.map +0 -1
  92. package/dist/es5/collide/collide.js.map +0 -1
  93. package/dist/es5/collide/shader-module.js +0 -39
  94. package/dist/es5/collide/shader-module.js.map +0 -1
  95. package/dist/es5/common/projection-utils.js.map +0 -1
  96. package/dist/es5/mask/utils.js +0 -136
  97. package/dist/es5/mask/utils.js.map +0 -1
  98. package/dist/esm/collide/collide-effect.js.map +0 -1
  99. package/dist/esm/collide/collide-pass.js.map +0 -1
  100. package/dist/esm/collide/collide.js +0 -78
  101. package/dist/esm/collide/collide.js.map +0 -1
  102. package/dist/esm/collide/shader-module.js +0 -32
  103. package/dist/esm/collide/shader-module.js.map +0 -1
  104. package/dist/esm/common/projection-utils.js.map +0 -1
  105. package/dist/esm/mask/utils.js +0 -109
  106. package/dist/esm/mask/utils.js.map +0 -1
  107. package/src/collide/collide.ts +0 -79
  108. package/src/collide/shader-module.ts +0 -113
  109. package/src/mask/utils.ts +0 -148
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-beta.2",
5
+ "version": "8.9.0-beta.4",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
@@ -40,5 +40,5 @@
40
40
  "@math.gl/web-mercator": "^3.6.2",
41
41
  "gl-matrix": "^3.0.0"
42
42
  },
43
- "gitHead": "5dae086e4f3eb46c30d8e761f9d600be4f68e949"
43
+ "gitHead": "f7c0eeaed1e62b0ae44ee45136b444f647e6cbd9"
44
44
  }
@@ -2,35 +2,35 @@ import {Framebuffer, Renderbuffer, Texture2D, cssToDeviceRatio} from '@luma.gl/c
2
2
  import {equals} from '@math.gl/core';
3
3
  import {_deepEqual as deepEqual} from '@deck.gl/core';
4
4
  import type {Effect, Layer, PreRenderOptions, Viewport} from '@deck.gl/core';
5
- import CollidePass from './collide-pass';
5
+ import CollisionFilterPass from './collision-filter-pass';
6
6
  import MaskEffect, {MaskPreRenderStats} from '../mask/mask-effect';
7
7
  // import {debugFBO} from '../utils/debug';
8
8
 
9
- type CollideExtensionProps = {
10
- collideTestProps?: {};
11
- collideGroup: string;
9
+ type CollisionFilterExtensionProps = {
10
+ collisionTestProps?: {};
11
+ collisionGroup: string;
12
12
  };
13
13
 
14
- // Factor by which to downscale Collide FBO relative to canvas
14
+ // Factor by which to downscale Collision FBO relative to canvas
15
15
  const DOWNSCALE = 2;
16
16
 
17
17
  type RenderInfo = {
18
- collideGroup: string;
19
- layers: Layer<CollideExtensionProps>[];
18
+ collisionGroup: string;
19
+ layers: Layer<CollisionFilterExtensionProps>[];
20
20
  layerBounds: ([number[], number[]] | null)[];
21
+ allLayersLoaded: boolean;
21
22
  };
22
23
 
23
- // Class to manage collide effect
24
- export default class CollideEffect implements Effect {
25
- id = 'collide-effect';
24
+ export default class CollisionFilterEffect implements Effect {
25
+ id = 'collision-filter-effect';
26
26
  props = null;
27
27
  useInPicking = true;
28
28
  order = 1;
29
29
 
30
30
  private channels: Record<string, RenderInfo> = {};
31
- private collidePass?: CollidePass;
32
- private collideFBOs: Record<string, Framebuffer> = {};
33
- private dummyCollideMap?: Texture2D;
31
+ private collisionFilterPass?: CollisionFilterPass;
32
+ private collisionFBOs: Record<string, Framebuffer> = {};
33
+ private dummyCollisionMap?: Texture2D;
34
34
  private lastViewport?: Viewport;
35
35
 
36
36
  preRender(
@@ -46,8 +46,8 @@ export default class CollideEffect implements Effect {
46
46
  preRenderStats = {}
47
47
  }: PreRenderOptions
48
48
  ): void {
49
- if (!this.dummyCollideMap) {
50
- this.dummyCollideMap = new Texture2D(gl, {width: 1, height: 1});
49
+ if (!this.dummyCollisionMap) {
50
+ this.dummyCollisionMap = new Texture2D(gl, {width: 1, height: 1});
51
51
  }
52
52
 
53
53
  if (isPicking) {
@@ -55,17 +55,17 @@ export default class CollideEffect implements Effect {
55
55
  return;
56
56
  }
57
57
 
58
- const collideLayers = layers.filter(
58
+ const collisionLayers = layers.filter(
59
59
  // @ts-ignore
60
- ({props: {visible, collideEnabled}}) => visible && collideEnabled
61
- ) as Layer<CollideExtensionProps>[];
62
- if (collideLayers.length === 0) {
60
+ ({props: {visible, collisionEnabled}}) => visible && collisionEnabled
61
+ ) as Layer<CollisionFilterExtensionProps>[];
62
+ if (collisionLayers.length === 0) {
63
63
  this.channels = {};
64
64
  return;
65
65
  }
66
66
 
67
- if (!this.collidePass) {
68
- this.collidePass = new CollidePass(gl, {id: 'default-collide'});
67
+ if (!this.collisionFilterPass) {
68
+ this.collisionFilterPass = new CollisionFilterPass(gl, {id: 'default-collision-filter'});
69
69
  }
70
70
 
71
71
  // Detect if mask has rendered. TODO: better dependency system for Effects
@@ -73,17 +73,17 @@ export default class CollideEffect implements Effect {
73
73
  const maskEffectRendered = (preRenderStats['mask-effect'] as MaskPreRenderStats)?.didRender;
74
74
 
75
75
  // Collect layers to render
76
- const channels = this._groupByCollideGroup(gl, collideLayers);
76
+ const channels = this._groupByCollisionGroup(gl, collisionLayers);
77
77
 
78
78
  const viewport = viewports[0];
79
79
  const viewportChanged =
80
80
  !this.lastViewport || !this.lastViewport.equals(viewport) || maskEffectRendered;
81
81
 
82
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({
83
+ for (const collisionGroup in channels) {
84
+ const collisionFBO = this.collisionFBOs[collisionGroup];
85
+ const renderInfo = channels[collisionGroup];
86
+ collisionFBO.resize({
87
87
  width: gl.canvas.width / DOWNSCALE,
88
88
  height: gl.canvas.height / DOWNSCALE
89
89
  });
@@ -97,7 +97,7 @@ export default class CollideEffect implements Effect {
97
97
  });
98
98
  }
99
99
 
100
- // debugFBO(this.collideFBOs[Object.keys(channels)[0]], {minimap: true});
100
+ // debugFBO(this.collisionFBOs[Object.keys(channels)[0]], {minimap: true});
101
101
  }
102
102
 
103
103
  private _render(
@@ -118,8 +118,8 @@ export default class CollideEffect implements Effect {
118
118
  viewportChanged: boolean;
119
119
  }
120
120
  ) {
121
- const {collideGroup} = renderInfo;
122
- const oldRenderInfo = this.channels[collideGroup];
121
+ const {collisionGroup} = renderInfo;
122
+ const oldRenderInfo = this.channels[collisionGroup];
123
123
  if (!oldRenderInfo) {
124
124
  return;
125
125
  }
@@ -129,19 +129,23 @@ export default class CollideEffect implements Effect {
129
129
  // If render info is new
130
130
  renderInfo === oldRenderInfo ||
131
131
  // If sublayers have changed
132
- !deepEqual(oldRenderInfo.layers, renderInfo.layers, 0) ||
132
+ !deepEqual(oldRenderInfo.layers, renderInfo.layers, 1) ||
133
133
  // If a sublayer's bounds have been updated
134
- renderInfo.layerBounds.some((b, i) => !equals(b, oldRenderInfo.layerBounds[i]));
134
+ renderInfo.layerBounds.some((b, i) => !equals(b, oldRenderInfo.layerBounds[i])) ||
135
+ // If a sublayer's isLoaded state has been updated
136
+ renderInfo.allLayersLoaded !== oldRenderInfo.allLayersLoaded ||
137
+ // Some prop is in transition
138
+ renderInfo.layers.some(layer => layer.props.transitions);
135
139
 
136
- this.channels[collideGroup] = renderInfo;
140
+ this.channels[collisionGroup] = renderInfo;
137
141
 
138
142
  if (needsRender) {
139
143
  this.lastViewport = viewport;
140
- const collideFBO = this.collideFBOs[collideGroup];
144
+ const collisionFBO = this.collisionFBOs[collisionGroup];
141
145
 
142
- // Rerender collide FBO
143
- this.collidePass!.renderCollideMap(collideFBO, {
144
- pass: 'collide',
146
+ // Rerender collision FBO
147
+ this.collisionFilterPass!.renderCollisionMap(collisionFBO, {
148
+ pass: 'collision-filter',
145
149
  isPicking: true,
146
150
  layers: renderInfo.layers,
147
151
  effects,
@@ -151,49 +155,48 @@ export default class CollideEffect implements Effect {
151
155
  views,
152
156
  moduleParameters: {
153
157
  // To avoid feedback loop forming between Framebuffer and active Texture.
154
- dummyCollideMap: this.dummyCollideMap,
155
- devicePixelRatio: cssToDeviceRatio(collideFBO.gl) / DOWNSCALE
158
+ dummyCollisionMap: this.dummyCollisionMap,
159
+ devicePixelRatio: cssToDeviceRatio(collisionFBO.gl) / DOWNSCALE
156
160
  }
157
161
  });
158
162
  }
159
163
  }
160
164
 
161
165
  /**
162
- * Group layers by collideGroup
163
- * Returns a map from collideGroup to render info
166
+ * Group layers by collisionGroup
167
+ * Returns a map from collisionGroup to render info
164
168
  */
165
- private _groupByCollideGroup(
169
+ private _groupByCollisionGroup(
166
170
  gl: WebGLRenderingContext,
167
- collideLayers: Layer<CollideExtensionProps>[]
171
+ collisionLayers: Layer<CollisionFilterExtensionProps>[]
168
172
  ): Record<string, RenderInfo> {
169
173
  const channelMap = {};
170
- for (const layer of collideLayers) {
171
- const {collideGroup} = layer.props;
172
- let channelInfo = channelMap[collideGroup];
174
+ for (const layer of collisionLayers) {
175
+ const {collisionGroup} = layer.props;
176
+ let channelInfo = channelMap[collisionGroup];
173
177
  if (!channelInfo) {
174
- channelInfo = {
175
- collideGroup,
176
- layers: [],
177
- layerBounds: []
178
- };
179
- channelMap[collideGroup] = channelInfo;
178
+ channelInfo = {collisionGroup, layers: [], layerBounds: [], allLayersLoaded: true};
179
+ channelMap[collisionGroup] = channelInfo;
180
180
  }
181
181
  channelInfo.layers.push(layer);
182
182
  channelInfo.layerBounds.push(layer.getBounds());
183
+ if (!layer.isLoaded) {
184
+ channelInfo.allLayersLoaded = false;
185
+ }
183
186
  }
184
187
 
185
188
  // Create any new passes and remove any old ones
186
- for (const collideGroup of Object.keys(channelMap)) {
187
- if (!this.collideFBOs[collideGroup]) {
188
- this.createFBO(gl, collideGroup);
189
+ for (const collisionGroup of Object.keys(channelMap)) {
190
+ if (!this.collisionFBOs[collisionGroup]) {
191
+ this.createFBO(gl, collisionGroup);
189
192
  }
190
- if (!this.channels[collideGroup]) {
191
- this.channels[collideGroup] = channelMap[collideGroup];
193
+ if (!this.channels[collisionGroup]) {
194
+ this.channels[collisionGroup] = channelMap[collisionGroup];
192
195
  }
193
196
  }
194
- for (const collideGroup of Object.keys(this.collideFBOs)) {
195
- if (!channelMap[collideGroup]) {
196
- this.destroyFBO(collideGroup);
197
+ for (const collisionGroup of Object.keys(this.collisionFBOs)) {
198
+ if (!channelMap[collisionGroup]) {
199
+ this.destroyFBO(collisionGroup);
197
200
  }
198
201
  }
199
202
 
@@ -201,30 +204,30 @@ export default class CollideEffect implements Effect {
201
204
  }
202
205
 
203
206
  getModuleParameters(layer: Layer): {
204
- collideFBO: Framebuffer;
205
- dummyCollideMap: Texture2D;
207
+ collisionFBO: Framebuffer;
208
+ dummyCollisionMap: Texture2D;
206
209
  } {
207
- const {collideGroup} = (layer as Layer<CollideExtensionProps>).props;
208
- const {collideFBOs, dummyCollideMap} = this;
209
- return {collideFBO: collideFBOs[collideGroup], dummyCollideMap};
210
+ const {collisionGroup} = (layer as Layer<CollisionFilterExtensionProps>).props;
211
+ const {collisionFBOs, dummyCollisionMap} = this;
212
+ return {collisionFBO: collisionFBOs[collisionGroup], dummyCollisionMap};
210
213
  }
211
214
 
212
215
  cleanup(): void {
213
- if (this.dummyCollideMap) {
214
- this.dummyCollideMap.delete();
215
- this.dummyCollideMap = undefined;
216
+ if (this.dummyCollisionMap) {
217
+ this.dummyCollisionMap.delete();
218
+ this.dummyCollisionMap = undefined;
216
219
  }
217
220
  this.channels = {};
218
- for (const collideGroup of Object.keys(this.collideFBOs)) {
219
- this.destroyFBO(collideGroup);
221
+ for (const collisionGroup of Object.keys(this.collisionFBOs)) {
222
+ this.destroyFBO(collisionGroup);
220
223
  }
221
- this.collideFBOs = {};
224
+ this.collisionFBOs = {};
222
225
  this.lastViewport = undefined;
223
226
  }
224
227
 
225
- createFBO(gl: WebGLRenderingContext, collideGroup: string) {
228
+ createFBO(gl: WebGLRenderingContext, collisionGroup: string) {
226
229
  const {width, height} = gl.canvas;
227
- const collideMap = new Texture2D(gl, {
230
+ const collisionMap = new Texture2D(gl, {
228
231
  width,
229
232
  height,
230
233
  parameters: {
@@ -236,23 +239,23 @@ export default class CollideEffect implements Effect {
236
239
  });
237
240
 
238
241
  const depthBuffer = new Renderbuffer(gl, {format: gl.DEPTH_COMPONENT16, width, height});
239
- this.collideFBOs[collideGroup] = new Framebuffer(gl, {
240
- id: `Collide-${collideGroup}`,
242
+ this.collisionFBOs[collisionGroup] = new Framebuffer(gl, {
243
+ id: `Collision-${collisionGroup}`,
241
244
  width,
242
245
  height,
243
246
  attachments: {
244
- [gl.COLOR_ATTACHMENT0]: collideMap,
247
+ [gl.COLOR_ATTACHMENT0]: collisionMap,
245
248
  [gl.DEPTH_ATTACHMENT]: depthBuffer
246
249
  }
247
250
  });
248
251
  }
249
252
 
250
- destroyFBO(collideGroup: string) {
251
- const fbo = this.collideFBOs[collideGroup];
253
+ destroyFBO(collisionGroup: string) {
254
+ const fbo = this.collisionFBOs[collisionGroup];
252
255
  for (const attachment of Object.values(fbo.attachments as Texture2D[])) {
253
256
  attachment.delete();
254
257
  }
255
258
  fbo.delete();
256
- delete this.collideFBOs[collideGroup];
259
+ delete this.collisionFBOs[collisionGroup];
257
260
  }
258
261
  }
@@ -1,10 +1,10 @@
1
1
  import {Framebuffer, withParameters} from '@luma.gl/core';
2
2
  import {_LayersPass as LayersPass, LayersPassRenderOptions} from '@deck.gl/core';
3
3
 
4
- type CollidePassRenderOptions = LayersPassRenderOptions & {};
4
+ type CollisionFilterPassRenderOptions = LayersPassRenderOptions & {};
5
5
 
6
- export default class CollidePass extends LayersPass {
7
- renderCollideMap(target: Framebuffer, options: CollidePassRenderOptions) {
6
+ export default class CollisionFilterPass extends LayersPass {
7
+ renderCollisionMap(target: Framebuffer, options: CollisionFilterPassRenderOptions) {
8
8
  const gl = this.gl;
9
9
 
10
10
  const padding = 1;
@@ -19,14 +19,14 @@ export default class CollidePass extends LayersPass {
19
19
  depthTest: true,
20
20
  depthRange: [0, 1]
21
21
  },
22
- () => this.render({...options, target, pass: 'collide'})
22
+ () => this.render({...options, target, pass: 'collision'})
23
23
  );
24
24
  }
25
25
 
26
26
  getModuleParameters() {
27
- // Draw picking colors into collide FBO
27
+ // Draw picking colors into collision FBO
28
28
  return {
29
- drawToCollideMap: true,
29
+ drawToCollisionMap: true,
30
30
  pickingActive: 1,
31
31
  pickingAttribute: false,
32
32
  lightSources: {}
@@ -0,0 +1,83 @@
1
+ import {Accessor, Layer, LayerContext, LayerExtension} from '@deck.gl/core';
2
+ import collision from './shader-module';
3
+ import CollisionFilterEffect from './collision-filter-effect';
4
+
5
+ const defaultProps = {
6
+ getCollisionPriority: {type: 'accessor', value: 0},
7
+ collisionEnabled: true,
8
+ collisionGroup: {type: 'string', value: 'default'},
9
+ collisionTestProps: {}
10
+ };
11
+
12
+ export type CollisionFilterExtensionProps<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
+ getCollisionPriority?: Accessor<DataT, number>;
17
+
18
+ /**
19
+ * Enable/disable collisions. If collisions are disabled, all objects are rendered.
20
+ * @default true
21
+ */
22
+ collisionEnabled: boolean;
23
+
24
+ /**
25
+ * Collision group this layer belongs to. If it is not set, the 'default' collision group is used
26
+ */
27
+ collisionGroup?: string;
28
+
29
+ /**
30
+ * Props to override when rendering collision map
31
+ */
32
+ collisionTestProps?: {};
33
+ };
34
+
35
+ /** Allows layers to hide overlapping objects. */
36
+ export default class CollisionFilterExtension extends LayerExtension {
37
+ static defaultProps = defaultProps;
38
+ static extensionName = 'CollisionFilterExtension';
39
+
40
+ getShaders(this: Layer<CollisionFilterExtensionProps>): any {
41
+ return {modules: [collision]};
42
+ }
43
+
44
+ /* eslint-disable camelcase */
45
+ draw(this: Layer<CollisionFilterExtensionProps>, {uniforms, context, moduleParameters}: any) {
46
+ const {collisionEnabled} = this.props;
47
+ const {collisionFBO, drawToCollisionMap} = moduleParameters;
48
+ const enabled = collisionEnabled && Boolean(collisionFBO);
49
+ uniforms.collision_enabled = enabled;
50
+
51
+ if (drawToCollisionMap) {
52
+ // Override any props with those defined in collisionTestProps
53
+ // @ts-ignore
54
+ this.props = this.clone(this.props.collisionTestProps).props;
55
+ }
56
+ }
57
+
58
+ initializeState(
59
+ this: Layer<CollisionFilterExtensionProps>,
60
+ context: LayerContext,
61
+ extension: this
62
+ ) {
63
+ if (this.getAttributeManager() === null) {
64
+ return;
65
+ }
66
+ this.context.deck?._addDefaultEffect(new CollisionFilterEffect());
67
+ const attributeManager = this.getAttributeManager();
68
+ attributeManager!.add({
69
+ collisionPriorities: {
70
+ size: 1,
71
+ accessor: 'getCollisionPriority',
72
+ shaderAttributes: {
73
+ collisionPriorities: {divisor: 0},
74
+ instanceCollisionPriorities: {divisor: 1}
75
+ }
76
+ }
77
+ });
78
+ }
79
+
80
+ getNeedsPickingBuffer(this: Layer<CollisionFilterExtensionProps>): boolean {
81
+ return this.props.collisionEnabled;
82
+ }
83
+ }
@@ -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 collisionPriorities;
8
+ #else
9
+ attribute float instanceCollisionPriorities;
10
+ #endif
11
+
12
+ uniform sampler2D collision_texture;
13
+ uniform bool collision_sort;
14
+ uniform bool collision_enabled;
15
+
16
+ vec2 collision_getCoords(vec4 position) {
17
+ vec4 collision_clipspace = project_common_position_to_clipspace(position);
18
+ return (1.0 + collision_clipspace.xy / collision_clipspace.w) / 2.0;
19
+ }
20
+
21
+ float collision_match(vec2 tex, vec3 pickingColor) {
22
+ vec4 collision_pickingColor = texture2D(collision_texture, tex);
23
+ float delta = dot(abs(collision_pickingColor.rgb - pickingColor), vec3(1.0));
24
+ float e = 0.001;
25
+ return step(delta, e);
26
+ }
27
+
28
+ float collision_isVisible(vec2 texCoords, vec3 pickingColor) {
29
+ if (!collision_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 += collision_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 collision_fade = 1.0;
59
+ `,
60
+ 'vs:DECKGL_FILTER_GL_POSITION': `
61
+ if (collision_sort) {
62
+ #ifdef NON_INSTANCED_MODEL
63
+ float collisionPriority = collisionPriorities;
64
+ #else
65
+ float collisionPriority = instanceCollisionPriorities;
66
+ #endif
67
+ position.z = -0.001 * collisionPriority * position.w; // Support range -1000 -> 1000
68
+ }
69
+
70
+ if (collision_enabled) {
71
+ vec4 collision_common_position = project_position(vec4(geometry.worldPosition, 1.0));
72
+ vec2 collision_texCoords = collision_getCoords(collision_common_position);
73
+ collision_fade = collision_isVisible(collision_texCoords, geometry.pickingColor / 255.0);
74
+ if (collision_fade < 0.0001) {
75
+ position = vec4(0.);
76
+ }
77
+ }
78
+ `,
79
+ 'vs:DECKGL_FILTER_COLOR': `
80
+ color.a *= collision_fade;
81
+ `
82
+ };
83
+
84
+ type CollisionModuleSettings = {
85
+ collisionFBO?: Framebuffer;
86
+ drawToCollisionMap?: boolean;
87
+ dummyCollisionMap?: Texture2D;
88
+ };
89
+
90
+ /* eslint-disable camelcase */
91
+ type CollisionUniforms = {collision_sort?: boolean; collision_texture?: Framebuffer | Texture2D};
92
+
93
+ const getCollisionUniforms = (
94
+ opts: CollisionModuleSettings | {},
95
+ uniforms: Record<string, any>
96
+ ): CollisionUniforms => {
97
+ if (!opts || !('dummyCollisionMap' in opts)) {
98
+ return {};
99
+ }
100
+ const {collisionFBO, drawToCollisionMap, dummyCollisionMap} = opts;
101
+ return {
102
+ collision_sort: Boolean(drawToCollisionMap),
103
+ collision_texture: !drawToCollisionMap && collisionFBO ? collisionFBO : dummyCollisionMap
104
+ };
105
+ };
106
+
107
+ export default {
108
+ name: 'collision',
109
+ dependencies: [project],
110
+ vs,
111
+ inject,
112
+ getUniforms: getCollisionUniforms
113
+ } as ShaderModule;
@@ -28,7 +28,7 @@ import type {Layer, LayerContext, Accessor, UpdateParameters} from '@deck.gl/cor
28
28
 
29
29
  const defaultProps = {
30
30
  getFilterValue: {type: 'accessor', value: 0},
31
- onFilteredItemsChange: {type: 'function', value: null, compare: false},
31
+ onFilteredItemsChange: {type: 'function', value: null, optional: true},
32
32
 
33
33
  filterEnabled: true,
34
34
  filterRange: [-1, 1],
package/src/index.ts CHANGED
@@ -4,9 +4,9 @@ export {default as Fp64Extension} from './fp64/fp64';
4
4
  export {default as PathStyleExtension} from './path-style/path-style';
5
5
  export {default as FillStyleExtension} from './fill-style/fill-style';
6
6
  export {default as ClipExtension} from './clip/clip';
7
- export {default as CollideExtension} from './collide/collide';
7
+ export {default as CollisionFilterExtension} from './collision-filter/collision-filter';
8
8
  export {default as MaskExtension} from './mask/mask';
9
- export {default as TerrainExtension} from './terrain/terrain';
9
+ export {default as _TerrainExtension} from './terrain/terrain';
10
10
 
11
11
  // Shader module
12
12
  export {default as project64} from './fp64/project64';
@@ -17,6 +17,6 @@ export type {DataFilterExtensionProps} from './data-filter/data-filter';
17
17
  export type {PathStyleExtensionProps} from './path-style/path-style';
18
18
  export type {FillStyleExtensionProps} from './fill-style/fill-style';
19
19
  export type {ClipExtensionProps} from './clip/clip';
20
- export type {CollideExtensionProps} from './collide/collide';
20
+ export type {CollisionFilterExtensionProps} from './collision-filter/collision-filter';
21
21
  export type {MaskExtensionProps} from './mask/mask';
22
22
  export type {TerrainExtensionProps} from './terrain/terrain';
@@ -2,13 +2,13 @@ import {Layer, Viewport, Effect, PreRenderOptions, CoordinateSystem, log} from '
2
2
  import {Texture2D} from '@luma.gl/core';
3
3
  import {equals} from '@math.gl/core';
4
4
  import MaskPass from './mask-pass';
5
- import {getMaskBounds, getMaskViewport, MaskBounds} from './utils';
5
+ import {joinLayerBounds, getRenderBounds, makeViewport, Bounds} from '../utils/projection-utils';
6
6
  // import {debugFBO} from '../utils/debug';
7
7
 
8
8
  type Mask = {
9
9
  /** The channel index */
10
10
  index: number;
11
- bounds: MaskBounds;
11
+ bounds: Bounds;
12
12
  coordinateOrigin: [number, number, number];
13
13
  coordinateSystem: CoordinateSystem;
14
14
  };
@@ -17,9 +17,9 @@ type Channel = {
17
17
  id: string;
18
18
  index: number;
19
19
  layers: Layer[];
20
- bounds: MaskBounds;
21
- maskBounds: MaskBounds;
22
- layerBounds: MaskBounds[];
20
+ bounds: Bounds | null;
21
+ maskBounds: Bounds;
22
+ layerBounds: Bounds[];
23
23
  coordinateOrigin: [number, number, number];
24
24
  coordinateSystem: CoordinateSystem;
25
25
  };
@@ -78,6 +78,11 @@ export default class MaskEffect implements Effect {
78
78
  const viewport = viewports[0];
79
79
  const viewportChanged = !this.lastViewport || !this.lastViewport.equals(viewport);
80
80
 
81
+ if (viewport.resolution !== undefined) {
82
+ log.warn('MaskExtension is not supported in GlobeView')();
83
+ return {didRender};
84
+ }
85
+
81
86
  for (const maskId in channelMap) {
82
87
  const result = this._renderChannel(channelMap[maskId], {
83
88
  layerFilter,
@@ -119,7 +124,17 @@ export default class MaskEffect implements Effect {
119
124
  // If a channel is new
120
125
  channelInfo === oldChannelInfo ||
121
126
  // If sublayers have changed
122
- oldChannelInfo.layers.length !== channelInfo.layers.length ||
127
+ channelInfo.layers.length !== oldChannelInfo.layers.length ||
128
+ channelInfo.layers.some(
129
+ (layer, i) =>
130
+ // Layer instance is updated
131
+ // Layer props might have changed
132
+ // Undetermined props could have an effect on the output geometry of a mask layer,
133
+ // for example getRadius+updateTriggers, radiusScale, modelMatrix
134
+ layer !== oldChannelInfo.layers[i] ||
135
+ // Some prop is in transition
136
+ layer.props.transitions
137
+ ) ||
123
138
  // If a sublayer's positions have been updated, the cached bounds will change shallowly
124
139
  channelInfo.layerBounds.some((b, i) => b !== oldChannelInfo.layerBounds[i]);
125
140
 
@@ -131,18 +146,22 @@ export default class MaskEffect implements Effect {
131
146
  // Recalculate mask bounds
132
147
  this.lastViewport = viewport;
133
148
 
134
- channelInfo.bounds = getMaskBounds({layers: channelInfo.layers, viewport});
149
+ const layerBounds = joinLayerBounds(channelInfo.layers, viewport);
150
+ channelInfo.bounds = layerBounds && getRenderBounds(layerBounds, viewport);
135
151
 
136
152
  if (maskChanged || !equals(channelInfo.bounds, oldChannelInfo.bounds)) {
137
153
  // Rerender mask FBO
138
154
  const {maskPass, maskMap} = this;
139
155
 
140
- const maskViewport = getMaskViewport({
141
- bounds: channelInfo.bounds,
142
- viewport,
143
- width: maskMap.width,
144
- height: maskMap.height
145
- });
156
+ const maskViewport =
157
+ layerBounds &&
158
+ makeViewport({
159
+ bounds: channelInfo.bounds!,
160
+ viewport,
161
+ width: maskMap.width,
162
+ height: maskMap.height,
163
+ border: 1
164
+ });
146
165
 
147
166
  channelInfo.maskBounds = maskViewport ? maskViewport.getBounds() : [0, 0, 1, 1];
148
167