UNPKG

@deck.gl/core

Version:

deck.gl core library

189 lines (184 loc) 6.53 kB
// deck.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import { BufferTransform } from '@luma.gl/engine'; import { fp64arithmetic } from '@luma.gl/shadertools'; import { GL } from '@luma.gl/constants'; import { getAttributeTypeFromSize, cycleBuffers, padBuffer, matchBuffer, getFloat32VertexFormat } from "./gpu-transition-utils.js"; import { GPUTransitionBase } from "./gpu-transition.js"; export default class GPUInterpolationTransition extends GPUTransitionBase { constructor({ device, attribute, timeline }) { super({ device, attribute, timeline }); this.type = 'interpolation'; this.transform = getTransform(device, attribute); } start(transitionSettings, numInstances) { const prevLength = this.currentLength; const prevStartIndices = this.currentStartIndices; super.start(transitionSettings, numInstances, transitionSettings.duration); if (transitionSettings.duration <= 0) { this.transition.cancel(); return; } const { buffers, attribute } = this; // Alternate between two buffers when new transitions start. // Last destination buffer is used as an attribute (from state), // And the other buffer is now the current buffer. cycleBuffers(buffers); buffers[0] = padBuffer({ device: this.device, buffer: buffers[0], attribute, fromLength: prevLength, toLength: this.currentLength, fromStartIndices: prevStartIndices, getData: transitionSettings.enter }); buffers[1] = matchBuffer({ device: this.device, source: buffers[0], target: buffers[1] }); this.setBuffer(buffers[1]); const { transform } = this; const model = transform.model; let vertexCount = Math.floor(this.currentLength / attribute.size); if (useFp64(attribute)) { vertexCount /= 2; } model.setVertexCount(vertexCount); if (attribute.isConstant) { model.setAttributes({ aFrom: buffers[0] }); model.setConstantAttributes({ aTo: attribute.value }); } else { model.setAttributes({ aFrom: buffers[0], aTo: attribute.getBuffer() }); } transform.transformFeedback.setBuffers({ vCurrent: buffers[1] }); } onUpdate() { const { duration, easing } = this.settings; const { time } = this.transition; let t = time / duration; if (easing) { t = easing(t); } const { model } = this.transform; const interpolationProps = { time: t }; model.shaderInputs.setProps({ interpolation: interpolationProps }); this.transform.run({ discard: true }); } delete() { super.delete(); this.transform.destroy(); } } const uniformBlock = `\ uniform interpolationUniforms { float time; } interpolation; `; const interpolationUniforms = { name: 'interpolation', vs: uniformBlock, uniformTypes: { time: 'f32' } }; const vs = `\ #version 300 es #define SHADER_NAME interpolation-transition-vertex-shader in ATTRIBUTE_TYPE aFrom; in ATTRIBUTE_TYPE aTo; out ATTRIBUTE_TYPE vCurrent; void main(void) { vCurrent = mix(aFrom, aTo, interpolation.time); gl_Position = vec4(0.0); } `; const vs64 = `\ #version 300 es #define SHADER_NAME interpolation-transition-vertex-shader in ATTRIBUTE_TYPE aFrom; in ATTRIBUTE_TYPE aFrom64Low; in ATTRIBUTE_TYPE aTo; in ATTRIBUTE_TYPE aTo64Low; out ATTRIBUTE_TYPE vCurrent; out ATTRIBUTE_TYPE vCurrent64Low; vec2 mix_fp64(vec2 a, vec2 b, float x) { vec2 range = sub_fp64(b, a); return sum_fp64(a, mul_fp64(range, vec2(x, 0.0))); } void main(void) { for (int i=0; i<ATTRIBUTE_SIZE; i++) { vec2 value = mix_fp64(vec2(aFrom[i], aFrom64Low[i]), vec2(aTo[i], aTo64Low[i]), interpolation.time); vCurrent[i] = value.x; vCurrent64Low[i] = value.y; } gl_Position = vec4(0.0); } `; function useFp64(attribute) { return attribute.doublePrecision && attribute.value instanceof Float64Array; } function getTransform(device, attribute) { const attributeSize = attribute.size; const attributeType = getAttributeTypeFromSize(attributeSize); const inputFormat = getFloat32VertexFormat(attributeSize); const bufferLayout = attribute.getBufferLayout(); if (useFp64(attribute)) { return new BufferTransform(device, { vs: vs64, bufferLayout: [ { name: 'aFrom', byteStride: 8 * attributeSize, attributes: [ { attribute: 'aFrom', format: inputFormat, byteOffset: 0 }, { attribute: 'aFrom64Low', format: inputFormat, byteOffset: 4 * attributeSize } ] }, { name: 'aTo', byteStride: 8 * attributeSize, attributes: [ { attribute: 'aTo', format: inputFormat, byteOffset: 0 }, { attribute: 'aTo64Low', format: inputFormat, byteOffset: 4 * attributeSize } ] } ], // @ts-expect-error fp64 module only sets ONE uniform via defaultUniforms modules: [fp64arithmetic, interpolationUniforms], defines: { // @ts-expect-error TODO fix luma type ATTRIBUTE_TYPE: attributeType, // @ts-expect-error TODO fix luma type ATTRIBUTE_SIZE: attributeSize }, // Default uniforms are not set without this moduleSettings: {}, varyings: ['vCurrent', 'vCurrent64Low'], bufferMode: 35980, disableWarnings: true }); } return new BufferTransform(device, { vs, bufferLayout: [ { name: 'aFrom', format: inputFormat }, { name: 'aTo', format: bufferLayout.attributes[0].format } ], modules: [interpolationUniforms], defines: { // @ts-expect-error TODO fix luma type ATTRIBUTE_TYPE: attributeType }, varyings: ['vCurrent'], // TODO investigate why this is needed disableWarnings: true }); } //# sourceMappingURL=gpu-interpolation-transition.js.map