{ "version": 3, "sources": ["index.js", "init.js", "utils/log.js", "utils/stats-manager.js", "utils/is-array.js", "utils/utils.js", "adapter/resources/resource.js", "adapter/resources/buffer.js", "adapter/type-utils/decode-data-type.js", "adapter/type-utils/decode-texture-format.js", "adapter/device.js", "utils/assert.js", "lib/luma.js", "adapter/canvas-context.js", "adapter/resources/texture.js", "adapter/resources/texture-view.js", "adapter/resources/external-texture.js", "lib/compiler-log/format-compiler-log.js", "lib/compiler-log/get-shader-info.js", "adapter/resources/shader.js", "adapter/resources/sampler.js", "adapter/resources/framebuffer.js", "adapter/resources/render-pipeline.js", "adapter/resources/render-pass.js", "adapter/resources/compute-pipeline.js", "adapter/resources/compute-pass.js", "adapter/resources/command-encoder.js", "adapter/resources/command-buffer.js", "adapter/type-utils/decode-attribute-type.js", "adapter/type-utils/decode-vertex-format.js", "adapter/attribute-utils/get-attribute-from-layouts.js", "adapter/resources/vertex-array.js", "adapter/resources/transform-feedback.js", "adapter/resources/query-set.js", "adapter/type-utils/decode-shader-types.js", "utils/array-utils-flat.js", "lib/uniforms/uniform-buffer-layout.js", "utils/array-equal.js", "lib/uniforms/uniform-block.js", "lib/uniforms/uniform-store.js", "adapter/type-utils/vertex-format-from-attribute.js", "utils/cast.js", "lib/uniforms/uniform.js", "utils/format-value.js", "utils/stub-methods.js", "utils/check-props.js", "utils/load-file.js", "utils/random.js", "utils/deep-equal.js", "utils/request-animation-frame.js"], "sourcesContent": ["// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nexport { VERSION } from \"./init.js\";\nexport { isTypedArray, isNumberArray } from \"./utils/is-array.js\";\n// MAIN API ACCESS POINTS\nexport { luma } from \"./lib/luma.js\";\nexport { Device, DeviceFeatures, DeviceLimits } from \"./adapter/device.js\";\nexport { CanvasContext } from \"./adapter/canvas-context.js\";\nexport { Resource } from \"./adapter/resources/resource.js\";\nexport { Buffer } from \"./adapter/resources/buffer.js\";\nexport { Texture } from \"./adapter/resources/texture.js\";\nexport { TextureView } from \"./adapter/resources/texture-view.js\";\nexport { ExternalTexture } from \"./adapter/resources/external-texture.js\";\nexport { Shader } from \"./adapter/resources/shader.js\";\nexport { Sampler } from \"./adapter/resources/sampler.js\";\nexport { Framebuffer } from \"./adapter/resources/framebuffer.js\";\nexport { RenderPipeline } from \"./adapter/resources/render-pipeline.js\";\nexport { RenderPass } from \"./adapter/resources/render-pass.js\";\nexport { ComputePipeline } from \"./adapter/resources/compute-pipeline.js\";\nexport { ComputePass } from \"./adapter/resources/compute-pass.js\";\nexport { CommandEncoder } from \"./adapter/resources/command-encoder.js\";\nexport { CommandBuffer } from \"./adapter/resources/command-buffer.js\";\nexport { VertexArray } from \"./adapter/resources/vertex-array.js\";\nexport { TransformFeedback } from \"./adapter/resources/transform-feedback.js\";\nexport { QuerySet } from \"./adapter/resources/query-set.js\";\nexport { UniformBufferLayout } from \"./lib/uniforms/uniform-buffer-layout.js\";\nexport { UniformBlock } from \"./lib/uniforms/uniform-block.js\";\nexport { UniformStore } from \"./lib/uniforms/uniform-store.js\";\n// TYPE UTILS\nexport { decodeVertexFormat } from \"./adapter/type-utils/decode-vertex-format.js\";\nexport { decodeTextureFormat } from \"./adapter/type-utils/decode-texture-format.js\";\nexport { getDataTypeFromTypedArray, getTypedArrayFromDataType, getVertexFormatFromAttribute } from \"./adapter/type-utils/vertex-format-from-attribute.js\";\n// SHADER TYPE UTILS\nexport { decodeShaderUniformType } from \"./adapter/type-utils/decode-shader-types.js\";\nexport { decodeShaderAttributeType } from \"./adapter/type-utils/decode-attribute-type.js\";\nexport { formatCompilerLog } from \"./lib/compiler-log/format-compiler-log.js\";\nexport { getAttributeInfosFromLayouts, mergeShaderLayout } from \"./adapter/attribute-utils/get-attribute-from-layouts.js\";\n// GENERAL UTILS\nexport { StatsManager } from \"./utils/stats-manager.js\";\nexport { assert } from \"./utils/assert.js\";\nexport { cast } from \"./utils/cast.js\";\nexport { log } from \"./utils/log.js\";\nexport { uid, isObjectEmpty } from \"./utils/utils.js\";\nexport { isUniformValue, splitUniformsAndBindings } from \"./lib/uniforms/uniform.js\";\nexport { formatValue } from \"./utils/format-value.js\";\nexport { stubRemovedMethods } from \"./utils/stub-methods.js\";\nexport { checkProps } from \"./utils/check-props.js\";\nexport { setPathPrefix, loadFile, loadImage, loadImageBitmap, loadScript } from \"./utils/load-file.js\";\nexport { getScratchArrayBuffer, getScratchArray, fillArray } from \"./utils/array-utils-flat.js\";\nexport { makeRandomNumberGenerator, random } from \"./utils/random.js\";\nexport { deepEqual } from \"./utils/deep-equal.js\";\n// ENGINE - TODO/move to @luma.gl/engine once that module is webgl-independent?\nexport { requestAnimationFrame, cancelAnimationFrame } from \"./utils/request-animation-frame.js\";\n// SHADER HELPERS\n/**\n * Marks GLSL shaders for syntax highlighting: glsl`...`\n * Install https://marketplace.visualstudio.com/items?itemName=boyswan.glsl-literal\n */\nexport const glsl = (x) => `${x}`;\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { isBrowser } from '@probe.gl/env';\nimport { log } from \"./utils/log.js\";\nimport { lumaStats } from \"./utils/stats-manager.js\";\n/**\n * By adding the result of init() to Device.VERSION we guarantee it will be called\n * @returns version\n */\nfunction initializeLuma() {\n // Version detection using babel plugin\n // @ts-expect-error\n const VERSION = typeof \"9.0.27\" !== 'undefined' ? \"9.0.27\" : 'running from source';\n const STARTUP_MESSAGE = 'set luma.log.level=1 (or higher) to trace rendering';\n // Assign luma.log.level in console to control logging: \\\n // 0: none, 1: minimal, 2: verbose, 3: attribute/uniforms, 4: gl logs\n // luma.log.break[], set to gl funcs, luma.log.profile[] set to model names`;\n if (globalThis.luma && globalThis.luma.VERSION !== VERSION) {\n throw new Error(`luma.gl - multiple VERSIONs detected: ${globalThis.luma.VERSION} vs ${VERSION}`);\n }\n if (!globalThis.luma) {\n if (isBrowser()) {\n log.log(1, `${VERSION} - ${STARTUP_MESSAGE}`)();\n }\n globalThis.luma = globalThis.luma || {\n VERSION,\n version: VERSION,\n log,\n // A global stats object that various components can add information to\n // E.g. see webgl/resource.js\n stats: lumaStats\n };\n }\n return VERSION;\n}\nexport const VERSION = initializeLuma();\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { Log } from '@probe.gl/log';\n/** Global log instance */\nexport const log = new Log({ id: 'luma.gl' });\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { Stats } from '@probe.gl/stats';\n/**\n * Helper class managing a collection of probe.gl stats objects\n */\nexport class StatsManager {\n stats = new Map();\n getStats(name) {\n return this.get(name);\n }\n get(name) {\n if (!this.stats.has(name)) {\n this.stats.set(name, new Stats({ id: name }));\n }\n return this.stats.get(name);\n }\n}\n/** Global stats for all luma.gl devices */\nexport const lumaStats = new StatsManager();\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n/**\n * Check is an array is a typed array\n * @param value value to be tested\n * @returns input as TypedArray, or null\n * @todo this should be provided by @math.gl/types\n */\nexport function isTypedArray(value) {\n return ArrayBuffer.isView(value) && !(value instanceof DataView) ? value : null;\n}\n/**\n * Check is an array is a numeric array (typed array or array of numbers)\n * @param value value to be tested\n * @returns input as NumberArray, or null\n * @todo this should be provided by @math.gl/types\n */\nexport function isNumberArray(value) {\n if (Array.isArray(value)) {\n return value.length === 0 || typeof value[0] === 'number' ? value : null;\n }\n return isTypedArray(value);\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nconst uidCounters = {};\n/**\n * Returns a UID.\n * @param id= - Identifier base name\n * @return uid\n **/\nexport function uid(id = 'id') {\n uidCounters[id] = uidCounters[id] || 1;\n const count = uidCounters[id]++;\n return `${id}-${count}`;\n}\n/** Returns true if given object is empty, false otherwise. */\nexport function isObjectEmpty(obj) {\n let isEmpty = true;\n // @ts-ignore key is unused\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for (const key in obj) {\n isEmpty = false;\n break;\n }\n return isEmpty;\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { uid } from \"../../utils/utils.js\";\n/**\n * Base class for GPU (WebGPU/WebGL) Resources\n */\nexport class Resource {\n /** Default properties for resource */\n static defaultProps = {\n id: 'undefined',\n handle: undefined,\n userData: undefined\n };\n /** props.id, for debugging. */\n id;\n props;\n userData = {};\n _device;\n /** Whether this resource has been destroyed */\n destroyed = false;\n /** For resources that allocate GPU memory */\n allocatedBytes = 0;\n /** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created \"sub\" resources. */\n _attachedResources = new Set();\n /**\n * Create a new Resource. Called from Subclass\n */\n constructor(device, props, defaultProps) {\n if (!device) {\n throw new Error('no device');\n }\n this._device = device;\n this.props = selectivelyMerge(props, defaultProps);\n const id = this.props.id !== 'undefined' ? this.props.id : uid(this[Symbol.toStringTag]);\n this.props.id = id;\n this.id = id;\n this.userData = this.props.userData || {};\n this.addStats();\n }\n /**\n * destroy can be called on any resource to release it before it is garbage collected.\n */\n destroy() {\n this.destroyResource();\n }\n /** @deprecated Use destroy() */\n delete() {\n this.destroy();\n return this;\n }\n toString() {\n return `${this[Symbol.toStringTag] || this.constructor.name}(${this.id})`;\n }\n /**\n * Combines a map of user props and default props, only including props from defaultProps\n * @returns returns a map of overridden default props\n */\n getProps() {\n return this.props;\n }\n // ATTACHED RESOURCES\n /**\n * Attaches a resource. Attached resources are auto destroyed when this resource is destroyed\n * Called automatically when sub resources are auto created but can be called by application\n */\n attachResource(resource) {\n this._attachedResources.add(resource);\n }\n /**\n * Detach an attached resource. The resource will no longer be auto-destroyed when this resource is destroyed.\n */\n detachResource(resource) {\n this._attachedResources.delete(resource);\n }\n /**\n * Destroys a resource (only if owned), and removes from the owned (auto-destroy) list for this resource.\n */\n destroyAttachedResource(resource) {\n if (this._attachedResources.delete(resource)) {\n resource.destroy();\n }\n }\n /** Destroy all owned resources. Make sure the resources are no longer needed before calling. */\n destroyAttachedResources() {\n for (const resource of Object.values(this._attachedResources)) {\n resource.destroy();\n }\n // don't remove while we are iterating\n this._attachedResources = new Set();\n }\n // PROTECTED METHODS\n /** Perform all destroy steps. Can be called by derived resources when overriding destroy() */\n destroyResource() {\n this.destroyAttachedResources();\n this.removeStats();\n this.destroyed = true;\n }\n /** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */\n removeStats() {\n const stats = this._device.statsManager.getStats('Resource Counts');\n const name = this[Symbol.toStringTag];\n stats.get(`${name}s Active`).decrementCount();\n }\n /** Called by subclass to track memory allocations */\n trackAllocatedMemory(bytes, name = this[Symbol.toStringTag]) {\n const stats = this._device.statsManager.getStats('Resource Counts');\n stats.get('GPU Memory').addCount(bytes);\n stats.get(`${name} Memory`).addCount(bytes);\n this.allocatedBytes = bytes;\n }\n /** Called by subclass to track memory deallocations */\n trackDeallocatedMemory(name = this[Symbol.toStringTag]) {\n const stats = this._device.statsManager.getStats('Resource Counts');\n stats.get('GPU Memory').subtractCount(this.allocatedBytes);\n stats.get(`${name} Memory`).subtractCount(this.allocatedBytes);\n this.allocatedBytes = 0;\n }\n /** Called by resource constructor to track object creation */\n addStats() {\n const stats = this._device.statsManager.getStats('Resource Counts');\n const name = this[Symbol.toStringTag];\n stats.get('Resources Created').incrementCount();\n stats.get(`${name}s Created`).incrementCount();\n stats.get(`${name}s Active`).incrementCount();\n }\n}\n/**\n * Combines a map of user props and default props, only including props from defaultProps\n * @param props\n * @param defaultProps\n * @returns returns a map of overridden default props\n */\nfunction selectivelyMerge(props, defaultProps) {\n const mergedProps = { ...defaultProps };\n for (const key in props) {\n if (props[key] !== undefined) {\n mergedProps[key] = props[key];\n }\n }\n return mergedProps;\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { Resource } from \"./resource.js\";\n/** Abstract GPU buffer */\nexport class Buffer extends Resource {\n static defaultProps = {\n ...Resource.defaultProps,\n usage: 0, // Buffer.COPY_DST | Buffer.COPY_SRC\n byteLength: 0,\n byteOffset: 0,\n data: null,\n indexType: 'uint16',\n mappedAtCreation: false\n };\n // Usage Flags\n static MAP_READ = 0x01;\n static MAP_WRITE = 0x02;\n static COPY_SRC = 0x0004;\n static COPY_DST = 0x0008;\n /** Index buffer */\n static INDEX = 0x0010;\n /** Vertex buffer */\n static VERTEX = 0x0020;\n /** Uniform buffer */\n static UNIFORM = 0x0040;\n /** Storage buffer */\n static STORAGE = 0x0080;\n static INDIRECT = 0x0100;\n static QUERY_RESOLVE = 0x0200;\n get [Symbol.toStringTag]() {\n return 'Buffer';\n }\n /** The usage with which this buffer was created */\n usage;\n /** For index buffers, whether indices are 16 or 32 bit */\n indexType;\n /** \"Time\" of last update */\n updateTimestamp;\n constructor(device, props) {\n const deducedProps = { ...props };\n // Deduce indexType\n if ((props.usage || 0) & Buffer.INDEX && !props.indexType) {\n if (props.data instanceof Uint32Array) {\n deducedProps.indexType = 'uint32';\n }\n else if (props.data instanceof Uint16Array) {\n deducedProps.indexType = 'uint16';\n }\n }\n super(device, deducedProps, Buffer.defaultProps);\n this.usage = props.usage || 0;\n this.indexType = deducedProps.indexType;\n // TODO - perhaps this should be set on async write completion?\n this.updateTimestamp = device.incrementTimestamp();\n }\n /** Read data synchronously. @note WebGL2 only */\n readSyncWebGL(byteOffset, byteLength) {\n throw new Error('not implemented');\n }\n // PROTECTED METHODS (INTENDED FOR USE BY OTHER FRAMEWORK CODE ONLY)\n /** Max amount of debug data saved. Two vec4's */\n static DEBUG_DATA_MAX_LENGTH = 32;\n /** A partial CPU-side copy of the data in this buffer, for debugging purposes */\n debugData = new ArrayBuffer(0);\n /** This doesn't handle partial non-zero offset updates correctly */\n _setDebugData(data, byteOffset, byteLength) {\n const buffer = ArrayBuffer.isView(data) ? data.buffer : data;\n const debugDataLength = Math.min(data ? data.byteLength : byteLength, Buffer.DEBUG_DATA_MAX_LENGTH);\n if (data === null) {\n this.debugData = new ArrayBuffer(debugDataLength);\n }\n else if (byteOffset === 0 && byteLength === data.byteLength) {\n this.debugData = buffer.slice(0, debugDataLength);\n }\n else {\n this.debugData = buffer.slice(byteOffset, byteOffset + debugDataLength);\n }\n }\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n/** Decodes a vertex type, returning byte length and flags (integer, signed, normalized) */\nexport function decodeVertexType(type) {\n const dataType = TYPE_MAP[type];\n const bytes = getDataTypeBytes(dataType);\n const normalized = type.includes('norm');\n const integer = !normalized && !type.startsWith('float');\n const signed = type.startsWith('s');\n return {\n dataType: TYPE_MAP[type],\n byteLength: bytes,\n integer,\n signed,\n normalized\n };\n}\nfunction getDataTypeBytes(type) {\n const bytes = TYPE_SIZES[type];\n // assert(bytes);\n return bytes;\n}\nconst TYPE_MAP = {\n uint8: 'uint8',\n sint8: 'sint8',\n unorm8: 'uint8',\n snorm8: 'sint8',\n uint16: 'uint16',\n sint16: 'sint16',\n unorm16: 'uint16',\n snorm16: 'sint16',\n float16: 'float16',\n float32: 'float32',\n uint32: 'uint32',\n sint32: 'sint32'\n};\nconst TYPE_SIZES = {\n uint8: 1,\n sint8: 1,\n uint16: 2,\n sint16: 2,\n float16: 2,\n float32: 4,\n uint32: 4,\n sint32: 4\n};\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { decodeVertexType } from \"./decode-data-type.js\";\n// prettier-ignore\nconst COMPRESSED_TEXTURE_FORMAT_PREFIXES = [\n 'bc1', 'bc2', 'bc3', 'bc4', 'bc5', 'bc6', 'bc7', 'etc1', 'etc2', 'eac', 'atc', 'astc', 'pvrtc'\n];\nconst REGEX = /^(rg?b?a?)([0-9]*)([a-z]*)(-srgb)?(-webgl|-unsized)?$/;\n/**\n * Returns true if a texture format is GPU compressed\n */\nexport function isTextureFormatCompressed(textureFormat) {\n return COMPRESSED_TEXTURE_FORMAT_PREFIXES.some(prefix => textureFormat.startsWith(prefix));\n}\n/**\n * Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized)\n */\nexport function decodeTextureFormat(format) {\n const matches = REGEX.exec(format);\n if (matches) {\n const [, format, length, type, srgb, suffix] = matches;\n if (format) {\n const dataType = `${type}${length}`;\n const decodedType = decodeVertexType(dataType);\n return {\n format: format,\n components: format.length,\n // dataType - overwritten by decodedType\n srgb: srgb === '-srgb',\n unsized: suffix === '-unsized',\n webgl: suffix === '-webgl',\n ...decodedType\n };\n }\n }\n return decodeNonStandardFormat(format);\n}\n// https://www.w3.org/TR/webgpu/#texture-format-caps\nconst EXCEPTIONS = {\n // Packed 16 bit formats\n 'rgba4unorm-webgl': { format: 'rgba', bpp: 2 },\n 'rgb565unorm-webgl': { format: 'rgb', bpp: 2 },\n 'rgb5a1unorm-webgl': { format: 'rgba', bbp: 2 },\n // Packed 32 bit formats\n rgb9e5ufloat: { format: 'rgb', bbp: 4 },\n rg11b10ufloat: { format: 'rgb', bbp: 4 },\n rgb10a2unorm: { format: 'rgba', bbp: 4 },\n 'rgb10a2uint-webgl': { format: 'rgba', bbp: 4 },\n // Depth/stencil\n stencil8: { components: 1, bpp: 1, a: 'stencil' },\n depth16unorm: { components: 1, bpp: 2, a: 'depth' },\n depth24plus: { components: 1, bpp: 3, a: 'depth' },\n depth32float: { components: 1, bpp: 4, a: 'depth' },\n 'depth24plus-stencil8': { components: 2, bpp: 4, a: 'depth-stencil' },\n // \"depth24unorm-stencil8\" feature\n 'depth24unorm-stencil8': { components: 2, bpp: 4, a: 'depth-stencil' },\n // \"depth32float-stencil8\" feature\n 'depth32float-stencil8': { components: 2, bpp: 4, a: 'depth-stencil' }\n};\nfunction decodeNonStandardFormat(format) {\n const data = EXCEPTIONS[format];\n if (!data) {\n throw new Error(`Unknown format ${format}`);\n }\n return {\n format: data.format || '',\n components: data.components || data.format?.length || 1,\n byteLength: data.bpp || 1,\n srgb: false,\n unsized: false\n };\n}\n/*\n'r8unorm':\t{s: \"float\"}, // \t\u2713\t\u2713\t\u2713\t},\n'r8snorm':\t{s: \"float\"}, // \t\t\u2713\t\t},\n'r8uint':\t{s: \"uint\"}, // \t\u2713\t\u2713\t\t},\n'r8sint':\t{s: \"sint\"}, // \t\u2713\t\u2713\t\t},\n'rg8unorm':\t{s: \"float\"}, // \t\u2713\t\u2713\t\u2713\t},\n'rg8snorm':\t{s: \"float\"}, // \t\t\u2713\t\t},\n'rg8uint':\t{s: \"uint\"}, // \t\u2713\t\u2713\t\t},\n'rg8sint':\t{s: \"sint\"}, // \t\u2713\t\u2713\t\t},\n'rgba8unorm':\t{s: \"float\"}, // \t\u2713\t\u2713\t\u2713\t\u2713},\n'rgba8unorm-srgb': {s: \"float\"}, // \t\u2713\t\u2713\t\u2713\t},\n'rgba8snorm':\t{s: \"float\"}, // \t\t\u2713\t\t\u2713},\n'rgba8uint':\t{s: \"uint\"}, // \t\u2713\t\u2713\t\t\u2713},\n'rgba8sint':\t{s: \"sint\"}, // \t\u2713\t\u2713\t\t\u2713},\n'bgra8unorm':\t{s: \"float\"}, // \t\u2713\t\u2713\t\u2713\t},\n'bgra8unorm-srgb': {s: \"float\"}, // \t\u2713\t\u2713\t\u2713\t},\n// 16-bit per component\n'r16uint': {s: \"uint\"}, // \t\u2713\t\u2713\t\t},\n'r16sint': {s: \"sint\"}, // \t\u2713\t\u2713\t\t},\n'r16float': {s: \"float\"}, // \t\u2713\t\u2713\t\u2713\t},\n'rg16uint': {s: \"uint\"}, // \t\u2713\t\u2713\t\t},\n'rg16sint': {s: \"sint\"}, // \t\u2713\t\u2713\t\t},\n'rg16float': {s: \"float\"}, // \t\u2713\t\u2713\t\u2713\t},\n'rgba16uint': {s: \"uint\"}, // \t\u2713\t\u2713\t\t\u2713},\n'rgba16sint': {s: \"sint\"}, // \t\u2713\t\u2713\t\t\u2713},\n'rgba16float': {s: \"float\"}, // \t\u2713\t\u2713\t\u2713\t\u2713},\n// 32-bit per component\n'r32uint': {s: \"uint\"}, // \t\u2713\t\t\t\u2713},\n'r32sint': {s: \"sint\"}, // \t\u2713\t\t\t\u2713},\n'r32float': {\"unfilterable-float\"\t\u2713\t\u2713\t\t\u2713},\n'rg32uint': {s: \"uint\"}, // \t\u2713\t\t\t\u2713},\n'rg32sint': {s: \"sint\"}, // \t\u2713\t\t\t\u2713},\n'rg32float': {\"unfilterable-float\"\t\u2713\t\t\t\u2713},\n'rgba32uint': {s: \"uint\"}, // \t\u2713\t\t\t\u2713},\n'rgba32sint': {s: \"sint\"}, // \t\u2713\t\t\t\u2713},\n'rgba32float': {\"unfilterable-float\"\t\u2713\t\t\t\u2713},\n// mixed component width\n'rgb10a2unorm': {s: \"float\"}, // \t\u2713\t\u2713\t\u2713\t}\n'rg11b10ufloat': {s: \"float\"}, // \t\t\u2713\t\t}\n// Format\tBytes per texel\tAspect\tGPUTextureSampleType\tValid image copy source\tValid image copy destination\n'stencil8': {1 \u2212 4\tstencil\t\"uint\"\t\u2713}\n'depth16unorm': {2\tdepth\t\"depth\"\t\u2713}\n'depth24plus': {4\tdepth\t\"depth\"\t\u2717}\n'depth24plus': {stencil8\t4 \u2212 8\tdepth\t\"depth\"\t\u2717}\n'stencil': {s: \"uint\"}, // \t\u2713}\n'depth32float': {4\tdepth\t\"depth\"\t\u2713\t\u2717}\n'depth24unorm': {stencil8\t4\tdepth\t\"depth\"\t\u2717}\n'stencil': {s: \"uint\"}, // \t\u2713}\n'depth32float': {stencil8}\n\n// Format\tBytes per block\tGPUTextureSampleType\tBlock Size\tFeature\n'rgb9e5ufloat': {c: 4, s: \"float\",\tbpp: 4/(1*1)},\n\n'bc1-rgba-unorm': {c: 4. s: \"float\", bpp: 8/(4 * 4) f: 'texture-compression-bc'},\n'bc1-rgba-unorm-srgb': {c: 4. s: \"float\", bpp: 8/(4 * 4) f: 'texture-compression-bc'},\n'bc2-rgba-unorm': {c: 4. s: \"float\", bpp: 16/(4 * 4) f: 'texture-compression-bc'},\n'bc2-rgba-unorm-srgb': {c: 4. s: \"float\", bpp: 16/(4 * 4) f: 'texture-compression-bc'},\n'bc3-rgba-unorm': {c: 4. s: \"float\", bpp: 16/(4 * 4) f: 'texture-compression-bc'},\n'bc3-rgba-unorm-srgb': {c: 4. s: \"float\", bpp: 16/(4 * 4) f: 'texture-compression-bc'},\n'bc4-r-unorm': {c: 1. s: \"float\", bpp: 8/(4 * 4) f: 'texture-compression-bc'},\n'bc4-r-snorm': {c: 1. s: \"float\", bpp: 8/(4 * 4) f: 'texture-compression-bc'},\n'bc5-rg-unorm': {c: 2. s: \"float\", bpp: 16/(4 * 4) f: 'texture-compression-bc'},\n'bc5-rg-snorm': { },\n'bc6h-rgb-ufloat': {\t16 },\n'bc6h-rgb-float': { },\n'bc7-rgba-unorm': {\t16 },\n'bc7-rgba-unorm-srgb': { },\n\n'etc2-rgb8unorm': {\t8\t\"float\"\t4 \u00D7 4\ttexture-compression-etc2 },\n'etc2-rgb8unorm-srgb': { },\n'etc2-rgb8a1unorm': {\t8 },\n'etc2-rgb8a1unorm-srgb': { },\n'etc2-rgba8unorm': {\t16 },\n'etc2-rgba8unorm-srgb': { },\n\n'eac-r11unorm': {\t8 },\n'eac-r11snorm': { },\n'eac-rg11unorm': {\t16 },\n'eac-rg11snorm': { },\n\n'astc-4x4-unorm': {\t16\t\"float\"\t4 \u00D7 4\ttexture-compression-astc },\n'astc-4x4-unorm-srgb': { },\n'astc-5x4-unorm': {\t16\t5 \u00D7 4 },\n'astc-5x4-unorm-srgb': { },\n'astc-5x5-unorm': {\t16\t5 \u00D7 5 },\n'astc-5x5-unorm-srgb': { },\n'astc-6x5-unorm': {\t16\t6 \u00D7 5 },\n'astc-6x5-unorm-srgb': { },\n'astc-6x6-unorm': {\t16\t6 \u00D7 6 },\n'astc-6x6-unorm-srgb': { },\n'astc-8x5-unorm': {\t16\t8 \u00D7 5 },\n'astc-8x5-unorm-srgb': { },\n'astc-8x6-unorm': {\t16\t8 \u00D7 6 },\n'astc-8x6-unorm-srgb': { },\n'astc-8x8-unorm': {\t16\t8 \u00D7 8 },\n'astc-8x8-unorm-srgb': { },\n'astc-10x5-unorm': {\t16\t10 \u00D7 5 },\n'astc-10x5-unorm-srgb': { },\n'astc-10x6-unorm': {\t16\t10 \u00D7 6 },\n'astc-10x6-unorm-srgb': { },\n'astc-10x8-unorm': {\t16\t10 \u00D7 8 },\n'astc-10x8-unorm-srgb': { },\n'astc-10x10-unorm': {\t16\t10 \u00D7 10 },\n'astc-10x10-unorm-srgb': { },\n'astc-12x10-unorm': {\t16\t12 \u00D7 10 },\n'astc-12x10-unorm-srgb': { },\n'astc-12x12-unorm': {\t16 },\n*/\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { VERSION } from \"../init.js\";\nimport { lumaStats } from \"../utils/stats-manager.js\";\nimport { log } from \"../utils/log.js\";\nimport { uid } from \"../utils/utils.js\";\nimport { Buffer } from \"./resources/buffer.js\";\nimport { isTextureFormatCompressed } from \"./type-utils/decode-texture-format.js\";\n/** Limits for a device (max supported sizes of resources, max number of bindings etc) */\nexport class DeviceLimits {\n}\n/** Set-like class for features (lets apps check for WebGL / WebGPU extensions) */\nexport class DeviceFeatures {\n features;\n disabledFeatures;\n constructor(features = [], disabledFeatures) {\n this.features = new Set(features);\n this.disabledFeatures = disabledFeatures || {};\n }\n *[Symbol.iterator]() {\n yield* this.features;\n }\n has(feature) {\n return !this.disabledFeatures[feature] && this.features.has(feature);\n }\n}\n/**\n * WebGPU Device/WebGL context abstraction\n */\nexport class Device {\n static defaultProps = {\n id: null,\n canvas: null,\n container: null,\n manageState: true,\n width: 800, // width are height are only used by headless gl\n height: 600,\n requestMaxLimits: true,\n debug: Boolean(log.get('debug')), // Instrument context (at the expense of performance)\n spector: Boolean(log.get('spector') || log.get('spectorjs')), // Initialize the SpectorJS WebGL debugger\n break: [],\n // TODO - Change these after confirming things work as expected\n initalizeFeatures: true,\n disabledFeatures: {\n 'compilation-status-async-webgl': true\n },\n // alpha: undefined,\n // depth: undefined,\n // stencil: undefined,\n // antialias: undefined,\n // premultipliedAlpha: undefined,\n // preserveDrawingBuffer: undefined,\n // failIfMajorPerformanceCaveat: undefined\n gl: null,\n // Callbacks\n onError: (error) => log.error(error.message)\n };\n get [Symbol.toStringTag]() {\n return 'Device';\n }\n static VERSION = VERSION;\n constructor(props) {\n this.props = { ...Device.defaultProps, ...props };\n this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());\n }\n /** id of this device, primarily for debugging */\n id;\n /** A copy of the device props */\n props;\n /** Available for the application to store data on the device */\n userData = {};\n /** stats */\n statsManager = lumaStats;\n /** Used by other luma.gl modules to store data on the device */\n _lumaData = {};\n /** Check if a specific texture format is GPU compressed */\n isTextureFormatCompressed(format) {\n return isTextureFormatCompressed(format);\n }\n /**\n * Trigger device loss.\n * @returns `true` if context loss could actually be triggered.\n * @note primarily intended for testing how application reacts to device loss\n */\n loseDevice() {\n return false;\n }\n /** Returns the default / primary canvas context. Throws an error if no canvas context is available (a WebGPU compute device) */\n getCanvasContext() {\n if (!this.canvasContext) {\n throw new Error('Device has no CanvasContext');\n }\n return this.canvasContext;\n }\n createTexture(props) {\n // Signature: new Texture2D(gl, url | Promise)\n if (props instanceof Promise || typeof props === 'string') {\n props = { data: props };\n }\n return this._createTexture(props);\n }\n createCommandEncoder(props = {}) {\n throw new Error('not implemented');\n }\n // WebGL specific HACKS - enables app to remove webgl import\n // Use until we have a better way to handle these\n /** @deprecated - will be removed - should use command encoder */\n readPixelsToArrayWebGL(source, options) {\n throw new Error('not implemented');\n }\n /** @deprecated - will be removed - should use command encoder */\n readPixelsToBufferWebGL(source, options) {\n throw new Error('not implemented');\n }\n /** @deprecated - will be removed - should use WebGPU parameters (pipeline) */\n setParametersWebGL(parameters) {\n throw new Error('not implemented');\n }\n /** @deprecated - will be removed - should use WebGPU parameters (pipeline) */\n getParametersWebGL(parameters) {\n throw new Error('not implemented');\n }\n /** @deprecated - will be removed - should use WebGPU parameters (pipeline) */\n withParametersWebGL(parameters, func) {\n throw new Error('not implemented');\n }\n /** @deprecated - will be removed - should use clear arguments in RenderPass */\n clearWebGL(options) {\n throw new Error('not implemented');\n }\n /** @deprecated - will be removed - should use for debugging only */\n resetWebGL() {\n throw new Error('not implemented');\n }\n timestamp = 0;\n /** A monotonic counter for tracking buffer and texture updates */\n incrementTimestamp() {\n return this.timestamp++;\n }\n // Error Handling\n /** Report unhandled device errors */\n onError(error) {\n this.props.onError(error);\n }\n // IMPLEMENTATION\n _getBufferProps(props) {\n if (props instanceof ArrayBuffer || ArrayBuffer.isView(props)) {\n props = { data: props };\n }\n // TODO - fragile, as this is done before we merge with default options\n // inside the Buffer constructor\n const newProps = { ...props };\n // Deduce indexType\n if ((props.usage || 0) & Buffer.INDEX && !props.indexType) {\n if (props.data instanceof Uint32Array) {\n newProps.indexType = 'uint32';\n }\n else if (props.data instanceof Uint16Array) {\n newProps.indexType = 'uint16';\n }\n else {\n log.warn('indices buffer content must be of integer type')();\n }\n }\n return newProps;\n }\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n// Recommendation is to ignore message but current test suite checks agains the\n// message so keep it for now.\nexport function assert(condition, message) {\n if (!condition) {\n throw new Error(message || 'luma.gl: assertion failed.');\n }\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { Device } from \"../adapter/device.js\";\nimport { lumaStats } from \"../utils/stats-manager.js\";\nimport { log } from \"../utils/log.js\";\nimport { assert } from \"../utils/assert.js\";\nconst deviceMap = new Map();\n/**\n * Entry point to the luma.gl GPU abstraction\n * Register WebGPU and/or WebGL devices (controls application bundle size)\n * Run-time selection of the first available Device\n */\nexport class luma {\n static defaultProps = {\n ...Device.defaultProps,\n type: 'best-available',\n devices: undefined\n };\n /** Global stats for all devices */\n static stats = lumaStats;\n /** Global log */\n static log = log;\n static registerDevices(deviceClasses /* : typeof Device */) {\n for (const deviceClass of deviceClasses) {\n assert(deviceClass.type && deviceClass.isSupported && deviceClass.create);\n deviceMap.set(deviceClass.type, deviceClass);\n }\n }\n static getAvailableDevices() {\n // @ts-expect-error\n return Array.from(deviceMap).map(Device => Device.type);\n }\n static getSupportedDevices() {\n return (Array.from(deviceMap)\n // @ts-expect-error\n .filter(Device => Device.isSupported())\n // @ts-expect-error\n .map(Device => Device.type));\n }\n static setDefaultDeviceProps(props) {\n Object.assign(Device.defaultProps, props);\n }\n /** Attach to an existing GPU API handle (WebGL2RenderingContext or GPUDevice). */\n static async attachDevice(props) {\n const devices = getDeviceMap(props.devices) || deviceMap;\n // WebGL\n if (props.handle instanceof WebGL2RenderingContext) {\n const WebGLDevice = devices.get('webgl');\n if (WebGLDevice) {\n return (await WebGLDevice.attach(props.handle));\n }\n }\n // TODO - WebGPU does not yet have a stable API\n // if (props.handle instanceof GPUDevice) {\n // const WebGPUDevice = devices.get('webgpu') as any;\n // if (WebGPUDevice) {\n // return (await WebGPUDevice.attach(props.handle)) as Device;\n // }\n // }\n // null\n if (props.handle === null) {\n const UnknownDevice = devices.get('unknown');\n if (UnknownDevice) {\n return (await UnknownDevice.attach(null));\n }\n }\n throw new Error('Failed to attach device. Ensure `@luma.gl/webgl` and/or `@luma.gl/webgpu` modules are imported.');\n }\n /** Creates a device. Asynchronously. */\n static async createDevice(props = {}) {\n props = { ...luma.defaultProps, ...props };\n if (props.gl) {\n props.type = 'webgl';\n }\n const devices = getDeviceMap(props.devices) || deviceMap;\n let WebGPUDevice;\n let WebGLDevice;\n switch (props.type) {\n case 'webgpu':\n WebGPUDevice = devices.get('webgpu');\n if (WebGPUDevice) {\n return await WebGPUDevice.create(props);\n }\n break;\n case 'webgl':\n WebGLDevice = devices.get('webgl');\n if (WebGLDevice) {\n return await WebGLDevice.create(props);\n }\n break;\n case 'unknown':\n const UnknownDevice = devices.get('unknown');\n if (UnknownDevice) {\n return await UnknownDevice.create(props);\n }\n break;\n case 'best-available':\n WebGPUDevice = devices.get('webgpu');\n if (WebGPUDevice?.isSupported?.()) {\n return await WebGPUDevice.create(props);\n }\n WebGLDevice = devices.get('webgl');\n if (WebGLDevice?.isSupported?.()) {\n return await WebGLDevice.create(props);\n }\n break;\n }\n throw new Error('No matching device found. Ensure `@luma.gl/webgl` and/or `@luma.gl/webgpu` modules are imported.');\n }\n static enforceWebGL2(enforce = true) {\n const prototype = HTMLCanvasElement.prototype;\n if (!enforce && prototype.originalGetContext) {\n // Reset the original getContext function\n prototype.getContext = prototype.originalGetContext;\n prototype.originalGetContext = undefined;\n return;\n }\n // Store the original getContext function\n prototype.originalGetContext = prototype.getContext;\n // Override the getContext function\n prototype.getContext = function (contextId, options) {\n // Attempt to force WebGL2 for all WebGL1 contexts\n if (contextId === 'webgl' || contextId === 'experimental-webgl') {\n return this.originalGetContext('webgl2', options);\n }\n // For any other type, return the original context\n return this.originalGetContext(contextId, options);\n };\n }\n}\n/** Convert a list of devices to a map */\nfunction getDeviceMap(deviceClasses /* : typeof Device */) {\n if (!deviceClasses || deviceClasses?.length === 0) {\n return null;\n }\n const map = new Map();\n for (const deviceClass of deviceClasses) {\n // assert(deviceClass.type && deviceClass.isSupported && deviceClass.create);\n map.set(deviceClass.type, deviceClass);\n }\n return map;\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { isBrowser } from '@probe.gl/env';\nimport { log } from \"../utils/log.js\";\nconst isPage = isBrowser() && typeof document !== 'undefined';\nconst isPageLoaded = () => isPage && document.readyState === 'complete';\nconst DEFAULT_CANVAS_CONTEXT_PROPS = {\n canvas: null,\n width: 800, // width are height are only used by headless gl\n height: 600,\n useDevicePixels: true,\n autoResize: true,\n container: null,\n visible: true,\n colorSpace: 'srgb',\n alphaMode: 'opaque'\n};\n/**\n * Manages a canvas. Supports both HTML or offscreen canvas\n * - Creates a new canvas or looks up a canvas from the DOM\n * - Provides check for DOM loaded\n * @todo commit(): https://github.com/w3ctag/design-reviews/issues/288\n * @todo transferControlToOffscreen: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/transferControlToOffscreen\n */\nexport class CanvasContext {\n id;\n props;\n canvas;\n htmlCanvas;\n offscreenCanvas;\n type;\n width = 1;\n height = 1;\n resizeObserver;\n /** State used by luma.gl classes: TODO - move to canvasContext*/\n _canvasSizeInfo = { clientWidth: 0, clientHeight: 0, devicePixelRatio: 1 };\n /** Check if the DOM is loaded */\n static get isPageLoaded() {\n return isPageLoaded();\n }\n /**\n * Get a 'lazy' promise that resolves when the DOM is loaded.\n * @note Since there may be limitations on number of `load` event listeners,\n * it is recommended avoid calling this function until actually needed.\n * I.e. don't call it until you know that you will be looking up a string in the DOM.\n */\n static pageLoaded = getPageLoadPromise();\n constructor(props) {\n this.props = { ...DEFAULT_CANVAS_CONTEXT_PROPS, ...props };\n props = this.props;\n if (!isBrowser()) {\n this.id = 'node-canvas-context';\n this.type = 'node';\n this.width = this.props.width;\n this.height = this.props.height;\n // TODO - does this prevent app from using jsdom style polyfills?\n this.canvas = null;\n return;\n }\n if (!props.canvas) {\n const canvas = createCanvas(props);\n const container = getContainer(props?.container || null);\n container.insertBefore(canvas, container.firstChild);\n this.canvas = canvas;\n if (!props?.visible) {\n this.canvas.style.visibility = 'hidden';\n }\n }\n else if (typeof props.canvas === 'string') {\n this.canvas = getCanvasFromDOM(props.canvas);\n }\n else {\n this.canvas = props.canvas;\n }\n if (this.canvas instanceof HTMLCanvasElement) {\n this.id = this.canvas.id;\n this.type = 'html-canvas';\n this.htmlCanvas = this.canvas;\n }\n else {\n this.id = 'offscreen-canvas';\n this.type = 'offscreen-canvas';\n this.offscreenCanvas = this.canvas;\n }\n // React to size changes\n if (this.canvas instanceof HTMLCanvasElement && props.autoResize) {\n this.resizeObserver = new ResizeObserver(entries => {\n for (const entry of entries) {\n if (entry.target === this.canvas) {\n this.update();\n }\n }\n });\n this.resizeObserver.observe(this.canvas);\n }\n }\n /**\n * Returns the current DPR, if props.useDevicePixels is true\n * Device refers to physical\n */\n getDevicePixelRatio(useDevicePixels) {\n if (typeof OffscreenCanvas !== 'undefined' && this.canvas instanceof OffscreenCanvas) {\n return 1;\n }\n useDevicePixels = useDevicePixels === undefined ? this.props.useDevicePixels : useDevicePixels;\n if (!useDevicePixels || useDevicePixels <= 0) {\n return 1;\n }\n // The param was mainly provide to support the test cases, could be removed\n if (useDevicePixels === true) {\n const dpr = typeof window !== 'undefined' && window.devicePixelRatio;\n return dpr || 1;\n }\n return useDevicePixels;\n }\n /**\n * Returns the size of drawing buffer in device pixels.\n * @note This can be different from the 'CSS' size of a canvas, and also from the\n * canvas' internal drawing buffer size (.width, .height).\n * This is the size required to cover the canvas, adjusted for DPR\n */\n getPixelSize() {\n switch (this.type) {\n case 'node':\n return [this.width, this.height];\n case 'offscreen-canvas':\n return [this.canvas.width, this.canvas.height];\n case 'html-canvas':\n const dpr = this.getDevicePixelRatio();\n const canvas = this.canvas;\n // If not attached to DOM client size can be 0\n return canvas.parentElement\n ? [canvas.clientWidth * dpr, canvas.clientHeight * dpr]\n : [this.canvas.width, this.canvas.height];\n default:\n throw new Error(this.type);\n }\n }\n getAspect() {\n const [width, height] = this.getPixelSize();\n return width / height;\n }\n /**\n * Returns multiplier need to convert CSS size to Device size\n */\n cssToDeviceRatio() {\n try {\n // For headless gl we might have used custom width and height\n // hence use cached clientWidth\n const [drawingBufferWidth] = this.getDrawingBufferSize();\n const { clientWidth } = this._canvasSizeInfo;\n return clientWidth ? drawingBufferWidth / clientWidth : 1;\n }\n catch {\n return 1;\n }\n }\n /**\n * Maps CSS pixel position to device pixel position\n */\n cssToDevicePixels(cssPixel, yInvert = true) {\n const ratio = this.cssToDeviceRatio();\n const [width, height] = this.getDrawingBufferSize();\n return scalePixels(cssPixel, ratio, width, height, yInvert);\n }\n /**\n * Use devicePixelRatio to set canvas width and height\n * @note this is a raw port of luma.gl v8 code. Might be worth a review\n */\n setDevicePixelRatio(devicePixelRatio, options = {}) {\n if (!this.htmlCanvas) {\n return;\n }\n // NOTE: if options.width and options.height not used remove in v8\n let clientWidth = 'width' in options ? options.width : this.htmlCanvas.clientWidth;\n let clientHeight = 'height' in options ? options.height : this.htmlCanvas.clientHeight;\n if (!clientWidth || !clientHeight) {\n log.log(1, 'Canvas clientWidth/clientHeight is 0')();\n // by forcing devicePixel ratio to 1, we do not scale canvas.width and height in each frame.\n devicePixelRatio = 1;\n clientWidth = this.htmlCanvas.width || 1;\n clientHeight = this.htmlCanvas.height || 1;\n }\n const cachedSize = this._canvasSizeInfo;\n // Check if canvas needs to be resized\n if (cachedSize.clientWidth !== clientWidth ||\n cachedSize.clientHeight !== clientHeight ||\n cachedSize.devicePixelRatio !== devicePixelRatio) {\n let clampedPixelRatio = devicePixelRatio;\n const canvasWidth = Math.floor(clientWidth * clampedPixelRatio);\n const canvasHeight = Math.floor(clientHeight * clampedPixelRatio);\n this.htmlCanvas.width = canvasWidth;\n this.htmlCanvas.height = canvasHeight;\n // Note: when devicePixelRatio is too high, it is possible we might hit system limit for\n // drawing buffer width and hight, in those cases they get clamped and resulting aspect ration may not be maintained\n // for those cases, reduce devicePixelRatio.\n const [drawingBufferWidth, drawingBufferHeight] = this.getDrawingBufferSize();\n if (drawingBufferWidth !== canvasWidth || drawingBufferHeight !== canvasHeight) {\n clampedPixelRatio = Math.min(drawingBufferWidth / clientWidth, drawingBufferHeight / clientHeight);\n this.htmlCanvas.width = Math.floor(clientWidth * clampedPixelRatio);\n this.htmlCanvas.height = Math.floor(clientHeight * clampedPixelRatio);\n log.warn('Device pixel ratio clamped')();\n }\n this._canvasSizeInfo.clientWidth = clientWidth;\n this._canvasSizeInfo.clientHeight = clientHeight;\n this._canvasSizeInfo.devicePixelRatio = devicePixelRatio;\n }\n }\n // PRIVATE\n /** @todo Major hack done to port the CSS methods above, base canvas context should not depend on WebGL */\n getDrawingBufferSize() {\n // @ts-expect-error This only works for WebGL\n const gl = this.device.gl;\n if (!gl) {\n // use default device pixel ratio\n throw new Error('canvas size');\n }\n return [gl.drawingBufferWidth, gl.drawingBufferHeight];\n }\n /**\n * Allows subclass constructor to override the canvas id for auto created canvases.\n * This can really help when debugging DOM in apps that create multiple devices\n */\n _setAutoCreatedCanvasId(id) {\n if (this.htmlCanvas?.id === 'lumagl-auto-created-canvas') {\n this.htmlCanvas.id = id;\n }\n }\n}\n// HELPER FUNCTIONS\n/** Returns a promise that resolves when the page is loaded */\nfunction getPageLoadPromise() {\n if (isPageLoaded() || typeof window === 'undefined') {\n return Promise.resolve();\n }\n return new Promise(resolve => {\n window.addEventListener('load', () => resolve());\n });\n}\nfunction getContainer(container) {\n if (typeof container === 'string') {\n const element = document.getElementById(container);\n if (!element && !isPageLoaded()) {\n throw new Error(`Accessing '${container}' before page was loaded`);\n }\n if (!element) {\n throw new Error(`${container} is not an HTML element`);\n }\n return element;\n }\n else if (container) {\n return container;\n }\n return document.body;\n}\n/** Get a Canvas element from DOM id */\nfunction getCanvasFromDOM(canvasId) {\n const canvas = document.getElementById(canvasId);\n if (!canvas && !isPageLoaded()) {\n throw new Error(`Accessing '${canvasId}' before page was loaded`);\n }\n if (!(canvas instanceof HTMLCanvasElement)) {\n throw new Error('Object is not a canvas element');\n }\n return canvas;\n}\n/** Create a new canvas */\nfunction createCanvas(props) {\n const { width, height } = props;\n const targetCanvas = document.createElement('canvas');\n targetCanvas.id = 'lumagl-auto-created-canvas';\n targetCanvas.width = width || 1;\n targetCanvas.height = height || 1;\n targetCanvas.style.width = Number.isFinite(width) ? `${width}px` : '100%';\n targetCanvas.style.height = Number.isFinite(height) ? `${height}px` : '100%';\n return targetCanvas;\n}\n/**\n *\n * @param pixel\n * @param ratio\n * @param width\n * @param height\n * @param yInvert\n * @returns\n */\nfunction scalePixels(pixel, ratio, width, height, yInvert) {\n const point = pixel;\n const x = scaleX(point[0], ratio, width);\n let y = scaleY(point[1], ratio, height, yInvert);\n // Find boundaries of next pixel to provide valid range of device pixel locations\n let t = scaleX(point[0] + 1, ratio, width);\n // If next pixel's position is clamped to boundary, use it as is, otherwise subtract 1 for current pixel boundary\n const xHigh = t === width - 1 ? t : t - 1;\n t = scaleY(point[1] + 1, ratio, height, yInvert);\n let yHigh;\n if (yInvert) {\n // If next pixel's position is clamped to boundary, use it as is, otherwise clamp it to valid range\n t = t === 0 ? t : t + 1;\n // swap y and yHigh\n yHigh = y;\n y = t;\n }\n else {\n // If next pixel's position is clamped to boundary, use it as is, otherwise clamp it to valid range\n yHigh = t === height - 1 ? t : t - 1;\n // y remains same\n }\n return {\n x,\n y,\n // when ratio < 1, current css pixel and next css pixel may point to same device pixel, set width/height to 1 in those cases.\n width: Math.max(xHigh - x + 1, 1),\n height: Math.max(yHigh - y + 1, 1)\n };\n}\nfunction scaleX(x, ratio, width) {\n // since we are rounding to nearest, when ratio > 1, edge pixels may point to out of bounds value, clamp to the limit\n const r = Math.min(Math.round(x * ratio), width - 1);\n return r;\n}\nfunction scaleY(y, ratio, height, yInvert) {\n // since we are rounding to nearest, when ratio > 1, edge pixels may point to out of bounds value, clamp to the limit\n return yInvert\n ? Math.max(0, height - 1 - Math.round(y * ratio))\n : Math.min(Math.round(y * ratio), height - 1);\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { Resource } from \"./resource.js\";\n/**\n * Abstract Texture interface\n * Texture Object\n * https://gpuweb.github.io/gpuweb/#gputexture\n */\nexport class Texture extends Resource {\n static defaultProps = {\n ...Resource.defaultProps,\n data: null,\n dimension: '2d',\n format: 'rgba8unorm',\n width: undefined,\n height: undefined,\n depth: 1,\n mipmaps: true,\n // type: undefined,\n compressed: false,\n // mipLevels: 1,\n usage: 0,\n // usage: GPUTextureUsage.COPY_DST\n mipLevels: undefined,\n samples: undefined,\n type: undefined,\n sampler: {},\n view: undefined\n };\n static COPY_SRC = 0x01;\n static COPY_DST = 0x02;\n static TEXTURE_BINDING = 0x04;\n static STORAGE_BINDING = 0x08;\n static RENDER_ATTACHMENT = 0x10;\n get [Symbol.toStringTag]() {\n return 'Texture';\n }\n /** dimension of this texture */\n dimension;\n /** format of this texture */\n format;\n /** width in pixels of this texture */\n width;\n /** height in pixels of this texture */\n height;\n /** depth of this texture */\n depth;\n /** \"Time\" of last update. Monotonically increasing timestamp */\n updateTimestamp;\n /** Do not use directly. Create with device.createTexture() */\n constructor(device, props, defaultProps = Texture.defaultProps) {\n super(device, props, defaultProps);\n this.dimension = this.props.dimension;\n this.format = this.props.format;\n this.width = this.props.width;\n this.height = this.props.height;\n this.depth = this.props.depth;\n // TODO - perhaps this should be set on async write completion?\n this.updateTimestamp = device.incrementTimestamp();\n }\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { Resource } from \"./resource.js\";\n/** Immutable TextureView object */\nexport class TextureView extends Resource {\n static defaultProps = {\n ...Resource.defaultProps,\n format: undefined,\n dimension: undefined,\n aspect: 'all',\n baseMipLevel: 0,\n mipLevelCount: undefined,\n baseArrayLayer: 0,\n arrayLayerCount: undefined\n };\n get [Symbol.toStringTag]() {\n return 'TextureView';\n }\n /** Should not be constructed directly. Use `texture.createView(props)` */\n constructor(device, props) {\n super(device, props, TextureView.defaultProps);\n }\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\nimport { Resource } from \"./resource.js\";\nexport class ExternalTexture extends Resource {\n static defaultProps = {\n ...Resource.defaultProps,\n source: null,\n colorSpace: 'srgb'\n };\n get [Symbol.toStringTag]() {\n return 'ExternalTexture';\n }\n constructor(device, props) {\n super(device, props, ExternalTexture.defaultProps);\n }\n}\n", "// luma.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n/** @returns annotated errors or warnings */\nexport function formatCompilerLog(shaderLog, source, options) {\n let formattedLog = '';\n const lines = source.split(/\\r?\\n/);\n const log = shaderLog.slice().sort((a, b) => a.lineNum - b.lineNum);\n switch (options?.showSourceCode || 'no') {\n case 'all':\n // Parse the error - note: browser and driver dependent\n let currentMessage = 0;\n for (let lineNum = 1; lineNum <= lines.length; lineNum++) {\n formattedLog += getNumberedLine(lines[lineNum - 1], lineNum, options);\n while (log.length > currentMessage && log[currentMessage].lineNum === lineNum) {\n const message = log[currentMessage++];\n formattedLog += formatCompilerMessage(message, lines, message.lineNum, {\n ...options,\n inlineSource: false\n });\n }\n }\n return formattedLog;\n case 'issues':\n case 'no':\n // Parse the error - note: browser and driver dependent\n for (const message of shaderLog) {\n formattedLog += formatCompilerMessage(message, lines, message.lineNum, {\n inlineSource: options?.showSourceCode !== 'no'\n });\n }\n return formattedLog;\n }\n}\n// Helpers\n/** Format one message */\nfunction formatCompilerMessage(message, lines, lineNum, options) {\n if (options?.inlineSource) {\n const numberedLines = getNumberedLines(lines, lineNum);\n // If we got error position on line add a `^^^` indicator on next line\n const positionIndicator = message.linePos > 0 ? `${' '.repeat(message.linePos + 5)}^^^\\n` : '';\n return `\n${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.message}\n\n`;\n }\n return options?.html\n ? `
${translatedSource}
`;\n }\n // Make it clickable so we can copy to clipboard\n const button = document.createElement('Button');\n button.innerHTML = `\n\n${htmlLog}\n
`;\n button.style.top = '10px';\n button.style.left = '10px';\n button.style.position = 'absolute';\n button.style.zIndex = '9999';\n button.style.width = '100%';\n button.style.textAlign = 'left';\n document.body.appendChild(button);\n const errors = document.getElementsByClassName('luma-compiler-log-error');\n if (errors[0]?.scrollIntoView) {\n errors[0].scrollIntoView();\n }\n // TODO - add a small embedded copy button (instead of main button)\n button.onclick = () => {\n // const source = this.source.replaceAll('\\n', '