@deck.gl/experimental-layers
Version:
Experimental layers for deck.gl
204 lines (182 loc) • 6.53 kB
JavaScript
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import { Layer } from '@deck.gl/core';
import GL from 'luma.gl/constants';
import { Model, Geometry, loadTextures } from 'luma.gl';
import BITMAP_VERTEX_SHADER from './bitmap-layer-vertex';
import BITMAP_FRAGMENT_SHADER from './bitmap-layer-fragment'; // Note: needs to match vertex shader
const MAX_BITMAPS = 11;
const defaultProps = {
images: {
type: 'array',
value: []
},
desaturate: {
type: 'number',
min: 0,
max: 1,
value: 0
},
blendMode: null,
// More context: because of the blending mode we're using for ground imagery,
// alpha is not effective when blending the bitmap layers with the base map.
// Instead we need to manually dim/blend rgb values with a background color.
transparentColor: {
type: 'color',
value: [0, 0, 0, 0]
},
tintColor: {
type: 'color',
value: [255, 255, 255]
},
// accessors
getCenter: {
type: 'accessor',
value: x => x.center
},
getRotation: {
type: 'accessor',
value: x => x.rotation
}
};
/*
* @class
* @param {object} props
* @param {number} props.transparentColor - color to interpret transparency to
* @param {number} props.tintColor - color bias
*/
export default class BitmapLayer extends Layer {
initializeState() {
const gl = this.context.gl;
this.setState({
model: this.getModel(gl)
});
const attributeManager = this.state.attributeManager;
attributeManager.addInstanced({
instanceCenter: {
size: 3,
accessor: 'getCenter'
},
instanceRotation: {
size: 3,
accessor: 'getRotation'
},
instanceBitmapIndex: {
size: 1,
update: this.calculateInstanceBitmapIndex
}
});
}
updateState(_ref) {
let props = _ref.props,
oldProps = _ref.oldProps;
if (props.images !== oldProps.images) {
let changed = !oldProps.images || props.images.length !== oldProps.images.length;
if (!changed) {
for (let i = 0; i < props.images.length; ++i) {
changed = changed || props.images[i] !== oldProps.images[i];
}
}
if (changed) {
this.loadMapImagesToTextures();
}
}
const desaturate = props.desaturate;
this.state.model.setUniforms({
desaturate
});
}
getModel(gl) {
// Two triangles making up a square to render the bitmap texture on
const verts = [[1, 1, 0], [-1, 1, 0], [1, -1, 0], [-1, 1, 0], [1, -1, 0], [-1, -1, 0]];
const positions = [];
const texCoords = [];
verts.forEach(vertex => {
// geometry: unit square centered on origin
positions.push(vertex[0] / 2, vertex[1] / 2, vertex[2] / 2); // texture: unit square with bottom left in origin
texCoords.push(vertex[0] / 2 + 0.5, -vertex[1] / 2 + 0.5);
});
const model = new Model(gl, {
id: this.props.id,
vs: BITMAP_VERTEX_SHADER,
fs: BITMAP_FRAGMENT_SHADER,
shaderCache: this.context.shaderCache,
geometry: new Geometry({
drawMode: GL.TRIANGLES,
vertexCount: 6,
attributes: {
positions: new Float32Array(positions),
texCoords: new Float32Array(texCoords)
}
}),
isInstanced: true
});
return model;
}
draw(_ref2) {
let uniforms = _ref2.uniforms;
const _this$props = this.props,
transparentColor = _this$props.transparentColor,
tintColor = _this$props.tintColor; // TODO fix zFighting
// Render the image
this.state.model.render(Object.assign({}, uniforms, {
transparentColor,
tintColor
}));
}
loadMapImagesToTextures() {
const model = this.state.model;
const images = this.props.images;
for (let i = 0; i < Math.min(images.length, MAX_BITMAPS); i++) {
loadTextures(this.context.gl, {
urls: [images[i]]
}).then((_ref3) => {
let _ref4 = _slicedToArray(_ref3, 1),
texture = _ref4[0];
return model.setUniforms({
[`uBitmap${i}`]: texture
});
});
}
}
getBitmapIndex(point) {
const url = point.imageUrl;
const idx = Math.max(this.props.images.indexOf(url), 0);
return idx >= MAX_BITMAPS ? 0 : idx;
}
calculateInstanceBitmapIndex(attribute) {
const data = this.props.data;
const value = attribute.value,
size = attribute.size;
let i = 0;
for (const point of data) {
const bitmapIndex = Number.isFinite(point.bitmapIndex) ? point.bitmapIndex : this.getBitmapIndex(point);
value[i] = bitmapIndex;
i += size;
}
}
}
BitmapLayer.layerName = 'BitmapLayer';
BitmapLayer.defaultProps = defaultProps;
//# sourceMappingURL=bitmap-layer.js.map