@deck.gl/extensions 9.0.0-beta.3 → 9.0.0-beta.5
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/brushing/shader-module.d.ts +1 -1
- package/dist/brushing/shader-module.d.ts.map +1 -1
- package/dist/data-filter/data-filter-extension.d.ts +38 -6
- package/dist/data-filter/data-filter-extension.d.ts.map +1 -1
- package/dist/data-filter/data-filter-extension.js +103 -13
- package/dist/data-filter/shader-module.d.ts +1 -1
- package/dist/data-filter/shader-module.d.ts.map +1 -1
- package/dist/data-filter/shader-module.js +31 -3
- package/dist/dist.dev.js +113 -19
- package/dist/index.cjs +114 -15
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +18 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/mask/mask-effect.d.ts +1 -1
- package/dist/mask/mask-effect.d.ts.map +1 -1
- package/dist/terrain/height-map-builder.d.ts +1 -1
- package/dist/terrain/height-map-builder.d.ts.map +1 -1
- package/dist/terrain/shader-module.d.ts +2 -2
- package/dist/terrain/shader-module.d.ts.map +1 -1
- package/dist/terrain/terrain-cover.d.ts +1 -1
- package/dist/terrain/terrain-cover.d.ts.map +1 -1
- package/dist/terrain/terrain-effect.d.ts +1 -1
- package/dist/terrain/terrain-effect.d.ts.map +1 -1
- package/dist/terrain/terrain-pass.d.ts +2 -2
- package/dist/terrain/terrain-pass.d.ts.map +1 -1
- package/dist/terrain/terrain-picking-pass.d.ts +1 -1
- package/dist/terrain/terrain-picking-pass.d.ts.map +1 -1
- package/dist.min.js +54 -26
- package/package.json +2 -2
- package/src/data-filter/data-filter-extension.ts +144 -22
- package/src/data-filter/shader-module.ts +31 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ShaderModule } from '@luma.gl/shadertools';
|
|
2
2
|
import type { Viewport } from '@deck.gl/core';
|
|
3
|
-
import type { BrushingExtensionProps } from
|
|
3
|
+
import type { BrushingExtensionProps } from "./brushing-extension.js";
|
|
4
4
|
type BrushingModuleSettings = {
|
|
5
5
|
viewport: Viewport;
|
|
6
6
|
mousePosition?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader-module.d.ts","sourceRoot":"","sources":["../../src/brushing/shader-module.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAC,sBAAsB,EAAC,
|
|
1
|
+
{"version":3,"file":"shader-module.d.ts","sourceRoot":"","sources":["../../src/brushing/shader-module.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAC,sBAAsB,EAAC,gCAA6B;AAEjE,KAAK,sBAAsB,GAAG;IAE5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,CAAC,EAAE;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;CACxC,GAAG,sBAAsB,CAAC;;AAkF3B,wBA4B0C"}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type { Layer, LayerContext, Accessor, UpdateParameters } from '@deck.gl/core';
|
|
2
2
|
import { LayerExtension } from '@deck.gl/core';
|
|
3
|
+
type FilterCategory = number | string;
|
|
3
4
|
export type DataFilterExtensionProps<DataT = any> = {
|
|
4
5
|
/**
|
|
5
6
|
* Accessor to retrieve the value for each object that it will be filtered by.
|
|
6
7
|
* Returns either a number (if `filterSize: 1`) or an array of numbers.
|
|
7
8
|
*/
|
|
8
9
|
getFilterValue?: Accessor<DataT, number | number[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Accessor to retrieve the category (`number | string`) for each object that it will be filtered by.
|
|
12
|
+
* Returns either a single category (if `filterSize: 1`) or an array of categories.
|
|
13
|
+
*/
|
|
14
|
+
getFilterCategory?: Accessor<DataT, FilterCategory | FilterCategory[]>;
|
|
9
15
|
/**
|
|
10
16
|
* Enable/disable the data filter. If the data filter is disabled, all objects are rendered.
|
|
11
17
|
* @default true
|
|
@@ -33,6 +39,11 @@ export type DataFilterExtensionProps<DataT = any> = {
|
|
|
33
39
|
* @default true
|
|
34
40
|
*/
|
|
35
41
|
filterTransformColor?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* The categories which define whether an object should be rendered.
|
|
44
|
+
* @default []
|
|
45
|
+
*/
|
|
46
|
+
filterCategories: FilterCategory[] | FilterCategory[][];
|
|
36
47
|
/**
|
|
37
48
|
* Only called if the `countItems` option is enabled.
|
|
38
49
|
*/
|
|
@@ -44,29 +55,38 @@ export type DataFilterExtensionProps<DataT = any> = {
|
|
|
44
55
|
}) => void;
|
|
45
56
|
};
|
|
46
57
|
type DataFilterExtensionOptions = {
|
|
58
|
+
/**
|
|
59
|
+
* The size of the category filter (number of columns to filter by). The category filter can show/hide data based on 1-4 properties of each object.
|
|
60
|
+
* @default 1
|
|
61
|
+
*/
|
|
62
|
+
categorySize?: 1 | 2 | 3 | 4;
|
|
47
63
|
/**
|
|
48
64
|
* The size of the filter (number of columns to filter by). The data filter can show/hide data based on 1-4 numeric properties of each object.
|
|
49
65
|
* @default 1
|
|
50
66
|
*/
|
|
51
|
-
filterSize
|
|
67
|
+
filterSize?: 1 | 2 | 3 | 4;
|
|
52
68
|
/**
|
|
53
69
|
* Use 64-bit precision instead of 32-bit.
|
|
54
70
|
* @default false
|
|
55
71
|
*/
|
|
56
|
-
fp64
|
|
72
|
+
fp64?: boolean;
|
|
57
73
|
/**
|
|
58
74
|
* If `true`, reports the number of filtered objects with the `onFilteredItemsChange` callback.
|
|
59
75
|
* @default `false`.
|
|
60
76
|
*/
|
|
61
|
-
countItems
|
|
77
|
+
countItems?: boolean;
|
|
62
78
|
};
|
|
63
79
|
/** Adds GPU-based data filtering functionalities to layers. It allows the layer to show/hide objects based on user-defined properties. */
|
|
64
|
-
export default class DataFilterExtension extends LayerExtension<DataFilterExtensionOptions
|
|
80
|
+
export default class DataFilterExtension extends LayerExtension<Required<DataFilterExtensionOptions>> {
|
|
65
81
|
static defaultProps: {
|
|
66
82
|
getFilterValue: {
|
|
67
83
|
type: string;
|
|
68
84
|
value: number;
|
|
69
85
|
};
|
|
86
|
+
getFilterCategory: {
|
|
87
|
+
type: string;
|
|
88
|
+
value: number;
|
|
89
|
+
};
|
|
70
90
|
onFilteredItemsChange: {
|
|
71
91
|
type: string;
|
|
72
92
|
value: null;
|
|
@@ -75,16 +95,28 @@ export default class DataFilterExtension extends LayerExtension<DataFilterExtens
|
|
|
75
95
|
filterEnabled: boolean;
|
|
76
96
|
filterRange: number[];
|
|
77
97
|
filterSoftRange: null;
|
|
98
|
+
filterCategories: number[];
|
|
78
99
|
filterTransformSize: boolean;
|
|
79
100
|
filterTransformColor: boolean;
|
|
80
101
|
};
|
|
81
102
|
static extensionName: string;
|
|
82
|
-
constructor(
|
|
103
|
+
constructor(opts: DataFilterExtensionOptions);
|
|
83
104
|
getShaders(this: Layer<DataFilterExtensionProps>, extension: this): any;
|
|
84
105
|
initializeState(this: Layer<DataFilterExtensionProps>, context: LayerContext, extension: this): void;
|
|
85
|
-
updateState(this: Layer<DataFilterExtensionProps>, { props, oldProps }: UpdateParameters<Layer<DataFilterExtensionProps
|
|
106
|
+
updateState(this: Layer<DataFilterExtensionProps>, { props, oldProps, changeFlags }: UpdateParameters<Layer<DataFilterExtensionProps>>, extension: this): void;
|
|
86
107
|
draw(this: Layer<DataFilterExtensionProps>, params: any, extension: this): void;
|
|
87
108
|
finalizeState(this: Layer<DataFilterExtensionProps>): void;
|
|
109
|
+
/**
|
|
110
|
+
* Updates the bitmask used on the GPU to perform the filter based on the
|
|
111
|
+
* `filterCategories` prop. The mapping between categories and bit in the bitmask
|
|
112
|
+
* is performed by `_getCategoryKey()`
|
|
113
|
+
*/
|
|
114
|
+
_updateCategoryBitMask(this: Layer<DataFilterExtensionProps>, params: any, extension: this): void;
|
|
115
|
+
/**
|
|
116
|
+
* Returns an index of bit in the bitmask for a given category. If the category has
|
|
117
|
+
* not yet been assigned a bit, a new one is assigned.
|
|
118
|
+
*/
|
|
119
|
+
_getCategoryKey(this: Layer<DataFilterExtensionProps>, category: FilterCategory, channel: number): number;
|
|
88
120
|
}
|
|
89
121
|
export {};
|
|
90
122
|
//# sourceMappingURL=data-filter-extension.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-filter-extension.d.ts","sourceRoot":"","sources":["../../src/data-filter/data-filter-extension.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAC,MAAM,eAAe,CAAC;AACnF,OAAO,
|
|
1
|
+
{"version":3,"file":"data-filter-extension.d.ts","sourceRoot":"","sources":["../../src/data-filter/data-filter-extension.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,18 +18,26 @@
|
|
|
18
18
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
19
|
// THE SOFTWARE.
|
|
20
20
|
import { GL } from '@luma.gl/constants';
|
|
21
|
-
import { LayerExtension } from '@deck.gl/core';
|
|
21
|
+
import { _deepEqual as deepEqual, LayerExtension, log } from '@deck.gl/core';
|
|
22
22
|
import { shaderModule, shaderModule64 } from "./shader-module.js";
|
|
23
23
|
import * as aggregator from "./aggregator.js";
|
|
24
24
|
const defaultProps = {
|
|
25
25
|
getFilterValue: { type: 'accessor', value: 0 },
|
|
26
|
+
getFilterCategory: { type: 'accessor', value: 0 },
|
|
26
27
|
onFilteredItemsChange: { type: 'function', value: null, optional: true },
|
|
27
28
|
filterEnabled: true,
|
|
28
29
|
filterRange: [-1, 1],
|
|
29
30
|
filterSoftRange: null,
|
|
31
|
+
filterCategories: [0],
|
|
30
32
|
filterTransformSize: true,
|
|
31
33
|
filterTransformColor: true
|
|
32
34
|
};
|
|
35
|
+
const defaultOptions = {
|
|
36
|
+
categorySize: 1,
|
|
37
|
+
filterSize: 1,
|
|
38
|
+
fp64: false,
|
|
39
|
+
countItems: false
|
|
40
|
+
};
|
|
33
41
|
const DATA_TYPE_FROM_SIZE = {
|
|
34
42
|
1: 'float',
|
|
35
43
|
2: 'vec2',
|
|
@@ -40,17 +48,16 @@ const DATA_TYPE_FROM_SIZE = {
|
|
|
40
48
|
export default class DataFilterExtension extends LayerExtension {
|
|
41
49
|
static { this.defaultProps = defaultProps; }
|
|
42
50
|
static { this.extensionName = 'DataFilterExtension'; }
|
|
43
|
-
constructor(
|
|
44
|
-
|
|
45
|
-
throw new Error('filterSize out of range');
|
|
46
|
-
}
|
|
47
|
-
super({ filterSize, fp64, countItems });
|
|
51
|
+
constructor(opts) {
|
|
52
|
+
super({ ...defaultOptions, ...opts });
|
|
48
53
|
}
|
|
49
54
|
getShaders(extension) {
|
|
50
|
-
const { filterSize, fp64 } = extension.opts;
|
|
55
|
+
const { categorySize, filterSize, fp64 } = extension.opts;
|
|
51
56
|
return {
|
|
52
57
|
modules: [fp64 ? shaderModule64 : shaderModule],
|
|
53
58
|
defines: {
|
|
59
|
+
DATACATEGORY_TYPE: DATA_TYPE_FROM_SIZE[categorySize],
|
|
60
|
+
DATACATEGORY_CHANNELS: categorySize,
|
|
54
61
|
DATAFILTER_TYPE: DATA_TYPE_FROM_SIZE[filterSize],
|
|
55
62
|
DATAFILTER_DOUBLE: Boolean(fp64)
|
|
56
63
|
}
|
|
@@ -58,11 +65,12 @@ export default class DataFilterExtension extends LayerExtension {
|
|
|
58
65
|
}
|
|
59
66
|
initializeState(context, extension) {
|
|
60
67
|
const attributeManager = this.getAttributeManager();
|
|
68
|
+
const { categorySize, filterSize, fp64 } = extension.opts;
|
|
61
69
|
if (attributeManager) {
|
|
62
70
|
attributeManager.add({
|
|
63
71
|
filterValues: {
|
|
64
|
-
size:
|
|
65
|
-
type:
|
|
72
|
+
size: filterSize,
|
|
73
|
+
type: fp64 ? GL.DOUBLE : GL.FLOAT,
|
|
66
74
|
accessor: 'getFilterValue',
|
|
67
75
|
shaderAttributes: {
|
|
68
76
|
filterValues: {
|
|
@@ -72,6 +80,22 @@ export default class DataFilterExtension extends LayerExtension {
|
|
|
72
80
|
divisor: 1
|
|
73
81
|
}
|
|
74
82
|
}
|
|
83
|
+
},
|
|
84
|
+
filterCategoryValues: {
|
|
85
|
+
size: categorySize,
|
|
86
|
+
type: GL.FLOAT,
|
|
87
|
+
accessor: 'getFilterCategory',
|
|
88
|
+
transform: categorySize === 1
|
|
89
|
+
? d => extension._getCategoryKey.call(this, d, 0)
|
|
90
|
+
: d => d.map((x, i) => extension._getCategoryKey.call(this, x, i)),
|
|
91
|
+
shaderAttributes: {
|
|
92
|
+
filterCategoryValues: {
|
|
93
|
+
divisor: 0
|
|
94
|
+
},
|
|
95
|
+
instanceFilterCategoryValues: {
|
|
96
|
+
divisor: 1
|
|
97
|
+
}
|
|
98
|
+
}
|
|
75
99
|
}
|
|
76
100
|
});
|
|
77
101
|
}
|
|
@@ -106,35 +130,62 @@ export default class DataFilterExtension extends LayerExtension {
|
|
|
106
130
|
this.setState({ filterFBO, filterModel });
|
|
107
131
|
}
|
|
108
132
|
}
|
|
109
|
-
updateState({ props, oldProps }) {
|
|
133
|
+
updateState({ props, oldProps, changeFlags }, extension) {
|
|
134
|
+
const attributeManager = this.getAttributeManager();
|
|
135
|
+
const { categorySize } = extension.opts;
|
|
110
136
|
if (this.state.filterModel) {
|
|
111
|
-
const attributeManager = this.getAttributeManager();
|
|
112
137
|
const filterNeedsUpdate =
|
|
113
138
|
// attributeManager must be defined for filterModel to be set
|
|
114
139
|
attributeManager.attributes.filterValues.needsUpdate() ||
|
|
140
|
+
attributeManager.attributes.filterCategoryValues?.needsUpdate() ||
|
|
115
141
|
props.filterEnabled !== oldProps.filterEnabled ||
|
|
116
142
|
props.filterRange !== oldProps.filterRange ||
|
|
117
|
-
props.filterSoftRange !== oldProps.filterSoftRange
|
|
143
|
+
props.filterSoftRange !== oldProps.filterSoftRange ||
|
|
144
|
+
props.filterCategories !== oldProps.filterCategories;
|
|
118
145
|
if (filterNeedsUpdate) {
|
|
119
146
|
this.setState({ filterNeedsUpdate });
|
|
120
147
|
}
|
|
121
148
|
}
|
|
149
|
+
if (attributeManager?.attributes.filterCategoryValues) {
|
|
150
|
+
// Update bitmask if accessor or selected categories has changed
|
|
151
|
+
const categoryBitMaskNeedsUpdate = attributeManager.attributes.filterCategoryValues.needsUpdate() ||
|
|
152
|
+
!deepEqual(props.filterCategories, oldProps.filterCategories, 2);
|
|
153
|
+
if (categoryBitMaskNeedsUpdate) {
|
|
154
|
+
this.setState({ categoryBitMaskNeedsUpdate });
|
|
155
|
+
}
|
|
156
|
+
// Need to recreate category map if categorySize has changed
|
|
157
|
+
const resetCategories = changeFlags.dataChanged;
|
|
158
|
+
if (resetCategories) {
|
|
159
|
+
this.setState({
|
|
160
|
+
categoryMap: Array(categorySize)
|
|
161
|
+
.fill(0)
|
|
162
|
+
.map(() => ({}))
|
|
163
|
+
});
|
|
164
|
+
attributeManager.attributes.filterCategoryValues.setNeedsUpdate('categoryMap');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
122
167
|
}
|
|
123
168
|
draw(params, extension) {
|
|
124
169
|
const filterFBO = this.state.filterFBO;
|
|
125
170
|
const filterModel = this.state.filterModel;
|
|
126
171
|
const filterNeedsUpdate = this.state.filterNeedsUpdate;
|
|
172
|
+
const categoryBitMaskNeedsUpdate = this.state.categoryBitMaskNeedsUpdate;
|
|
127
173
|
const { onFilteredItemsChange } = this.props;
|
|
174
|
+
if (categoryBitMaskNeedsUpdate) {
|
|
175
|
+
extension._updateCategoryBitMask.call(this, params, extension);
|
|
176
|
+
}
|
|
128
177
|
if (filterNeedsUpdate && onFilteredItemsChange && filterModel) {
|
|
129
|
-
const { attributes: { filterValues, filterIndices } } = this.getAttributeManager();
|
|
178
|
+
const { attributes: { filterValues, filterCategoryValues, filterIndices } } = this.getAttributeManager();
|
|
130
179
|
filterModel.setVertexCount(this.getNumInstances());
|
|
131
180
|
this.context.device.clearWebGL({ framebuffer: filterFBO, color: [0, 0, 0, 0] });
|
|
132
181
|
filterModel.updateModuleSettings(params.moduleParameters);
|
|
133
182
|
// @ts-expect-error filterValue and filterIndices should always have buffer value
|
|
134
183
|
filterModel.setAttributes({
|
|
135
184
|
...filterValues.getValue(),
|
|
185
|
+
...filterCategoryValues?.getValue(),
|
|
136
186
|
...filterIndices?.getValue()
|
|
137
187
|
});
|
|
188
|
+
filterModel.setUniforms(params.uniforms);
|
|
138
189
|
filterModel.device.withParametersWebGL({
|
|
139
190
|
framebuffer: filterFBO,
|
|
140
191
|
// ts-ignore 'readonly' cannot be assigned to the mutable type '[GLBlendEquation, GLBlendEquation]'
|
|
@@ -159,4 +210,43 @@ export default class DataFilterExtension extends LayerExtension {
|
|
|
159
210
|
filterFBO?.destroy();
|
|
160
211
|
filterModel?.destroy();
|
|
161
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Updates the bitmask used on the GPU to perform the filter based on the
|
|
215
|
+
* `filterCategories` prop. The mapping between categories and bit in the bitmask
|
|
216
|
+
* is performed by `_getCategoryKey()`
|
|
217
|
+
*/
|
|
218
|
+
_updateCategoryBitMask(params, extension) {
|
|
219
|
+
const { categorySize } = extension.opts;
|
|
220
|
+
const { filterCategories } = this.props;
|
|
221
|
+
const categoryBitMask = new Uint32Array([0, 0, 0, 0]);
|
|
222
|
+
const categoryFilters = (categorySize === 1 ? [filterCategories] : filterCategories);
|
|
223
|
+
const maxCategories = categorySize === 1 ? 128 : categorySize === 2 ? 64 : 32;
|
|
224
|
+
for (let c = 0; c < categoryFilters.length; c++) {
|
|
225
|
+
const categoryFilter = categoryFilters[c];
|
|
226
|
+
for (const category of categoryFilter) {
|
|
227
|
+
const key = extension._getCategoryKey.call(this, category, c);
|
|
228
|
+
if (key < maxCategories) {
|
|
229
|
+
const channel = c * (maxCategories / 32) + Math.floor(key / 32);
|
|
230
|
+
categoryBitMask[channel] += Math.pow(2, key % 32); // 1 << key fails for key > 30
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
log.warn(`Exceeded maximum number of categories (${maxCategories})`)();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/* eslint-disable-next-line camelcase */
|
|
238
|
+
params.uniforms.filter_categoryBitMask = categoryBitMask;
|
|
239
|
+
this.state.categoryBitMaskNeedsUpdate = false;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Returns an index of bit in the bitmask for a given category. If the category has
|
|
243
|
+
* not yet been assigned a bit, a new one is assigned.
|
|
244
|
+
*/
|
|
245
|
+
_getCategoryKey(category, channel) {
|
|
246
|
+
const categoryMap = this.state.categoryMap[channel];
|
|
247
|
+
if (!(category in categoryMap)) {
|
|
248
|
+
categoryMap[category] = Object.keys(categoryMap).length;
|
|
249
|
+
}
|
|
250
|
+
return categoryMap[category];
|
|
251
|
+
}
|
|
162
252
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ShaderModule } from '@luma.gl/shadertools';
|
|
2
|
-
import type { DataFilterExtensionProps } from
|
|
2
|
+
import type { DataFilterExtensionProps } from "./data-filter-extension.js";
|
|
3
3
|
type DataFilterModuleSettings = {
|
|
4
4
|
extensions: any[];
|
|
5
5
|
} & DataFilterExtensionProps;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader-module.d.ts","sourceRoot":"","sources":["../../src/data-filter/shader-module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAC,wBAAwB,EAAC,
|
|
1
|
+
{"version":3,"file":"shader-module.d.ts","sourceRoot":"","sources":["../../src/data-filter/shader-module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAC,wBAAwB,EAAC,mCAAgC;AA8FtE,KAAK,wBAAwB,GAAG;IAC9B,UAAU,EAAE,GAAG,EAAE,CAAC;CACnB,GAAG,wBAAwB,CAAC;AAkG7B,eAAO,MAAM,YAAY,EAAE,YAAY,CAAC,wBAAwB,CAM/D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,YAAY,CAAC,wBAAwB,CAMjE,CAAC"}
|
|
@@ -9,13 +9,16 @@ uniform DATAFILTER_TYPE filter_max;
|
|
|
9
9
|
uniform bool filter_useSoftMargin;
|
|
10
10
|
uniform bool filter_enabled;
|
|
11
11
|
uniform bool filter_transformSize;
|
|
12
|
+
uniform ivec4 filter_categoryBitMask;
|
|
12
13
|
|
|
13
14
|
#ifdef NON_INSTANCED_MODEL
|
|
14
15
|
#define DATAFILTER_ATTRIB filterValues
|
|
15
16
|
#define DATAFILTER_ATTRIB_64LOW filterValues64Low
|
|
17
|
+
#define DATACATEGORY_ATTRIB filterCategoryValues
|
|
16
18
|
#else
|
|
17
19
|
#define DATAFILTER_ATTRIB instanceFilterValues
|
|
18
20
|
#define DATAFILTER_ATTRIB_64LOW instanceFilterValues64Low
|
|
21
|
+
#define DATACATEGORY_ATTRIB instanceFilterCategoryValues
|
|
19
22
|
#endif
|
|
20
23
|
|
|
21
24
|
in DATAFILTER_TYPE DATAFILTER_ATTRIB;
|
|
@@ -25,6 +28,7 @@ in DATAFILTER_TYPE DATAFILTER_ATTRIB;
|
|
|
25
28
|
uniform DATAFILTER_TYPE filter_min64High;
|
|
26
29
|
uniform DATAFILTER_TYPE filter_max64High;
|
|
27
30
|
#endif
|
|
31
|
+
in DATACATEGORY_TYPE DATACATEGORY_ATTRIB;
|
|
28
32
|
|
|
29
33
|
out float dataFilter_value;
|
|
30
34
|
|
|
@@ -40,7 +44,7 @@ float dataFilter_reduceValue(vec3 value) {
|
|
|
40
44
|
float dataFilter_reduceValue(vec4 value) {
|
|
41
45
|
return min(min(value.x, value.y), min(value.z, value.w));
|
|
42
46
|
}
|
|
43
|
-
void dataFilter_setValue(DATAFILTER_TYPE valueFromMin, DATAFILTER_TYPE valueFromMax) {
|
|
47
|
+
void dataFilter_setValue(DATAFILTER_TYPE valueFromMin, DATAFILTER_TYPE valueFromMax, DATACATEGORY_TYPE category) {
|
|
44
48
|
if (filter_enabled) {
|
|
45
49
|
if (filter_useSoftMargin) {
|
|
46
50
|
dataFilter_value = dataFilter_reduceValue(
|
|
@@ -52,6 +56,29 @@ void dataFilter_setValue(DATAFILTER_TYPE valueFromMin, DATAFILTER_TYPE valueFrom
|
|
|
52
56
|
step(filter_min, valueFromMin) * step(valueFromMax, filter_max)
|
|
53
57
|
);
|
|
54
58
|
}
|
|
59
|
+
|
|
60
|
+
#if DATACATEGORY_CHANNELS == 1 // One 128-bit mask
|
|
61
|
+
int dataFilter_masks = filter_categoryBitMask[int(category / 32.0)];
|
|
62
|
+
#elif DATACATEGORY_CHANNELS == 2 // Two 64-bit masks
|
|
63
|
+
ivec2 dataFilter_masks = ivec2(
|
|
64
|
+
filter_categoryBitMask[int(category.x / 32.0)],
|
|
65
|
+
filter_categoryBitMask[int(category.y / 32.0) + 2]
|
|
66
|
+
);
|
|
67
|
+
#elif DATACATEGORY_CHANNELS == 3 // Three 32-bit masks
|
|
68
|
+
ivec3 dataFilter_masks = filter_categoryBitMask.xyz;
|
|
69
|
+
#else // Four 32-bit masks
|
|
70
|
+
ivec4 dataFilter_masks = filter_categoryBitMask;
|
|
71
|
+
#endif
|
|
72
|
+
|
|
73
|
+
// Shift mask and extract relevant bits
|
|
74
|
+
DATACATEGORY_TYPE dataFilter_bits = DATACATEGORY_TYPE(dataFilter_masks) / pow(DATACATEGORY_TYPE(2.0), mod(category, 32.0));
|
|
75
|
+
dataFilter_bits = mod(floor(dataFilter_bits), 2.0);
|
|
76
|
+
|
|
77
|
+
#if DATACATEGORY_CHANNELS == 1
|
|
78
|
+
if(dataFilter_bits == 0.0) dataFilter_value = 0.0;
|
|
79
|
+
#else
|
|
80
|
+
if(any(equal(dataFilter_bits, DATACATEGORY_TYPE(0.0)))) dataFilter_value = 0.0;
|
|
81
|
+
#endif
|
|
55
82
|
} else {
|
|
56
83
|
dataFilter_value = 1.0;
|
|
57
84
|
}
|
|
@@ -120,10 +147,11 @@ const inject = {
|
|
|
120
147
|
#ifdef DATAFILTER_DOUBLE
|
|
121
148
|
dataFilter_setValue(
|
|
122
149
|
DATAFILTER_ATTRIB - filter_min64High + DATAFILTER_ATTRIB_64LOW,
|
|
123
|
-
DATAFILTER_ATTRIB - filter_max64High + DATAFILTER_ATTRIB_64LOW
|
|
150
|
+
DATAFILTER_ATTRIB - filter_max64High + DATAFILTER_ATTRIB_64LOW,
|
|
151
|
+
DATACATEGORY_ATTRIB
|
|
124
152
|
);
|
|
125
153
|
#else
|
|
126
|
-
dataFilter_setValue(DATAFILTER_ATTRIB, DATAFILTER_ATTRIB);
|
|
154
|
+
dataFilter_setValue(DATAFILTER_ATTRIB, DATAFILTER_ATTRIB, DATACATEGORY_ATTRIB);
|
|
127
155
|
#endif
|
|
128
156
|
`,
|
|
129
157
|
'vs:#main-end': `
|
package/dist/dist.dev.js
CHANGED
|
@@ -916,13 +916,16 @@ uniform DATAFILTER_TYPE filter_max;
|
|
|
916
916
|
uniform bool filter_useSoftMargin;
|
|
917
917
|
uniform bool filter_enabled;
|
|
918
918
|
uniform bool filter_transformSize;
|
|
919
|
+
uniform ivec4 filter_categoryBitMask;
|
|
919
920
|
|
|
920
921
|
#ifdef NON_INSTANCED_MODEL
|
|
921
922
|
#define DATAFILTER_ATTRIB filterValues
|
|
922
923
|
#define DATAFILTER_ATTRIB_64LOW filterValues64Low
|
|
924
|
+
#define DATACATEGORY_ATTRIB filterCategoryValues
|
|
923
925
|
#else
|
|
924
926
|
#define DATAFILTER_ATTRIB instanceFilterValues
|
|
925
927
|
#define DATAFILTER_ATTRIB_64LOW instanceFilterValues64Low
|
|
928
|
+
#define DATACATEGORY_ATTRIB instanceFilterCategoryValues
|
|
926
929
|
#endif
|
|
927
930
|
|
|
928
931
|
in DATAFILTER_TYPE DATAFILTER_ATTRIB;
|
|
@@ -932,6 +935,7 @@ in DATAFILTER_TYPE DATAFILTER_ATTRIB;
|
|
|
932
935
|
uniform DATAFILTER_TYPE filter_min64High;
|
|
933
936
|
uniform DATAFILTER_TYPE filter_max64High;
|
|
934
937
|
#endif
|
|
938
|
+
in DATACATEGORY_TYPE DATACATEGORY_ATTRIB;
|
|
935
939
|
|
|
936
940
|
out float dataFilter_value;
|
|
937
941
|
|
|
@@ -947,7 +951,7 @@ float dataFilter_reduceValue(vec3 value) {
|
|
|
947
951
|
float dataFilter_reduceValue(vec4 value) {
|
|
948
952
|
return min(min(value.x, value.y), min(value.z, value.w));
|
|
949
953
|
}
|
|
950
|
-
void dataFilter_setValue(DATAFILTER_TYPE valueFromMin, DATAFILTER_TYPE valueFromMax) {
|
|
954
|
+
void dataFilter_setValue(DATAFILTER_TYPE valueFromMin, DATAFILTER_TYPE valueFromMax, DATACATEGORY_TYPE category) {
|
|
951
955
|
if (filter_enabled) {
|
|
952
956
|
if (filter_useSoftMargin) {
|
|
953
957
|
dataFilter_value = dataFilter_reduceValue(
|
|
@@ -959,6 +963,29 @@ void dataFilter_setValue(DATAFILTER_TYPE valueFromMin, DATAFILTER_TYPE valueFrom
|
|
|
959
963
|
step(filter_min, valueFromMin) * step(valueFromMax, filter_max)
|
|
960
964
|
);
|
|
961
965
|
}
|
|
966
|
+
|
|
967
|
+
#if DATACATEGORY_CHANNELS == 1 // One 128-bit mask
|
|
968
|
+
int dataFilter_masks = filter_categoryBitMask[int(category / 32.0)];
|
|
969
|
+
#elif DATACATEGORY_CHANNELS == 2 // Two 64-bit masks
|
|
970
|
+
ivec2 dataFilter_masks = ivec2(
|
|
971
|
+
filter_categoryBitMask[int(category.x / 32.0)],
|
|
972
|
+
filter_categoryBitMask[int(category.y / 32.0) + 2]
|
|
973
|
+
);
|
|
974
|
+
#elif DATACATEGORY_CHANNELS == 3 // Three 32-bit masks
|
|
975
|
+
ivec3 dataFilter_masks = filter_categoryBitMask.xyz;
|
|
976
|
+
#else // Four 32-bit masks
|
|
977
|
+
ivec4 dataFilter_masks = filter_categoryBitMask;
|
|
978
|
+
#endif
|
|
979
|
+
|
|
980
|
+
// Shift mask and extract relevant bits
|
|
981
|
+
DATACATEGORY_TYPE dataFilter_bits = DATACATEGORY_TYPE(dataFilter_masks) / pow(DATACATEGORY_TYPE(2.0), mod(category, 32.0));
|
|
982
|
+
dataFilter_bits = mod(floor(dataFilter_bits), 2.0);
|
|
983
|
+
|
|
984
|
+
#if DATACATEGORY_CHANNELS == 1
|
|
985
|
+
if(dataFilter_bits == 0.0) dataFilter_value = 0.0;
|
|
986
|
+
#else
|
|
987
|
+
if(any(equal(dataFilter_bits, DATACATEGORY_TYPE(0.0)))) dataFilter_value = 0.0;
|
|
988
|
+
#endif
|
|
962
989
|
} else {
|
|
963
990
|
dataFilter_value = 1.0;
|
|
964
991
|
}
|
|
@@ -1028,10 +1055,11 @@ in float dataFilter_value;
|
|
|
1028
1055
|
#ifdef DATAFILTER_DOUBLE
|
|
1029
1056
|
dataFilter_setValue(
|
|
1030
1057
|
DATAFILTER_ATTRIB - filter_min64High + DATAFILTER_ATTRIB_64LOW,
|
|
1031
|
-
DATAFILTER_ATTRIB - filter_max64High + DATAFILTER_ATTRIB_64LOW
|
|
1058
|
+
DATAFILTER_ATTRIB - filter_max64High + DATAFILTER_ATTRIB_64LOW,
|
|
1059
|
+
DATACATEGORY_ATTRIB
|
|
1032
1060
|
);
|
|
1033
1061
|
#else
|
|
1034
|
-
dataFilter_setValue(DATAFILTER_ATTRIB, DATAFILTER_ATTRIB);
|
|
1062
|
+
dataFilter_setValue(DATAFILTER_ATTRIB, DATAFILTER_ATTRIB, DATACATEGORY_ATTRIB);
|
|
1035
1063
|
#endif
|
|
1036
1064
|
`,
|
|
1037
1065
|
"vs:#main-end": `
|
|
@@ -1166,13 +1194,21 @@ void main() {
|
|
|
1166
1194
|
// src/data-filter/data-filter-extension.ts
|
|
1167
1195
|
var defaultProps2 = {
|
|
1168
1196
|
getFilterValue: { type: "accessor", value: 0 },
|
|
1197
|
+
getFilterCategory: { type: "accessor", value: 0 },
|
|
1169
1198
|
onFilteredItemsChange: { type: "function", value: null, optional: true },
|
|
1170
1199
|
filterEnabled: true,
|
|
1171
1200
|
filterRange: [-1, 1],
|
|
1172
1201
|
filterSoftRange: null,
|
|
1202
|
+
filterCategories: [0],
|
|
1173
1203
|
filterTransformSize: true,
|
|
1174
1204
|
filterTransformColor: true
|
|
1175
1205
|
};
|
|
1206
|
+
var defaultOptions = {
|
|
1207
|
+
categorySize: 1,
|
|
1208
|
+
filterSize: 1,
|
|
1209
|
+
fp64: false,
|
|
1210
|
+
countItems: false
|
|
1211
|
+
};
|
|
1176
1212
|
var DATA_TYPE_FROM_SIZE = {
|
|
1177
1213
|
1: "float",
|
|
1178
1214
|
2: "vec2",
|
|
@@ -1180,21 +1216,16 @@ void main() {
|
|
|
1180
1216
|
4: "vec4"
|
|
1181
1217
|
};
|
|
1182
1218
|
var DataFilterExtension = class extends import_core4.LayerExtension {
|
|
1183
|
-
constructor({
|
|
1184
|
-
|
|
1185
|
-
fp64: fp642 = false,
|
|
1186
|
-
countItems = false
|
|
1187
|
-
} = {}) {
|
|
1188
|
-
if (!DATA_TYPE_FROM_SIZE[filterSize]) {
|
|
1189
|
-
throw new Error("filterSize out of range");
|
|
1190
|
-
}
|
|
1191
|
-
super({ filterSize, fp64: fp642, countItems });
|
|
1219
|
+
constructor(opts) {
|
|
1220
|
+
super({ ...defaultOptions, ...opts });
|
|
1192
1221
|
}
|
|
1193
1222
|
getShaders(extension) {
|
|
1194
|
-
const { filterSize, fp64: fp642 } = extension.opts;
|
|
1223
|
+
const { categorySize, filterSize, fp64: fp642 } = extension.opts;
|
|
1195
1224
|
return {
|
|
1196
1225
|
modules: [fp642 ? shaderModule64 : shaderModule],
|
|
1197
1226
|
defines: {
|
|
1227
|
+
DATACATEGORY_TYPE: DATA_TYPE_FROM_SIZE[categorySize],
|
|
1228
|
+
DATACATEGORY_CHANNELS: categorySize,
|
|
1198
1229
|
DATAFILTER_TYPE: DATA_TYPE_FROM_SIZE[filterSize],
|
|
1199
1230
|
DATAFILTER_DOUBLE: Boolean(fp642)
|
|
1200
1231
|
}
|
|
@@ -1202,11 +1233,12 @@ void main() {
|
|
|
1202
1233
|
}
|
|
1203
1234
|
initializeState(context, extension) {
|
|
1204
1235
|
const attributeManager = this.getAttributeManager();
|
|
1236
|
+
const { categorySize, filterSize, fp64: fp642 } = extension.opts;
|
|
1205
1237
|
if (attributeManager) {
|
|
1206
1238
|
attributeManager.add({
|
|
1207
1239
|
filterValues: {
|
|
1208
|
-
size:
|
|
1209
|
-
type:
|
|
1240
|
+
size: filterSize,
|
|
1241
|
+
type: fp642 ? GLEnum.DOUBLE : GLEnum.FLOAT,
|
|
1210
1242
|
accessor: "getFilterValue",
|
|
1211
1243
|
shaderAttributes: {
|
|
1212
1244
|
filterValues: {
|
|
@@ -1216,6 +1248,20 @@ void main() {
|
|
|
1216
1248
|
divisor: 1
|
|
1217
1249
|
}
|
|
1218
1250
|
}
|
|
1251
|
+
},
|
|
1252
|
+
filterCategoryValues: {
|
|
1253
|
+
size: categorySize,
|
|
1254
|
+
type: GLEnum.FLOAT,
|
|
1255
|
+
accessor: "getFilterCategory",
|
|
1256
|
+
transform: categorySize === 1 ? (d) => extension._getCategoryKey.call(this, d, 0) : (d) => d.map((x, i) => extension._getCategoryKey.call(this, x, i)),
|
|
1257
|
+
shaderAttributes: {
|
|
1258
|
+
filterCategoryValues: {
|
|
1259
|
+
divisor: 0
|
|
1260
|
+
},
|
|
1261
|
+
instanceFilterCategoryValues: {
|
|
1262
|
+
divisor: 1
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1219
1265
|
}
|
|
1220
1266
|
});
|
|
1221
1267
|
}
|
|
@@ -1251,31 +1297,51 @@ void main() {
|
|
|
1251
1297
|
this.setState({ filterFBO, filterModel });
|
|
1252
1298
|
}
|
|
1253
1299
|
}
|
|
1254
|
-
updateState({ props, oldProps }) {
|
|
1300
|
+
updateState({ props, oldProps, changeFlags }, extension) {
|
|
1301
|
+
const attributeManager = this.getAttributeManager();
|
|
1302
|
+
const { categorySize } = extension.opts;
|
|
1255
1303
|
if (this.state.filterModel) {
|
|
1256
|
-
const
|
|
1257
|
-
const filterNeedsUpdate = attributeManager.attributes.filterValues.needsUpdate() || props.filterEnabled !== oldProps.filterEnabled || props.filterRange !== oldProps.filterRange || props.filterSoftRange !== oldProps.filterSoftRange;
|
|
1304
|
+
const filterNeedsUpdate = attributeManager.attributes.filterValues.needsUpdate() || attributeManager.attributes.filterCategoryValues?.needsUpdate() || props.filterEnabled !== oldProps.filterEnabled || props.filterRange !== oldProps.filterRange || props.filterSoftRange !== oldProps.filterSoftRange || props.filterCategories !== oldProps.filterCategories;
|
|
1258
1305
|
if (filterNeedsUpdate) {
|
|
1259
1306
|
this.setState({ filterNeedsUpdate });
|
|
1260
1307
|
}
|
|
1261
1308
|
}
|
|
1309
|
+
if (attributeManager?.attributes.filterCategoryValues) {
|
|
1310
|
+
const categoryBitMaskNeedsUpdate = attributeManager.attributes.filterCategoryValues.needsUpdate() || !(0, import_core4._deepEqual)(props.filterCategories, oldProps.filterCategories, 2);
|
|
1311
|
+
if (categoryBitMaskNeedsUpdate) {
|
|
1312
|
+
this.setState({ categoryBitMaskNeedsUpdate });
|
|
1313
|
+
}
|
|
1314
|
+
const resetCategories = changeFlags.dataChanged;
|
|
1315
|
+
if (resetCategories) {
|
|
1316
|
+
this.setState({
|
|
1317
|
+
categoryMap: Array(categorySize).fill(0).map(() => ({}))
|
|
1318
|
+
});
|
|
1319
|
+
attributeManager.attributes.filterCategoryValues.setNeedsUpdate("categoryMap");
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1262
1322
|
}
|
|
1263
1323
|
draw(params, extension) {
|
|
1264
1324
|
const filterFBO = this.state.filterFBO;
|
|
1265
1325
|
const filterModel = this.state.filterModel;
|
|
1266
1326
|
const filterNeedsUpdate = this.state.filterNeedsUpdate;
|
|
1327
|
+
const categoryBitMaskNeedsUpdate = this.state.categoryBitMaskNeedsUpdate;
|
|
1267
1328
|
const { onFilteredItemsChange } = this.props;
|
|
1329
|
+
if (categoryBitMaskNeedsUpdate) {
|
|
1330
|
+
extension._updateCategoryBitMask.call(this, params, extension);
|
|
1331
|
+
}
|
|
1268
1332
|
if (filterNeedsUpdate && onFilteredItemsChange && filterModel) {
|
|
1269
1333
|
const {
|
|
1270
|
-
attributes: { filterValues, filterIndices }
|
|
1334
|
+
attributes: { filterValues, filterCategoryValues, filterIndices }
|
|
1271
1335
|
} = this.getAttributeManager();
|
|
1272
1336
|
filterModel.setVertexCount(this.getNumInstances());
|
|
1273
1337
|
this.context.device.clearWebGL({ framebuffer: filterFBO, color: [0, 0, 0, 0] });
|
|
1274
1338
|
filterModel.updateModuleSettings(params.moduleParameters);
|
|
1275
1339
|
filterModel.setAttributes({
|
|
1276
1340
|
...filterValues.getValue(),
|
|
1341
|
+
...filterCategoryValues?.getValue(),
|
|
1277
1342
|
...filterIndices?.getValue()
|
|
1278
1343
|
});
|
|
1344
|
+
filterModel.setUniforms(params.uniforms);
|
|
1279
1345
|
filterModel.device.withParametersWebGL(
|
|
1280
1346
|
{
|
|
1281
1347
|
framebuffer: filterFBO,
|
|
@@ -1301,6 +1367,34 @@ void main() {
|
|
|
1301
1367
|
filterFBO?.destroy();
|
|
1302
1368
|
filterModel?.destroy();
|
|
1303
1369
|
}
|
|
1370
|
+
_updateCategoryBitMask(params, extension) {
|
|
1371
|
+
const { categorySize } = extension.opts;
|
|
1372
|
+
const { filterCategories } = this.props;
|
|
1373
|
+
const categoryBitMask = new Uint32Array([0, 0, 0, 0]);
|
|
1374
|
+
const categoryFilters = categorySize === 1 ? [filterCategories] : filterCategories;
|
|
1375
|
+
const maxCategories = categorySize === 1 ? 128 : categorySize === 2 ? 64 : 32;
|
|
1376
|
+
for (let c = 0; c < categoryFilters.length; c++) {
|
|
1377
|
+
const categoryFilter = categoryFilters[c];
|
|
1378
|
+
for (const category of categoryFilter) {
|
|
1379
|
+
const key = extension._getCategoryKey.call(this, category, c);
|
|
1380
|
+
if (key < maxCategories) {
|
|
1381
|
+
const channel = c * (maxCategories / 32) + Math.floor(key / 32);
|
|
1382
|
+
categoryBitMask[channel] += Math.pow(2, key % 32);
|
|
1383
|
+
} else {
|
|
1384
|
+
import_core4.log.warn(`Exceeded maximum number of categories (${maxCategories})`)();
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
params.uniforms.filter_categoryBitMask = categoryBitMask;
|
|
1389
|
+
this.state.categoryBitMaskNeedsUpdate = false;
|
|
1390
|
+
}
|
|
1391
|
+
_getCategoryKey(category, channel) {
|
|
1392
|
+
const categoryMap = this.state.categoryMap[channel];
|
|
1393
|
+
if (!(category in categoryMap)) {
|
|
1394
|
+
categoryMap[category] = Object.keys(categoryMap).length;
|
|
1395
|
+
}
|
|
1396
|
+
return categoryMap[category];
|
|
1397
|
+
}
|
|
1304
1398
|
};
|
|
1305
1399
|
DataFilterExtension.defaultProps = defaultProps2;
|
|
1306
1400
|
DataFilterExtension.extensionName = "DataFilterExtension";
|