Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Repository Guidance

This file applies to the entire `deck.gl` repository. More specific `AGENTS.md` files in
subdirectories may add local guidance.

## Setup Commands

- Install dependencies from the repo root: `yarn`
- Build packages: `yarn build`
- Run lint: `yarn lint`
- Run all tests: `yarn test`
- Run headless tests: `yarn test-headless`
- Run render tests: `yarn test-render`
- Run browser tests: `yarn test-browser`
- Run website checks: `yarn test-website`
- Use the exact script names from `package.json`; do not substitute spaced forms such as
`yarn test headless`.

## Before Committing

- Run the most relevant tests for the changed packages, integrations, examples, or docs.
- Run `yarn lint` for JavaScript and TypeScript changes. If lint failures are unrelated existing
issues, call that out explicitly instead of hiding it.
- If dependencies or package metadata changed, run `yarn` in the repo root and include any
`yarn.lock` updates.
- Do not reformat files you are not otherwise changing. Keep formatting-only churn separate from
logic changes when practical.

## Ready For Merge

When asked to "get ready for merge", do a full merge-readiness pass:

- Audit the public API surface touched by the change. Add or update TSDoc for every new or changed
public class, function, method, property, and type.
- Do a documentation pass when behavior, public API, examples, or migration guidance changed.
Include relevant module docs, examples, sidebars, `docs/whats-new.md`, and upgrade or migration
guide content.
- Keep upgrade guides focused on breaking changes, removals, and deprecations. Put new-feature
notes in the appropriate module docs or release notes instead.
- Run `yarn` in the repo root so workspace metadata and `yarn.lock` are up to date, especially
after any `package.json` change.
- Run `yarn build` as the repo-wide type, declaration, and package build gate.
- Run `yarn lint` for the final lint and formatting gate, then review the resulting diff.
- Run the relevant tests for the changed packages, examples, integrations, and docs/website wiring.
Typical commands are `yarn test`, `yarn test-headless`, `yarn test-render`, `yarn test-browser`,
and `yarn test-website`.
- For website or docs changes, run the website check from the repo root with `yarn test-website`.
- Prepare a copyable Markdown PR description based on the branch diff compared to `master`. Start
with the PR goals, then list the actual changes and validation.
- In the final handoff, call out which merge-readiness gates passed, which were not run, and any
remaining risk or unrelated pre-existing failures.

## Code Style

- Prefer TypeScript and ES module syntax.
- Match the surrounding file style. In source files, use single quotes and semicolons.
- Never abbreviate variable names. Use camelCase for variables, functions, and fields; PascalCase
for types and classes; and CAPITAL_CASE for constants.
- Prefer verb-noun names for functions and methods.
- File names should be kebab-case unless an existing local convention differs.

## Dependencies

- Be conservative with new external dependencies. Add one only when it provides meaningful
capability, not just a small utility.
- Prefer vis.gl ecosystem packages when they fit the layering. Lower-level math or utility modules
should not depend on deck.gl.
- Prefer math.gl modules for math helpers.
- Avoid lodash-style dependencies for simple operations.

## Investigation

- Do not fix problems by adding caches. Investigate why the problem occurs and address the root
cause.
3 changes: 3 additions & 0 deletions docs/api-reference/core/deck.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ The canvas to render into. Can be either a HTMLCanvasElement or the element id.

luma.gl Device used to manage the application's connection with the GPU. Will be auto-created if not supplied.

When a `Device` is supplied, Deck does not destroy it when finalized. While the `Deck` instance is active, Deck owns the `device.props.onResize` callback for the active render canvas context; use `DeckProps.onResize` to observe Deck canvas resizes.

#### `deviceProps` ([DeviceProps](https://luma.gl/docs/api-reference/core/device#deviceprops) | [WebGLDeviceProps](https://luma.gl/docs/api-reference/webgl/#webgldeviceprops)) {#deviceprops}

Options used for creating a new luma.gl GPU [Device](https://luma.gl/docs/api-reference/core/device).
Expand Down Expand Up @@ -551,6 +553,7 @@ Receives arguments:
* `size`
- `width` (number) - the new width of the deck canvas, in client pixels
- `height` (number) - the new height of the deck canvas, in client pixels
* `canvasContext` ([CanvasContext](https://luma.gl/docs/api-reference/core/canvas-context), optional) - the luma.gl canvas context that reported the resize


#### `onBeforeRender` (Function) {#onbeforerender}
Expand Down
66 changes: 32 additions & 34 deletions modules/core/src/lib/deck-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Copyright (c) vis.gl contributors

import {Buffer, Texture} from '@luma.gl/core';
import type {Device} from '@luma.gl/core';
import type {CanvasContext, Device} from '@luma.gl/core';
import PickLayersPass, {PickingColorDecoder} from '../passes/pick-layers-pass';
import log from '../utils/log';
import {getClosestObject, getUniqueObjects, PickedPixel} from './picking/query-object';
Expand Down Expand Up @@ -44,6 +44,7 @@ type PickOperationContext = {
layers: Layer[];
views: Record<string, View>;
viewports: Viewport[];
canvasContext?: CanvasContext;
onViewportActive: (viewport: Viewport) => void;
effects: Effect[];
};
Expand Down Expand Up @@ -157,7 +158,7 @@ export default class DeckPicker {
// Private

/** Ensures that picking framebuffer exists and matches the canvas size */
_resizeBuffer() {
_resizeBuffer(canvasContext: CanvasContext = this.device.getDefaultCanvasContext()) {
// Create a frame buffer if not already available
if (!this.pickingFBO) {
const pickingColorTexture = this.device.createTexture({
Expand Down Expand Up @@ -186,10 +187,11 @@ export default class DeckPicker {
}
}

// Resize it to current canvas size (this is a noop if size hasn't changed)
const {canvas} = this.device.getDefaultCanvasContext();
this.pickingFBO?.resize({width: canvas.width, height: canvas.height});
this.depthFBO?.resize({width: canvas.width, height: canvas.height});
// Picking renders in drawing-buffer pixels. DPR and useDevicePixels can make that size
// differ from the canvas/CSS size used for viewport bookkeeping.
const [width, height] = canvasContext.getDrawingBufferSize();
this.pickingFBO?.resize({width, height});
this.depthFBO?.resize({width, height});
}

/** Preliminary filtering of the layers list. Skid picking pass if no layer is pickable. */
Expand Down Expand Up @@ -217,14 +219,15 @@ export default class DeckPicker {
depth = 1,
mode = 'query',
unproject3D,
canvasContext = this.device.getDefaultCanvasContext(),
onViewportActive,
effects
}: PickByPointOptions & PickOperationContext): Promise<{
result: PickingInfo[];
emptyInfo: PickingInfo;
}> {
// @ts-expect-error TODO - assuming WebGL context
const pixelRatio = this.device.canvasContext.cssToDeviceRatio();
// Picking starts in CSS pixels, so use the canvas context's current conversion ratio.
const pixelRatio = canvasContext.cssToDeviceRatio();

const pickableLayers = this._getPickable(layers);

Expand All @@ -235,13 +238,12 @@ export default class DeckPicker {
};
}

this._resizeBuffer();
this._resizeBuffer(canvasContext);

// Convert from canvas top-left to WebGL bottom-left coordinates
// Top-left coordinates [x, y] to bottom-left coordinates [deviceX, deviceY]
// And compensate for pixelRatio
// @ts-expect-error TODO - assuming WebGL context
const devicePixelRange = this.device.canvasContext.cssToDevicePixels([x, y], true);
// And compensate for the context's current CSS-to-device ratio.
const devicePixelRange = canvasContext.cssToDevicePixels([x, y], true);
const devicePixel = [
devicePixelRange.x + Math.floor(devicePixelRange.width / 2),
devicePixelRange.y + Math.floor(devicePixelRange.height / 2)
Expand Down Expand Up @@ -381,14 +383,15 @@ export default class DeckPicker {
depth = 1,
mode = 'query',
unproject3D,
canvasContext = this.device.getDefaultCanvasContext(),
onViewportActive,
effects
}: PickByPointOptions & PickOperationContext): {
result: PickingInfo[];
emptyInfo: PickingInfo;
} {
// @ts-expect-error TODO - assuming WebGL context
const pixelRatio = this.device.canvasContext.cssToDeviceRatio();
// Keep the sync picking path aligned with the same canvas context state used for drawing.
const pixelRatio = canvasContext.cssToDeviceRatio();

const pickableLayers = this._getPickable(layers);

Expand All @@ -399,13 +402,12 @@ export default class DeckPicker {
};
}

this._resizeBuffer();
this._resizeBuffer(canvasContext);

// Convert from canvas top-left to WebGL bottom-left coordinates
// Top-left coordinates [x, y] to bottom-left coordinates [deviceX, deviceY]
// And compensate for pixelRatio
// @ts-expect-error TODO - assuming WebGL context
const devicePixelRange = this.device.canvasContext.cssToDevicePixels([x, y], true);
// And compensate for the context's current CSS-to-device ratio.
const devicePixelRange = canvasContext.cssToDevicePixels([x, y], true);
const devicePixel = [
devicePixelRange.x + Math.floor(devicePixelRange.width / 2),
devicePixelRange.y + Math.floor(devicePixelRange.height / 2)
Expand Down Expand Up @@ -544,6 +546,7 @@ export default class DeckPicker {
height = 1,
mode = 'query',
maxObjects = null,
canvasContext = this.device.getDefaultCanvasContext(),
onViewportActive,
effects
}: PickByRectOptions & PickOperationContext): Promise<PickingInfo[]> {
Expand All @@ -553,22 +556,19 @@ export default class DeckPicker {
return [];
}

this._resizeBuffer();
this._resizeBuffer(canvasContext);

// Convert from canvas top-left to WebGL bottom-left coordinates
// And compensate for pixelRatio
// @ts-expect-error TODO - assuming WebGL context
const pixelRatio = this.device.canvasContext.cssToDeviceRatio();
// @ts-expect-error TODO - assuming WebGL context
const leftTop = this.device.canvasContext.cssToDevicePixels([x, y], true);
// And compensate for the context's current CSS-to-device ratio.
const pixelRatio = canvasContext.cssToDeviceRatio();
const leftTop = canvasContext.cssToDevicePixels([x, y], true);

// take left and top (y inverted in device pixels) from start location
const deviceLeft = leftTop.x;
const deviceTop = leftTop.y + leftTop.height;

// take right and bottom (y inverted in device pixels) from end location
// @ts-expect-error TODO - assuming WebGL context
const rightBottom = this.device.canvasContext.cssToDevicePixels([x + width, y + height], true);
const rightBottom = canvasContext.cssToDevicePixels([x + width, y + height], true);
const deviceRight = rightBottom.x + rightBottom.width;
const deviceBottom = rightBottom.y;

Expand Down Expand Up @@ -651,6 +651,7 @@ export default class DeckPicker {
height = 1,
mode = 'query',
maxObjects = null,
canvasContext = this.device.getDefaultCanvasContext(),
onViewportActive,
effects
}: PickByRectOptions & PickOperationContext): PickingInfo[] {
Expand All @@ -660,22 +661,19 @@ export default class DeckPicker {
return [];
}

this._resizeBuffer();
this._resizeBuffer(canvasContext);

// Convert from canvas top-left to WebGL bottom-left coordinates
// And compensate for pixelRatio
// @ts-expect-error TODO - assuming WebGL context
const pixelRatio = this.device.canvasContext.cssToDeviceRatio();
// @ts-expect-error TODO - assuming WebGL context
const leftTop = this.device.canvasContext.cssToDevicePixels([x, y], true);
// And compensate for the context's current CSS-to-device ratio.
const pixelRatio = canvasContext.cssToDeviceRatio();
const leftTop = canvasContext.cssToDevicePixels([x, y], true);

// take left and top (y inverted in device pixels) from start location
const deviceLeft = leftTop.x;
const deviceTop = leftTop.y + leftTop.height;

// take right and bottom (y inverted in device pixels) from end location
// @ts-expect-error TODO - assuming WebGL context
const rightBottom = this.device.canvasContext.cssToDevicePixels([x + width, y + height], true);
const rightBottom = canvasContext.cssToDevicePixels([x + width, y + height], true);
const deviceRight = rightBottom.x + rightBottom.width;
const deviceBottom = rightBottom.y;

Expand Down
Loading
Loading