@deck.gl/core 9.3.0-alpha.2 → 9.3.0-alpha.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/controllers/terrain-controller.d.ts +30 -0
- package/dist/controllers/terrain-controller.d.ts.map +1 -0
- package/dist/controllers/terrain-controller.js +127 -0
- package/dist/controllers/terrain-controller.js.map +1 -0
- package/dist/dist.dev.js +3137 -1160
- package/dist/index.cjs +584 -181
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/attribute/gl-utils.d.ts +1 -2
- package/dist/lib/attribute/gl-utils.d.ts.map +1 -1
- package/dist/lib/attribute/gl-utils.js +2 -2
- package/dist/lib/attribute/gl-utils.js.map +1 -1
- package/dist/lib/deck-picker.d.ts +3 -2
- package/dist/lib/deck-picker.d.ts.map +1 -1
- package/dist/lib/deck-picker.js +74 -17
- package/dist/lib/deck-picker.js.map +1 -1
- package/dist/lib/deck.d.ts +62 -0
- package/dist/lib/deck.d.ts.map +1 -1
- package/dist/lib/deck.js +219 -77
- package/dist/lib/deck.js.map +1 -1
- package/dist/lib/init.js +2 -2
- package/dist/lib/layer.d.ts.map +1 -1
- package/dist/lib/layer.js +60 -9
- package/dist/lib/layer.js.map +1 -1
- package/dist/lib/view-manager.js +1 -1
- package/dist/lib/view-manager.js.map +1 -1
- package/dist/passes/pick-layers-pass.d.ts.map +1 -1
- package/dist/passes/pick-layers-pass.js +7 -2
- package/dist/passes/pick-layers-pass.js.map +1 -1
- package/dist/passes/screen-pass-uniforms.d.ts +1 -1
- package/dist/passes/screen-pass-uniforms.js +1 -1
- package/dist/shaderlib/color/color.d.ts +1 -4
- package/dist/shaderlib/color/color.d.ts.map +1 -1
- package/dist/shaderlib/color/color.js +0 -12
- package/dist/shaderlib/color/color.js.map +1 -1
- package/dist/shaderlib/misc/layer-uniforms.d.ts +3 -2
- package/dist/shaderlib/misc/layer-uniforms.d.ts.map +1 -1
- package/dist/shaderlib/misc/layer-uniforms.js +10 -1
- package/dist/shaderlib/misc/layer-uniforms.js.map +1 -1
- package/dist/shaderlib/picking/picking.d.ts +3 -2
- package/dist/shaderlib/picking/picking.d.ts.map +1 -1
- package/dist/shaderlib/picking/picking.js +29 -0
- package/dist/shaderlib/picking/picking.js.map +1 -1
- package/dist/shaderlib/project/project.glsl.js +1 -1
- package/dist/shaderlib/project/project.wgsl.d.ts.map +1 -1
- package/dist/shaderlib/project/project.wgsl.js +4 -6
- package/dist/shaderlib/project/project.wgsl.js.map +1 -1
- package/dist/shaderlib/shadow/shadow.d.ts +2 -2
- package/dist/shaderlib/shadow/shadow.js +1 -1
- package/dist/transitions/gpu-interpolation-transition.js +2 -2
- package/dist/transitions/gpu-interpolation-transition.js.map +1 -1
- package/dist/transitions/gpu-spring-transition.js +1 -1
- package/dist/transitions/gpu-transition-utils.d.ts.map +1 -1
- package/dist/transitions/gpu-transition-utils.js +3 -4
- package/dist/transitions/gpu-transition-utils.js.map +1 -1
- package/dist/utils/typed-array-manager.js.map +1 -1
- package/dist.min.js +506 -234
- package/package.json +6 -7
- package/src/controllers/terrain-controller.ts +155 -0
- package/src/index.ts +1 -0
- package/src/lib/attribute/gl-utils.ts +2 -2
- package/src/lib/deck-picker.ts +98 -17
- package/src/lib/deck.ts +334 -86
- package/src/lib/layer.ts +98 -8
- package/src/lib/view-manager.ts +1 -1
- package/src/passes/pick-layers-pass.ts +6 -2
- package/src/passes/screen-pass-uniforms.ts +1 -1
- package/src/shaderlib/color/color.ts +0 -12
- package/src/shaderlib/misc/layer-uniforms.ts +11 -1
- package/src/shaderlib/picking/picking.ts +30 -0
- package/src/shaderlib/project/project.glsl.ts +1 -1
- package/src/shaderlib/project/project.wgsl.ts +4 -6
- package/src/shaderlib/shadow/shadow.ts +1 -1
- package/src/transitions/gpu-interpolation-transition.ts +2 -2
- package/src/transitions/gpu-spring-transition.ts +1 -1
- package/src/transitions/gpu-transition-utils.ts +4 -5
- package/src/utils/typed-array-manager.ts +3 -3
package/src/lib/deck.ts
CHANGED
|
@@ -20,7 +20,7 @@ import {luma} from '@luma.gl/core';
|
|
|
20
20
|
import {webgl2Adapter} from '@luma.gl/webgl';
|
|
21
21
|
import {Timeline} from '@luma.gl/engine';
|
|
22
22
|
import {AnimationLoop} from '@luma.gl/engine';
|
|
23
|
-
import {GL} from '@luma.gl/constants';
|
|
23
|
+
import {GL} from '@luma.gl/webgl/constants';
|
|
24
24
|
import type {CanvasContextProps, Device, DeviceProps, Framebuffer, Parameters} from '@luma.gl/core';
|
|
25
25
|
import type {ShaderModule} from '@luma.gl/shadertools';
|
|
26
26
|
|
|
@@ -81,6 +81,12 @@ type CursorState = {
|
|
|
81
81
|
isDragging: boolean;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
type InternalPickingMode = 'sync' | 'async';
|
|
85
|
+
type PointPickResult = {
|
|
86
|
+
result: PickingInfo[];
|
|
87
|
+
emptyInfo: PickingInfo;
|
|
88
|
+
};
|
|
89
|
+
|
|
84
90
|
export type DeckProps<ViewsT extends ViewOrViews = null> = {
|
|
85
91
|
/** Id of this Deck instance */
|
|
86
92
|
id?: string;
|
|
@@ -103,6 +109,10 @@ export type DeckProps<ViewsT extends ViewOrViews = null> = {
|
|
|
103
109
|
* @default `0`
|
|
104
110
|
*/
|
|
105
111
|
pickingRadius?: number;
|
|
112
|
+
/** Selects the internal picking policy used by deck-managed events and controllers.
|
|
113
|
+
* @default `'auto'`
|
|
114
|
+
*/
|
|
115
|
+
pickAsync?: InternalPickingMode | 'auto';
|
|
106
116
|
|
|
107
117
|
/** WebGL parameters to be set before each frame is rendered. */
|
|
108
118
|
parameters?: Parameters;
|
|
@@ -233,6 +243,7 @@ const defaultProps: DeckProps = {
|
|
|
233
243
|
viewState: null,
|
|
234
244
|
initialViewState: null,
|
|
235
245
|
pickingRadius: 0,
|
|
246
|
+
pickAsync: 'auto',
|
|
236
247
|
layerFilter: null,
|
|
237
248
|
parameters: {},
|
|
238
249
|
parent: null,
|
|
@@ -333,6 +344,8 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
333
344
|
gpuMemory: 0
|
|
334
345
|
};
|
|
335
346
|
private _metricsCounter: number = 0;
|
|
347
|
+
private _hoverPickSequence: number = 0;
|
|
348
|
+
private _pointerDownPickSequence: number = 0;
|
|
336
349
|
|
|
337
350
|
private _needsRedraw: false | string = 'Initial render';
|
|
338
351
|
private _pickRequest: {
|
|
@@ -356,6 +369,7 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
356
369
|
* This object is reused for subsequent `onClick` and `onDrag*` callbacks.
|
|
357
370
|
*/
|
|
358
371
|
private _lastPointerDownInfo: PickingInfo | null = null;
|
|
372
|
+
private _lastPointerDownInfoPromise: Promise<PickingInfo> | null = null;
|
|
359
373
|
|
|
360
374
|
constructor(props: DeckProps<ViewsT>) {
|
|
361
375
|
// @ts-ignore views
|
|
@@ -423,7 +437,10 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
423
437
|
this.animationLoop?.stop();
|
|
424
438
|
this.animationLoop?.destroy();
|
|
425
439
|
this.animationLoop = null;
|
|
440
|
+
this._hoverPickSequence++;
|
|
441
|
+
this._pointerDownPickSequence++;
|
|
426
442
|
this._lastPointerDownInfo = null;
|
|
443
|
+
this._lastPointerDownInfoPromise = null;
|
|
427
444
|
|
|
428
445
|
this.layerManager?.finalize();
|
|
429
446
|
this.layerManager = null;
|
|
@@ -474,6 +491,7 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
474
491
|
|
|
475
492
|
// Merge with existing props
|
|
476
493
|
Object.assign(this.props, props);
|
|
494
|
+
this._validateInternalPickingMode();
|
|
477
495
|
|
|
478
496
|
// Update CSS size of canvas
|
|
479
497
|
this._setCanvasSize(this.props);
|
|
@@ -631,6 +649,47 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
631
649
|
}
|
|
632
650
|
|
|
633
651
|
/** Query the object rendered on top at a given point */
|
|
652
|
+
async pickObjectAsync(opts: {
|
|
653
|
+
/** x position in pixels */
|
|
654
|
+
x: number;
|
|
655
|
+
/** y position in pixels */
|
|
656
|
+
y: number;
|
|
657
|
+
/** Radius of tolerance in pixels. Default `0`. */
|
|
658
|
+
radius?: number;
|
|
659
|
+
/** A list of layer ids to query from. If not specified, then all pickable and visible layers are queried. */
|
|
660
|
+
layerIds?: string[];
|
|
661
|
+
/** If `true`, `info.coordinate` will be a 3D point by unprojecting the `x, y` screen coordinates onto the picked geometry. Default `false`. */
|
|
662
|
+
unproject3D?: boolean;
|
|
663
|
+
}): Promise<PickingInfo | null> {
|
|
664
|
+
const infos = (await this._pickAsync('pickObjectAsync', 'pickObject Time', opts)).result;
|
|
665
|
+
return infos.length ? infos[0] : null;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Query all objects rendered on top within a bounding box
|
|
670
|
+
* @note Caveat: this method performs multiple async GPU queries, so state could potentially change between calls.
|
|
671
|
+
*/
|
|
672
|
+
async pickObjectsAsync(opts: {
|
|
673
|
+
/** Left of the bounding box in pixels */
|
|
674
|
+
x: number;
|
|
675
|
+
/** Top of the bounding box in pixels */
|
|
676
|
+
y: number;
|
|
677
|
+
/** Width of the bounding box in pixels. Default `1` */
|
|
678
|
+
width?: number;
|
|
679
|
+
/** Height of the bounding box in pixels. Default `1` */
|
|
680
|
+
height?: number;
|
|
681
|
+
/** A list of layer ids to query from. If not specified, then all pickable and visible layers are queried. */
|
|
682
|
+
layerIds?: string[];
|
|
683
|
+
/** If specified, limits the number of objects that can be returned. */
|
|
684
|
+
maxObjects?: number | null;
|
|
685
|
+
}): Promise<PickingInfo[]> {
|
|
686
|
+
return await this._pickAsync('pickObjectsAsync', 'pickObjects Time', opts);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Query the object rendered on top at a given point
|
|
691
|
+
* @deprecated WebGL only. Use `pickObjectsAsync` instead
|
|
692
|
+
*/
|
|
634
693
|
pickObject(opts: {
|
|
635
694
|
/** x position in pixels */
|
|
636
695
|
x: number;
|
|
@@ -647,7 +706,10 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
647
706
|
return infos.length ? infos[0] : null;
|
|
648
707
|
}
|
|
649
708
|
|
|
650
|
-
|
|
709
|
+
/**
|
|
710
|
+
* Query all rendered objects at a given point
|
|
711
|
+
* @deprecated WebGL only. Use `pickObjectsAsync` instead
|
|
712
|
+
*/
|
|
651
713
|
pickMultipleObjects(opts: {
|
|
652
714
|
/** x position in pixels */
|
|
653
715
|
x: number;
|
|
@@ -666,7 +728,10 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
666
728
|
return this._pick('pickObject', 'pickMultipleObjects Time', opts).result;
|
|
667
729
|
}
|
|
668
730
|
|
|
669
|
-
|
|
731
|
+
/**
|
|
732
|
+
* Query all objects rendered on top within a bounding box
|
|
733
|
+
* @deprecated WebGL only. Use `pickObjectsAsync` instead
|
|
734
|
+
*/
|
|
670
735
|
pickObjects(opts: {
|
|
671
736
|
/** Left of the bounding box in pixels */
|
|
672
737
|
x: number;
|
|
@@ -689,8 +754,12 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
689
754
|
* @private
|
|
690
755
|
*/
|
|
691
756
|
private _pickPositionForController(x: number, y: number): {coordinate?: number[]} | null {
|
|
692
|
-
const
|
|
693
|
-
|
|
757
|
+
const internalPickingMode = this._getInternalPickingMode();
|
|
758
|
+
if (internalPickingMode !== 'sync') {
|
|
759
|
+
return null;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
return this.pickObject({x, y, radius: 0, unproject3D: true});
|
|
694
763
|
}
|
|
695
764
|
|
|
696
765
|
/** Experimental
|
|
@@ -733,6 +802,166 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
733
802
|
|
|
734
803
|
// Private Methods
|
|
735
804
|
|
|
805
|
+
private _resolveInternalPickingMode(): InternalPickingMode {
|
|
806
|
+
const {pickAsync} = this.props;
|
|
807
|
+
const deviceType = this.device?.type || this.props.deviceProps?.type;
|
|
808
|
+
|
|
809
|
+
if (pickAsync === 'auto') {
|
|
810
|
+
return deviceType === 'webgpu' ? 'async' : 'sync';
|
|
811
|
+
}
|
|
812
|
+
if (pickAsync === 'sync' && deviceType === 'webgpu') {
|
|
813
|
+
throw new Error('`pickAsync: "sync"` is not supported when Deck is using a WebGPU device.');
|
|
814
|
+
}
|
|
815
|
+
return pickAsync;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
private _getInternalPickingMode(): InternalPickingMode | null {
|
|
819
|
+
try {
|
|
820
|
+
return this._resolveInternalPickingMode();
|
|
821
|
+
} catch (error) {
|
|
822
|
+
this.props.onError?.(error as Error);
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
private _validateInternalPickingMode(): void {
|
|
828
|
+
this._getInternalPickingMode();
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
private _getFirstPickedInfo({result, emptyInfo}: PointPickResult): PickingInfo {
|
|
832
|
+
return result[0] || emptyInfo;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
private _shouldUnproject3D(layers = this.layerManager?.getLayers() || []): boolean {
|
|
836
|
+
return layers.some(layer => layer.props.pickable === '3d');
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
private _getPointPickOptions(
|
|
840
|
+
x: number,
|
|
841
|
+
y: number,
|
|
842
|
+
opts: Partial<PickByPointOptions> = {},
|
|
843
|
+
layers = this.layerManager?.getLayers() || []
|
|
844
|
+
): PickByPointOptions {
|
|
845
|
+
return {
|
|
846
|
+
x,
|
|
847
|
+
y,
|
|
848
|
+
radius: this.props.pickingRadius,
|
|
849
|
+
unproject3D: this._shouldUnproject3D(layers),
|
|
850
|
+
...opts
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
private _pickPointSync(opts: PickByPointOptions): PointPickResult {
|
|
855
|
+
return this._pick('pickObject', 'pickObject Time', opts);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
private _pickPointAsync(opts: PickByPointOptions): Promise<PointPickResult> {
|
|
859
|
+
return this._pickAsync('pickObjectAsync', 'pickObject Time', opts);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
private _getLastPointerDownPickingInfo(
|
|
863
|
+
x: number,
|
|
864
|
+
y: number,
|
|
865
|
+
layers = this.layerManager?.getLayers() || []
|
|
866
|
+
): PickingInfo {
|
|
867
|
+
return this.deckPicker!.getLastPickedObject(
|
|
868
|
+
{
|
|
869
|
+
x,
|
|
870
|
+
y,
|
|
871
|
+
layers,
|
|
872
|
+
viewports: this.getViewports({x, y})
|
|
873
|
+
},
|
|
874
|
+
this._lastPointerDownInfo
|
|
875
|
+
) as PickingInfo;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
private _applyHoverCallbacks(
|
|
879
|
+
{result, emptyInfo}: PointPickResult,
|
|
880
|
+
event: MjolnirPointerEvent
|
|
881
|
+
): void {
|
|
882
|
+
if (!this.widgetManager) {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
this.cursorState.isHovering = result.length > 0;
|
|
887
|
+
|
|
888
|
+
let pickedInfo = emptyInfo;
|
|
889
|
+
let handled = false;
|
|
890
|
+
for (const info of result) {
|
|
891
|
+
pickedInfo = info;
|
|
892
|
+
handled = info.layer?.onHover(info, event) || handled;
|
|
893
|
+
}
|
|
894
|
+
if (!handled) {
|
|
895
|
+
this.props.onHover?.(pickedInfo, event);
|
|
896
|
+
this.widgetManager.onHover(pickedInfo, event);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
private _dispatchPickingEvent(info: PickingInfo, event: MjolnirGestureEvent): void {
|
|
901
|
+
if (!this.layerManager || !this.widgetManager) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
const eventHandlerProp = EVENT_HANDLERS[event.type];
|
|
906
|
+
if (!eventHandlerProp) {
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
const {layer} = info;
|
|
911
|
+
const layerHandler = layer && (layer[eventHandlerProp] || layer.props[eventHandlerProp]);
|
|
912
|
+
const rootHandler = this.props[eventHandlerProp];
|
|
913
|
+
let handled = false;
|
|
914
|
+
|
|
915
|
+
if (layerHandler) {
|
|
916
|
+
handled = layerHandler.call(layer, info, event);
|
|
917
|
+
}
|
|
918
|
+
if (!handled) {
|
|
919
|
+
rootHandler?.(info, event);
|
|
920
|
+
this.widgetManager.onEvent(info, event);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
private _pickAsync(
|
|
925
|
+
method: 'pickObjectAsync',
|
|
926
|
+
statKey: string,
|
|
927
|
+
opts: PickByPointOptions & {layerIds?: string[]}
|
|
928
|
+
): Promise<{
|
|
929
|
+
result: PickingInfo[];
|
|
930
|
+
emptyInfo: PickingInfo;
|
|
931
|
+
}>;
|
|
932
|
+
private _pickAsync(
|
|
933
|
+
method: 'pickObjectsAsync',
|
|
934
|
+
statKey: string,
|
|
935
|
+
opts: PickByRectOptions & {layerIds?: string[]}
|
|
936
|
+
): Promise<PickingInfo[]>;
|
|
937
|
+
|
|
938
|
+
private _pickAsync(
|
|
939
|
+
method: 'pickObjectAsync' | 'pickObjectsAsync',
|
|
940
|
+
statKey: string,
|
|
941
|
+
opts: (PickByPointOptions | PickByRectOptions) & {layerIds?: string[]}
|
|
942
|
+
) {
|
|
943
|
+
assert(this.deckPicker);
|
|
944
|
+
|
|
945
|
+
const {stats} = this;
|
|
946
|
+
|
|
947
|
+
stats.get('Pick Count').incrementCount();
|
|
948
|
+
stats.get(statKey).timeStart();
|
|
949
|
+
|
|
950
|
+
const infos = this.deckPicker[method]({
|
|
951
|
+
// layerManager, viewManager and effectManager are always defined if deckPicker is
|
|
952
|
+
layers: this.layerManager!.getLayers(opts),
|
|
953
|
+
views: this.viewManager!.getViews(),
|
|
954
|
+
viewports: this.getViewports(opts),
|
|
955
|
+
onViewportActive: this.layerManager!.activateViewport,
|
|
956
|
+
effects: this.effectManager!.getEffects(),
|
|
957
|
+
...opts
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
stats.get(statKey).timeEnd();
|
|
961
|
+
|
|
962
|
+
return infos;
|
|
963
|
+
}
|
|
964
|
+
|
|
736
965
|
private _pick(
|
|
737
966
|
method: 'pickObject',
|
|
738
967
|
statKey: string,
|
|
@@ -992,46 +1221,41 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
992
1221
|
|
|
993
1222
|
/** Actually run picking */
|
|
994
1223
|
private _pickAndCallback() {
|
|
995
|
-
if (this.device?.type === 'webgpu') {
|
|
996
|
-
return;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
1224
|
const {_pickRequest} = this;
|
|
1000
1225
|
|
|
1001
1226
|
if (_pickRequest.event) {
|
|
1002
|
-
|
|
1227
|
+
const event = _pickRequest.event;
|
|
1003
1228
|
const layers = this.layerManager?.getLayers() || [];
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
// Execute callbacks
|
|
1022
|
-
let pickedInfo = emptyInfo;
|
|
1023
|
-
let handled = false;
|
|
1024
|
-
for (const info of result) {
|
|
1025
|
-
pickedInfo = info;
|
|
1026
|
-
handled = info.layer?.onHover(info, _pickRequest.event) || handled;
|
|
1229
|
+
const pickOptions = this._getPointPickOptions(
|
|
1230
|
+
_pickRequest.x,
|
|
1231
|
+
_pickRequest.y,
|
|
1232
|
+
{
|
|
1233
|
+
radius: _pickRequest.radius,
|
|
1234
|
+
mode: _pickRequest.mode
|
|
1235
|
+
},
|
|
1236
|
+
layers
|
|
1237
|
+
);
|
|
1238
|
+
const internalPickingMode = this._getInternalPickingMode();
|
|
1239
|
+
const hoverPickSequence = ++this._hoverPickSequence;
|
|
1240
|
+
|
|
1241
|
+
_pickRequest.event = null;
|
|
1242
|
+
|
|
1243
|
+
if (!internalPickingMode) {
|
|
1244
|
+
return;
|
|
1027
1245
|
}
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
this.
|
|
1246
|
+
|
|
1247
|
+
if (internalPickingMode === 'sync') {
|
|
1248
|
+
this._applyHoverCallbacks(this._pickPointSync(pickOptions), event);
|
|
1249
|
+
return;
|
|
1031
1250
|
}
|
|
1032
1251
|
|
|
1033
|
-
|
|
1034
|
-
|
|
1252
|
+
this._pickPointAsync(pickOptions)
|
|
1253
|
+
.then(({result, emptyInfo}) => {
|
|
1254
|
+
if (hoverPickSequence === this._hoverPickSequence) {
|
|
1255
|
+
this._applyHoverCallbacks({result, emptyInfo}, event);
|
|
1256
|
+
}
|
|
1257
|
+
})
|
|
1258
|
+
.catch(error => this.props.onError?.(error));
|
|
1035
1259
|
}
|
|
1036
1260
|
}
|
|
1037
1261
|
|
|
@@ -1044,6 +1268,7 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
1044
1268
|
|
|
1045
1269
|
private _setDevice(device: Device) {
|
|
1046
1270
|
this.device = device;
|
|
1271
|
+
this._validateInternalPickingMode();
|
|
1047
1272
|
|
|
1048
1273
|
if (!this.animationLoop) {
|
|
1049
1274
|
// finalize() has been called
|
|
@@ -1231,10 +1456,7 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
1231
1456
|
this.layerManager!.updateLayers();
|
|
1232
1457
|
|
|
1233
1458
|
// Perform picking request if any
|
|
1234
|
-
|
|
1235
|
-
if (this.device?.type !== 'webgpu') {
|
|
1236
|
-
this._pickAndCallback();
|
|
1237
|
-
}
|
|
1459
|
+
this._pickAndCallback();
|
|
1238
1460
|
|
|
1239
1461
|
// Redraw if necessary
|
|
1240
1462
|
this.redraw();
|
|
@@ -1279,61 +1501,87 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
|
|
|
1279
1501
|
return;
|
|
1280
1502
|
}
|
|
1281
1503
|
|
|
1282
|
-
let info: PickingInfo;
|
|
1283
|
-
|
|
1284
|
-
// For click events, check if any layer has pickable: '3d' to determine if we need depth picking
|
|
1285
1504
|
const layers = this.layerManager.getLayers();
|
|
1286
|
-
const
|
|
1505
|
+
const internalPickingMode = this._getInternalPickingMode();
|
|
1287
1506
|
|
|
1288
|
-
if (
|
|
1289
|
-
|
|
1290
|
-
const pickResult = this._pick('pickObject', 'pickObject Time', {
|
|
1291
|
-
x: pos.x,
|
|
1292
|
-
y: pos.y,
|
|
1293
|
-
radius: this.props.pickingRadius,
|
|
1294
|
-
unproject3D: true
|
|
1295
|
-
});
|
|
1296
|
-
info = pickResult.result[0] || pickResult.emptyInfo;
|
|
1297
|
-
} else {
|
|
1298
|
-
// Reuse last picked object for other events
|
|
1299
|
-
info = this.deckPicker!.getLastPickedObject(
|
|
1300
|
-
{
|
|
1301
|
-
x: pos.x,
|
|
1302
|
-
y: pos.y,
|
|
1303
|
-
layers,
|
|
1304
|
-
viewports: this.getViewports(pos)
|
|
1305
|
-
},
|
|
1306
|
-
this._lastPointerDownInfo
|
|
1307
|
-
) as PickingInfo;
|
|
1507
|
+
if (!internalPickingMode) {
|
|
1508
|
+
return;
|
|
1308
1509
|
}
|
|
1309
1510
|
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
this.
|
|
1511
|
+
if (internalPickingMode === 'sync') {
|
|
1512
|
+
const info =
|
|
1513
|
+
event.type === 'click' && this._shouldUnproject3D(layers)
|
|
1514
|
+
? this._getFirstPickedInfo(
|
|
1515
|
+
this._pickPointSync(
|
|
1516
|
+
this._getPointPickOptions(pos.x, pos.y, {unproject3D: true}, layers)
|
|
1517
|
+
)
|
|
1518
|
+
)
|
|
1519
|
+
: this._getLastPointerDownPickingInfo(pos.x, pos.y, layers);
|
|
1520
|
+
|
|
1521
|
+
this._dispatchPickingEvent(info, event);
|
|
1522
|
+
return;
|
|
1321
1523
|
}
|
|
1524
|
+
|
|
1525
|
+
const pointerDownInfoPromise =
|
|
1526
|
+
this._lastPointerDownInfoPromise ||
|
|
1527
|
+
Promise.resolve(this._getLastPointerDownPickingInfo(pos.x, pos.y, layers));
|
|
1528
|
+
|
|
1529
|
+
pointerDownInfoPromise
|
|
1530
|
+
.then(info => {
|
|
1531
|
+
this._dispatchPickingEvent(info, event);
|
|
1532
|
+
})
|
|
1533
|
+
.catch(error => this.props.onError?.(error));
|
|
1322
1534
|
};
|
|
1323
1535
|
|
|
1324
1536
|
/** Internal use only: evnet handler for pointerdown */
|
|
1325
1537
|
_onPointerDown = (event: MjolnirPointerEvent) => {
|
|
1326
|
-
|
|
1327
|
-
if (
|
|
1538
|
+
const pos = event.offsetCenter;
|
|
1539
|
+
if (!pos) {
|
|
1328
1540
|
return;
|
|
1329
1541
|
}
|
|
1330
|
-
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1542
|
+
|
|
1543
|
+
const internalPickingMode = this._getInternalPickingMode();
|
|
1544
|
+
if (!internalPickingMode) {
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
const layers = this.layerManager?.getLayers() || [];
|
|
1549
|
+
const pointerDownPickSequence = ++this._pointerDownPickSequence;
|
|
1550
|
+
|
|
1551
|
+
if (internalPickingMode === 'sync') {
|
|
1552
|
+
const pickedInfo = this._pickPointSync({
|
|
1553
|
+
x: pos.x,
|
|
1554
|
+
y: pos.y,
|
|
1555
|
+
radius: this.props.pickingRadius
|
|
1556
|
+
});
|
|
1557
|
+
const info = this._getFirstPickedInfo(pickedInfo);
|
|
1558
|
+
this._lastPointerDownInfo = info;
|
|
1559
|
+
this._lastPointerDownInfoPromise = Promise.resolve(info);
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
const pickPromise = this._pickPointAsync(this._getPointPickOptions(pos.x, pos.y, {}, layers))
|
|
1564
|
+
.then(pickResult => this._getFirstPickedInfo(pickResult))
|
|
1565
|
+
.then(info => {
|
|
1566
|
+
if (pointerDownPickSequence === this._pointerDownPickSequence) {
|
|
1567
|
+
this._lastPointerDownInfo = info;
|
|
1568
|
+
}
|
|
1569
|
+
return info;
|
|
1570
|
+
})
|
|
1571
|
+
.catch(error => {
|
|
1572
|
+
this.props.onError?.(error);
|
|
1573
|
+
const fallbackInfo =
|
|
1574
|
+
this.deckPicker && this.viewManager
|
|
1575
|
+
? this._getLastPointerDownPickingInfo(pos.x, pos.y, layers)
|
|
1576
|
+
: ({} as PickingInfo);
|
|
1577
|
+
if (pointerDownPickSequence === this._pointerDownPickSequence) {
|
|
1578
|
+
this._lastPointerDownInfo = fallbackInfo;
|
|
1579
|
+
}
|
|
1580
|
+
return fallbackInfo;
|
|
1581
|
+
});
|
|
1582
|
+
|
|
1583
|
+
this._lastPointerDownInfo = null;
|
|
1584
|
+
this._lastPointerDownInfoPromise = pickPromise;
|
|
1337
1585
|
};
|
|
1338
1586
|
|
|
1339
1587
|
private _getFrameStats(): void {
|
package/src/lib/layer.ts
CHANGED
|
@@ -1071,14 +1071,10 @@ export default abstract class Layer<PropsT extends {} = {}> extends Component<
|
|
|
1071
1071
|
context.device.setParametersWebGL({polygonOffset: offsets});
|
|
1072
1072
|
}
|
|
1073
1073
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
} else {
|
|
1079
|
-
model.setParameters(parameters);
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1074
|
+
const webGPUDrawParameters =
|
|
1075
|
+
context.device instanceof WebGLDevice ? null : splitWebGPUDrawParameters(parameters);
|
|
1076
|
+
|
|
1077
|
+
applyModelParameters(this.getModels(), renderPass, parameters, webGPUDrawParameters);
|
|
1082
1078
|
|
|
1083
1079
|
// Call subclass lifecycle method
|
|
1084
1080
|
if (context.device instanceof WebGLDevice) {
|
|
@@ -1093,6 +1089,9 @@ export default abstract class Layer<PropsT extends {} = {}> extends Component<
|
|
|
1093
1089
|
this.draw(opts);
|
|
1094
1090
|
});
|
|
1095
1091
|
} else {
|
|
1092
|
+
if (webGPUDrawParameters?.renderPassParameters) {
|
|
1093
|
+
renderPass.setParameters(webGPUDrawParameters.renderPassParameters);
|
|
1094
|
+
}
|
|
1096
1095
|
const opts: DrawOptions = {renderPass, shaderModuleProps, uniforms, parameters, context};
|
|
1097
1096
|
|
|
1098
1097
|
// extensions
|
|
@@ -1344,3 +1343,94 @@ export default abstract class Layer<PropsT extends {} = {}> extends Component<
|
|
|
1344
1343
|
this.setNeedsUpdate();
|
|
1345
1344
|
}
|
|
1346
1345
|
}
|
|
1346
|
+
|
|
1347
|
+
function splitWebGPUDrawParameters(parameters: LumaParameters): {
|
|
1348
|
+
pipelineParameters: LumaParameters;
|
|
1349
|
+
renderPassParameters?: {blendConstant: [number, number, number, number]};
|
|
1350
|
+
} {
|
|
1351
|
+
const {blendConstant, ...pipelineParameters} = parameters as LumaParameters & {
|
|
1352
|
+
blendConstant?: [number, number, number, number];
|
|
1353
|
+
};
|
|
1354
|
+
|
|
1355
|
+
return blendConstant
|
|
1356
|
+
? {
|
|
1357
|
+
pipelineParameters,
|
|
1358
|
+
renderPassParameters: {blendConstant}
|
|
1359
|
+
}
|
|
1360
|
+
: {pipelineParameters};
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
function applyModelParameters(
|
|
1364
|
+
models: Model[],
|
|
1365
|
+
renderPass: RenderPass,
|
|
1366
|
+
parameters: LumaParameters,
|
|
1367
|
+
webGPUDrawParameters: ReturnType<typeof splitWebGPUDrawParameters> | null
|
|
1368
|
+
): void {
|
|
1369
|
+
for (const model of models) {
|
|
1370
|
+
if (model.device.type === 'webgpu') {
|
|
1371
|
+
syncModelAttachmentFormats(model, renderPass);
|
|
1372
|
+
// TODO(ibgreen): model.setParameters currently wipes parameters. Semantics TBD.
|
|
1373
|
+
model.setParameters({
|
|
1374
|
+
...model.parameters,
|
|
1375
|
+
...webGPUDrawParameters?.pipelineParameters
|
|
1376
|
+
});
|
|
1377
|
+
} else {
|
|
1378
|
+
model.setParameters(parameters);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
function syncModelAttachmentFormats(model: Model, renderPass: RenderPass): void {
|
|
1384
|
+
const framebuffer =
|
|
1385
|
+
renderPass.props.framebuffer ||
|
|
1386
|
+
((
|
|
1387
|
+
renderPass as RenderPass & {
|
|
1388
|
+
framebuffer?: {
|
|
1389
|
+
colorAttachments: Array<{texture: {format: string}}>;
|
|
1390
|
+
depthStencilAttachment: {texture: {format: string}} | null;
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
).framebuffer ??
|
|
1394
|
+
null);
|
|
1395
|
+
|
|
1396
|
+
if (!framebuffer) {
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
const colorAttachmentFormats = framebuffer.colorAttachments.map(
|
|
1401
|
+
attachment => attachment?.texture?.format ?? null
|
|
1402
|
+
);
|
|
1403
|
+
const depthStencilAttachmentFormat = framebuffer.depthStencilAttachment?.texture?.format;
|
|
1404
|
+
|
|
1405
|
+
const modelWithProps = model as unknown as {
|
|
1406
|
+
props: {
|
|
1407
|
+
colorAttachmentFormats?: (string | null)[];
|
|
1408
|
+
depthStencilAttachmentFormat?: string;
|
|
1409
|
+
};
|
|
1410
|
+
_setPipelineNeedsUpdate(reason: string): void;
|
|
1411
|
+
};
|
|
1412
|
+
|
|
1413
|
+
if (
|
|
1414
|
+
!equalAttachmentFormats(modelWithProps.props.colorAttachmentFormats, colorAttachmentFormats) ||
|
|
1415
|
+
modelWithProps.props.depthStencilAttachmentFormat !== depthStencilAttachmentFormat
|
|
1416
|
+
) {
|
|
1417
|
+
modelWithProps.props.colorAttachmentFormats = colorAttachmentFormats;
|
|
1418
|
+
modelWithProps.props.depthStencilAttachmentFormat = depthStencilAttachmentFormat;
|
|
1419
|
+
modelWithProps._setPipelineNeedsUpdate('attachment formats');
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
function equalAttachmentFormats(left?: (string | null)[], right?: (string | null)[]): boolean {
|
|
1424
|
+
if (left === right) {
|
|
1425
|
+
return true;
|
|
1426
|
+
}
|
|
1427
|
+
if (!left || !right || left.length !== right.length) {
|
|
1428
|
+
return false;
|
|
1429
|
+
}
|
|
1430
|
+
for (let i = 0; i < left.length; i++) {
|
|
1431
|
+
if (left[i] !== right[i]) {
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
return true;
|
|
1436
|
+
}
|
package/src/lib/view-manager.ts
CHANGED
|
@@ -181,7 +181,7 @@ export default class ViewManager<ViewsT extends View[]> {
|
|
|
181
181
|
typeof viewOrViewId === 'string' ? this.getView(viewOrViewId) : viewOrViewId;
|
|
182
182
|
// Backward compatibility: view state for single view
|
|
183
183
|
const viewState = (view && this.viewState[view.getViewStateId()]) || this.viewState;
|
|
184
|
-
return view ? view.filterViewState(viewState) : viewState
|
|
184
|
+
return (view ? view.filterViewState(viewState) : viewState) as AnyViewStateOf<ViewsT>;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
getViewport(viewId: string): Viewport | undefined {
|