UNPKG

@deck.gl/experimental-layers

Version:

Experimental layers for deck.gl

204 lines (182 loc) 6.53 kB
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