@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.
- package/dist/dist.dev.js +3688 -14538
- package/dist/es5/brushing/brushing.js +0 -8
- package/dist/es5/brushing/brushing.js.map +1 -1
- package/dist/es5/clip/clip.js +5 -5
- package/dist/es5/clip/clip.js.map +1 -1
- package/dist/es5/collide/collide-effect.js +285 -0
- package/dist/es5/collide/collide-effect.js.map +1 -0
- package/dist/es5/collide/collide-pass.js +80 -0
- package/dist/es5/collide/collide-pass.js.map +1 -0
- package/dist/es5/collide/collide.js +116 -0
- package/dist/es5/collide/collide.js.map +1 -0
- package/dist/es5/collide/shader-module.js +39 -0
- package/dist/es5/collide/shader-module.js.map +1 -0
- package/dist/es5/common/projection-utils.js +164 -0
- package/dist/es5/common/projection-utils.js.map +1 -0
- package/dist/es5/data-filter/shader-module.js +1 -0
- package/dist/es5/data-filter/shader-module.js.map +1 -1
- package/dist/es5/fill-style/fill-style.js +16 -125
- package/dist/es5/fill-style/fill-style.js.map +1 -1
- package/dist/es5/fill-style/shaders.glsl.js +6 -8
- package/dist/es5/fill-style/shaders.glsl.js.map +1 -1
- package/dist/es5/fp64/project64.glsl.js +1 -1
- package/dist/es5/index.js +16 -0
- package/dist/es5/index.js.map +1 -1
- package/dist/es5/mask/mask-effect.js +280 -0
- package/dist/es5/mask/mask-effect.js.map +1 -0
- package/dist/es5/mask/mask-pass.js +106 -0
- package/dist/es5/mask/mask-pass.js.map +1 -0
- package/dist/es5/mask/mask.js +17 -4
- package/dist/es5/mask/mask.js.map +1 -1
- package/dist/es5/mask/shader-module.js +1 -1
- package/dist/es5/mask/shader-module.js.map +1 -1
- package/dist/es5/mask/utils.js +136 -0
- package/dist/es5/mask/utils.js.map +1 -0
- package/dist/es5/path-style/shaders.glsl.js +1 -1
- package/dist/es5/terrain/height-map-builder.js +116 -0
- package/dist/es5/terrain/height-map-builder.js.map +1 -0
- package/dist/es5/terrain/shader-module.js +84 -0
- package/dist/es5/terrain/shader-module.js.map +1 -0
- package/dist/es5/terrain/terrain-cover.js +259 -0
- package/dist/es5/terrain/terrain-cover.js.map +1 -0
- package/dist/es5/terrain/terrain-effect.js +337 -0
- package/dist/es5/terrain/terrain-effect.js.map +1 -0
- package/dist/es5/terrain/terrain-pass.js +122 -0
- package/dist/es5/terrain/terrain-pass.js.map +1 -0
- package/dist/es5/terrain/terrain-picking-pass.js +130 -0
- package/dist/es5/terrain/terrain-picking-pass.js.map +1 -0
- package/dist/es5/terrain/terrain.js +101 -0
- package/dist/es5/terrain/terrain.js.map +1 -0
- package/dist/es5/terrain/utils.js +32 -0
- package/dist/es5/terrain/utils.js.map +1 -0
- package/dist/es5/utils/debug.js +71 -0
- package/dist/es5/utils/debug.js.map +1 -0
- package/dist/esm/brushing/brushing.js +0 -7
- package/dist/esm/brushing/brushing.js.map +1 -1
- package/dist/esm/clip/clip.js +5 -4
- package/dist/esm/clip/clip.js.map +1 -1
- package/dist/esm/collide/collide-effect.js +250 -0
- package/dist/esm/collide/collide-effect.js.map +1 -0
- package/dist/esm/collide/collide-pass.js +30 -0
- package/dist/esm/collide/collide-pass.js.map +1 -0
- package/dist/esm/collide/collide.js +78 -0
- package/dist/esm/collide/collide.js.map +1 -0
- package/dist/esm/collide/shader-module.js +32 -0
- package/dist/esm/collide/shader-module.js.map +1 -0
- package/dist/esm/common/projection-utils.js +130 -0
- package/dist/esm/common/projection-utils.js.map +1 -0
- package/dist/esm/data-filter/shader-module.js +1 -0
- package/dist/esm/data-filter/shader-module.js.map +1 -1
- package/dist/esm/fill-style/fill-style.js +20 -72
- package/dist/esm/fill-style/fill-style.js.map +1 -1
- package/dist/esm/fill-style/shaders.glsl.js +5 -7
- package/dist/esm/fill-style/shaders.glsl.js.map +1 -1
- package/dist/esm/fp64/project64.glsl.js +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/mask/mask-effect.js +233 -0
- package/dist/esm/mask/mask-effect.js.map +1 -0
- package/dist/esm/mask/mask-pass.js +62 -0
- package/dist/esm/mask/mask-pass.js.map +1 -0
- package/dist/esm/mask/mask.js +14 -3
- package/dist/esm/mask/mask.js.map +1 -1
- package/dist/esm/mask/shader-module.js +1 -1
- package/dist/esm/mask/shader-module.js.map +1 -1
- package/dist/esm/mask/utils.js +109 -0
- package/dist/esm/mask/utils.js.map +1 -0
- package/dist/esm/path-style/shaders.glsl.js +1 -1
- package/dist/esm/terrain/height-map-builder.js +92 -0
- package/dist/esm/terrain/height-map-builder.js.map +1 -0
- package/dist/esm/terrain/shader-module.js +73 -0
- package/dist/esm/terrain/shader-module.js.map +1 -0
- package/dist/esm/terrain/terrain-cover.js +219 -0
- package/dist/esm/terrain/terrain-cover.js.map +1 -0
- package/dist/esm/terrain/terrain-effect.js +231 -0
- package/dist/esm/terrain/terrain-effect.js.map +1 -0
- package/dist/esm/terrain/terrain-pass.js +69 -0
- package/dist/esm/terrain/terrain-pass.js.map +1 -0
- package/dist/esm/terrain/terrain-picking-pass.js +75 -0
- package/dist/esm/terrain/terrain-picking-pass.js.map +1 -0
- package/dist/esm/terrain/terrain.js +62 -0
- package/dist/esm/terrain/terrain.js.map +1 -0
- package/dist/esm/terrain/utils.js +21 -0
- package/dist/esm/terrain/utils.js.map +1 -0
- package/dist/esm/utils/debug.js +61 -0
- package/dist/esm/utils/debug.js.map +1 -0
- package/dist.min.js +1359 -1
- package/package.json +6 -4
- package/src/brushing/brushing.ts +0 -11
- package/src/clip/clip.ts +6 -5
- package/src/collide/collide-effect.ts +257 -0
- package/src/collide/collide-pass.ts +35 -0
- package/src/collide/collide.ts +79 -0
- package/src/collide/shader-module.ts +113 -0
- package/src/common/projection-utils.ts +187 -0
- package/src/data-filter/shader-module.ts +6 -0
- package/src/fill-style/fill-style.ts +15 -53
- package/src/fill-style/shaders.glsl.ts +6 -7
- package/src/index.ts +4 -0
- package/src/mask/mask-effect.ts +255 -0
- package/src/mask/mask-pass.ts +67 -0
- package/src/mask/mask.ts +17 -7
- package/src/mask/shader-module.ts +7 -1
- package/src/mask/utils.ts +148 -0
- package/src/terrain/height-map-builder.ts +120 -0
- package/src/terrain/shader-module.ts +161 -0
- package/src/terrain/terrain-cover.ts +225 -0
- package/src/terrain/terrain-effect.ts +223 -0
- package/src/terrain/terrain-pass.ts +86 -0
- package/src/terrain/terrain-picking-pass.ts +87 -0
- package/src/terrain/terrain.ts +74 -0
- package/src/terrain/utils.ts +29 -0
- package/src/utils/debug.ts +59 -0
- package/typed/brushing/brushing.d.ts +0 -1
- package/typed/brushing/brushing.d.ts.map +1 -1
- package/typed/brushing/brushing.js +83 -0
- package/typed/brushing/shader-module.js +116 -0
- package/typed/clip/clip.d.ts +1 -1
- package/typed/clip/clip.d.ts.map +1 -1
- package/typed/clip/clip.js +114 -0
- package/typed/collide/collide-effect.d.ts +28 -0
- package/typed/collide/collide-effect.d.ts.map +1 -0
- package/typed/collide/collide-pass.d.ts +14 -0
- package/typed/collide/collide-pass.d.ts.map +1 -0
- package/typed/collide/collide.d.ts +41 -0
- package/typed/collide/collide.d.ts.map +1 -0
- package/typed/collide/shader-module.d.ts +4 -0
- package/typed/collide/shader-module.d.ts.map +1 -0
- package/typed/common/projection-utils.d.ts +27 -0
- package/typed/common/projection-utils.d.ts.map +1 -0
- package/typed/data-filter/aggregator.js +98 -0
- package/typed/data-filter/data-filter.js +159 -0
- package/typed/data-filter/shader-module.d.ts.map +1 -1
- package/typed/data-filter/shader-module.js +152 -0
- package/typed/fill-style/fill-style.d.ts +14 -5
- package/typed/fill-style/fill-style.d.ts.map +1 -1
- package/typed/fill-style/fill-style.js +152 -0
- package/typed/fill-style/shaders.glsl.d.ts.map +1 -1
- package/typed/fill-style/shaders.glsl.js +95 -0
- package/typed/fp64/fp64.js +34 -0
- package/typed/fp64/project64.glsl.js +100 -0
- package/typed/fp64/project64.js +50 -0
- package/typed/index.d.ts +4 -0
- package/typed/index.d.ts.map +1 -1
- package/typed/index.js +9 -0
- package/typed/mask/mask-effect.d.ts +42 -0
- package/typed/mask/mask-effect.d.ts.map +1 -0
- package/typed/mask/mask-pass.d.ts +19 -0
- package/typed/mask/mask-pass.d.ts.map +1 -0
- package/typed/mask/mask.d.ts +9 -3
- package/typed/mask/mask.d.ts.map +1 -1
- package/typed/mask/mask.js +48 -0
- package/typed/mask/shader-module.d.ts.map +1 -1
- package/typed/mask/shader-module.js +73 -0
- package/typed/mask/utils.d.ts +13 -0
- package/typed/mask/utils.d.ts.map +1 -0
- package/typed/path-style/path-style.js +107 -0
- package/typed/path-style/shaders.glsl.js +93 -0
- package/typed/terrain/height-map-builder.d.ts +38 -0
- package/typed/terrain/height-map-builder.d.ts.map +1 -0
- package/typed/terrain/height-map.d.ts +27 -0
- package/typed/terrain/height-map.d.ts.map +1 -0
- package/typed/terrain/shader-module-offset.d.ts +4 -0
- package/typed/terrain/shader-module-offset.d.ts.map +1 -0
- package/typed/terrain/shader-module-source.d.ts +4 -0
- package/typed/terrain/shader-module-source.d.ts.map +1 -0
- package/typed/terrain/shader-module.d.ts +31 -0
- package/typed/terrain/shader-module.d.ts.map +1 -0
- package/typed/terrain/terrain-cover.d.ts +46 -0
- package/typed/terrain/terrain-cover.d.ts.map +1 -0
- package/typed/terrain/terrain-effect.d.ts +29 -0
- package/typed/terrain/terrain-effect.d.ts.map +1 -0
- package/typed/terrain/terrain-pass.d.ts +11 -0
- package/typed/terrain/terrain-pass.d.ts.map +1 -0
- package/typed/terrain/terrain-picking-pass.d.ts +19 -0
- package/typed/terrain/terrain-picking-pass.d.ts.map +1 -0
- package/typed/terrain/terrain.d.ts +21 -0
- package/typed/terrain/terrain.d.ts.map +1 -0
- package/typed/terrain/utils.d.ts +5 -0
- package/typed/terrain/utils.d.ts.map +1 -0
- package/typed/utils/debug.d.ts +6 -0
- 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-
|
|
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": "
|
|
30
|
-
"prepublishOnly": "npm run build-bundle && npm run build-bundle -- --env
|
|
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": "
|
|
43
|
+
"gitHead": "47223d1ea084c3f9b0c9f0f9736682850bb5db85"
|
|
42
44
|
}
|
package/src/brushing/brushing.ts
CHANGED
|
@@ -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 (
|
|
111
|
-
clipByInstance = this.props.clipByInstance
|
|
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
|
|
128
|
-
const {clipBounds
|
|
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;
|