Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
6 changes: 5 additions & 1 deletion examples/website/map-tile/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import ZoomRangeWidget from './zoom-range-widget';

import type {Position, MapViewState} from '@deck.gl/core';
import type {TileLayerPickingInfo} from '@deck.gl/geo-layers';
import type {Device} from '@luma.gl/core';

const INITIAL_VIEW_STATE: MapViewState = {
latitude: 47.65,
Expand Down Expand Up @@ -58,7 +59,8 @@ export default function App({
visibleMinZoom,
visibleMaxZoom = 7,
zoomOffset = 0,
useExtent = false
useExtent = false,
device
}: {
showBorder?: boolean;
onTilesLoad?: () => void;
Expand All @@ -69,6 +71,7 @@ export default function App({
visibleMaxZoom?: number;
zoomOffset?: number;
useExtent?: boolean;
device?: Device;
}) {
const [zoom, setZoom] = useState(INITIAL_VIEW_STATE.zoom);
const onViewStateChange = useCallback(
Expand Down Expand Up @@ -130,6 +133,7 @@ export default function App({

return (
<DeckGL
device={device}
layers={[tileLayer]}
views={new MapView({repeat: true})}
initialViewState={INITIAL_VIEW_STATE}
Expand Down
12 changes: 10 additions & 2 deletions examples/website/wms/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {_WMSLayer as WMSLayer} from '@deck.gl/geo-layers';
import type {MapViewState} from '@deck.gl/core';
import type {BitmapLayerPickingInfo} from '@deck.gl/layers';
import type {ImageSourceMetadata} from '@loaders.gl/loader-utils';
import type {Device} from '@luma.gl/core';

const INITIAL_VIEW_STATE: MapViewState = {
longitude: -122.4,
Expand Down Expand Up @@ -42,13 +43,15 @@ export default function App({
layers = SAMPLE_SERVICE.layers,
initialViewState = INITIAL_VIEW_STATE,
onMetadataLoad = console.log, // eslint-disable-line
onMetadataLoadError = console.error // eslint-disable-line
onMetadataLoadError = console.error, // eslint-disable-line
device
}: {
serviceUrl?: string;
layers?: string[];
initialViewState?: MapViewState;
onMetadataLoad?: (metadata: ImageSourceMetadata) => void;
onMetadataLoadError?: (error: Error) => void;
device?: Device;
}) {
const [selection, setSelection] = useState<{
x: number;
Expand Down Expand Up @@ -79,7 +82,12 @@ export default function App({

return (
<>
<DeckGL layers={[layer]} initialViewState={initialViewState} controller={CONTROLLER} />
<DeckGL
device={device}
layers={[layer]}
initialViewState={initialViewState}
controller={CONTROLLER}
/>
{selection && (
<div
className="selected-feature-info"
Expand Down
21 changes: 18 additions & 3 deletions modules/layers/src/bitmap-layer/bitmap-layer-uniforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,21 @@
import type {Texture} from '@luma.gl/core';
import type {ShaderModule} from '@luma.gl/shadertools';

const uniformBlock = `\
const uniformBlockWGSL = /* wgsl */ `
struct BitmapUniforms {
bounds: vec4<f32>,
coordinateConversion: f32,
desaturate: f32,
tintColor: vec3<f32>,
transparentColor: vec4<f32>,
};

@group(0) @binding(auto) var<uniform> bitmap: BitmapUniforms;
@group(0) @binding(auto) var bitmapTexture: texture_2d<f32>;
@group(0) @binding(auto) var bitmapTextureSampler: sampler;
`;

const uniformBlockGLSL = `\
layout(std140) uniform bitmapUniforms {
vec4 bounds;
float coordinateConversion;
Expand All @@ -26,8 +40,9 @@ export type BitmapProps = {

export const bitmapUniforms = {
name: 'bitmap',
vs: uniformBlock,
fs: uniformBlock,
source: uniformBlockWGSL,
vs: uniformBlockGLSL,
fs: uniformBlockGLSL,
uniformTypes: {
bounds: 'vec4<f32>',
coordinateConversion: 'f32',
Expand Down
23 changes: 21 additions & 2 deletions modules/layers/src/bitmap-layer/bitmap-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import {
Layer,
color as colorModule,
project32,
picking,
CoordinateSystem,
Expand All @@ -23,6 +24,7 @@ import {lngLatToWorld} from '@math.gl/web-mercator';
import createMesh from './create-mesh';

import {bitmapUniforms, BitmapProps} from './bitmap-layer-uniforms';
import source from './bitmap-layer.wgsl';
import vs from './bitmap-layer-vertex';
import fs from './bitmap-layer-fragment';

Expand Down Expand Up @@ -129,7 +131,16 @@ export default class BitmapLayer<ExtraPropsT extends {} = {}> extends Layer<
};

getShaders() {
return super.getShaders({vs, fs, modules: [project32, picking, bitmapUniforms]});
const isWebGPU = this.context.device.type === 'webgpu';

return super.getShaders({
...(isWebGPU && {source}),
vs,
fs,
modules: isWebGPU
? [colorModule, project32, picking, bitmapUniforms]
: [project32, picking, bitmapUniforms]
});
}

initializeState() {
Expand Down Expand Up @@ -256,10 +267,18 @@ export default class BitmapLayer<ExtraPropsT extends {} = {}> extends Layer<
| |
0,1 --- 1,1
*/
const bufferLayout =
this.context.device.type === 'webgpu'
? this.getAttributeManager()!
.getBufferLayouts({isInstanced: false})
// WebGPU index buffers are bound separately from vertex buffer layouts.
.filter(layout => layout.name !== 'indices')
: this.getAttributeManager()!.getBufferLayouts();

return new Model(this.context.device, {
...this.getShaders(),
id: this.props.id,
bufferLayout: this.getAttributeManager()!.getBufferLayouts(),
bufferLayout,
topology: 'triangle-list',
isInstanced: false
});
Expand Down
121 changes: 121 additions & 0 deletions modules/layers/src/bitmap-layer/bitmap-layer.wgsl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// deck.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

export default /* wgsl */ `\
Comment thread
ibgreen-openai marked this conversation as resolved.
struct Attributes {
@location(0) positions: vec3<f32>,
@location(1) positions64Low: vec3<f32>,
@location(2) texCoords: vec2<f32>,
};

struct Varyings {
@builtin(position) position: vec4<f32>,
@location(0) vTexCoord: vec2<f32>,
@location(1) vTexPos: vec2<f32>,
};

// from degrees to Web Mercator
fn lnglat_to_mercator(lnglat: vec2<f32>) -> vec2<f32> {
let x = lnglat.x;
let y = clamp(lnglat.y, -89.9, 89.9);
return vec2<f32>(
radians(x) + PI,
PI + log(tan(PI * 0.25 + radians(y) * 0.5))
) * WORLD_SCALE;
}

// from Web Mercator to degrees
fn mercator_to_lnglat(xy: vec2<f32>) -> vec2<f32> {
let position = xy / WORLD_SCALE;
return degrees(vec2<f32>(
position.x - PI,
atan(exp(position.y - PI)) * 2.0 - PI * 0.5
));
}

fn color_desaturate(colorValue: vec3<f32>) -> vec3<f32> {
let luminance = (colorValue.r + colorValue.g + colorValue.b) * 0.333333333;
return mix(colorValue, vec3<f32>(luminance), bitmap.desaturate);
}

fn color_tint(colorValue: vec3<f32>) -> vec3<f32> {
return colorValue * bitmap.tintColor;
}

fn apply_opacity(colorValue: vec3<f32>, alpha: f32) -> vec4<f32> {
if (bitmap.transparentColor.a == 0.0) {
return vec4<f32>(colorValue, alpha);
}
let blendedAlpha = alpha + bitmap.transparentColor.a * (1.0 - alpha);
let highLightRatio = alpha / blendedAlpha;
let blendedRGB = mix(bitmap.transparentColor.rgb, colorValue, highLightRatio);
return vec4<f32>(blendedRGB, blendedAlpha);
}

fn getUV(position: vec2<f32>) -> vec2<f32> {
return vec2<f32>(
(position.x - bitmap.bounds[0]) / (bitmap.bounds[2] - bitmap.bounds[0]),
(position.y - bitmap.bounds[3]) / (bitmap.bounds[1] - bitmap.bounds[3])
);
}

// Pack the top 12 bits of two normalized floats into three 8-bit values.
fn packUVsIntoRGB(uv: vec2<f32>) -> vec3<f32> {
let uv8bit = floor(uv * 256.0);
let uvFraction = fract(uv * 256.0);
let uvFraction4bit = floor(uvFraction * 16.0);
let fractions = uvFraction4bit.x + uvFraction4bit.y * 16.0;
return vec3<f32>(uv8bit, fractions) / 255.0;
}

@vertex
fn vertexMain(attributes: Attributes) -> Varyings {
var output: Varyings;
geometry.worldPosition = attributes.positions;
geometry.uv = attributes.texCoords;
geometry.pickingColor = vec3<f32>(1.0, 0.0, 0.0);

let projectedPosition = project_position_to_clipspace_and_commonspace(
attributes.positions,
attributes.positions64Low,
vec3<f32>(0.0)
);
geometry.position = projectedPosition.commonPosition;
output.position = projectedPosition.clipPosition;
output.vTexCoord = attributes.texCoords;
output.vTexPos = vec2<f32>(0.0);

if (bitmap.coordinateConversion < -0.5) {
output.vTexPos = geometry.position.xy + project.commonOrigin.xy;
} else if (bitmap.coordinateConversion > 0.5) {
output.vTexPos = geometry.worldPosition.xy;
}

return output;
}

@fragment
fn fragmentMain(input: Varyings) -> @location(0) vec4<f32> {
var uv = input.vTexCoord;
if (bitmap.coordinateConversion < -0.5) {
uv = getUV(mercator_to_lnglat(input.vTexPos));
} else if (bitmap.coordinateConversion > 0.5) {
uv = getUV(lnglat_to_mercator(input.vTexPos));
}

let bitmapColor = textureSample(bitmapTexture, bitmapTextureSampler, uv);
let colorValue = apply_opacity(
color_tint(color_desaturate(bitmapColor.rgb)),
bitmapColor.a * layer.opacity
);

geometry.uv = uv;

if (picking.isActive > 0.5 && picking.isAttribute < 0.5) {
Comment thread
ibgreen-openai marked this conversation as resolved.
Outdated
return vec4<f32>(packUVsIntoRGB(uv), 1.0);
}

return deckgl_premultiplied_alpha(colorValue);
Comment thread
ibgreen-openai marked this conversation as resolved.
Outdated
}
`;
4 changes: 4 additions & 0 deletions website/src/examples/tile-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {makeExample} from '../components';
class MapTileDemo extends Component {
static title = 'Raster Map Tiles';

static hasDeviceTabs = true;

static code = `${GITHUB_TREE}/examples/website/map-tile`;

static parameters = {
Expand Down Expand Up @@ -61,6 +63,8 @@ class MapTileDemo extends Component {
return (
<App
{...otherProps}
key={this.props.device?.type}
device={this.props.device}
showBorder={params.showBorder.value}
minZoom={params.minZoom.value}
maxZoom={params.maxZoom.value}
Expand Down
4 changes: 4 additions & 0 deletions website/src/examples/wms-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ const SERVICES = {
class WMSDemo extends Component {
static title = 'Web Map Service (WMS)';

static hasDeviceTabs = true;

static code = `${GITHUB_TREE}/examples/website/wms`;

static parameters = {
Expand Down Expand Up @@ -126,6 +128,8 @@ class WMSDemo extends Component {
<DemoContainer>
<App
{...otherProps}
key={this.props.device?.type}
device={this.props.device}
serviceUrl={service.serviceUrl}
initialViewState={service.viewState}
layers={layers[params.layer.value] || service.defaultLayers}
Expand Down
Loading