@deck.gl/extensions 8.9.0-alpha.5 → 8.9.0-beta.2
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 +286 -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 +251 -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 +230 -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 +7 -6
- package/src/collide/collide-effect.ts +258 -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 +7 -1
- 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 +222 -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 +5 -2
- 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
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import {WebMercatorViewport, OrthographicViewport} from '@deck.gl/core';
|
|
2
|
+
import type {Layer, Viewport} from '@deck.gl/core';
|
|
3
|
+
|
|
4
|
+
/** Bounds in CARTESIAN coordinates */
|
|
5
|
+
export type Bounds = [minX: number, minY: number, maxX: number, maxY: number];
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* Compute the union of bounds from multiple layers
|
|
9
|
+
* Returns bounds in CARTESIAN coordinates
|
|
10
|
+
*/
|
|
11
|
+
export function joinLayerBounds(
|
|
12
|
+
/** The layers to combine */
|
|
13
|
+
layers: Layer[],
|
|
14
|
+
/** A Viewport instance that is used to determine the type of the view */
|
|
15
|
+
viewport: Viewport
|
|
16
|
+
): Bounds | null {
|
|
17
|
+
// Join the bounds of layer data
|
|
18
|
+
const bounds: Bounds = [Infinity, Infinity, -Infinity, -Infinity];
|
|
19
|
+
for (const layer of layers) {
|
|
20
|
+
const layerBounds = layer.getBounds();
|
|
21
|
+
if (layerBounds) {
|
|
22
|
+
const bottomLeftCommon = layer.projectPosition(layerBounds[0], {viewport, autoOffset: false});
|
|
23
|
+
const topRightCommon = layer.projectPosition(layerBounds[1], {viewport, autoOffset: false});
|
|
24
|
+
|
|
25
|
+
bounds[0] = Math.min(bounds[0], bottomLeftCommon[0]);
|
|
26
|
+
bounds[1] = Math.min(bounds[1], bottomLeftCommon[1]);
|
|
27
|
+
bounds[2] = Math.max(bounds[2], topRightCommon[0]);
|
|
28
|
+
bounds[3] = Math.max(bounds[3], topRightCommon[1]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (Number.isFinite(bounds[0])) {
|
|
33
|
+
return bounds;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const MAX_VIEWPORT_SIZE = 2048;
|
|
39
|
+
|
|
40
|
+
/** Construct a viewport that just covers the target bounds. Used for rendering to common space indexed texture. */
|
|
41
|
+
export function makeViewport(opts: {
|
|
42
|
+
/** The cartesian bounds of layers that will render into this texture */
|
|
43
|
+
bounds: Bounds;
|
|
44
|
+
/** Target width. If not specified, will be deduced from zoom */
|
|
45
|
+
width?: number;
|
|
46
|
+
/** Target height. If not specified, will be deduced from zoom */
|
|
47
|
+
height?: number;
|
|
48
|
+
/** Target zoom. If not specified, will be deduced from width and height */
|
|
49
|
+
zoom?: number;
|
|
50
|
+
/** Border around the viewport in pixels */
|
|
51
|
+
border?: number;
|
|
52
|
+
/** A viewport used to determine the output type */
|
|
53
|
+
viewport: Viewport;
|
|
54
|
+
}): Viewport | null {
|
|
55
|
+
const {bounds, viewport, border = 0} = opts;
|
|
56
|
+
const {isGeospatial} = viewport;
|
|
57
|
+
|
|
58
|
+
if (bounds[2] <= bounds[0] || bounds[3] <= bounds[1]) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const centerWorld = viewport.unprojectPosition([
|
|
63
|
+
(bounds[0] + bounds[2]) / 2,
|
|
64
|
+
(bounds[1] + bounds[3]) / 2,
|
|
65
|
+
0
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
const maxSize = MAX_VIEWPORT_SIZE - border * 2;
|
|
69
|
+
let {width, height, zoom} = opts;
|
|
70
|
+
if (zoom === undefined) {
|
|
71
|
+
// Use width and height to determine zoom
|
|
72
|
+
const scale = Math.min(width! / (bounds[2] - bounds[0]), height! / (bounds[3] - bounds[1]));
|
|
73
|
+
zoom = Math.min(Math.log2(scale), 20);
|
|
74
|
+
} else if (!width || !height) {
|
|
75
|
+
// Use zoom to determine width and height
|
|
76
|
+
const scale = 2 ** zoom;
|
|
77
|
+
width = Math.round(Math.abs(bounds[2] - bounds[0]) * scale);
|
|
78
|
+
height = Math.round(Math.abs(bounds[3] - bounds[1]) * scale);
|
|
79
|
+
if (width > maxSize || height > maxSize) {
|
|
80
|
+
const r = maxSize / Math.max(width, height);
|
|
81
|
+
width = Math.round(width * r);
|
|
82
|
+
height = Math.round(height * r);
|
|
83
|
+
zoom += Math.log2(r);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// TODO - find a more generic way to construct this viewport
|
|
88
|
+
// Geospatial viewports may not be web-mercator
|
|
89
|
+
return isGeospatial
|
|
90
|
+
? new WebMercatorViewport({
|
|
91
|
+
x: border,
|
|
92
|
+
y: border,
|
|
93
|
+
width,
|
|
94
|
+
height,
|
|
95
|
+
longitude: centerWorld[0],
|
|
96
|
+
latitude: centerWorld[1],
|
|
97
|
+
zoom,
|
|
98
|
+
orthographic: true
|
|
99
|
+
})
|
|
100
|
+
: new OrthographicViewport({
|
|
101
|
+
x: border,
|
|
102
|
+
y: border,
|
|
103
|
+
width,
|
|
104
|
+
height,
|
|
105
|
+
target: centerWorld,
|
|
106
|
+
zoom,
|
|
107
|
+
flipY: false
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Returns viewport bounds in CARTESIAN coordinates */
|
|
112
|
+
export function getViewportBounds(viewport: Viewport, zRange?: [number, number]): Bounds {
|
|
113
|
+
// Viewport bounds in world coordinates
|
|
114
|
+
let viewportBoundsWorld: Bounds;
|
|
115
|
+
if (zRange && zRange.length === 2) {
|
|
116
|
+
const [minZ, maxZ] = zRange;
|
|
117
|
+
const bounds0 = viewport.getBounds({z: minZ});
|
|
118
|
+
const bounds1 = viewport.getBounds({z: maxZ});
|
|
119
|
+
viewportBoundsWorld = [
|
|
120
|
+
Math.min(bounds0[0], bounds1[0]),
|
|
121
|
+
Math.min(bounds0[1], bounds1[1]),
|
|
122
|
+
Math.max(bounds0[2], bounds1[2]),
|
|
123
|
+
Math.max(bounds0[3], bounds1[3])
|
|
124
|
+
];
|
|
125
|
+
} else {
|
|
126
|
+
viewportBoundsWorld = viewport.getBounds();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Viewport bounds in cartesian coordinates
|
|
130
|
+
const viewportBottomLeftCommon = viewport.projectPosition(viewportBoundsWorld.slice(0, 2));
|
|
131
|
+
const viewportTopRightCommon = viewport.projectPosition(viewportBoundsWorld.slice(2, 4));
|
|
132
|
+
return [
|
|
133
|
+
viewportBottomLeftCommon[0],
|
|
134
|
+
viewportBottomLeftCommon[1],
|
|
135
|
+
viewportTopRightCommon[0],
|
|
136
|
+
viewportTopRightCommon[1]
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/*
|
|
141
|
+
* Determine the common space bounds that best cover the given data for the given viewport
|
|
142
|
+
* Returns bounds in CARTESIAN coordinates
|
|
143
|
+
*/
|
|
144
|
+
export function getRenderBounds(
|
|
145
|
+
layerBounds: Bounds,
|
|
146
|
+
viewport: Viewport,
|
|
147
|
+
zRange?: [number, number]
|
|
148
|
+
): Bounds {
|
|
149
|
+
if (!layerBounds) {
|
|
150
|
+
return [0, 0, 1, 1];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const viewportBounds = getViewportBounds(viewport, zRange);
|
|
154
|
+
// Expand viewport bounds by 2X. Heurestically chosen to avoid masking
|
|
155
|
+
// errors when mask is partially out of view
|
|
156
|
+
const paddedBounds = doubleBounds(viewportBounds);
|
|
157
|
+
|
|
158
|
+
// When bounds of the layers are smaller than the viewport bounds simply use
|
|
159
|
+
// mask bounds, so as to maximize resolution & avoid rerenders
|
|
160
|
+
if (
|
|
161
|
+
layerBounds[2] - layerBounds[0] <= paddedBounds[2] - paddedBounds[0] &&
|
|
162
|
+
layerBounds[3] - layerBounds[1] <= paddedBounds[3] - paddedBounds[1]
|
|
163
|
+
) {
|
|
164
|
+
return layerBounds;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// As viewport shrinks, to avoid pixelation along mask edges
|
|
168
|
+
// we need to reduce the bounds and only render the visible portion
|
|
169
|
+
// of the mask.
|
|
170
|
+
// We pad the viewport bounds to capture the section
|
|
171
|
+
// of the mask just outside the viewport to correctly maskByInstance.
|
|
172
|
+
// Intersect mask & padded viewport bounds
|
|
173
|
+
return [
|
|
174
|
+
Math.max(layerBounds[0], paddedBounds[0]),
|
|
175
|
+
Math.max(layerBounds[1], paddedBounds[1]),
|
|
176
|
+
Math.min(layerBounds[2], paddedBounds[2]),
|
|
177
|
+
Math.min(layerBounds[3], paddedBounds[3])
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function doubleBounds(bounds: Bounds): Bounds {
|
|
182
|
+
const dx = bounds[2] - bounds[0];
|
|
183
|
+
const dy = bounds[3] - bounds[1];
|
|
184
|
+
const centerX = (bounds[0] + bounds[2]) / 2;
|
|
185
|
+
const centerY = (bounds[1] + bounds[3]) / 2;
|
|
186
|
+
return [centerX - dx, centerY - dy, centerX + dx, centerY + dy];
|
|
187
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {_ShaderModule as ShaderModule} from '@deck.gl/core
|
|
1
|
+
import {_ShaderModule as ShaderModule} from '@deck.gl/core';
|
|
2
2
|
|
|
3
3
|
import type {DataFilterExtensionProps} from './data-filter';
|
|
4
4
|
|
|
@@ -146,6 +146,12 @@ const inject = {
|
|
|
146
146
|
#endif
|
|
147
147
|
`,
|
|
148
148
|
|
|
149
|
+
'vs:#main-end': `
|
|
150
|
+
if (dataFilter_value == 0.0) {
|
|
151
|
+
gl_Position = vec4(0.);
|
|
152
|
+
}
|
|
153
|
+
`,
|
|
154
|
+
|
|
149
155
|
'vs:DECKGL_FILTER_SIZE': `
|
|
150
156
|
if (filter_transformSize) {
|
|
151
157
|
size = size * dataFilter_value;
|
|
@@ -15,8 +15,15 @@ import type {
|
|
|
15
15
|
|
|
16
16
|
const defaultProps = {
|
|
17
17
|
fillPatternEnabled: true,
|
|
18
|
-
fillPatternAtlas:
|
|
19
|
-
|
|
18
|
+
fillPatternAtlas: {
|
|
19
|
+
type: 'image',
|
|
20
|
+
value: null,
|
|
21
|
+
async: true,
|
|
22
|
+
parameters: {
|
|
23
|
+
[GL.TEXTURE_MIN_FILTER]: GL.LINEAR
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
fillPatternMapping: {type: 'object', value: {}, async: true},
|
|
20
27
|
fillPatternMask: true,
|
|
21
28
|
getFillPattern: {type: 'accessor', value: d => d.pattern},
|
|
22
29
|
getFillPatternScale: {type: 'accessor', value: 1},
|
|
@@ -29,7 +36,7 @@ export type FillStyleExtensionProps<DataT = any> = {
|
|
|
29
36
|
*/
|
|
30
37
|
fillPatternEnabled?: boolean;
|
|
31
38
|
/** Sprite image url or texture that packs all your patterns into one layout. */
|
|
32
|
-
fillPatternAtlas?: Texture;
|
|
39
|
+
fillPatternAtlas?: string | Texture;
|
|
33
40
|
/** Pattern names mapped to pattern definitions, or a url that points to a JSON file. */
|
|
34
41
|
fillPatternMapping?:
|
|
35
42
|
| string
|
|
@@ -71,15 +78,6 @@ type FillStyleExtensionOptions = {
|
|
|
71
78
|
pattern: boolean;
|
|
72
79
|
};
|
|
73
80
|
|
|
74
|
-
const DEFAULT_TEXTURE_PARAMETERS = {
|
|
75
|
-
[GL.TEXTURE_MIN_FILTER]: GL.LINEAR,
|
|
76
|
-
// GL.LINEAR is the default value but explicitly set it here
|
|
77
|
-
[GL.TEXTURE_MAG_FILTER]: GL.LINEAR,
|
|
78
|
-
// for texture boundary artifact
|
|
79
|
-
[GL.TEXTURE_WRAP_S]: GL.CLAMP_TO_EDGE,
|
|
80
|
-
[GL.TEXTURE_WRAP_T]: GL.CLAMP_TO_EDGE
|
|
81
|
-
};
|
|
82
|
-
|
|
83
81
|
/** Adds selected features to layers that render a "fill", such as the `PolygonLayer` and `ScatterplotLayer`. */
|
|
84
82
|
export default class FillStyleExtension extends LayerExtension<FillStyleExtensionOptions> {
|
|
85
83
|
static defaultProps = defaultProps;
|
|
@@ -170,11 +168,8 @@ export default class FillStyleExtension extends LayerExtension<FillStyleExtensio
|
|
|
170
168
|
return;
|
|
171
169
|
}
|
|
172
170
|
|
|
173
|
-
if (props.fillPatternAtlas && props.fillPatternAtlas !== oldProps.fillPatternAtlas) {
|
|
174
|
-
extension.loadPatternAtlas.call(this);
|
|
175
|
-
}
|
|
176
171
|
if (props.fillPatternMapping && props.fillPatternMapping !== oldProps.fillPatternMapping) {
|
|
177
|
-
|
|
172
|
+
this.getAttributeManager()!.invalidate('getFillPattern');
|
|
178
173
|
}
|
|
179
174
|
}
|
|
180
175
|
|
|
@@ -183,9 +178,9 @@ export default class FillStyleExtension extends LayerExtension<FillStyleExtensio
|
|
|
183
178
|
return;
|
|
184
179
|
}
|
|
185
180
|
|
|
186
|
-
const {
|
|
181
|
+
const {fillPatternAtlas} = this.props;
|
|
187
182
|
this.setModuleParameters({
|
|
188
|
-
fillPatternTexture:
|
|
183
|
+
fillPatternTexture: fillPatternAtlas || this.state.emptyTexture
|
|
189
184
|
});
|
|
190
185
|
}
|
|
191
186
|
|
|
@@ -195,42 +190,9 @@ export default class FillStyleExtension extends LayerExtension<FillStyleExtensio
|
|
|
195
190
|
emptyTexture?.delete();
|
|
196
191
|
}
|
|
197
192
|
|
|
198
|
-
async loadPatternAtlas(this: Layer<FillStyleExtensionProps>) {
|
|
199
|
-
const {fillPatternAtlas, fetch} = this.props;
|
|
200
|
-
this.state.patternTexture?.delete();
|
|
201
|
-
this.setState({patternTexture: null});
|
|
202
|
-
let image = fillPatternAtlas;
|
|
203
|
-
if (typeof image === 'string') {
|
|
204
|
-
image = await fetch(image, {propName: 'fillPatternAtlas', layer: this});
|
|
205
|
-
}
|
|
206
|
-
const patternTexture =
|
|
207
|
-
image instanceof Texture2D
|
|
208
|
-
? image
|
|
209
|
-
: new Texture2D(this.context.gl, {
|
|
210
|
-
data: image,
|
|
211
|
-
parameters: DEFAULT_TEXTURE_PARAMETERS
|
|
212
|
-
});
|
|
213
|
-
this.setState({patternTexture});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
async loadPatternMapping(this: Layer<FillStyleExtensionProps>) {
|
|
217
|
-
const {fillPatternMapping, fetch} = this.props;
|
|
218
|
-
this.setState({patternMapping: null});
|
|
219
|
-
let patternMapping = fillPatternMapping;
|
|
220
|
-
if (typeof patternMapping === 'string') {
|
|
221
|
-
patternMapping = await fetch(patternMapping, {
|
|
222
|
-
propName: 'fillPatternMapping',
|
|
223
|
-
layer: this
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
this.setState({patternMapping});
|
|
227
|
-
this.getAttributeManager()!.invalidate('getFillPattern');
|
|
228
|
-
this.setNeedsUpdate();
|
|
229
|
-
}
|
|
230
|
-
|
|
231
193
|
getPatternFrame(this: Layer<FillStyleExtensionProps>, name: string) {
|
|
232
|
-
const {
|
|
233
|
-
const def =
|
|
194
|
+
const {fillPatternMapping} = this.getCurrentLayer()!.props;
|
|
195
|
+
const def = fillPatternMapping && fillPatternMapping[name];
|
|
234
196
|
return def ? [def.x, def.y, def.width, def.height] : [0, 0, 0, 0];
|
|
235
197
|
}
|
|
236
198
|
}
|
|
@@ -26,7 +26,7 @@ uniform vec2 fill_patternTextureSize;
|
|
|
26
26
|
|
|
27
27
|
varying vec2 fill_uv;
|
|
28
28
|
varying vec4 fill_patternBounds;
|
|
29
|
-
varying
|
|
29
|
+
varying vec4 fill_patternPlacement;
|
|
30
30
|
`;
|
|
31
31
|
|
|
32
32
|
const patternFs = `
|
|
@@ -37,7 +37,7 @@ uniform vec2 fill_uvCoordinateOrigin;
|
|
|
37
37
|
uniform vec2 fill_uvCoordinateOrigin64Low;
|
|
38
38
|
|
|
39
39
|
varying vec4 fill_patternBounds;
|
|
40
|
-
varying
|
|
40
|
+
varying vec4 fill_patternPlacement;
|
|
41
41
|
varying vec2 fill_uv;
|
|
42
42
|
|
|
43
43
|
const float FILL_UV_SCALE = 512.0 / 40000000.0;
|
|
@@ -52,13 +52,13 @@ const inject = {
|
|
|
52
52
|
if (fill_patternEnabled) {
|
|
53
53
|
fill_patternBounds = FILL_PATTERN_FRAME_ATTRIB / vec4(fill_patternTextureSize, fill_patternTextureSize);
|
|
54
54
|
fill_patternPlacement.xy = FILL_PATTERN_OFFSET_ATTRIB;
|
|
55
|
-
fill_patternPlacement.
|
|
55
|
+
fill_patternPlacement.zw = FILL_PATTERN_SCALE_ATTRIB * FILL_PATTERN_FRAME_ATTRIB.zw;
|
|
56
56
|
}
|
|
57
57
|
`,
|
|
58
58
|
|
|
59
59
|
'fs:DECKGL_FILTER_COLOR': `
|
|
60
60
|
if (fill_patternEnabled) {
|
|
61
|
-
|
|
61
|
+
vec2 scale = FILL_UV_SCALE * fill_patternPlacement.zw;
|
|
62
62
|
vec2 patternUV = mod(mod(fill_uvCoordinateOrigin, scale) + fill_uvCoordinateOrigin64Low + fill_uv, scale) / scale;
|
|
63
63
|
patternUV = mod(fill_patternPlacement.xy + patternUV, 1.0);
|
|
64
64
|
|
|
@@ -99,10 +99,9 @@ function getPatternUniforms(
|
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
101
|
if ('viewport' in opts) {
|
|
102
|
-
const {
|
|
103
|
-
const {
|
|
102
|
+
const {fillPatternMask = true, fillPatternEnabled = true} = opts;
|
|
103
|
+
const {project_uCommonOrigin: coordinateOriginCommon} = uniforms as ProjectUniforms;
|
|
104
104
|
|
|
105
|
-
const coordinateOriginCommon = viewport.projectPosition(project_uCoordinateOrigin);
|
|
106
105
|
const coordinateOriginCommon64Low = [
|
|
107
106
|
fp64LowPart(coordinateOriginCommon[0]),
|
|
108
107
|
fp64LowPart(coordinateOriginCommon[1])
|
package/src/index.ts
CHANGED
|
@@ -4,7 +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
8
|
export {default as MaskExtension} from './mask/mask';
|
|
9
|
+
export {default as TerrainExtension} from './terrain/terrain';
|
|
8
10
|
|
|
9
11
|
// Shader module
|
|
10
12
|
export {default as project64} from './fp64/project64';
|
|
@@ -15,4 +17,6 @@ export type {DataFilterExtensionProps} from './data-filter/data-filter';
|
|
|
15
17
|
export type {PathStyleExtensionProps} from './path-style/path-style';
|
|
16
18
|
export type {FillStyleExtensionProps} from './fill-style/fill-style';
|
|
17
19
|
export type {ClipExtensionProps} from './clip/clip';
|
|
20
|
+
export type {CollideExtensionProps} from './collide/collide';
|
|
18
21
|
export type {MaskExtensionProps} from './mask/mask';
|
|
22
|
+
export type {TerrainExtensionProps} from './terrain/terrain';
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import {Layer, Viewport, Effect, PreRenderOptions, CoordinateSystem, log} from '@deck.gl/core';
|
|
2
|
+
import {Texture2D} from '@luma.gl/core';
|
|
3
|
+
import {equals} from '@math.gl/core';
|
|
4
|
+
import MaskPass from './mask-pass';
|
|
5
|
+
import {getMaskBounds, getMaskViewport, MaskBounds} from './utils';
|
|
6
|
+
// import {debugFBO} from '../utils/debug';
|
|
7
|
+
|
|
8
|
+
type Mask = {
|
|
9
|
+
/** The channel index */
|
|
10
|
+
index: number;
|
|
11
|
+
bounds: MaskBounds;
|
|
12
|
+
coordinateOrigin: [number, number, number];
|
|
13
|
+
coordinateSystem: CoordinateSystem;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type Channel = {
|
|
17
|
+
id: string;
|
|
18
|
+
index: number;
|
|
19
|
+
layers: Layer[];
|
|
20
|
+
bounds: MaskBounds;
|
|
21
|
+
maskBounds: MaskBounds;
|
|
22
|
+
layerBounds: MaskBounds[];
|
|
23
|
+
coordinateOrigin: [number, number, number];
|
|
24
|
+
coordinateSystem: CoordinateSystem;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type MaskPreRenderStats = {
|
|
28
|
+
didRender: boolean;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Class to manage mask effect
|
|
32
|
+
export default class MaskEffect implements Effect {
|
|
33
|
+
id = 'mask-effect';
|
|
34
|
+
props = null;
|
|
35
|
+
useInPicking = true;
|
|
36
|
+
order = 0;
|
|
37
|
+
|
|
38
|
+
private dummyMaskMap?: Texture2D;
|
|
39
|
+
private channels: (Channel | null)[] = [];
|
|
40
|
+
private masks: Record<string, Mask> | null = null;
|
|
41
|
+
private maskPass?: MaskPass;
|
|
42
|
+
private maskMap?: Texture2D;
|
|
43
|
+
private lastViewport?: Viewport;
|
|
44
|
+
|
|
45
|
+
preRender(
|
|
46
|
+
gl: WebGLRenderingContext,
|
|
47
|
+
{layers, layerFilter, viewports, onViewportActive, views, isPicking}: PreRenderOptions
|
|
48
|
+
): MaskPreRenderStats {
|
|
49
|
+
let didRender = false;
|
|
50
|
+
if (!this.dummyMaskMap) {
|
|
51
|
+
this.dummyMaskMap = new Texture2D(gl, {
|
|
52
|
+
width: 1,
|
|
53
|
+
height: 1
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (isPicking) {
|
|
58
|
+
// Do not update on picking pass
|
|
59
|
+
return {didRender};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const maskLayers = layers.filter(l => l.props.visible && l.props.operation.includes('mask'));
|
|
63
|
+
if (maskLayers.length === 0) {
|
|
64
|
+
this.masks = null;
|
|
65
|
+
this.channels.length = 0;
|
|
66
|
+
return {didRender};
|
|
67
|
+
}
|
|
68
|
+
this.masks = {};
|
|
69
|
+
|
|
70
|
+
if (!this.maskPass) {
|
|
71
|
+
this.maskPass = new MaskPass(gl, {id: 'default-mask'});
|
|
72
|
+
this.maskMap = this.maskPass.maskMap;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Map layers to channels
|
|
76
|
+
const channelMap = this._sortMaskChannels(maskLayers);
|
|
77
|
+
// TODO - support multiple views
|
|
78
|
+
const viewport = viewports[0];
|
|
79
|
+
const viewportChanged = !this.lastViewport || !this.lastViewport.equals(viewport);
|
|
80
|
+
|
|
81
|
+
for (const maskId in channelMap) {
|
|
82
|
+
const result = this._renderChannel(channelMap[maskId], {
|
|
83
|
+
layerFilter,
|
|
84
|
+
onViewportActive,
|
|
85
|
+
views,
|
|
86
|
+
viewport,
|
|
87
|
+
viewportChanged
|
|
88
|
+
});
|
|
89
|
+
didRender ||= result;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// debugFBO(this.maskMap, {opaque: true});
|
|
93
|
+
return {didRender};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private _renderChannel(
|
|
97
|
+
channelInfo: Channel,
|
|
98
|
+
{
|
|
99
|
+
layerFilter,
|
|
100
|
+
onViewportActive,
|
|
101
|
+
views,
|
|
102
|
+
viewport,
|
|
103
|
+
viewportChanged
|
|
104
|
+
}: {
|
|
105
|
+
layerFilter: PreRenderOptions['layerFilter'];
|
|
106
|
+
onViewportActive: PreRenderOptions['onViewportActive'];
|
|
107
|
+
views: PreRenderOptions['views'];
|
|
108
|
+
viewport: Viewport;
|
|
109
|
+
viewportChanged: boolean;
|
|
110
|
+
}
|
|
111
|
+
): boolean {
|
|
112
|
+
let didRender = false;
|
|
113
|
+
const oldChannelInfo = this.channels[channelInfo.index];
|
|
114
|
+
if (!oldChannelInfo) {
|
|
115
|
+
return didRender;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const maskChanged =
|
|
119
|
+
// If a channel is new
|
|
120
|
+
channelInfo === oldChannelInfo ||
|
|
121
|
+
// If sublayers have changed
|
|
122
|
+
oldChannelInfo.layers.length !== channelInfo.layers.length ||
|
|
123
|
+
// If a sublayer's positions have been updated, the cached bounds will change shallowly
|
|
124
|
+
channelInfo.layerBounds.some((b, i) => b !== oldChannelInfo.layerBounds[i]);
|
|
125
|
+
|
|
126
|
+
channelInfo.bounds = oldChannelInfo.bounds;
|
|
127
|
+
channelInfo.maskBounds = oldChannelInfo.maskBounds;
|
|
128
|
+
this.channels[channelInfo.index] = channelInfo;
|
|
129
|
+
|
|
130
|
+
if (maskChanged || viewportChanged) {
|
|
131
|
+
// Recalculate mask bounds
|
|
132
|
+
this.lastViewport = viewport;
|
|
133
|
+
|
|
134
|
+
channelInfo.bounds = getMaskBounds({layers: channelInfo.layers, viewport});
|
|
135
|
+
|
|
136
|
+
if (maskChanged || !equals(channelInfo.bounds, oldChannelInfo.bounds)) {
|
|
137
|
+
// Rerender mask FBO
|
|
138
|
+
const {maskPass, maskMap} = this;
|
|
139
|
+
|
|
140
|
+
const maskViewport = getMaskViewport({
|
|
141
|
+
bounds: channelInfo.bounds,
|
|
142
|
+
viewport,
|
|
143
|
+
width: maskMap.width,
|
|
144
|
+
height: maskMap.height
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
channelInfo.maskBounds = maskViewport ? maskViewport.getBounds() : [0, 0, 1, 1];
|
|
148
|
+
|
|
149
|
+
// @ts-ignore (2532) This method is only called from preRender where maskPass is defined
|
|
150
|
+
maskPass.render({
|
|
151
|
+
pass: 'mask',
|
|
152
|
+
channel: channelInfo.index,
|
|
153
|
+
layers: channelInfo.layers,
|
|
154
|
+
layerFilter,
|
|
155
|
+
viewports: maskViewport ? [maskViewport] : [],
|
|
156
|
+
onViewportActive,
|
|
157
|
+
views,
|
|
158
|
+
moduleParameters: {
|
|
159
|
+
devicePixelRatio: 1
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
didRender = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// @ts-ignore (2532) This method is only called from preRender where masks is defined
|
|
168
|
+
this.masks[channelInfo.id] = {
|
|
169
|
+
index: channelInfo.index,
|
|
170
|
+
bounds: channelInfo.maskBounds,
|
|
171
|
+
coordinateOrigin: channelInfo.coordinateOrigin,
|
|
172
|
+
coordinateSystem: channelInfo.coordinateSystem
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return didRender;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Find a channel to render each mask into
|
|
180
|
+
* If a maskId already exists, diff and update the existing channel
|
|
181
|
+
* Otherwise replace a removed mask
|
|
182
|
+
* Otherwise create a new channel
|
|
183
|
+
* Returns a map from mask layer id to channel info
|
|
184
|
+
*/
|
|
185
|
+
private _sortMaskChannels(maskLayers: Layer[]): Record<string, Channel> {
|
|
186
|
+
const channelMap = {};
|
|
187
|
+
let channelCount = 0;
|
|
188
|
+
for (const layer of maskLayers) {
|
|
189
|
+
const {id} = layer.root;
|
|
190
|
+
let channelInfo = channelMap[id];
|
|
191
|
+
if (!channelInfo) {
|
|
192
|
+
if (++channelCount > 4) {
|
|
193
|
+
log.warn('Too many mask layers. The max supported is 4')();
|
|
194
|
+
continue; // eslint-disable-line no-continue
|
|
195
|
+
}
|
|
196
|
+
channelInfo = {
|
|
197
|
+
id,
|
|
198
|
+
index: this.channels.findIndex(c => c?.id === id),
|
|
199
|
+
layers: [],
|
|
200
|
+
layerBounds: [],
|
|
201
|
+
coordinateOrigin: layer.root.props.coordinateOrigin,
|
|
202
|
+
coordinateSystem: layer.root.props.coordinateSystem
|
|
203
|
+
};
|
|
204
|
+
channelMap[id] = channelInfo;
|
|
205
|
+
}
|
|
206
|
+
channelInfo.layers.push(layer);
|
|
207
|
+
channelInfo.layerBounds.push(layer.getBounds());
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
for (let i = 0; i < 4; i++) {
|
|
211
|
+
const channelInfo = this.channels[i];
|
|
212
|
+
if (!channelInfo || !(channelInfo.id in channelMap)) {
|
|
213
|
+
// The mask id at this channel no longer exists
|
|
214
|
+
this.channels[i] = null;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
for (const maskId in channelMap) {
|
|
219
|
+
const channelInfo = channelMap[maskId];
|
|
220
|
+
|
|
221
|
+
if (channelInfo.index < 0) {
|
|
222
|
+
channelInfo.index = this.channels.findIndex(c => !c);
|
|
223
|
+
this.channels[channelInfo.index] = channelInfo;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return channelMap;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
getModuleParameters(): {
|
|
230
|
+
maskMap: Texture2D;
|
|
231
|
+
maskChannels: Record<string, Mask> | null;
|
|
232
|
+
} {
|
|
233
|
+
return {
|
|
234
|
+
maskMap: this.masks ? this.maskMap : this.dummyMaskMap,
|
|
235
|
+
maskChannels: this.masks
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
cleanup(): void {
|
|
240
|
+
if (this.dummyMaskMap) {
|
|
241
|
+
this.dummyMaskMap.delete();
|
|
242
|
+
this.dummyMaskMap = undefined;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (this.maskPass) {
|
|
246
|
+
this.maskPass.delete();
|
|
247
|
+
this.maskPass = undefined;
|
|
248
|
+
this.maskMap = undefined;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
this.lastViewport = undefined;
|
|
252
|
+
this.masks = null;
|
|
253
|
+
this.channels.length = 0;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {Framebuffer, Texture2D, withParameters} from '@luma.gl/core';
|
|
2
|
+
import {_LayersPass as LayersPass, LayersPassRenderOptions} from '@deck.gl/core';
|
|
3
|
+
|
|
4
|
+
type MaskPassRenderOptions = LayersPassRenderOptions & {
|
|
5
|
+
/** The channel to render into, 0:red, 1:green, 2:blue, 3:alpha */
|
|
6
|
+
channel: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default class MaskPass extends LayersPass {
|
|
10
|
+
maskMap: Texture2D;
|
|
11
|
+
fbo: Framebuffer;
|
|
12
|
+
|
|
13
|
+
constructor(gl, props: {id: string; mapSize?: number}) {
|
|
14
|
+
super(gl, props);
|
|
15
|
+
|
|
16
|
+
const {mapSize = 2048} = props;
|
|
17
|
+
|
|
18
|
+
this.maskMap = new Texture2D(gl, {
|
|
19
|
+
width: mapSize,
|
|
20
|
+
height: mapSize,
|
|
21
|
+
parameters: {
|
|
22
|
+
[gl.TEXTURE_MIN_FILTER]: gl.LINEAR,
|
|
23
|
+
[gl.TEXTURE_MAG_FILTER]: gl.LINEAR,
|
|
24
|
+
[gl.TEXTURE_WRAP_S]: gl.CLAMP_TO_EDGE,
|
|
25
|
+
[gl.TEXTURE_WRAP_T]: gl.CLAMP_TO_EDGE
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
this.fbo = new Framebuffer(gl, {
|
|
30
|
+
id: 'maskmap',
|
|
31
|
+
width: mapSize,
|
|
32
|
+
height: mapSize,
|
|
33
|
+
attachments: {
|
|
34
|
+
[gl.COLOR_ATTACHMENT0]: this.maskMap
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
render(options: MaskPassRenderOptions) {
|
|
40
|
+
const gl = this.gl;
|
|
41
|
+
|
|
42
|
+
const colorMask = [false, false, false, false];
|
|
43
|
+
colorMask[options.channel] = true;
|
|
44
|
+
|
|
45
|
+
return withParameters(
|
|
46
|
+
gl,
|
|
47
|
+
{
|
|
48
|
+
clearColor: [255, 255, 255, 255],
|
|
49
|
+
blend: true,
|
|
50
|
+
blendFunc: [gl.ZERO, gl.ONE],
|
|
51
|
+
blendEquation: gl.FUNC_SUBTRACT,
|
|
52
|
+
colorMask,
|
|
53
|
+
depthTest: false
|
|
54
|
+
},
|
|
55
|
+
() => super.render({...options, target: this.fbo, pass: 'mask'})
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
shouldDrawLayer(layer) {
|
|
60
|
+
return layer.props.operation.includes('mask');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
delete() {
|
|
64
|
+
this.fbo.delete();
|
|
65
|
+
this.maskMap.delete();
|
|
66
|
+
}
|
|
67
|
+
}
|