"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name2 in all) __defProp(target, name2, { get: all[name2], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; // dist/index.js var dist_exports = {}; __export(dist_exports, { Buffer: () => Buffer2, CanvasContext: () => CanvasContext, CommandBuffer: () => CommandBuffer, CommandEncoder: () => CommandEncoder, ComputePass: () => ComputePass, ComputePipeline: () => ComputePipeline, Device: () => Device, DeviceFeatures: () => DeviceFeatures, DeviceLimits: () => DeviceLimits, ExternalTexture: () => ExternalTexture, Framebuffer: () => Framebuffer, QuerySet: () => QuerySet, RenderPass: () => RenderPass, RenderPipeline: () => RenderPipeline, Resource: () => Resource, Sampler: () => Sampler, Shader: () => Shader, StatsManager: () => StatsManager, Texture: () => Texture, TextureView: () => TextureView, TransformFeedback: () => TransformFeedback, UniformBlock: () => UniformBlock, UniformBufferLayout: () => UniformBufferLayout, UniformStore: () => UniformStore, VERSION: () => VERSION, VertexArray: () => VertexArray, assert: () => assert, cancelAnimationFrame: () => cancelAnimationFrame, cast: () => cast, checkProps: () => checkProps, decodeShaderAttributeType: () => decodeShaderAttributeType, decodeShaderUniformType: () => decodeShaderUniformType, decodeTextureFormat: () => decodeTextureFormat, decodeVertexFormat: () => decodeVertexFormat, deepEqual: () => deepEqual, fillArray: () => fillArray, formatCompilerLog: () => formatCompilerLog, formatValue: () => formatValue, getAttributeInfosFromLayouts: () => getAttributeInfosFromLayouts, getDataTypeFromTypedArray: () => getDataTypeFromTypedArray, getScratchArray: () => getScratchArray, getScratchArrayBuffer: () => getScratchArrayBuffer, getTypedArrayFromDataType: () => getTypedArrayFromDataType, getVertexFormatFromAttribute: () => getVertexFormatFromAttribute, glsl: () => glsl, isNumberArray: () => isNumberArray, isObjectEmpty: () => isObjectEmpty, isTypedArray: () => isTypedArray, isUniformValue: () => isUniformValue, loadFile: () => loadFile, loadImage: () => loadImage, loadImageBitmap: () => loadImageBitmap, loadScript: () => loadScript, log: () => log, luma: () => luma, makeRandomNumberGenerator: () => makeRandomNumberGenerator, mergeShaderLayout: () => mergeShaderLayout, random: () => random, requestAnimationFrame: () => requestAnimationFrame, setPathPrefix: () => setPathPrefix, splitUniformsAndBindings: () => splitUniformsAndBindings, stubRemovedMethods: () => stubRemovedMethods, uid: () => uid }); module.exports = __toCommonJS(dist_exports); // dist/init.js var import_env = require("@probe.gl/env"); // dist/utils/log.js var import_log = require("@probe.gl/log"); var log = new import_log.Log({ id: "luma.gl" }); // dist/utils/stats-manager.js var import_stats = require("@probe.gl/stats"); var StatsManager = class { stats = /* @__PURE__ */ new Map(); getStats(name2) { return this.get(name2); } get(name2) { if (!this.stats.has(name2)) { this.stats.set(name2, new import_stats.Stats({ id: name2 })); } return this.stats.get(name2); } }; var lumaStats = new StatsManager(); // dist/init.js function initializeLuma() { const VERSION2 = true ? "9.0.27" : "running from source"; const STARTUP_MESSAGE = "set luma.log.level=1 (or higher) to trace rendering"; if (globalThis.luma && globalThis.luma.VERSION !== VERSION2) { throw new Error(`luma.gl - multiple VERSIONs detected: ${globalThis.luma.VERSION} vs ${VERSION2}`); } if (!globalThis.luma) { if ((0, import_env.isBrowser)()) { log.log(1, `${VERSION2} - ${STARTUP_MESSAGE}`)(); } globalThis.luma = globalThis.luma || { VERSION: VERSION2, version: VERSION2, log, // A global stats object that various components can add information to // E.g. see webgl/resource.js stats: lumaStats }; } return VERSION2; } var VERSION = initializeLuma(); // dist/utils/is-array.js function isTypedArray(value) { return ArrayBuffer.isView(value) && !(value instanceof DataView) ? value : null; } function isNumberArray(value) { if (Array.isArray(value)) { return value.length === 0 || typeof value[0] === "number" ? value : null; } return isTypedArray(value); } // dist/utils/utils.js var uidCounters = {}; function uid(id = "id") { uidCounters[id] = uidCounters[id] || 1; const count = uidCounters[id]++; return `${id}-${count}`; } function isObjectEmpty(obj) { let isEmpty = true; for (const key in obj) { isEmpty = false; break; } return isEmpty; } // dist/adapter/resources/resource.js var Resource = class { /** props.id, for debugging. */ id; props; userData = {}; _device; /** Whether this resource has been destroyed */ destroyed = false; /** For resources that allocate GPU memory */ allocatedBytes = 0; /** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created "sub" resources. */ _attachedResources = /* @__PURE__ */ new Set(); /** * Create a new Resource. Called from Subclass */ constructor(device, props, defaultProps) { if (!device) { throw new Error("no device"); } this._device = device; this.props = selectivelyMerge(props, defaultProps); const id = this.props.id !== "undefined" ? this.props.id : uid(this[Symbol.toStringTag]); this.props.id = id; this.id = id; this.userData = this.props.userData || {}; this.addStats(); } /** * destroy can be called on any resource to release it before it is garbage collected. */ destroy() { this.destroyResource(); } /** @deprecated Use destroy() */ delete() { this.destroy(); return this; } toString() { return `${this[Symbol.toStringTag] || this.constructor.name}(${this.id})`; } /** * Combines a map of user props and default props, only including props from defaultProps * @returns returns a map of overridden default props */ getProps() { return this.props; } // ATTACHED RESOURCES /** * Attaches a resource. Attached resources are auto destroyed when this resource is destroyed * Called automatically when sub resources are auto created but can be called by application */ attachResource(resource) { this._attachedResources.add(resource); } /** * Detach an attached resource. The resource will no longer be auto-destroyed when this resource is destroyed. */ detachResource(resource) { this._attachedResources.delete(resource); } /** * Destroys a resource (only if owned), and removes from the owned (auto-destroy) list for this resource. */ destroyAttachedResource(resource) { if (this._attachedResources.delete(resource)) { resource.destroy(); } } /** Destroy all owned resources. Make sure the resources are no longer needed before calling. */ destroyAttachedResources() { for (const resource of Object.values(this._attachedResources)) { resource.destroy(); } this._attachedResources = /* @__PURE__ */ new Set(); } // PROTECTED METHODS /** Perform all destroy steps. Can be called by derived resources when overriding destroy() */ destroyResource() { this.destroyAttachedResources(); this.removeStats(); this.destroyed = true; } /** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */ removeStats() { const stats = this._device.statsManager.getStats("Resource Counts"); const name2 = this[Symbol.toStringTag]; stats.get(`${name2}s Active`).decrementCount(); } /** Called by subclass to track memory allocations */ trackAllocatedMemory(bytes, name2 = this[Symbol.toStringTag]) { const stats = this._device.statsManager.getStats("Resource Counts"); stats.get("GPU Memory").addCount(bytes); stats.get(`${name2} Memory`).addCount(bytes); this.allocatedBytes = bytes; } /** Called by subclass to track memory deallocations */ trackDeallocatedMemory(name2 = this[Symbol.toStringTag]) { const stats = this._device.statsManager.getStats("Resource Counts"); stats.get("GPU Memory").subtractCount(this.allocatedBytes); stats.get(`${name2} Memory`).subtractCount(this.allocatedBytes); this.allocatedBytes = 0; } /** Called by resource constructor to track object creation */ addStats() { const stats = this._device.statsManager.getStats("Resource Counts"); const name2 = this[Symbol.toStringTag]; stats.get("Resources Created").incrementCount(); stats.get(`${name2}s Created`).incrementCount(); stats.get(`${name2}s Active`).incrementCount(); } }; /** Default properties for resource */ __publicField(Resource, "defaultProps", { id: "undefined", handle: void 0, userData: void 0 }); function selectivelyMerge(props, defaultProps) { const mergedProps = { ...defaultProps }; for (const key in props) { if (props[key] !== void 0) { mergedProps[key] = props[key]; } } return mergedProps; } // dist/adapter/resources/buffer.js var _Buffer = class extends Resource { get [Symbol.toStringTag]() { return "Buffer"; } /** The usage with which this buffer was created */ usage; /** For index buffers, whether indices are 16 or 32 bit */ indexType; /** "Time" of last update */ updateTimestamp; constructor(device, props) { const deducedProps = { ...props }; if ((props.usage || 0) & _Buffer.INDEX && !props.indexType) { if (props.data instanceof Uint32Array) { deducedProps.indexType = "uint32"; } else if (props.data instanceof Uint16Array) { deducedProps.indexType = "uint16"; } } super(device, deducedProps, _Buffer.defaultProps); this.usage = props.usage || 0; this.indexType = deducedProps.indexType; this.updateTimestamp = device.incrementTimestamp(); } /** Read data synchronously. @note WebGL2 only */ readSyncWebGL(byteOffset, byteLength) { throw new Error("not implemented"); } /** A partial CPU-side copy of the data in this buffer, for debugging purposes */ debugData = new ArrayBuffer(0); /** This doesn't handle partial non-zero offset updates correctly */ _setDebugData(data, byteOffset, byteLength) { const buffer = ArrayBuffer.isView(data) ? data.buffer : data; const debugDataLength = Math.min(data ? data.byteLength : byteLength, _Buffer.DEBUG_DATA_MAX_LENGTH); if (data === null) { this.debugData = new ArrayBuffer(debugDataLength); } else if (byteOffset === 0 && byteLength === data.byteLength) { this.debugData = buffer.slice(0, debugDataLength); } else { this.debugData = buffer.slice(byteOffset, byteOffset + debugDataLength); } } }; var Buffer2 = _Buffer; __publicField(Buffer2, "defaultProps", { ...Resource.defaultProps, usage: 0, // Buffer.COPY_DST | Buffer.COPY_SRC byteLength: 0, byteOffset: 0, data: null, indexType: "uint16", mappedAtCreation: false }); // Usage Flags __publicField(Buffer2, "MAP_READ", 1); __publicField(Buffer2, "MAP_WRITE", 2); __publicField(Buffer2, "COPY_SRC", 4); __publicField(Buffer2, "COPY_DST", 8); /** Index buffer */ __publicField(Buffer2, "INDEX", 16); /** Vertex buffer */ __publicField(Buffer2, "VERTEX", 32); /** Uniform buffer */ __publicField(Buffer2, "UNIFORM", 64); /** Storage buffer */ __publicField(Buffer2, "STORAGE", 128); __publicField(Buffer2, "INDIRECT", 256); __publicField(Buffer2, "QUERY_RESOLVE", 512); // PROTECTED METHODS (INTENDED FOR USE BY OTHER FRAMEWORK CODE ONLY) /** Max amount of debug data saved. Two vec4's */ __publicField(Buffer2, "DEBUG_DATA_MAX_LENGTH", 32); // dist/adapter/type-utils/decode-data-type.js function decodeVertexType(type) { const dataType = TYPE_MAP[type]; const bytes = getDataTypeBytes(dataType); const normalized = type.includes("norm"); const integer = !normalized && !type.startsWith("float"); const signed = type.startsWith("s"); return { dataType: TYPE_MAP[type], byteLength: bytes, integer, signed, normalized }; } function getDataTypeBytes(type) { const bytes = TYPE_SIZES[type]; return bytes; } var TYPE_MAP = { uint8: "uint8", sint8: "sint8", unorm8: "uint8", snorm8: "sint8", uint16: "uint16", sint16: "sint16", unorm16: "uint16", snorm16: "sint16", float16: "float16", float32: "float32", uint32: "uint32", sint32: "sint32" }; var TYPE_SIZES = { uint8: 1, sint8: 1, uint16: 2, sint16: 2, float16: 2, float32: 4, uint32: 4, sint32: 4 }; // dist/adapter/type-utils/decode-texture-format.js var COMPRESSED_TEXTURE_FORMAT_PREFIXES = [ "bc1", "bc2", "bc3", "bc4", "bc5", "bc6", "bc7", "etc1", "etc2", "eac", "atc", "astc", "pvrtc" ]; var REGEX = /^(rg?b?a?)([0-9]*)([a-z]*)(-srgb)?(-webgl|-unsized)?$/; function isTextureFormatCompressed(textureFormat) { return COMPRESSED_TEXTURE_FORMAT_PREFIXES.some((prefix) => textureFormat.startsWith(prefix)); } function decodeTextureFormat(format) { const matches = REGEX.exec(format); if (matches) { const [, format2, length, type, srgb, suffix] = matches; if (format2) { const dataType = `${type}${length}`; const decodedType = decodeVertexType(dataType); return { format: format2, components: format2.length, // dataType - overwritten by decodedType srgb: srgb === "-srgb", unsized: suffix === "-unsized", webgl: suffix === "-webgl", ...decodedType }; } } return decodeNonStandardFormat(format); } var EXCEPTIONS = { // Packed 16 bit formats "rgba4unorm-webgl": { format: "rgba", bpp: 2 }, "rgb565unorm-webgl": { format: "rgb", bpp: 2 }, "rgb5a1unorm-webgl": { format: "rgba", bbp: 2 }, // Packed 32 bit formats rgb9e5ufloat: { format: "rgb", bbp: 4 }, rg11b10ufloat: { format: "rgb", bbp: 4 }, rgb10a2unorm: { format: "rgba", bbp: 4 }, "rgb10a2uint-webgl": { format: "rgba", bbp: 4 }, // Depth/stencil stencil8: { components: 1, bpp: 1, a: "stencil" }, depth16unorm: { components: 1, bpp: 2, a: "depth" }, depth24plus: { components: 1, bpp: 3, a: "depth" }, depth32float: { components: 1, bpp: 4, a: "depth" }, "depth24plus-stencil8": { components: 2, bpp: 4, a: "depth-stencil" }, // "depth24unorm-stencil8" feature "depth24unorm-stencil8": { components: 2, bpp: 4, a: "depth-stencil" }, // "depth32float-stencil8" feature "depth32float-stencil8": { components: 2, bpp: 4, a: "depth-stencil" } }; function decodeNonStandardFormat(format) { var _a; const data = EXCEPTIONS[format]; if (!data) { throw new Error(`Unknown format ${format}`); } return { format: data.format || "", components: data.components || ((_a = data.format) == null ? void 0 : _a.length) || 1, byteLength: data.bpp || 1, srgb: false, unsized: false }; } // dist/adapter/device.js var DeviceLimits = class { }; var DeviceFeatures = class { features; disabledFeatures; constructor(features = [], disabledFeatures) { this.features = new Set(features); this.disabledFeatures = disabledFeatures || {}; } *[Symbol.iterator]() { yield* this.features; } has(feature) { return !this.disabledFeatures[feature] && this.features.has(feature); } }; var _Device = class { get [Symbol.toStringTag]() { return "Device"; } constructor(props) { this.props = { ..._Device.defaultProps, ...props }; this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase()); } /** id of this device, primarily for debugging */ id; /** A copy of the device props */ props; /** Available for the application to store data on the device */ userData = {}; /** stats */ statsManager = lumaStats; /** Used by other luma.gl modules to store data on the device */ _lumaData = {}; /** Check if a specific texture format is GPU compressed */ isTextureFormatCompressed(format) { return isTextureFormatCompressed(format); } /** * Trigger device loss. * @returns `true` if context loss could actually be triggered. * @note primarily intended for testing how application reacts to device loss */ loseDevice() { return false; } /** Returns the default / primary canvas context. Throws an error if no canvas context is available (a WebGPU compute device) */ getCanvasContext() { if (!this.canvasContext) { throw new Error("Device has no CanvasContext"); } return this.canvasContext; } createTexture(props) { if (props instanceof Promise || typeof props === "string") { props = { data: props }; } return this._createTexture(props); } createCommandEncoder(props = {}) { throw new Error("not implemented"); } // WebGL specific HACKS - enables app to remove webgl import // Use until we have a better way to handle these /** @deprecated - will be removed - should use command encoder */ readPixelsToArrayWebGL(source, options) { throw new Error("not implemented"); } /** @deprecated - will be removed - should use command encoder */ readPixelsToBufferWebGL(source, options) { throw new Error("not implemented"); } /** @deprecated - will be removed - should use WebGPU parameters (pipeline) */ setParametersWebGL(parameters) { throw new Error("not implemented"); } /** @deprecated - will be removed - should use WebGPU parameters (pipeline) */ getParametersWebGL(parameters) { throw new Error("not implemented"); } /** @deprecated - will be removed - should use WebGPU parameters (pipeline) */ withParametersWebGL(parameters, func) { throw new Error("not implemented"); } /** @deprecated - will be removed - should use clear arguments in RenderPass */ clearWebGL(options) { throw new Error("not implemented"); } /** @deprecated - will be removed - should use for debugging only */ resetWebGL() { throw new Error("not implemented"); } timestamp = 0; /** A monotonic counter for tracking buffer and texture updates */ incrementTimestamp() { return this.timestamp++; } // Error Handling /** Report unhandled device errors */ onError(error) { this.props.onError(error); } // IMPLEMENTATION _getBufferProps(props) { if (props instanceof ArrayBuffer || ArrayBuffer.isView(props)) { props = { data: props }; } const newProps = { ...props }; if ((props.usage || 0) & Buffer2.INDEX && !props.indexType) { if (props.data instanceof Uint32Array) { newProps.indexType = "uint32"; } else if (props.data instanceof Uint16Array) { newProps.indexType = "uint16"; } else { log.warn("indices buffer content must be of integer type")(); } } return newProps; } }; var Device = _Device; __publicField(Device, "defaultProps", { id: null, canvas: null, container: null, manageState: true, width: 800, // width are height are only used by headless gl height: 600, requestMaxLimits: true, debug: Boolean(log.get("debug")), // Instrument context (at the expense of performance) spector: Boolean(log.get("spector") || log.get("spectorjs")), // Initialize the SpectorJS WebGL debugger break: [], // TODO - Change these after confirming things work as expected initalizeFeatures: true, disabledFeatures: { "compilation-status-async-webgl": true }, // alpha: undefined, // depth: undefined, // stencil: undefined, // antialias: undefined, // premultipliedAlpha: undefined, // preserveDrawingBuffer: undefined, // failIfMajorPerformanceCaveat: undefined gl: null, // Callbacks onError: (error) => log.error(error.message) }); __publicField(Device, "VERSION", VERSION); // dist/utils/assert.js function assert(condition, message) { if (!condition) { throw new Error(message || "luma.gl: assertion failed."); } } // dist/lib/luma.js var deviceMap = /* @__PURE__ */ new Map(); var _luma = class { static registerDevices(deviceClasses) { for (const deviceClass of deviceClasses) { assert(deviceClass.type && deviceClass.isSupported && deviceClass.create); deviceMap.set(deviceClass.type, deviceClass); } } static getAvailableDevices() { return Array.from(deviceMap).map((Device2) => Device2.type); } static getSupportedDevices() { return Array.from(deviceMap).filter((Device2) => Device2.isSupported()).map((Device2) => Device2.type); } static setDefaultDeviceProps(props) { Object.assign(Device.defaultProps, props); } /** Attach to an existing GPU API handle (WebGL2RenderingContext or GPUDevice). */ static async attachDevice(props) { const devices = getDeviceMap(props.devices) || deviceMap; if (props.handle instanceof WebGL2RenderingContext) { const WebGLDevice = devices.get("webgl"); if (WebGLDevice) { return await WebGLDevice.attach(props.handle); } } if (props.handle === null) { const UnknownDevice = devices.get("unknown"); if (UnknownDevice) { return await UnknownDevice.attach(null); } } throw new Error("Failed to attach device. Ensure `@luma.gl/webgl` and/or `@luma.gl/webgpu` modules are imported."); } /** Creates a device. Asynchronously. */ static async createDevice(props = {}) { var _a, _b; props = { ..._luma.defaultProps, ...props }; if (props.gl) { props.type = "webgl"; } const devices = getDeviceMap(props.devices) || deviceMap; let WebGPUDevice; let WebGLDevice; switch (props.type) { case "webgpu": WebGPUDevice = devices.get("webgpu"); if (WebGPUDevice) { return await WebGPUDevice.create(props); } break; case "webgl": WebGLDevice = devices.get("webgl"); if (WebGLDevice) { return await WebGLDevice.create(props); } break; case "unknown": const UnknownDevice = devices.get("unknown"); if (UnknownDevice) { return await UnknownDevice.create(props); } break; case "best-available": WebGPUDevice = devices.get("webgpu"); if ((_a = WebGPUDevice == null ? void 0 : WebGPUDevice.isSupported) == null ? void 0 : _a.call(WebGPUDevice)) { return await WebGPUDevice.create(props); } WebGLDevice = devices.get("webgl"); if ((_b = WebGLDevice == null ? void 0 : WebGLDevice.isSupported) == null ? void 0 : _b.call(WebGLDevice)) { return await WebGLDevice.create(props); } break; } throw new Error("No matching device found. Ensure `@luma.gl/webgl` and/or `@luma.gl/webgpu` modules are imported."); } static enforceWebGL2(enforce = true) { const prototype = HTMLCanvasElement.prototype; if (!enforce && prototype.originalGetContext) { prototype.getContext = prototype.originalGetContext; prototype.originalGetContext = void 0; return; } prototype.originalGetContext = prototype.getContext; prototype.getContext = function(contextId, options) { if (contextId === "webgl" || contextId === "experimental-webgl") { return this.originalGetContext("webgl2", options); } return this.originalGetContext(contextId, options); }; } }; var luma = _luma; __publicField(luma, "defaultProps", { ...Device.defaultProps, type: "best-available", devices: void 0 }); /** Global stats for all devices */ __publicField(luma, "stats", lumaStats); /** Global log */ __publicField(luma, "log", log); function getDeviceMap(deviceClasses) { if (!deviceClasses || (deviceClasses == null ? void 0 : deviceClasses.length) === 0) { return null; } const map = /* @__PURE__ */ new Map(); for (const deviceClass of deviceClasses) { map.set(deviceClass.type, deviceClass); } return map; } // dist/adapter/canvas-context.js var import_env2 = require("@probe.gl/env"); var isPage = (0, import_env2.isBrowser)() && typeof document !== "undefined"; var isPageLoaded = () => isPage && document.readyState === "complete"; var DEFAULT_CANVAS_CONTEXT_PROPS = { canvas: null, width: 800, // width are height are only used by headless gl height: 600, useDevicePixels: true, autoResize: true, container: null, visible: true, colorSpace: "srgb", alphaMode: "opaque" }; var CanvasContext = class { id; props; canvas; htmlCanvas; offscreenCanvas; type; width = 1; height = 1; resizeObserver; /** State used by luma.gl classes: TODO - move to canvasContext*/ _canvasSizeInfo = { clientWidth: 0, clientHeight: 0, devicePixelRatio: 1 }; /** Check if the DOM is loaded */ static get isPageLoaded() { return isPageLoaded(); } constructor(props) { this.props = { ...DEFAULT_CANVAS_CONTEXT_PROPS, ...props }; props = this.props; if (!(0, import_env2.isBrowser)()) { this.id = "node-canvas-context"; this.type = "node"; this.width = this.props.width; this.height = this.props.height; this.canvas = null; return; } if (!props.canvas) { const canvas = createCanvas(props); const container = getContainer((props == null ? void 0 : props.container) || null); container.insertBefore(canvas, container.firstChild); this.canvas = canvas; if (!(props == null ? void 0 : props.visible)) { this.canvas.style.visibility = "hidden"; } } else if (typeof props.canvas === "string") { this.canvas = getCanvasFromDOM(props.canvas); } else { this.canvas = props.canvas; } if (this.canvas instanceof HTMLCanvasElement) { this.id = this.canvas.id; this.type = "html-canvas"; this.htmlCanvas = this.canvas; } else { this.id = "offscreen-canvas"; this.type = "offscreen-canvas"; this.offscreenCanvas = this.canvas; } if (this.canvas instanceof HTMLCanvasElement && props.autoResize) { this.resizeObserver = new ResizeObserver((entries) => { for (const entry of entries) { if (entry.target === this.canvas) { this.update(); } } }); this.resizeObserver.observe(this.canvas); } } /** * Returns the current DPR, if props.useDevicePixels is true * Device refers to physical */ getDevicePixelRatio(useDevicePixels) { if (typeof OffscreenCanvas !== "undefined" && this.canvas instanceof OffscreenCanvas) { return 1; } useDevicePixels = useDevicePixels === void 0 ? this.props.useDevicePixels : useDevicePixels; if (!useDevicePixels || useDevicePixels <= 0) { return 1; } if (useDevicePixels === true) { const dpr = typeof window !== "undefined" && window.devicePixelRatio; return dpr || 1; } return useDevicePixels; } /** * Returns the size of drawing buffer in device pixels. * @note This can be different from the 'CSS' size of a canvas, and also from the * canvas' internal drawing buffer size (.width, .height). * This is the size required to cover the canvas, adjusted for DPR */ getPixelSize() { switch (this.type) { case "node": return [this.width, this.height]; case "offscreen-canvas": return [this.canvas.width, this.canvas.height]; case "html-canvas": const dpr = this.getDevicePixelRatio(); const canvas = this.canvas; return canvas.parentElement ? [canvas.clientWidth * dpr, canvas.clientHeight * dpr] : [this.canvas.width, this.canvas.height]; default: throw new Error(this.type); } } getAspect() { const [width, height] = this.getPixelSize(); return width / height; } /** * Returns multiplier need to convert CSS size to Device size */ cssToDeviceRatio() { try { const [drawingBufferWidth] = this.getDrawingBufferSize(); const { clientWidth } = this._canvasSizeInfo; return clientWidth ? drawingBufferWidth / clientWidth : 1; } catch { return 1; } } /** * Maps CSS pixel position to device pixel position */ cssToDevicePixels(cssPixel, yInvert = true) { const ratio = this.cssToDeviceRatio(); const [width, height] = this.getDrawingBufferSize(); return scalePixels(cssPixel, ratio, width, height, yInvert); } /** * Use devicePixelRatio to set canvas width and height * @note this is a raw port of luma.gl v8 code. Might be worth a review */ setDevicePixelRatio(devicePixelRatio, options = {}) { if (!this.htmlCanvas) { return; } let clientWidth = "width" in options ? options.width : this.htmlCanvas.clientWidth; let clientHeight = "height" in options ? options.height : this.htmlCanvas.clientHeight; if (!clientWidth || !clientHeight) { log.log(1, "Canvas clientWidth/clientHeight is 0")(); devicePixelRatio = 1; clientWidth = this.htmlCanvas.width || 1; clientHeight = this.htmlCanvas.height || 1; } const cachedSize = this._canvasSizeInfo; if (cachedSize.clientWidth !== clientWidth || cachedSize.clientHeight !== clientHeight || cachedSize.devicePixelRatio !== devicePixelRatio) { let clampedPixelRatio = devicePixelRatio; const canvasWidth = Math.floor(clientWidth * clampedPixelRatio); const canvasHeight = Math.floor(clientHeight * clampedPixelRatio); this.htmlCanvas.width = canvasWidth; this.htmlCanvas.height = canvasHeight; const [drawingBufferWidth, drawingBufferHeight] = this.getDrawingBufferSize(); if (drawingBufferWidth !== canvasWidth || drawingBufferHeight !== canvasHeight) { clampedPixelRatio = Math.min(drawingBufferWidth / clientWidth, drawingBufferHeight / clientHeight); this.htmlCanvas.width = Math.floor(clientWidth * clampedPixelRatio); this.htmlCanvas.height = Math.floor(clientHeight * clampedPixelRatio); log.warn("Device pixel ratio clamped")(); } this._canvasSizeInfo.clientWidth = clientWidth; this._canvasSizeInfo.clientHeight = clientHeight; this._canvasSizeInfo.devicePixelRatio = devicePixelRatio; } } // PRIVATE /** @todo Major hack done to port the CSS methods above, base canvas context should not depend on WebGL */ getDrawingBufferSize() { const gl = this.device.gl; if (!gl) { throw new Error("canvas size"); } return [gl.drawingBufferWidth, gl.drawingBufferHeight]; } /** * Allows subclass constructor to override the canvas id for auto created canvases. * This can really help when debugging DOM in apps that create multiple devices */ _setAutoCreatedCanvasId(id) { var _a; if (((_a = this.htmlCanvas) == null ? void 0 : _a.id) === "lumagl-auto-created-canvas") { this.htmlCanvas.id = id; } } }; /** * Get a 'lazy' promise that resolves when the DOM is loaded. * @note Since there may be limitations on number of `load` event listeners, * it is recommended avoid calling this function until actually needed. * I.e. don't call it until you know that you will be looking up a string in the DOM. */ __publicField(CanvasContext, "pageLoaded", getPageLoadPromise()); function getPageLoadPromise() { if (isPageLoaded() || typeof window === "undefined") { return Promise.resolve(); } return new Promise((resolve) => { window.addEventListener("load", () => resolve()); }); } function getContainer(container) { if (typeof container === "string") { const element = document.getElementById(container); if (!element && !isPageLoaded()) { throw new Error(`Accessing '${container}' before page was loaded`); } if (!element) { throw new Error(`${container} is not an HTML element`); } return element; } else if (container) { return container; } return document.body; } function getCanvasFromDOM(canvasId) { const canvas = document.getElementById(canvasId); if (!canvas && !isPageLoaded()) { throw new Error(`Accessing '${canvasId}' before page was loaded`); } if (!(canvas instanceof HTMLCanvasElement)) { throw new Error("Object is not a canvas element"); } return canvas; } function createCanvas(props) { const { width, height } = props; const targetCanvas = document.createElement("canvas"); targetCanvas.id = "lumagl-auto-created-canvas"; targetCanvas.width = width || 1; targetCanvas.height = height || 1; targetCanvas.style.width = Number.isFinite(width) ? `${width}px` : "100%"; targetCanvas.style.height = Number.isFinite(height) ? `${height}px` : "100%"; return targetCanvas; } function scalePixels(pixel, ratio, width, height, yInvert) { const point = pixel; const x = scaleX(point[0], ratio, width); let y = scaleY(point[1], ratio, height, yInvert); let t = scaleX(point[0] + 1, ratio, width); const xHigh = t === width - 1 ? t : t - 1; t = scaleY(point[1] + 1, ratio, height, yInvert); let yHigh; if (yInvert) { t = t === 0 ? t : t + 1; yHigh = y; y = t; } else { yHigh = t === height - 1 ? t : t - 1; } return { x, y, // when ratio < 1, current css pixel and next css pixel may point to same device pixel, set width/height to 1 in those cases. width: Math.max(xHigh - x + 1, 1), height: Math.max(yHigh - y + 1, 1) }; } function scaleX(x, ratio, width) { const r = Math.min(Math.round(x * ratio), width - 1); return r; } function scaleY(y, ratio, height, yInvert) { return yInvert ? Math.max(0, height - 1 - Math.round(y * ratio)) : Math.min(Math.round(y * ratio), height - 1); } // dist/adapter/resources/texture.js var _Texture = class extends Resource { get [Symbol.toStringTag]() { return "Texture"; } /** dimension of this texture */ dimension; /** format of this texture */ format; /** width in pixels of this texture */ width; /** height in pixels of this texture */ height; /** depth of this texture */ depth; /** "Time" of last update. Monotonically increasing timestamp */ updateTimestamp; /** Do not use directly. Create with device.createTexture() */ constructor(device, props, defaultProps = _Texture.defaultProps) { super(device, props, defaultProps); this.dimension = this.props.dimension; this.format = this.props.format; this.width = this.props.width; this.height = this.props.height; this.depth = this.props.depth; this.updateTimestamp = device.incrementTimestamp(); } }; var Texture = _Texture; __publicField(Texture, "defaultProps", { ...Resource.defaultProps, data: null, dimension: "2d", format: "rgba8unorm", width: void 0, height: void 0, depth: 1, mipmaps: true, // type: undefined, compressed: false, // mipLevels: 1, usage: 0, // usage: GPUTextureUsage.COPY_DST mipLevels: void 0, samples: void 0, type: void 0, sampler: {}, view: void 0 }); __publicField(Texture, "COPY_SRC", 1); __publicField(Texture, "COPY_DST", 2); __publicField(Texture, "TEXTURE_BINDING", 4); __publicField(Texture, "STORAGE_BINDING", 8); __publicField(Texture, "RENDER_ATTACHMENT", 16); // dist/adapter/resources/texture-view.js var _TextureView = class extends Resource { get [Symbol.toStringTag]() { return "TextureView"; } /** Should not be constructed directly. Use `texture.createView(props)` */ constructor(device, props) { super(device, props, _TextureView.defaultProps); } }; var TextureView = _TextureView; __publicField(TextureView, "defaultProps", { ...Resource.defaultProps, format: void 0, dimension: void 0, aspect: "all", baseMipLevel: 0, mipLevelCount: void 0, baseArrayLayer: 0, arrayLayerCount: void 0 }); // dist/adapter/resources/external-texture.js var _ExternalTexture = class extends Resource { get [Symbol.toStringTag]() { return "ExternalTexture"; } constructor(device, props) { super(device, props, _ExternalTexture.defaultProps); } }; var ExternalTexture = _ExternalTexture; __publicField(ExternalTexture, "defaultProps", { ...Resource.defaultProps, source: null, colorSpace: "srgb" }); // dist/lib/compiler-log/format-compiler-log.js function formatCompilerLog(shaderLog, source, options) { let formattedLog = ""; const lines = source.split(/\r?\n/); const log2 = shaderLog.slice().sort((a, b) => a.lineNum - b.lineNum); switch ((options == null ? void 0 : options.showSourceCode) || "no") { case "all": let currentMessage = 0; for (let lineNum = 1; lineNum <= lines.length; lineNum++) { formattedLog += getNumberedLine(lines[lineNum - 1], lineNum, options); while (log2.length > currentMessage && log2[currentMessage].lineNum === lineNum) { const message = log2[currentMessage++]; formattedLog += formatCompilerMessage(message, lines, message.lineNum, { ...options, inlineSource: false }); } } return formattedLog; case "issues": case "no": for (const message of shaderLog) { formattedLog += formatCompilerMessage(message, lines, message.lineNum, { inlineSource: (options == null ? void 0 : options.showSourceCode) !== "no" }); } return formattedLog; } } function formatCompilerMessage(message, lines, lineNum, options) { if (options == null ? void 0 : options.inlineSource) { const numberedLines = getNumberedLines(lines, lineNum); const positionIndicator = message.linePos > 0 ? `${" ".repeat(message.linePos + 5)}^^^ ` : ""; return ` ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.message} `; } return (options == null ? void 0 : options.html) ? `
${translatedSource}
`;
}
const button = document.createElement("Button");
button.innerHTML = `
${htmlLog}
`;
button.style.top = "10px";
button.style.left = "10px";
button.style.position = "absolute";
button.style.zIndex = "9999";
button.style.width = "100%";
button.style.textAlign = "left";
document.body.appendChild(button);
const errors = document.getElementsByClassName("luma-compiler-log-error");
if ((_a = errors[0]) == null ? void 0 : _a.scrollIntoView) {
errors[0].scrollIntoView();
}
button.onclick = () => {
const dataURI = `data:text/plain,${encodeURIComponent(this.source)}`;
navigator.clipboard.writeText(dataURI);
};
}
};
var Shader = _Shader;
__publicField(Shader, "defaultProps", {
...Resource.defaultProps,
language: "auto",
stage: void 0,
source: "",
sourceMap: null,
entryPoint: "main",
debug: "errors"
});
function getShaderIdFromProps(props) {
return getShaderInfo(props.source).name || props.id || uid(`unnamed ${props.stage}-shader`);
}
// dist/adapter/resources/sampler.js
var _Sampler = class extends Resource {
get [Symbol.toStringTag]() {
return "Sampler";
}
constructor(device, props) {
super(device, props, _Sampler.defaultProps);
}
};
var Sampler = _Sampler;
__publicField(Sampler, "defaultProps", {
...Resource.defaultProps,
type: "color-sampler",
addressModeU: "clamp-to-edge",
addressModeV: "clamp-to-edge",
addressModeW: "clamp-to-edge",
magFilter: "nearest",
minFilter: "nearest",
mipmapFilter: "nearest",
lodMinClamp: 0,
lodMaxClamp: 32,
// Per WebGPU spec
compare: "less-equal",
maxAnisotropy: 1
});
// dist/adapter/resources/framebuffer.js
var _Framebuffer = class extends Resource {
get [Symbol.toStringTag]() {
return "Framebuffer";
}
/** Width of all attachments in this framebuffer */
width;
/** Height of all attachments in this framebuffer */
height;
/** Color attachments */
colorAttachments = [];
/** Depth-stencil attachment, if provided */
depthStencilAttachment = null;
constructor(device, props = {}) {
super(device, props, _Framebuffer.defaultProps);
this.width = this.props.width;
this.height = this.props.height;
}
resize(size) {
let updateSize = !size;
if (size) {
const [width, height] = Array.isArray(size) ? size : [size.width, size.height];
updateSize = updateSize || height !== this.height || width !== this.width;
this.width = width;
this.height = height;
}
if (updateSize) {
log.log(2, `Resizing framebuffer ${this.id} to ${this.width}x${this.height}`)();
this.resizeAttachments(this.width, this.height);
}
}
/** Auto creates any textures */
autoCreateAttachmentTextures() {
if (this.props.colorAttachments.length === 0 && !this.props.depthStencilAttachment) {
throw new Error("Framebuffer has noattachments");
}
this.colorAttachments = this.props.colorAttachments.map((attachment2) => {
if (typeof attachment2 === "string") {
const texture = this.createColorTexture(attachment2);
this.attachResource(texture);
return texture.view;
}
if (attachment2 instanceof Texture) {
return attachment2.view;
}
return attachment2;
});
const attachment = this.props.depthStencilAttachment;
if (attachment) {
if (typeof attachment === "string") {
const texture = this.createDepthStencilTexture(attachment);
this.attachResource(texture);
this.depthStencilAttachment = texture.view;
} else if (attachment instanceof Texture) {
this.depthStencilAttachment = attachment.view;
} else {
this.depthStencilAttachment = attachment;
}
}
}
/** Create a color texture */
createColorTexture(format) {
return this.device.createTexture({
id: "color-attachment",
usage: Texture.RENDER_ATTACHMENT,
format,
width: this.width,
height: this.height
});
}
/** Create depth stencil texture */
createDepthStencilTexture(format) {
return this.device.createTexture({
id: "depth-stencil-attachment",
usage: Texture.RENDER_ATTACHMENT,
format,
width: this.width,
height: this.height
});
}
/**
* Default implementation of resize
* Creates new textures with correct size for all attachments.
* and destroys existing textures if owned
*/
resizeAttachments(width, height) {
for (let i = 0; i < this.colorAttachments.length; ++i) {
if (this.colorAttachments[i]) {
const resizedTexture = this.device._createTexture({
...this.colorAttachments[i].props,
width,
height
});
this.destroyAttachedResource(this.colorAttachments[i]);
this.colorAttachments[i] = resizedTexture.view;
this.attachResource(resizedTexture.view);
}
}
if (this.depthStencilAttachment) {
const resizedTexture = this.device._createTexture({
...this.depthStencilAttachment.props,
width,
height
});
this.destroyAttachedResource(this.depthStencilAttachment);
this.depthStencilAttachment = resizedTexture.view;
this.attachResource(resizedTexture);
}
}
};
var Framebuffer = _Framebuffer;
__publicField(Framebuffer, "defaultProps", {
...Resource.defaultProps,
width: 1,
height: 1,
colorAttachments: [],
// ['rgba8unorm'],
depthStencilAttachment: null
// 'depth24plus-stencil8'
});
// dist/adapter/resources/render-pipeline.js
var _RenderPipeline = class extends Resource {
get [Symbol.toStringTag]() {
return "RenderPipeline";
}
/** The merged layout */
shaderLayout;
/** Buffer map describing buffer interleaving etc */
bufferLayout;
/** The linking status of the pipeline. 'pending' if linking is asynchronous, and on production */
linkStatus = "pending";
/** The hash of the pipeline */
hash = "";
constructor(device, props) {
super(device, props, _RenderPipeline.defaultProps);
this.shaderLayout = this.props.shaderLayout;
this.bufferLayout = this.props.bufferLayout || [];
}
// DEPRECATED METHODS
/**
* Uniforms
* @deprecated Use uniforms buffers
* @note textures, samplers and uniform buffers should be set via `setBindings()`, these are not considered uniforms.
* @note In WebGL uniforms have a performance penalty, they are reset before each call to enable pipeline sharing.
*/
setUniformsWebGL(uniforms) {
throw new Error("Use uniform blocks");
}
};
var RenderPipeline = _RenderPipeline;
__publicField(RenderPipeline, "defaultProps", {
...Resource.defaultProps,
vs: null,
vertexEntryPoint: "vertexMain",
vsConstants: {},
fs: null,
fragmentEntryPoint: "fragmentMain",
fsConstants: {},
shaderLayout: null,
bufferLayout: [],
topology: "triangle-list",
parameters: {},
// isInstanced: false,
// instanceCount: 0,
// vertexCount: 0,
bindings: {},
uniforms: {}
});
// dist/adapter/resources/render-pass.js
var _RenderPass = class extends Resource {
get [Symbol.toStringTag]() {
return "RenderPass";
}
constructor(device, props) {
super(device, props, _RenderPass.defaultProps);
}
};
var RenderPass = _RenderPass;
/** Default properties for RenderPass */
__publicField(RenderPass, "defaultProps", {
...Resource.defaultProps,
framebuffer: null,
parameters: void 0,
clearColor: [0, 0, 0, 0],
clearDepth: 1,
clearStencil: 0,
depthReadOnly: false,
stencilReadOnly: false,
discard: false,
occlusionQuerySet: void 0,
timestampQuerySet: void 0,
beginTimestampIndex: void 0,
endTimestampIndex: void 0
});
// dist/adapter/resources/compute-pipeline.js
var _ComputePipeline = class extends Resource {
get [Symbol.toStringTag]() {
return "ComputePipeline";
}
hash = "";
constructor(device, props) {
super(device, props, _ComputePipeline.defaultProps);
}
};
var ComputePipeline = _ComputePipeline;
__publicField(ComputePipeline, "defaultProps", {
...Resource.defaultProps,
shader: void 0,
entryPoint: void 0,
constants: {},
shaderLayout: void 0
});
// dist/adapter/resources/compute-pass.js
var _ComputePass = class extends Resource {
get [Symbol.toStringTag]() {
return "ComputePass";
}
constructor(device, props) {
super(device, props, _ComputePass.defaultProps);
}
};
var ComputePass = _ComputePass;
__publicField(ComputePass, "defaultProps", {
...Resource.defaultProps,
timestampQuerySet: void 0,
beginTimestampIndex: void 0,
endTimestampIndex: void 0
});
// dist/adapter/resources/command-encoder.js
var _CommandEncoder = class extends Resource {
get [Symbol.toStringTag]() {
return "CommandEncoder";
}
constructor(device, props) {
super(device, props, _CommandEncoder.defaultProps);
}
};
var CommandEncoder = _CommandEncoder;
__publicField(CommandEncoder, "defaultProps", {
...Resource.defaultProps,
measureExecutionTime: void 0
});
// dist/adapter/resources/command-buffer.js
var _CommandBuffer = class extends Resource {
get [Symbol.toStringTag]() {
return "CommandBuffer";
}
constructor(device, props) {
super(device, props, _CommandBuffer.defaultProps);
}
};
var CommandBuffer = _CommandBuffer;
__publicField(CommandBuffer, "defaultProps", {
...Resource.defaultProps
});
// dist/adapter/type-utils/decode-attribute-type.js
function decodeShaderAttributeType(attributeType) {
const [dataType, components] = TYPE_INFO[attributeType];
const integer = dataType === "i32" || dataType === "u32";
const signed = dataType !== "u32";
const byteLength = TYPE_SIZES2[dataType] * components;
const defaultVertexFormat = getCompatibleVertexFormat(dataType, components);
return {
dataType,
components,
defaultVertexFormat,
byteLength,
integer,
signed
};
}
function getCompatibleVertexFormat(dataType, components) {
let vertexType;
switch (dataType) {
case "f32":
vertexType = "float32";
break;
case "i32":
vertexType = "sint32";
break;
case "u32":
vertexType = "uint32";
break;
case "f16":
return components <= 2 ? "float16x2" : "float16x4";
}
if (components === 1) {
return vertexType;
}
return `${vertexType}x${components}`;
}
var TYPE_INFO = {
f32: ["f32", 1],
"vec2