Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@luma.gl/engine

Package Overview
Dependencies
Maintainers
6
Versions
177
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@luma.gl/engine - npm Package Compare versions

Comparing version 9.1.0-alpha.19 to 9.1.0-beta.1

dist/animation-loop/animation-loop-template.js.map

1

dist/animation-loop/animation-loop-template.js

@@ -25,1 +25,2 @@ // luma.gl

}
//# sourceMappingURL=animation-loop-template.js.map

@@ -461,1 +461,2 @@ // luma.gl

}
//# sourceMappingURL=animation-loop.js.map

@@ -5,1 +5,2 @@ // luma.gl

export {};
//# sourceMappingURL=animation-props.js.map

@@ -34,1 +34,2 @@ // luma.gl

}
//# sourceMappingURL=make-animation-loop.js.map

@@ -18,1 +18,2 @@ // luma.gl

}
//# sourceMappingURL=request-animation-frame.js.map

@@ -60,1 +60,2 @@ // luma.gl

}
//# sourceMappingURL=key-frames.js.map

@@ -108,1 +108,2 @@ // luma.gl

}
//# sourceMappingURL=timeline.js.map

@@ -43,1 +43,2 @@ // luma.gl

}
//# sourceMappingURL=load-file.js.map

@@ -17,1 +17,2 @@ // luma.gl

}
//# sourceMappingURL=random.js.map

@@ -36,2 +36,3 @@ import type { Texture, TextureProps, Sampler, TextureView, Device, Texture1DData, Texture2DData, Texture3DData, TextureArrayData, TextureCubeData, TextureCubeArrayData } from '@luma.gl/core';

readonly device: Device;
readonly id: string;
texture: Texture;

@@ -45,2 +46,4 @@ sampler: Sampler;

protected rejectReady: (error: Error) => void;
get [Symbol.toStringTag](): string;
toString(): string;
constructor(device: Device, props: AsyncTextureProps);

@@ -47,0 +50,0 @@ initAsync(props: AsyncTextureProps): Promise<void>;

// luma.gl, MIT license
// Copyright (c) vis.gl contributors
import { loadImageBitmap } from "../application-utils/load-file.js";
import { uid } from "../utils/uid.js";
/**

@@ -12,2 +13,3 @@ * It is very convenient to be able to initialize textures with promises

device;
id;
// TODO - should we type these as possibly `null`? It will make usage harder?

@@ -25,4 +27,12 @@ // @ts-expect-error

rejectReady = () => { };
get [Symbol.toStringTag]() {
return 'AsyncTexture';
}
toString() {
return `AsyncTexture:"${this.id}"(${this.isReady ? 'ready' : 'loading'})`;
}
constructor(device, props) {
this.device = device;
this.id = props.id || uid('async-texture');
// this.id = typeof props?.data === 'string' ? props.data.slice(-20) : uid('async-texture');
// Signature: new AsyncTexture(device, {data: url})

@@ -106,1 +116,2 @@ if (typeof props?.data === 'string' && props.dimension === '2d') {

}
//# sourceMappingURL=async-texture.js.map

@@ -83,1 +83,2 @@ // luma.gl

}
//# sourceMappingURL=buffer-transform.js.map

@@ -255,1 +255,2 @@ // luma.gl

}
//# sourceMappingURL=computation.js.map
// luma.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { Texture } from '@luma.gl/core';
/**

@@ -34,3 +35,18 @@ * Helper class for working with repeated transformations / computations

constructor(device, props) {
super({ current: device.createFramebuffer(props), next: device.createFramebuffer(props) });
props = { ...props };
let colorAttachments = props.colorAttachments?.map(colorAttachment => typeof colorAttachment !== 'string'
? colorAttachment
: device.createTexture({
format: colorAttachment,
usage: Texture.COPY_DST | Texture.RENDER_ATTACHMENT
}));
const current = device.createFramebuffer({ ...props, colorAttachments });
colorAttachments = props.colorAttachments?.map(colorAttachment => typeof colorAttachment !== 'string'
? colorAttachment
: device.createTexture({
format: colorAttachment,
usage: Texture.COPY_DST | Texture.RENDER_ATTACHMENT
}));
const next = device.createFramebuffer({ ...props, colorAttachments });
super({ current, next });
}

@@ -76,1 +92,2 @@ /**

}
//# sourceMappingURL=swap.js.map

6

dist/compute/texture-transform.js
// luma.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { getPassthroughFS } from '@luma.gl/shadertools';
import { Model } from "../model/model.js";
import { getPassthroughFS } from '@luma.gl/shadertools';
import { uid } from "../utils/uid.js";
const FS_OUTPUT_VARIABLE = 'transform_output';

@@ -30,3 +31,3 @@ /**

this.model = new Model(this.device, {
id: props.id || 'texture-transform-model',
id: props.id || uid('texture-transform-model'),
fs: props.fs ||

@@ -113,1 +114,2 @@ getPassthroughFS({

}
//# sourceMappingURL=texture-transform.js.map

@@ -47,1 +47,2 @@ // luma.gl

}
//# sourceMappingURL=copy-texture-to-image.js.map

@@ -52,1 +52,2 @@ // luma.gl

}
//# sourceMappingURL=debug-framebuffer.js.map

@@ -28,1 +28,2 @@ // luma.gl

}
//# sourceMappingURL=debug-shader-layout.js.map

@@ -40,1 +40,2 @@ // luma.gl

}
//# sourceMappingURL=pixel-data-utils.js.map

@@ -12,3 +12,5 @@ import type { RenderPipelineProps, ComputePipelineProps } from '@luma.gl/core';

readonly device: Device;
readonly cachingEnabled: boolean;
readonly destroyPolicy: 'unused' | 'never';
readonly debug: boolean;
private _hashCounter;

@@ -18,7 +20,15 @@ private readonly _hashes;

private readonly _computePipelineCache;
get [Symbol.toStringTag](): string;
toString(): string;
constructor(device: Device);
/** Return a RenderPipeline matching props. Reuses a similar pipeline if already created. */
/** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
createRenderPipeline(props: RenderPipelineProps): RenderPipeline;
/** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
createComputePipeline(props: ComputePipelineProps): ComputePipeline;
release(pipeline: RenderPipeline | ComputePipeline): void;
/** Destroy a cached pipeline, removing it from the cache (depending on destroy policy) */
private _destroyPipeline;
/** Get the appropriate cache for the type of pipeline */
private _getCache;
/** Calculate a hash based on all the inputs for a compute pipeline */
private _hashComputePipeline;

@@ -25,0 +35,0 @@ /** Calculate a hash based on all the inputs for a render pipeline */

// luma.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { RenderPipeline, ComputePipeline } from '@luma.gl/core';
import { RenderPipeline, ComputePipeline, log } from '@luma.gl/core';
import { uid } from "../utils/uid.js";
/**

@@ -17,3 +18,5 @@ * Efficiently creates / caches pipelines

device;
cachingEnabled;
destroyPolicy;
debug;
_hashCounter = 0;

@@ -23,26 +26,53 @@ _hashes = {};

_computePipelineCache = {};
get [Symbol.toStringTag]() {
return 'PipelineFactory';
}
toString() {
return `PipelineFactory(${this.device.id})`;
}
constructor(device) {
this.device = device;
this.destroyPolicy = device.props._factoryDestroyPolicy;
this.cachingEnabled = device.props._cachePipelines;
this.destroyPolicy = device.props._cacheDestroyPolicy;
this.debug = device.props.debugFactories;
}
/** Return a RenderPipeline matching props. Reuses a similar pipeline if already created. */
/** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
createRenderPipeline(props) {
if (!this.cachingEnabled) {
return this.device.createRenderPipeline(props);
}
const allProps = { ...RenderPipeline.defaultProps, ...props };
const cache = this._renderPipelineCache;
const hash = this._hashRenderPipeline(allProps);
if (!this._renderPipelineCache[hash]) {
const pipeline = this.device.createRenderPipeline({
let pipeline = cache[hash]?.pipeline;
if (!pipeline) {
pipeline = this.device.createRenderPipeline({
...allProps,
id: allProps.id ? `${allProps.id}-cached` : undefined
id: allProps.id ? `${allProps.id}-cached` : uid('unnamed-cached')
});
pipeline.hash = hash;
this._renderPipelineCache[hash] = { pipeline, useCount: 0 };
cache[hash] = { pipeline, useCount: 1 };
if (this.debug) {
log.warn(`${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
}
}
this._renderPipelineCache[hash].useCount++;
return this._renderPipelineCache[hash].pipeline;
else {
cache[hash].useCount++;
if (this.debug) {
log.warn(`${this}: ${cache[hash].pipeline} reused, count=${cache[hash].useCount}, (id=${props.id})`)();
}
}
return pipeline;
}
/** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
createComputePipeline(props) {
if (!this.cachingEnabled) {
return this.device.createComputePipeline(props);
}
const allProps = { ...ComputePipeline.defaultProps, ...props };
const cache = this._computePipelineCache;
const hash = this._hashComputePipeline(allProps);
if (!this._computePipelineCache[hash]) {
const pipeline = this.device.createComputePipeline({
let pipeline = cache[hash]?.pipeline;
if (!pipeline) {
pipeline = this.device.createComputePipeline({
...allProps,

@@ -52,22 +82,72 @@ id: allProps.id ? `${allProps.id}-cached` : undefined

pipeline.hash = hash;
this._computePipelineCache[hash] = { pipeline, useCount: 0 };
cache[hash] = { pipeline, useCount: 1 };
if (this.debug) {
log.warn(`${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
}
}
this._computePipelineCache[hash].useCount++;
return this._computePipelineCache[hash].pipeline;
else {
cache[hash].useCount++;
if (this.debug) {
log.warn(`${this}: ${cache[hash].pipeline} reused, count=${cache[hash].useCount}, (id=${props.id})`)();
}
}
return pipeline;
}
release(pipeline) {
if (!this.cachingEnabled) {
pipeline.destroy();
return;
}
const cache = this._getCache(pipeline);
const hash = pipeline.hash;
const cache = pipeline instanceof ComputePipeline ? this._computePipelineCache : this._renderPipelineCache;
cache[hash].useCount--;
if (cache[hash].useCount === 0) {
if (this.destroyPolicy === 'unused') {
cache[hash].pipeline.destroy();
delete cache[hash];
this._destroyPipeline(pipeline);
if (this.debug) {
log.warn(`${this}: ${pipeline} released and destroyed`)();
}
}
else if (cache[hash].useCount < 0) {
log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
cache[hash].useCount = 0;
}
else if (this.debug) {
log.warn(`${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
}
}
// PRIVATE
/** Destroy a cached pipeline, removing it from the cache (depending on destroy policy) */
_destroyPipeline(pipeline) {
const cache = this._getCache(pipeline);
switch (this.destroyPolicy) {
case 'never':
return false;
case 'unused':
delete cache[pipeline.hash];
pipeline.destroy();
return true;
}
}
/** Get the appropriate cache for the type of pipeline */
_getCache(pipeline) {
let cache;
if (pipeline instanceof ComputePipeline) {
cache = this._computePipelineCache;
}
if (pipeline instanceof RenderPipeline) {
cache = this._renderPipelineCache;
}
if (!cache) {
throw new Error(`${this}`);
}
if (!cache[pipeline.hash]) {
throw new Error(`${this}: ${pipeline} matched incorrect entry`);
}
return cache;
}
/** Calculate a hash based on all the inputs for a compute pipeline */
_hashComputePipeline(props) {
const { type } = this.device;
const shaderHash = this._getHash(props.shader.source);
return `${shaderHash}`;
return `${type}/C/${shaderHash}`;
}

@@ -83,6 +163,8 @@ /** Calculate a hash based on all the inputs for a render pipeline */

const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
switch (this.device.type) {
const { type } = this.device;
switch (type) {
case 'webgl':
// WebGL is more dynamic
return `${vsHash}/${fsHash}V${varyingHash}BL${bufferLayoutHash}`;
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}BL${bufferLayoutHash}`;
case 'webgpu':
default:

@@ -93,3 +175,3 @@ // On WebGPU we need to rebuild the pipeline if topology, parameters or bufferLayout change

// create a deepHash() to deduplicate?
return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`;
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`;
}

@@ -104,1 +186,2 @@ }

}
//# sourceMappingURL=pipeline-factory.js.map

@@ -8,4 +8,8 @@ import { Device, Shader, ShaderProps } from '@luma.gl/core';

readonly device: Device;
readonly cachingEnabled: boolean;
readonly destroyPolicy: 'unused' | 'never';
readonly debug: boolean;
private readonly _cache;
get [Symbol.toStringTag](): string;
toString(): string;
/** @internal */

@@ -17,4 +21,4 @@ constructor(device: Device);

release(shader: Shader): void;
private _hashShader;
protected _hashShader(value: Shader | ShaderProps): string;
}
//# sourceMappingURL=shader-factory.d.ts.map
// luma.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { Shader } from '@luma.gl/core';
import { Shader, log } from '@luma.gl/core';
/** Manages a cached pool of Shaders for reuse. */

@@ -14,11 +14,24 @@ export class ShaderFactory {

device;
cachingEnabled;
destroyPolicy;
debug;
_cache = {};
get [Symbol.toStringTag]() {
return 'ShaderFactory';
}
toString() {
return `${this[Symbol.toStringTag]}(${this.device.id})`;
}
/** @internal */
constructor(device) {
this.device = device;
this.destroyPolicy = device.props._factoryDestroyPolicy;
this.cachingEnabled = device.props._cacheShaders;
this.destroyPolicy = device.props._cacheDestroyPolicy;
this.debug = true; // device.props.debugFactories;
}
/** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
createShader(props) {
if (!this.cachingEnabled) {
return this.device.createShader(props);
}
const key = this._hashShader(props);

@@ -31,5 +44,13 @@ let cacheEntry = this._cache[key];

});
this._cache[key] = cacheEntry = { shader, useCount: 0 };
this._cache[key] = cacheEntry = { shader, useCount: 1 };
if (this.debug) {
log.warn(`${this}: Created new shader ${shader.id}`)();
}
}
cacheEntry.useCount++;
else {
cacheEntry.useCount++;
if (this.debug) {
log.warn(`${this}: Reusing shader ${cacheEntry.shader.id} count=${cacheEntry.useCount}`)();
}
}
return cacheEntry.shader;

@@ -39,2 +60,6 @@ }

release(shader) {
if (!this.cachingEnabled) {
shader.destroy();
return;
}
const key = this._hashShader(shader);

@@ -48,4 +73,13 @@ const cacheEntry = this._cache[key];

cacheEntry.shader.destroy();
if (this.debug) {
log.warn(`${this}: Releasing shader ${shader.id}, destroyed`)();
}
}
}
else if (cacheEntry.useCount < 0) {
throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
}
else if (this.debug) {
log.warn(`${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
}
}

@@ -58,1 +92,2 @@ }

}
//# sourceMappingURL=shader-factory.js.map

@@ -19,1 +19,2 @@ // luma.gl

}
//# sourceMappingURL=cone-geometry.js.map

@@ -202,1 +202,2 @@ // luma.gl

};
//# sourceMappingURL=cube-geometry.js.map

@@ -17,1 +17,2 @@ // luma.gl

}
//# sourceMappingURL=cylinder-geometry.js.map

@@ -156,1 +156,2 @@ // luma.gl

}
//# sourceMappingURL=ico-sphere-geometry.js.map

@@ -106,1 +106,2 @@ // luma.gl

}
//# sourceMappingURL=plane-geometry.js.map

@@ -88,1 +88,2 @@ // luma.gl

}
//# sourceMappingURL=sphere-geometry.js.map

@@ -112,1 +112,2 @@ // luma.gl

}
//# sourceMappingURL=truncated-cone-geometry.js.map

@@ -5,1 +5,2 @@ // luma.gl

export {};
//# sourceMappingURL=geometry-table.js.map

@@ -43,1 +43,2 @@ // luma.gl

// }
//# sourceMappingURL=geometry-utils.js.map

@@ -93,1 +93,2 @@ // luma.gl

}
//# sourceMappingURL=geometry.js.map

@@ -103,1 +103,2 @@ // luma.gl

}
//# sourceMappingURL=gpu-geometry.js.map

@@ -46,1 +46,2 @@ "use strict";

*/
//# sourceMappingURL=gpu-table.js.map

@@ -47,1 +47,2 @@ // luma.gl

export { LegacyPickingManager } from "./modules/picking/legacy-picking-manager.js";
//# sourceMappingURL=index.js.map

@@ -119,2 +119,4 @@ import type { TypedArray } from '@math.gl/types';

_lastDrawTimestamp: number;
get [Symbol.toStringTag](): string;
toString(): string;
constructor(device: Device, props: ModelProps);

@@ -200,8 +202,10 @@ destroy(): void;

*/
setUniforms(uniforms: Record<string, UniformValue>): void;
setUniformsWebGL(uniforms: Record<string, UniformValue>): void;
/**
* @deprecated Updates shader module settings (which results in uniforms being set)
*/
updateModuleSettings(props: Record<string, any>): void;
/** Get texture / texture view from any async textures */
updateModuleSettingsWebGL(props: Record<string, any>): void;
/** Check that bindings are loaded. Returns id of first binding that is still loading. */
_areBindingsLoading(): string | false;
/** Extracts texture view from loaded async textures. Returns null if any textures have not yet been loaded. */
_getBindings(): Record<string, Binding>;

@@ -208,0 +212,0 @@ /** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */

@@ -114,2 +114,8 @@ // luma.gl

_lastDrawTimestamp = -1;
get [Symbol.toStringTag]() {
return 'Model';
}
toString() {
return `Model(${this.id})`;
}
constructor(device, props) {

@@ -175,3 +181,4 @@ this.props = { ...Model.defaultProps, ...props };

this.vertexArray = device.createVertexArray({
renderPipeline: this.pipeline
shaderLayout: this.pipeline.shaderLayout,
bufferLayout: this.pipeline.bufferLayout
});

@@ -205,7 +212,7 @@ // Now we can apply geometry attributes

if (props.uniforms) {
this.setUniforms(props.uniforms);
this.setUniformsWebGL(props.uniforms);
}
if (props.moduleSettings) {
// log.warn('Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()')();
this.updateModuleSettings(props.moduleSettings);
this.updateModuleSettingsWebGL(props.moduleSettings);
}

@@ -219,13 +226,15 @@ if (props.transformFeedback) {

destroy() {
if (this._destroyed)
return;
this.pipelineFactory.release(this.pipeline);
this.shaderFactory.release(this.pipeline.vs);
if (this.pipeline.fs) {
this.shaderFactory.release(this.pipeline.fs);
if (!this._destroyed) {
// Release pipeline before we destroy the shaders used by the pipeline
this.pipelineFactory.release(this.pipeline);
// Release the shaders
this.shaderFactory.release(this.pipeline.vs);
if (this.pipeline.fs) {
this.shaderFactory.release(this.pipeline.fs);
}
this._uniformStore.destroy();
// TODO - mark resource as managed and destroyIfManaged() ?
this._gpuGeometry?.destroy();
this._destroyed = true;
}
this._uniformStore.destroy();
// TODO - mark resource as managed and destroyIfManaged() ?
this._gpuGeometry?.destroy();
this._destroyed = true;
}

@@ -254,5 +263,17 @@ // Draw call

draw(renderPass) {
this.predraw();
const loadingBinding = this._areBindingsLoading();
if (loadingBinding) {
log.info(LOG_DRAW_PRIORITY, `>>> DRAWING ABORTED ${this.id}: ${loadingBinding} not loaded`)();
return false;
}
try {
renderPass.pushDebugGroup(`${this}.predraw(${renderPass})`);
this.predraw();
}
finally {
renderPass.popDebugGroup();
}
let drawSuccess;
try {
renderPass.pushDebugGroup(`${this}.draw(${renderPass})`);
this._logDrawCallStart();

@@ -293,2 +314,3 @@ // Update the pipeline if invalidated

finally {
renderPass.popDebugGroup();
this._logDrawCallEnd();

@@ -351,3 +373,4 @@ }

this.vertexArray = this.device.createVertexArray({
renderPipeline: this.pipeline
shaderLayout: this.pipeline.shaderLayout,
bufferLayout: this.pipeline.bufferLayout
});

@@ -495,3 +518,3 @@ // Reapply geometry attributes to the new vertex array

*/
setUniforms(uniforms) {
setUniformsWebGL(uniforms) {
if (!isObjectEmpty(uniforms)) {

@@ -506,3 +529,3 @@ this.pipeline.setUniformsWebGL(uniforms);

*/
updateModuleSettings(props) {
updateModuleSettingsWebGL(props) {
// log.warn('Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()')();

@@ -515,16 +538,26 @@ const { bindings, uniforms } = splitUniformsAndBindings(this._getModuleUniforms(props));

// Internal methods
/** Get texture / texture view from any async textures */
/** Check that bindings are loaded. Returns id of first binding that is still loading. */
_areBindingsLoading() {
for (const binding of Object.values(this.bindings)) {
if (binding instanceof AsyncTexture && !binding.isReady) {
return binding.id;
}
}
return false;
}
/** Extracts texture view from loaded async textures. Returns null if any textures have not yet been loaded. */
_getBindings() {
// Extract actual textures from async textures. If not loaded, null
return Object.entries(this.bindings).reduce((acc, [name, binding]) => {
const validBindings = {};
for (const [name, binding] of Object.entries(this.bindings)) {
if (binding instanceof AsyncTexture) {
// Check that async textures are loaded
if (binding.isReady) {
acc[name] = binding.texture;
validBindings[name] = binding.texture;
}
}
else {
acc[name] = binding;
validBindings[name] = binding;
}
return acc;
}, {});
}
return validBindings;
}

@@ -731,1 +764,2 @@ /** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */

}
//# sourceMappingURL=model.js.map

@@ -21,1 +21,2 @@ // luma.gl

}
//# sourceMappingURL=split-uniforms-and-bindings.js.map

@@ -5,6 +5,23 @@ // luma.gl

import { ClipSpace } from "./clip-space.js";
const BACKGROUND_FS_WGSL = /* wgsl */ `\
@group(0) @binding(0) var backgroundTexture: texture_2d<f32>;
@group(0) @binding(1) var backgroundTextureSampler: sampler;
fn billboardTexture_getTextureUV(coordinates: vec2<f32>) -> vec2<f32> {
let iTexSize: vec2<u32> = textureDimensions(backgroundTexture, 0) * 2;
let texSize: vec2<f32> = vec2<f32>(f32(iTexSize.x), f32(iTexSize.y));
var position: vec2<f32> = coordinates.xy / texSize;
return position;
}
@fragment
fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
let position: vec2<f32> = billboardTexture_getTextureUV(inputs.coordinate);
return textureSample(backgroundTexture, backgroundTextureSampler, position);
}
`;
const BACKGROUND_FS = /* glsl */ `\
#version 300 es
precision highp float;
precision highp float;
uniform sampler2D backgroundTexture;

@@ -14,3 +31,3 @@ out vec4 fragColor;

vec2 billboardTexture_getTextureUV() {
ivec2 iTexSize = textureSize(backgroundTexture, 0) * 2;
ivec2 iTexSize = textureDimensions(backgroundTexture, 0) * 2;
vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));

@@ -33,2 +50,3 @@ vec2 position = gl_FragCoord.xy / texSize;

id: props.id || 'background-texture-model',
source: BACKGROUND_FS_WGSL,
fs: BACKGROUND_FS,

@@ -63,1 +81,2 @@ parameters: {

}
//# sourceMappingURL=billboard-texture-model.js.map

@@ -37,1 +37,2 @@ // luma.gl

};
//# sourceMappingURL=billboard-texture-module.js.map

@@ -6,23 +6,25 @@ // luma.gl

import { Geometry } from "../geometry/geometry.js";
import { uid } from "../utils/uid.js";
const CLIPSPACE_VERTEX_SHADER_WGSL = /* wgsl */ `\
struct VertexInput {
aClipSpacePosition: vec2<f32>;
aTexCoord: vec2<f32>;
aCoordinate: vec2<f32>;
struct VertexInputs {
@location(0) clipSpacePosition: vec2<f32>,
@location(1) texCoord: vec2<f32>,
@location(2) coordinate: vec2<f32>
}
struct FragmentInput {
@builtin(position) Position : vec4<f32>;
@location(0) position : vec2<f32>;
@location(1) coordinate : vec2<f32>;
@location(2) uv : vec2<f32>;
struct FragmentInputs {
@builtin(position) Position : vec4<f32>,
@location(0) position : vec2<f32>,
@location(1) coordinate : vec2<f32>,
@location(2) uv : vec2<f32>
};
@stage(vertex)
fn vertexMain(input: VertexInput) -> FragmentInput {
var output: FragmentInput;
output.Position = vec4(aClipSpacePosition, 0., 1.);
output.position = input.aClipSpacePosition;
output.coordinate = input.aCoordinate;
output.uv = aTexCoord;
@vertex
fn vertexMain(inputs: VertexInputs) -> FragmentInputs {
var outputs: FragmentInputs;
outputs.Position = vec4(inputs.clipSpacePosition, 0., 1.);
outputs.position = inputs.clipSpacePosition;
outputs.coordinate = inputs.coordinate;
outputs.uv = inputs.texCoord;
return outputs;
}

@@ -32,5 +34,5 @@ `;

#version 300 es
in vec2 aClipSpacePosition;
in vec2 aTexCoord;
in vec2 aCoordinate;
in vec2 clipSpacePosition;
in vec2 texCoord;
in vec2 coordinate;

@@ -42,6 +44,6 @@ out vec2 position;

void main(void) {
gl_Position = vec4(aClipSpacePosition, 0., 1.);
position = aClipSpacePosition;
coordinate = aCoordinate;
uv = aTexCoord;
gl_Position = vec4(clipSpacePosition, 0., 1.);
position = clipSpacePosition;
coordinate = coordinate;
uv = texCoord;
}

@@ -59,7 +61,7 @@ `;

if (props.source) {
props = { ...props, source: `${CLIPSPACE_VERTEX_SHADER_WGSL}\m${props.source}` };
props = { ...props, source: `${CLIPSPACE_VERTEX_SHADER_WGSL}\n${props.source}` };
}
super(device, {
id: props.id || uid('clip-space'),
...props,
source: CLIPSPACE_VERTEX_SHADER_WGSL,
vs: CLIPSPACE_VERTEX_SHADER,

@@ -71,5 +73,5 @@ vertexCount: 4,

attributes: {
aClipSpacePosition: { size: 2, value: new Float32Array(POSITIONS) },
aTexCoord: { size: 2, value: new Float32Array(TEX_COORDS) },
aCoordinate: { size: 2, value: new Float32Array(TEX_COORDS) }
clipSpacePosition: { size: 2, value: new Float32Array(POSITIONS) },
texCoord: { size: 2, value: new Float32Array(TEX_COORDS) },
coordinate: { size: 2, value: new Float32Array(TEX_COORDS) }
}

@@ -80,1 +82,2 @@ })

}
//# sourceMappingURL=clip-space.js.map

@@ -177,1 +177,2 @@ // luma.gl

// }
//# sourceMappingURL=color-picking.js.map

@@ -148,1 +148,2 @@ // luma.gl

};
//# sourceMappingURL=index-picking.js.map

@@ -76,1 +76,2 @@ // luma.gl

}
//# sourceMappingURL=legacy-picking-manager.js.map

@@ -101,1 +101,2 @@ // luma.gl

}
//# sourceMappingURL=picking-manager.js.map

@@ -109,1 +109,2 @@ // luma.gl

};
//# sourceMappingURL=picking-uniforms.js.map

@@ -117,1 +117,2 @@ // luma.gl

}
//# sourceMappingURL=get-fragment-shader.js.map

@@ -34,3 +34,13 @@ // luma.gl

this.clipSpace = new ClipSpace(device, {
fs: `\
source: /* wgsl */ `\
@group(0) @binding(0) var sourceTexture: texture_2d<f32>;
@group(0) @binding(1) var sourceTextureSampler: sampler;
@fragment
fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
let texCoord: vec2<f32> = inputs.coordinate;
return textureSample(sourceTexture, sourceTextureSampler, texCoord);
}
`,
fs: /* glsl */ `\
#version 300 es

@@ -108,6 +118,5 @@

first = false;
// eslint-disable-next-line no-shadow
const sourceTexture = this.swapFramebuffers.current.colorAttachments[0].texture;
const swapBufferTexture = this.swapFramebuffers.current.colorAttachments[0].texture;
const bindings = {
sourceTexture
sourceTexture: swapBufferTexture
// texSize: [sourceTextures.width, sourceTextures.height]

@@ -190,1 +199,2 @@ };

}
//# sourceMappingURL=shader-pass-renderer.js.map

@@ -88,1 +88,2 @@ // luma.gl

}
//# sourceMappingURL=group-node.js.map

@@ -39,1 +39,2 @@ // luma.gl

}
//# sourceMappingURL=model-node.js.map

@@ -157,1 +157,2 @@ // luma.gl

}
//# sourceMappingURL=scenegraph-node.js.map

@@ -119,1 +119,2 @@ // luma.gl

}
//# sourceMappingURL=shader-inputs.js.map

@@ -51,1 +51,2 @@ // luma.gl

}
//# sourceMappingURL=deep-equal.js.map

@@ -15,1 +15,2 @@ // luma.gl

}
//# sourceMappingURL=uid.js.map
{
"name": "@luma.gl/engine",
"version": "9.1.0-alpha.19",
"version": "9.1.0-beta.1",
"description": "3D Engine Components for luma.gl",

@@ -43,12 +43,12 @@ "type": "module",

"peerDependencies": {
"@luma.gl/core": "9.1.0-alpha.17",
"@luma.gl/shadertools": "9.1.0-alpha.17"
"@luma.gl/core": "9.1.0-alpha.19",
"@luma.gl/shadertools": "9.1.0-alpha.19"
},
"dependencies": {
"@math.gl/core": "4.1.0-alpha.3",
"@math.gl/types": "4.1.0-alpha.3",
"@math.gl/core": "^4.1.0",
"@math.gl/types": "^4.1.0",
"@probe.gl/log": "^4.0.8",
"@probe.gl/stats": "^4.0.8"
},
"gitHead": "c836c09a5105e2515a036abff4a1b926d245a152"
"gitHead": "e04bfb138f96d690992f0e0a67b358cbe23bd59f"
}

@@ -19,2 +19,3 @@ // luma.gl, MIT license

import {loadImageBitmap} from '../application-utils/load-file';
import {uid} from '../utils/uid';

@@ -58,2 +59,3 @@ export type AsyncTextureProps = Omit<TextureProps, 'data'> & AsyncTextureDataProps;

readonly device: Device;
readonly id: string;

@@ -75,4 +77,14 @@ // TODO - should we type these as possibly `null`? It will make usage harder?

get [Symbol.toStringTag]() {
return 'AsyncTexture';
}
toString(): string {
return `AsyncTexture:"${this.id}"(${this.isReady ? 'ready' : 'loading'})`;
}
constructor(device: Device, props: AsyncTextureProps) {
this.device = device;
this.id = props.id || uid('async-texture');
// this.id = typeof props?.data === 'string' ? props.data.slice(-20) : uid('async-texture');

@@ -79,0 +91,0 @@ // Signature: new AsyncTexture(device, {data: url})

@@ -6,3 +6,3 @@ // luma.gl

import type {BufferProps, FramebufferProps} from '@luma.gl/core';
import {Device, Resource, Buffer, Framebuffer} from '@luma.gl/core';
import {Device, Resource, Buffer, Framebuffer, Texture} from '@luma.gl/core';

@@ -43,3 +43,27 @@ /**

constructor(device: Device, props: FramebufferProps) {
super({current: device.createFramebuffer(props), next: device.createFramebuffer(props)});
props = {...props};
let colorAttachments = props.colorAttachments?.map(colorAttachment =>
typeof colorAttachment !== 'string'
? colorAttachment
: device.createTexture({
format: colorAttachment,
usage: Texture.COPY_DST | Texture.RENDER_ATTACHMENT
})
);
const current = device.createFramebuffer({...props, colorAttachments});
colorAttachments = props.colorAttachments?.map(colorAttachment =>
typeof colorAttachment !== 'string'
? colorAttachment
: device.createTexture({
format: colorAttachment,
usage: Texture.COPY_DST | Texture.RENDER_ATTACHMENT
})
);
const next = device.createFramebuffer({...props, colorAttachments});
super({current, next});
}

@@ -46,0 +70,0 @@

@@ -6,4 +6,5 @@ // luma.gl

import {Buffer, Device, Framebuffer, RenderPassProps, Sampler, Texture} from '@luma.gl/core';
import {getPassthroughFS} from '@luma.gl/shadertools';
import {Model, ModelProps} from '../model/model';
import {getPassthroughFS} from '@luma.gl/shadertools';
import {uid} from '../utils/uid';

@@ -64,3 +65,3 @@ /**

this.model = new Model(this.device, {
id: props.id || 'texture-transform-model',
id: props.id || uid('texture-transform-model'),
fs:

@@ -67,0 +68,0 @@ props.fs ||

@@ -6,3 +6,4 @@ // luma.gl

import type {RenderPipelineProps, ComputePipelineProps} from '@luma.gl/core';
import {Device, RenderPipeline, ComputePipeline} from '@luma.gl/core';
import {Device, RenderPipeline, ComputePipeline, log} from '@luma.gl/core';
import {uid} from '../utils/uid';

@@ -28,3 +29,5 @@ export type PipelineFactoryProps = RenderPipelineProps;

readonly device: Device;
readonly cachingEnabled: boolean;
readonly destroyPolicy: 'unused' | 'never';
readonly debug: boolean;

@@ -36,33 +39,65 @@ private _hashCounter: number = 0;

get [Symbol.toStringTag](): string {
return 'PipelineFactory';
}
toString(): string {
return `PipelineFactory(${this.device.id})`;
}
constructor(device: Device) {
this.device = device;
this.destroyPolicy = device.props._factoryDestroyPolicy;
this.cachingEnabled = device.props._cachePipelines;
this.destroyPolicy = device.props._cacheDestroyPolicy;
this.debug = device.props.debugFactories;
}
/** Return a RenderPipeline matching props. Reuses a similar pipeline if already created. */
/** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
createRenderPipeline(props: RenderPipelineProps): RenderPipeline {
if (!this.cachingEnabled) {
return this.device.createRenderPipeline(props);
}
const allProps: Required<RenderPipelineProps> = {...RenderPipeline.defaultProps, ...props};
const cache = this._renderPipelineCache;
const hash = this._hashRenderPipeline(allProps);
if (!this._renderPipelineCache[hash]) {
const pipeline = this.device.createRenderPipeline({
let pipeline: RenderPipeline = cache[hash]?.pipeline;
if (!pipeline) {
pipeline = this.device.createRenderPipeline({
...allProps,
id: allProps.id ? `${allProps.id}-cached` : undefined
id: allProps.id ? `${allProps.id}-cached` : uid('unnamed-cached')
});
pipeline.hash = hash;
this._renderPipelineCache[hash] = {pipeline, useCount: 0};
cache[hash] = {pipeline, useCount: 1};
if (this.debug) {
log.warn(`${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
}
} else {
cache[hash].useCount++;
if (this.debug) {
log.warn(
`${this}: ${cache[hash].pipeline} reused, count=${cache[hash].useCount}, (id=${props.id})`
)();
}
}
this._renderPipelineCache[hash].useCount++;
return this._renderPipelineCache[hash].pipeline;
return pipeline;
}
/** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
createComputePipeline(props: ComputePipelineProps): ComputePipeline {
if (!this.cachingEnabled) {
return this.device.createComputePipeline(props);
}
const allProps: Required<ComputePipelineProps> = {...ComputePipeline.defaultProps, ...props};
const cache = this._computePipelineCache;
const hash = this._hashComputePipeline(allProps);
if (!this._computePipelineCache[hash]) {
const pipeline = this.device.createComputePipeline({
let pipeline: ComputePipeline = cache[hash]?.pipeline;
if (!pipeline) {
pipeline = this.device.createComputePipeline({
...allProps,

@@ -72,19 +107,38 @@ id: allProps.id ? `${allProps.id}-cached` : undefined

pipeline.hash = hash;
this._computePipelineCache[hash] = {pipeline, useCount: 0};
cache[hash] = {pipeline, useCount: 1};
if (this.debug) {
log.warn(`${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
}
} else {
cache[hash].useCount++;
if (this.debug) {
log.warn(
`${this}: ${cache[hash].pipeline} reused, count=${cache[hash].useCount}, (id=${props.id})`
)();
}
}
this._computePipelineCache[hash].useCount++;
return this._computePipelineCache[hash].pipeline;
return pipeline;
}
release(pipeline: RenderPipeline | ComputePipeline): void {
if (!this.cachingEnabled) {
pipeline.destroy();
return;
}
const cache = this._getCache(pipeline);
const hash = pipeline.hash;
const cache =
pipeline instanceof ComputePipeline ? this._computePipelineCache : this._renderPipelineCache;
cache[hash].useCount--;
if (cache[hash].useCount === 0) {
if (this.destroyPolicy === 'unused') {
cache[hash].pipeline.destroy();
delete cache[hash];
this._destroyPipeline(pipeline);
if (this.debug) {
log.warn(`${this}: ${pipeline} released and destroyed`)();
}
} else if (cache[hash].useCount < 0) {
log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
cache[hash].useCount = 0;
} else if (this.debug) {
log.warn(`${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
}

@@ -94,5 +148,45 @@ }

// PRIVATE
/** Destroy a cached pipeline, removing it from the cache (depending on destroy policy) */
private _destroyPipeline(pipeline: RenderPipeline | ComputePipeline): boolean {
const cache = this._getCache(pipeline);
switch (this.destroyPolicy) {
case 'never':
return false;
case 'unused':
delete cache[pipeline.hash];
pipeline.destroy();
return true;
}
}
/** Get the appropriate cache for the type of pipeline */
private _getCache(
pipeline: RenderPipeline | ComputePipeline
): Record<string, RenderPipelineCacheItem> | Record<string, ComputePipelineCacheItem> {
let cache:
| Record<string, RenderPipelineCacheItem>
| Record<string, ComputePipelineCacheItem>
| undefined;
if (pipeline instanceof ComputePipeline) {
cache = this._computePipelineCache;
}
if (pipeline instanceof RenderPipeline) {
cache = this._renderPipelineCache;
}
if (!cache) {
throw new Error(`${this}`);
}
if (!cache[pipeline.hash]) {
throw new Error(`${this}: ${pipeline} matched incorrect entry`);
}
return cache;
}
/** Calculate a hash based on all the inputs for a compute pipeline */
private _hashComputePipeline(props: ComputePipelineProps): string {
const {type} = this.device;
const shaderHash = this._getHash(props.shader.source);
return `${shaderHash}`;
return `${type}/C/${shaderHash}`;
}

@@ -111,7 +205,9 @@

switch (this.device.type) {
const {type} = this.device;
switch (type) {
case 'webgl':
// WebGL is more dynamic
return `${vsHash}/${fsHash}V${varyingHash}BL${bufferLayoutHash}`;
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}BL${bufferLayoutHash}`;
case 'webgpu':
default:

@@ -122,3 +218,3 @@ // On WebGPU we need to rebuild the pipeline if topology, parameters or bufferLayout change

// create a deepHash() to deduplicate?
return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`;
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`;
}

@@ -125,0 +221,0 @@ }

@@ -5,3 +5,3 @@ // luma.gl

import {Device, Shader, ShaderProps} from '@luma.gl/core';
import {Device, Shader, ShaderProps, log} from '@luma.gl/core';

@@ -19,9 +19,22 @@ /** Manages a cached pool of Shaders for reuse. */

public readonly device: Device;
readonly cachingEnabled: boolean;
readonly destroyPolicy: 'unused' | 'never';
readonly debug: boolean;
private readonly _cache: Record<string, {shader: Shader; useCount: number}> = {};
get [Symbol.toStringTag](): string {
return 'ShaderFactory';
}
toString(): string {
return `${this[Symbol.toStringTag]}(${this.device.id})`;
}
/** @internal */
constructor(device: Device) {
this.device = device;
this.destroyPolicy = device.props._factoryDestroyPolicy;
this.cachingEnabled = device.props._cacheShaders;
this.destroyPolicy = device.props._cacheDestroyPolicy;
this.debug = true; // device.props.debugFactories;
}

@@ -31,2 +44,6 @@

createShader(props: ShaderProps): Shader {
if (!this.cachingEnabled) {
return this.device.createShader(props);
}
const key = this._hashShader(props);

@@ -40,6 +57,13 @@

});
this._cache[key] = cacheEntry = {shader, useCount: 0};
this._cache[key] = cacheEntry = {shader, useCount: 1};
if (this.debug) {
log.warn(`${this}: Created new shader ${shader.id}`)();
}
} else {
cacheEntry.useCount++;
if (this.debug) {
log.warn(`${this}: Reusing shader ${cacheEntry.shader.id} count=${cacheEntry.useCount}`)();
}
}
cacheEntry.useCount++;
return cacheEntry.shader;

@@ -50,2 +74,7 @@ }

release(shader: Shader): void {
if (!this.cachingEnabled) {
shader.destroy();
return;
}
const key = this._hashShader(shader);

@@ -59,3 +88,10 @@ const cacheEntry = this._cache[key];

cacheEntry.shader.destroy();
if (this.debug) {
log.warn(`${this}: Releasing shader ${shader.id}, destroyed`)();
}
}
} else if (cacheEntry.useCount < 0) {
throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
} else if (this.debug) {
log.warn(`${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
}

@@ -67,5 +103,5 @@ }

private _hashShader(value: Shader | ShaderProps): string {
protected _hashShader(value: Shader | ShaderProps): string {
return `${value.stage}:${value.source}`;
}
}

@@ -224,2 +224,10 @@ // luma.gl

get [Symbol.toStringTag](): string {
return 'Model';
}
toString(): string {
return `Model(${this.id})`;
}
constructor(device: Device, props: ModelProps) {

@@ -299,3 +307,4 @@ this.props = {...Model.defaultProps, ...props};

this.vertexArray = device.createVertexArray({
renderPipeline: this.pipeline
shaderLayout: this.pipeline.shaderLayout,
bufferLayout: this.pipeline.bufferLayout
});

@@ -332,7 +341,7 @@

if (props.uniforms) {
this.setUniforms(props.uniforms);
this.setUniformsWebGL(props.uniforms);
}
if (props.moduleSettings) {
// log.warn('Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()')();
this.updateModuleSettings(props.moduleSettings);
this.updateModuleSettingsWebGL(props.moduleSettings);
}

@@ -348,12 +357,15 @@ if (props.transformFeedback) {

destroy(): void {
if (this._destroyed) return;
this.pipelineFactory.release(this.pipeline);
this.shaderFactory.release(this.pipeline.vs);
if (this.pipeline.fs) {
this.shaderFactory.release(this.pipeline.fs);
if (!this._destroyed) {
// Release pipeline before we destroy the shaders used by the pipeline
this.pipelineFactory.release(this.pipeline);
// Release the shaders
this.shaderFactory.release(this.pipeline.vs);
if (this.pipeline.fs) {
this.shaderFactory.release(this.pipeline.fs);
}
this._uniformStore.destroy();
// TODO - mark resource as managed and destroyIfManaged() ?
this._gpuGeometry?.destroy();
this._destroyed = true;
}
this._uniformStore.destroy();
// TODO - mark resource as managed and destroyIfManaged() ?
this._gpuGeometry?.destroy();
this._destroyed = true;
}

@@ -387,6 +399,18 @@

draw(renderPass: RenderPass): boolean {
this.predraw();
const loadingBinding = this._areBindingsLoading();
if (loadingBinding) {
log.info(LOG_DRAW_PRIORITY, `>>> DRAWING ABORTED ${this.id}: ${loadingBinding} not loaded`)();
return false;
}
try {
renderPass.pushDebugGroup(`${this}.predraw(${renderPass})`);
this.predraw();
} finally {
renderPass.popDebugGroup();
}
let drawSuccess: boolean;
try {
renderPass.pushDebugGroup(`${this}.draw(${renderPass})`);
this._logDrawCallStart();

@@ -402,2 +426,3 @@

// TODO this is a busy initialized check for all bindings every frame
const syncBindings = this._getBindings();

@@ -431,2 +456,3 @@ this.pipeline.setBindings(syncBindings, {

} finally {
renderPass.popDebugGroup();
this._logDrawCallEnd();

@@ -498,3 +524,4 @@ }

this.vertexArray = this.device.createVertexArray({
renderPipeline: this.pipeline
shaderLayout: this.pipeline.shaderLayout,
bufferLayout: this.pipeline.bufferLayout
});

@@ -667,3 +694,3 @@

*/
setUniforms(uniforms: Record<string, UniformValue>): void {
setUniformsWebGL(uniforms: Record<string, UniformValue>): void {
if (!isObjectEmpty(uniforms)) {

@@ -679,3 +706,3 @@ this.pipeline.setUniformsWebGL(uniforms);

*/
updateModuleSettings(props: Record<string, any>): void {
updateModuleSettingsWebGL(props: Record<string, any>): void {
// log.warn('Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()')();

@@ -690,15 +717,28 @@ const {bindings, uniforms} = splitUniformsAndBindings(this._getModuleUniforms(props));

/** Get texture / texture view from any async textures */
/** Check that bindings are loaded. Returns id of first binding that is still loading. */
_areBindingsLoading(): string | false {
for (const binding of Object.values(this.bindings)) {
if (binding instanceof AsyncTexture && !binding.isReady) {
return binding.id;
}
}
return false;
}
/** Extracts texture view from loaded async textures. Returns null if any textures have not yet been loaded. */
_getBindings(): Record<string, Binding> {
// Extract actual textures from async textures. If not loaded, null
return Object.entries(this.bindings).reduce<Record<string, Binding>>((acc, [name, binding]) => {
const validBindings: Record<string, Binding> = {};
for (const [name, binding] of Object.entries(this.bindings)) {
if (binding instanceof AsyncTexture) {
// Check that async textures are loaded
if (binding.isReady) {
acc[name] = binding.texture;
validBindings[name] = binding.texture;
}
} else {
acc[name] = binding;
validBindings[name] = binding;
}
return acc;
}, {});
}
return validBindings;
}

@@ -705,0 +745,0 @@

@@ -9,6 +9,24 @@ // luma.gl

const BACKGROUND_FS_WGSL = /* wgsl */ `\
@group(0) @binding(0) var backgroundTexture: texture_2d<f32>;
@group(0) @binding(1) var backgroundTextureSampler: sampler;
fn billboardTexture_getTextureUV(coordinates: vec2<f32>) -> vec2<f32> {
let iTexSize: vec2<u32> = textureDimensions(backgroundTexture, 0) * 2;
let texSize: vec2<f32> = vec2<f32>(f32(iTexSize.x), f32(iTexSize.y));
var position: vec2<f32> = coordinates.xy / texSize;
return position;
}
@fragment
fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
let position: vec2<f32> = billboardTexture_getTextureUV(inputs.coordinate);
return textureSample(backgroundTexture, backgroundTextureSampler, position);
}
`;
const BACKGROUND_FS = /* glsl */ `\
#version 300 es
precision highp float;
precision highp float;
uniform sampler2D backgroundTexture;

@@ -18,3 +36,3 @@ out vec4 fragColor;

vec2 billboardTexture_getTextureUV() {
ivec2 iTexSize = textureSize(backgroundTexture, 0) * 2;
ivec2 iTexSize = textureDimensions(backgroundTexture, 0) * 2;
vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));

@@ -50,2 +68,3 @@ vec2 position = gl_FragCoord.xy / texSize;

id: props.id || 'background-texture-model',
source: BACKGROUND_FS_WGSL,
fs: BACKGROUND_FS,

@@ -52,0 +71,0 @@ parameters: {

@@ -9,24 +9,26 @@ // luma.gl

import {Geometry} from '../geometry/geometry';
import {uid} from '../utils/uid';
const CLIPSPACE_VERTEX_SHADER_WGSL = /* wgsl */ `\
struct VertexInput {
aClipSpacePosition: vec2<f32>;
aTexCoord: vec2<f32>;
aCoordinate: vec2<f32>;
struct VertexInputs {
@location(0) clipSpacePosition: vec2<f32>,
@location(1) texCoord: vec2<f32>,
@location(2) coordinate: vec2<f32>
}
struct FragmentInput {
@builtin(position) Position : vec4<f32>;
@location(0) position : vec2<f32>;
@location(1) coordinate : vec2<f32>;
@location(2) uv : vec2<f32>;
struct FragmentInputs {
@builtin(position) Position : vec4<f32>,
@location(0) position : vec2<f32>,
@location(1) coordinate : vec2<f32>,
@location(2) uv : vec2<f32>
};
@stage(vertex)
fn vertexMain(input: VertexInput) -> FragmentInput {
var output: FragmentInput;
output.Position = vec4(aClipSpacePosition, 0., 1.);
output.position = input.aClipSpacePosition;
output.coordinate = input.aCoordinate;
output.uv = aTexCoord;
@vertex
fn vertexMain(inputs: VertexInputs) -> FragmentInputs {
var outputs: FragmentInputs;
outputs.Position = vec4(inputs.clipSpacePosition, 0., 1.);
outputs.position = inputs.clipSpacePosition;
outputs.coordinate = inputs.coordinate;
outputs.uv = inputs.texCoord;
return outputs;
}

@@ -37,5 +39,5 @@ `;

#version 300 es
in vec2 aClipSpacePosition;
in vec2 aTexCoord;
in vec2 aCoordinate;
in vec2 clipSpacePosition;
in vec2 texCoord;
in vec2 coordinate;

@@ -47,6 +49,6 @@ out vec2 position;

void main(void) {
gl_Position = vec4(aClipSpacePosition, 0., 1.);
position = aClipSpacePosition;
coordinate = aCoordinate;
uv = aTexCoord;
gl_Position = vec4(clipSpacePosition, 0., 1.);
position = clipSpacePosition;
coordinate = coordinate;
uv = texCoord;
}

@@ -70,8 +72,8 @@ `;

if (props.source) {
props = {...props, source: `${CLIPSPACE_VERTEX_SHADER_WGSL}\m${props.source}`};
props = {...props, source: `${CLIPSPACE_VERTEX_SHADER_WGSL}\n${props.source}`};
}
super(device, {
id: props.id || uid('clip-space'),
...props,
source: CLIPSPACE_VERTEX_SHADER_WGSL,
vs: CLIPSPACE_VERTEX_SHADER,

@@ -83,5 +85,5 @@ vertexCount: 4,

attributes: {
aClipSpacePosition: {size: 2, value: new Float32Array(POSITIONS)},
aTexCoord: {size: 2, value: new Float32Array(TEX_COORDS)},
aCoordinate: {size: 2, value: new Float32Array(TEX_COORDS)}
clipSpacePosition: {size: 2, value: new Float32Array(POSITIONS)},
texCoord: {size: 2, value: new Float32Array(TEX_COORDS)},
coordinate: {size: 2, value: new Float32Array(TEX_COORDS)}
}

@@ -88,0 +90,0 @@ })

@@ -59,3 +59,14 @@ // luma.gl

this.clipSpace = new ClipSpace(device, {
fs: `\
source: /* wgsl */ `\
@group(0) @binding(0) var sourceTexture: texture_2d<f32>;
@group(0) @binding(1) var sourceTextureSampler: sampler;
@fragment
fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
let texCoord: vec2<f32> = inputs.coordinate;
return textureSample(sourceTexture, sourceTextureSampler, texCoord);
}
`,
fs: /* glsl */ `\
#version 300 es

@@ -148,7 +159,6 @@

// eslint-disable-next-line no-shadow
const sourceTexture = this.swapFramebuffers.current.colorAttachments[0].texture;
const swapBufferTexture = this.swapFramebuffers.current.colorAttachments[0].texture;
const bindings = {
sourceTexture
sourceTexture: swapBufferTexture
// texSize: [sourceTextures.width, sourceTextures.height]

@@ -155,0 +165,0 @@ };

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc