(function webpackUniversalModuleDefinition(root, factory) { if (typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if (typeof define === 'function' && define.amd) define([], factory); else if (typeof exports === 'object') exports['luma'] = factory(); else root['luma'] = factory();})(globalThis, function () { "use strict"; var __exports__ = (() => { var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; 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 __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], 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 __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default")); var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; // external-global-plugin:@luma.gl/core var require_core = __commonJS({ "external-global-plugin:@luma.gl/core"(exports, module) { module.exports = globalThis.luma; } }); // bundle.ts var bundle_exports = {}; __export(bundle_exports, { AnimationLoop: () => AnimationLoop, AnimationLoopTemplate: () => AnimationLoopTemplate, BufferTransform: () => BufferTransform, ClipSpace: () => ClipSpace, Computation: () => Computation, ConeGeometry: () => ConeGeometry, CubeGeometry: () => CubeGeometry, CylinderGeometry: () => CylinderGeometry, GPUGeometry: () => GPUGeometry, Geometry: () => Geometry, GroupNode: () => GroupNode, IcoSphereGeometry: () => IcoSphereGeometry, KeyFrames: () => KeyFrames, Model: () => Model, ModelNode: () => ModelNode, PipelineFactory: () => PipelineFactory, PlaneGeometry: () => PlaneGeometry, ScenegraphNode: () => ScenegraphNode, ShaderFactory: () => ShaderFactory, SphereGeometry: () => SphereGeometry, TextureTransform: () => TextureTransform, Timeline: () => Timeline, TruncatedConeGeometry: () => TruncatedConeGeometry, _ShaderInputs: () => ShaderInputs, makeAnimationLoop: () => makeAnimationLoop }); __reExport(bundle_exports, __toESM(require_core(), 1)); // src/animation/timeline.ts var channelHandles = 1; var animationHandles = 1; var Timeline = class { time = 0; channels = /* @__PURE__ */ new Map(); animations = /* @__PURE__ */ new Map(); playing = false; lastEngineTime = -1; constructor() { } addChannel(props) { const { delay = 0, duration = Number.POSITIVE_INFINITY, rate = 1, repeat = 1 } = props; const channelId = channelHandles++; const channel = { time: 0, delay, duration, rate, repeat }; this._setChannelTime(channel, this.time); this.channels.set(channelId, channel); return channelId; } removeChannel(channelId) { this.channels.delete(channelId); for (const [animationHandle, animation] of this.animations) { if (animation.channel === channelId) { this.detachAnimation(animationHandle); } } } isFinished(channelId) { const channel = this.channels.get(channelId); if (channel === void 0) { return false; } return this.time >= channel.delay + channel.duration * channel.repeat; } getTime(channelId) { if (channelId === void 0) { return this.time; } const channel = this.channels.get(channelId); if (channel === void 0) { return -1; } return channel.time; } setTime(time) { this.time = Math.max(0, time); const channels = this.channels.values(); for (const channel of channels) { this._setChannelTime(channel, this.time); } const animations = this.animations.values(); for (const animationData of animations) { const { animation, channel } = animationData; animation.setTime(this.getTime(channel)); } } play() { this.playing = true; } pause() { this.playing = false; this.lastEngineTime = -1; } reset() { this.setTime(0); } attachAnimation(animation, channelHandle) { const animationHandle = animationHandles++; this.animations.set(animationHandle, { animation, channel: channelHandle }); animation.setTime(this.getTime(channelHandle)); return animationHandle; } detachAnimation(channelId) { this.animations.delete(channelId); } update(engineTime) { if (this.playing) { if (this.lastEngineTime === -1) { this.lastEngineTime = engineTime; } this.setTime(this.time + (engineTime - this.lastEngineTime)); this.lastEngineTime = engineTime; } } _setChannelTime(channel, time) { const offsetTime = time - channel.delay; const totalDuration = channel.duration * channel.repeat; if (offsetTime >= totalDuration) { channel.time = channel.duration * channel.rate; } else { channel.time = Math.max(0, offsetTime) % channel.duration; channel.time *= channel.rate; } } }; // src/animation/key-frames.ts var KeyFrames = class { startIndex = -1; endIndex = -1; factor = 0; times = []; values = []; _lastTime = -1; constructor(keyFrames) { this.setKeyFrames(keyFrames); this.setTime(0); } setKeyFrames(keyFrames) { const numKeys = keyFrames.length; this.times.length = numKeys; this.values.length = numKeys; for (let i = 0; i < numKeys; ++i) { this.times[i] = keyFrames[i][0]; this.values[i] = keyFrames[i][1]; } this._calculateKeys(this._lastTime); } setTime(time) { time = Math.max(0, time); if (time !== this._lastTime) { this._calculateKeys(time); this._lastTime = time; } } getStartTime() { return this.times[this.startIndex]; } getEndTime() { return this.times[this.endIndex]; } getStartData() { return this.values[this.startIndex]; } getEndData() { return this.values[this.endIndex]; } _calculateKeys(time) { let index2 = 0; const numKeys = this.times.length; for (index2 = 0; index2 < numKeys - 2; ++index2) { if (this.times[index2 + 1] > time) { break; } } this.startIndex = index2; this.endIndex = index2 + 1; const startTime = this.times[this.startIndex]; const endTime = this.times[this.endIndex]; this.factor = Math.min(Math.max(0, (time - startTime) / (endTime - startTime)), 1); } }; // src/animation-loop/animation-loop-template.ts var AnimationLoopTemplate = class { constructor(animationProps) { } async onInitialize(animationProps) { return null; } }; // src/animation-loop/animation-loop.ts var import_core = __toESM(require_core(), 1); var import_core2 = __toESM(require_core(), 1); // ../../node_modules/@probe.gl/stats/dist/utils/hi-res-timestamp.js function getHiResTimestamp() { let timestamp; if (typeof window !== "undefined" && window.performance) { timestamp = window.performance.now(); } else if (typeof process !== "undefined" && process.hrtime) { const timeParts = process.hrtime(); timestamp = timeParts[0] * 1e3 + timeParts[1] / 1e6; } else { timestamp = Date.now(); } return timestamp; } // ../../node_modules/@probe.gl/stats/dist/lib/stat.js var Stat = class { constructor(name, type) { this.sampleSize = 1; this.time = 0; this.count = 0; this.samples = 0; this.lastTiming = 0; this.lastSampleTime = 0; this.lastSampleCount = 0; this._count = 0; this._time = 0; this._samples = 0; this._startTime = 0; this._timerPending = false; this.name = name; this.type = type; this.reset(); } reset() { this.time = 0; this.count = 0; this.samples = 0; this.lastTiming = 0; this.lastSampleTime = 0; this.lastSampleCount = 0; this._count = 0; this._time = 0; this._samples = 0; this._startTime = 0; this._timerPending = false; return this; } setSampleSize(samples) { this.sampleSize = samples; return this; } /** Call to increment count (+1) */ incrementCount() { this.addCount(1); return this; } /** Call to decrement count (-1) */ decrementCount() { this.subtractCount(1); return this; } /** Increase count */ addCount(value) { this._count += value; this._samples++; this._checkSampling(); return this; } /** Decrease count */ subtractCount(value) { this._count -= value; this._samples++; this._checkSampling(); return this; } /** Add an arbitrary timing and bump the count */ addTime(time) { this._time += time; this.lastTiming = time; this._samples++; this._checkSampling(); return this; } /** Start a timer */ timeStart() { this._startTime = getHiResTimestamp(); this._timerPending = true; return this; } /** End a timer. Adds to time and bumps the timing count. */ timeEnd() { if (!this._timerPending) { return this; } this.addTime(getHiResTimestamp() - this._startTime); this._timerPending = false; this._checkSampling(); return this; } getSampleAverageCount() { return this.sampleSize > 0 ? this.lastSampleCount / this.sampleSize : 0; } /** Calculate average time / count for the previous window */ getSampleAverageTime() { return this.sampleSize > 0 ? this.lastSampleTime / this.sampleSize : 0; } /** Calculate counts per second for the previous window */ getSampleHz() { return this.lastSampleTime > 0 ? this.sampleSize / (this.lastSampleTime / 1e3) : 0; } getAverageCount() { return this.samples > 0 ? this.count / this.samples : 0; } /** Calculate average time / count */ getAverageTime() { return this.samples > 0 ? this.time / this.samples : 0; } /** Calculate counts per second */ getHz() { return this.time > 0 ? this.samples / (this.time / 1e3) : 0; } _checkSampling() { if (this._samples === this.sampleSize) { this.lastSampleTime = this._time; this.lastSampleCount = this._count; this.count += this._count; this.time += this._time; this.samples += this._samples; this._time = 0; this._count = 0; this._samples = 0; } } }; // ../../node_modules/@probe.gl/stats/dist/lib/stats.js var Stats = class { constructor(options) { this.stats = {}; this.id = options.id; this.stats = {}; this._initializeStats(options.stats); Object.seal(this); } /** Acquire a stat. Create if it doesn't exist. */ get(name, type = "count") { return this._getOrCreate({ name, type }); } get size() { return Object.keys(this.stats).length; } /** Reset all stats */ reset() { for (const stat of Object.values(this.stats)) { stat.reset(); } return this; } forEach(fn) { for (const stat of Object.values(this.stats)) { fn(stat); } } getTable() { const table = {}; this.forEach((stat) => { table[stat.name] = { time: stat.time || 0, count: stat.count || 0, average: stat.getAverageTime() || 0, hz: stat.getHz() || 0 }; }); return table; } _initializeStats(stats = []) { stats.forEach((stat) => this._getOrCreate(stat)); } _getOrCreate(stat) { const { name, type } = stat; let result = this.stats[name]; if (!result) { if (stat instanceof Stat) { result = stat; } else { result = new Stat(name, type); } this.stats[name] = result; } return result; } }; // src/animation-loop/animation-loop.ts var statIdCounter = 0; var DEFAULT_ANIMATION_LOOP_PROPS = { device: null, onAddHTML: () => "", onInitialize: async () => { return null; }, onRender: () => { }, onFinalize: () => { }, onError: (error) => console.error(error), // eslint-disable-line no-console stats: import_core.luma.stats.get(`animation-loop-${statIdCounter++}`), // view parameters useDevicePixels: true, autoResizeViewport: false, autoResizeDrawingBuffer: false }; var AnimationLoop = class { device = null; canvas = null; props; animationProps = null; timeline = null; stats; cpuTime; gpuTime; frameRate; display; needsRedraw = "initialized"; _initialized = false; _running = false; _animationFrameId = null; _nextFramePromise = null; _resolveNextFrame = null; _cpuStartTime = 0; // _gpuTimeQuery: Query | null = null; /* * @param {HTMLCanvasElement} canvas - if provided, width and height will be passed to context */ constructor(props) { this.props = { ...DEFAULT_ANIMATION_LOOP_PROPS, ...props }; props = this.props; if (!props.device) { throw new Error("No device provided"); } const { useDevicePixels = true } = this.props; this.stats = props.stats || new Stats({ id: "animation-loop-stats" }); this.cpuTime = this.stats.get("CPU Time"); this.gpuTime = this.stats.get("GPU Time"); this.frameRate = this.stats.get("Frame Rate"); this.setProps({ autoResizeViewport: props.autoResizeViewport, autoResizeDrawingBuffer: props.autoResizeDrawingBuffer, useDevicePixels }); this.start = this.start.bind(this); this.stop = this.stop.bind(this); this._onMousemove = this._onMousemove.bind(this); this._onMouseleave = this._onMouseleave.bind(this); } destroy() { this.stop(); this._setDisplay(null); } /** @deprecated Use .destroy() */ delete() { this.destroy(); } /** Flags this animation loop as needing redraw */ setNeedsRedraw(reason) { this.needsRedraw = this.needsRedraw || reason; return this; } /** TODO - move these props to CanvasContext? */ setProps(props) { if ("autoResizeViewport" in props) { this.props.autoResizeViewport = props.autoResizeViewport || false; } if ("autoResizeDrawingBuffer" in props) { this.props.autoResizeDrawingBuffer = props.autoResizeDrawingBuffer || false; } if ("useDevicePixels" in props) { this.props.useDevicePixels = props.useDevicePixels || false; } return this; } /** Starts a render loop if not already running */ async start() { if (this._running) { return this; } this._running = true; try { let appContext; if (!this._initialized) { this._initialized = true; await this._initDevice(); this._initialize(); await this.props.onInitialize(this._getAnimationProps()); } if (!this._running) { return null; } if (appContext !== false) { this._cancelAnimationFrame(); this._requestAnimationFrame(); } return this; } catch (err) { const error = err instanceof Error ? err : new Error("Unknown error"); this.props.onError(error); throw error; } } /** Stops a render loop if already running, finalizing */ stop() { if (this._running) { if (this.animationProps) { this.props.onFinalize(this.animationProps); } this._cancelAnimationFrame(); this._nextFramePromise = null; this._resolveNextFrame = null; this._running = false; } return this; } /** Explicitly draw a frame */ redraw() { if (this.device?.isLost) { return this; } this._beginFrameTimers(); this._setupFrame(); this._updateAnimationProps(); this._renderFrame(this._getAnimationProps()); this._clearNeedsRedraw(); if (this._resolveNextFrame) { this._resolveNextFrame(this); this._nextFramePromise = null; this._resolveNextFrame = null; } this._endFrameTimers(); return this; } /** Add a timeline, it will be automatically updated by the animation loop. */ attachTimeline(timeline) { this.timeline = timeline; return this.timeline; } /** Remove a timeline */ detachTimeline() { this.timeline = null; } /** Wait until a render completes */ waitForRender() { this.setNeedsRedraw("waitForRender"); if (!this._nextFramePromise) { this._nextFramePromise = new Promise((resolve) => { this._resolveNextFrame = resolve; }); } return this._nextFramePromise; } /** TODO - should use device.deviceContext */ async toDataURL() { this.setNeedsRedraw("toDataURL"); await this.waitForRender(); if (this.canvas instanceof HTMLCanvasElement) { return this.canvas.toDataURL(); } throw new Error("OffscreenCanvas"); } // PRIVATE METHODS _initialize() { this._startEventHandling(); this._initializeAnimationProps(); this._updateAnimationProps(); this._resizeCanvasDrawingBuffer(); this._resizeViewport(); } _setDisplay(display) { if (this.display) { this.display.destroy(); this.display.animationLoop = null; } if (display) { display.animationLoop = this; } this.display = display; } _requestAnimationFrame() { if (!this._running) { return; } this._animationFrameId = (0, import_core2.requestAnimationFrame)(this._animationFrame.bind(this)); } _cancelAnimationFrame() { if (this._animationFrameId === null) { return; } (0, import_core2.cancelAnimationFrame)(this._animationFrameId); this._animationFrameId = null; } _animationFrame() { if (!this._running) { return; } this.redraw(); this._requestAnimationFrame(); } // Called on each frame, can be overridden to call onRender multiple times // to support e.g. stereoscopic rendering _renderFrame(animationProps) { if (this.display) { this.display._renderFrame(animationProps); return; } this.props.onRender(this._getAnimationProps()); this.device.submit(); } _clearNeedsRedraw() { this.needsRedraw = false; } _setupFrame() { this._resizeCanvasDrawingBuffer(); this._resizeViewport(); } // Initialize the object that will be passed to app callbacks _initializeAnimationProps() { if (!this.device) { throw new Error("loop"); } this.animationProps = { animationLoop: this, device: this.device, canvas: this.device?.canvasContext?.canvas, timeline: this.timeline, // Initial values useDevicePixels: this.props.useDevicePixels, needsRedraw: false, // Placeholders width: 1, height: 1, aspect: 1, // Animation props time: 0, startTime: Date.now(), engineTime: 0, tick: 0, tock: 0, // Experimental _mousePosition: null // Event props }; } _getAnimationProps() { if (!this.animationProps) { throw new Error("animationProps"); } return this.animationProps; } // Update the context object that will be passed to app callbacks _updateAnimationProps() { if (!this.animationProps) { return; } const { width, height, aspect } = this._getSizeAndAspect(); if (width !== this.animationProps.width || height !== this.animationProps.height) { this.setNeedsRedraw("drawing buffer resized"); } if (aspect !== this.animationProps.aspect) { this.setNeedsRedraw("drawing buffer aspect changed"); } this.animationProps.width = width; this.animationProps.height = height; this.animationProps.aspect = aspect; this.animationProps.needsRedraw = this.needsRedraw; this.animationProps.engineTime = Date.now() - this.animationProps.startTime; if (this.timeline) { this.timeline.update(this.animationProps.engineTime); } this.animationProps.tick = Math.floor(this.animationProps.time / 1e3 * 60); this.animationProps.tock++; this.animationProps.time = this.timeline ? this.timeline.getTime() : this.animationProps.engineTime; } /** Wait for supplied device */ async _initDevice() { this.device = await this.props.device; if (!this.device) { throw new Error("No device provided"); } this.canvas = this.device.canvasContext?.canvas || null; } _createInfoDiv() { if (this.canvas && this.props.onAddHTML) { const wrapperDiv = document.createElement("div"); document.body.appendChild(wrapperDiv); wrapperDiv.style.position = "relative"; const div = document.createElement("div"); div.style.position = "absolute"; div.style.left = "10px"; div.style.bottom = "10px"; div.style.width = "300px"; div.style.background = "white"; if (this.canvas instanceof HTMLCanvasElement) { wrapperDiv.appendChild(this.canvas); } wrapperDiv.appendChild(div); const html = this.props.onAddHTML(div); if (html) { div.innerHTML = html; } } } _getSizeAndAspect() { if (!this.device) { return { width: 1, height: 1, aspect: 1 }; } const [width, height] = this.device?.canvasContext?.getPixelSize() || [1, 1]; let aspect = 1; const canvas2 = this.device?.canvasContext?.canvas; if (canvas2 && canvas2.clientHeight) { aspect = canvas2.clientWidth / canvas2.clientHeight; } else if (width > 0 && height > 0) { aspect = width / height; } return { width, height, aspect }; } /** Default viewport setup */ _resizeViewport() { if (this.props.autoResizeViewport && this.device.gl) { this.device.gl.viewport( 0, 0, // @ts-expect-error Expose canvasContext this.device.gl.drawingBufferWidth, // @ts-expect-error Expose canvasContext this.device.gl.drawingBufferHeight ); } } /** * Resize the render buffer of the canvas to match canvas client size * Optionally multiplying with devicePixel ratio */ _resizeCanvasDrawingBuffer() { if (this.props.autoResizeDrawingBuffer) { this.device?.canvasContext?.resize({ useDevicePixels: this.props.useDevicePixels }); } } _beginFrameTimers() { this.frameRate.timeEnd(); this.frameRate.timeStart(); this.cpuTime.timeStart(); } _endFrameTimers() { this.cpuTime.timeEnd(); } // Event handling _startEventHandling() { if (this.canvas) { this.canvas.addEventListener("mousemove", this._onMousemove.bind(this)); this.canvas.addEventListener("mouseleave", this._onMouseleave.bind(this)); } } _onMousemove(event) { if (event instanceof MouseEvent) { this._getAnimationProps()._mousePosition = [event.offsetX, event.offsetY]; } } _onMouseleave(event) { this._getAnimationProps()._mousePosition = null; } }; // src/animation-loop/make-animation-loop.ts var import_core3 = __toESM(require_core(), 1); function makeAnimationLoop(AnimationLoopTemplateCtor, props) { let renderLoop = null; const device = props?.device || import_core3.luma.createDevice(); const animationLoop = new AnimationLoop({ ...props, device, async onInitialize(animationProps) { renderLoop = new AnimationLoopTemplateCtor(animationProps); return await renderLoop?.onInitialize(animationProps); }, onRender: (animationProps) => renderLoop?.onRender(animationProps), onFinalize: (animationProps) => renderLoop?.onFinalize(animationProps) }); animationLoop.getInfo = () => { return this.AnimationLoopTemplateCtor.info; }; return animationLoop; } // src/model/model.ts var import_core9 = __toESM(require_core(), 1); var import_core10 = __toESM(require_core(), 1); var import_core11 = __toESM(require_core(), 1); var import_core12 = __toESM(require_core(), 1); // ../shadertools/src/lib/glsl-utils/highlight.ts var glsl = (x) => `${x}`; // ../shadertools/src/lib/utils/assert.ts function assert(condition, message) { if (!condition) { throw new Error(message || "shadertools: assertion failed."); } } // ../shadertools/src/lib/filters/prop-types.ts var DEFAULT_PROP_VALIDATORS = { number: { type: "number", validate(value, propType) { return Number.isFinite(value) && typeof propType === "object" && (propType.max === void 0 || value <= propType.max) && (propType.min === void 0 || value >= propType.min); } }, array: { type: "array", validate(value, propType) { return Array.isArray(value) || ArrayBuffer.isView(value); } } }; function makePropValidators(propTypes) { const propValidators = {}; for (const [name, propType] of Object.entries(propTypes)) { propValidators[name] = makePropValidator(propType); } return propValidators; } function getValidatedProperties(properties, propValidators, errorMessage) { const validated = {}; for (const [key, propsValidator] of Object.entries(propValidators)) { if (properties && key in properties && !propsValidator.private) { if (propsValidator.validate) { assert( propsValidator.validate(properties[key], propsValidator), `${errorMessage}: invalid ${key}` ); } validated[key] = properties[key]; } else { validated[key] = propsValidator.value; } } return validated; } function makePropValidator(propType) { let type = getTypeOf(propType); if (type !== "object") { return { value: propType, ...DEFAULT_PROP_VALIDATORS[type], type }; } if (typeof propType === "object") { if (!propType) { return { type: "object", value: null }; } if (propType.type !== void 0) { return { ...propType, ...DEFAULT_PROP_VALIDATORS[propType.type], type: propType.type }; } if (propType.value === void 0) { return { type: "object", value: propType }; } type = getTypeOf(propType.value); return { ...propType, ...DEFAULT_PROP_VALIDATORS[type], type }; } throw new Error("props"); } function getTypeOf(value) { if (Array.isArray(value) || ArrayBuffer.isView(value)) { return "array"; } return typeof value; } // ../shadertools/src/module-injectors.ts var MODULE_INJECTORS_VS = glsl`\ #ifdef MODULE_LOGDEPTH logdepth_adjustPosition(gl_Position); #endif `; var MODULE_INJECTORS_FS = glsl`\ #ifdef MODULE_MATERIAL gl_FragColor = material_filterColor(gl_FragColor); #endif #ifdef MODULE_LIGHTING gl_FragColor = lighting_filterColor(gl_FragColor); #endif #ifdef MODULE_FOG gl_FragColor = fog_filterColor(gl_FragColor); #endif #ifdef MODULE_PICKING gl_FragColor = picking_filterHighlightColor(gl_FragColor); gl_FragColor = picking_filterPickingColor(gl_FragColor); #endif #ifdef MODULE_LOGDEPTH logdepth_setFragDepth(); #endif `; // ../shadertools/src/lib/shader-assembly/shader-injections.ts var MODULE_INJECTORS = { vertex: MODULE_INJECTORS_VS, fragment: MODULE_INJECTORS_FS }; var REGEX_START_OF_MAIN = /void\s+main\s*\([^)]*\)\s*\{\n?/; var REGEX_END_OF_MAIN = /}\n?[^{}]*$/; var fragments = []; var DECLARATION_INJECT_MARKER = "__LUMA_INJECT_DECLARATIONS__"; function normalizeInjections(injections) { const result = { vertex: {}, fragment: {} }; for (const hook in injections) { let injection = injections[hook]; const stage = getHookStage(hook); if (typeof injection === "string") { injection = { order: 0, injection }; } result[stage][hook] = injection; } return result; } function getHookStage(hook) { const type = hook.slice(0, 2); switch (type) { case "vs": return "vertex"; case "fs": return "fragment"; default: throw new Error(type); } } function injectShader(source, stage, inject, injectStandardStubs = false) { const isVertex = stage === "vertex"; for (const key in inject) { const fragmentData = inject[key]; fragmentData.sort((a, b) => a.order - b.order); fragments.length = fragmentData.length; for (let i = 0, len = fragmentData.length; i < len; ++i) { fragments[i] = fragmentData[i].injection; } const fragmentString = `${fragments.join("\n")} `; switch (key) { case "vs:#decl": if (isVertex) { source = source.replace(DECLARATION_INJECT_MARKER, fragmentString); } break; case "vs:#main-start": if (isVertex) { source = source.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString); } break; case "vs:#main-end": if (isVertex) { source = source.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match); } break; case "fs:#decl": if (!isVertex) { source = source.replace(DECLARATION_INJECT_MARKER, fragmentString); } break; case "fs:#main-start": if (!isVertex) { source = source.replace(REGEX_START_OF_MAIN, (match) => match + fragmentString); } break; case "fs:#main-end": if (!isVertex) { source = source.replace(REGEX_END_OF_MAIN, (match) => fragmentString + match); } break; default: source = source.replace(key, (match) => match + fragmentString); } } source = source.replace(DECLARATION_INJECT_MARKER, ""); if (injectStandardStubs) { source = source.replace(/\}\s*$/, (match) => match + MODULE_INJECTORS[stage]); } return source; } // ../shadertools/src/lib/shader-module/shader-module-instance.ts var index = 1; var ShaderModuleInstance = class { name; vs; fs; getModuleUniforms; dependencies; deprecations; defines; injections; uniforms = {}; uniformTypes = {}; static instantiateModules(modules) { return modules.map((module) => { if (module instanceof ShaderModuleInstance) { return module; } assert( typeof module !== "string", `Shader module use by name is deprecated. Import shader module '${JSON.stringify( module )}' and use it directly.` ); if (!module.name) { console.warn("shader module has no name"); module.name = `shader-module-${index++}`; } const moduleObject = new ShaderModuleInstance(module); moduleObject.dependencies = ShaderModuleInstance.instantiateModules( module.dependencies || [] ); return moduleObject; }); } constructor(props) { const { name, vs, fs, dependencies = [], uniformTypes = {}, uniformPropTypes = {}, getUniforms, deprecations = [], defines = {}, inject = {} } = props; assert(typeof name === "string"); this.name = name; this.vs = vs; this.fs = fs; this.getModuleUniforms = getUniforms; this.dependencies = ShaderModuleInstance.instantiateModules(dependencies); this.deprecations = this._parseDeprecationDefinitions(deprecations); this.defines = defines; this.injections = normalizeInjections(inject); this.uniformTypes = uniformTypes; if (uniformPropTypes) { this.uniforms = makePropValidators(uniformPropTypes); } } // Extracts the source code chunk for the specified shader type from the named shader module getModuleSource(stage) { let moduleSource; switch (stage) { case "vertex": moduleSource = this.vs || ""; break; case "fragment": moduleSource = this.fs || ""; break; default: assert(false); } const moduleName = this.name.toUpperCase().replace(/[^0-9a-z]/gi, "_"); return `// ----- MODULE ${this.name} --------------- #define MODULE_${moduleName} ${moduleSource} `; } getUniforms(userProps, uniforms) { if (this.getModuleUniforms) { return this.getModuleUniforms(userProps, uniforms); } return getValidatedProperties(userProps, this.uniforms, this.name); } getDefines() { return this.defines; } // Warn about deprecated uniforms or functions checkDeprecations(shaderSource, log6) { this.deprecations.forEach((def) => { if (def.regex?.test(shaderSource)) { if (def.deprecated) { log6.deprecated(def.old, def.new)(); } else { log6.removed(def.old, def.new)(); } } }); } _parseDeprecationDefinitions(deprecations) { deprecations.forEach((def) => { switch (def.type) { case "function": def.regex = new RegExp(`\\b${def.old}\\(`); break; default: def.regex = new RegExp(`${def.type} ${def.old};`); } }); return deprecations; } _defaultGetUniforms(opts = {}) { const uniforms = {}; const propTypes = this.uniforms; for (const key in propTypes) { const propDef = propTypes[key]; if (key in opts && !propDef.private) { if (propDef.validate) { assert(propDef.validate(opts[key], propDef), `${this.name}: invalid ${key}`); } uniforms[key] = opts[key]; } else { uniforms[key] = propDef.value; } } return uniforms; } }; // ../shadertools/src/lib/shader-assembly/select-shaders.ts function selectShaders(props) { if (props.source && props.platformInfo.type === "webgpu") { const propsCopy = { ...props, vs: void 0, fs: void 0 }; return propsCopy; } if (!props.vs) { throw new Error("no vertex shader"); } const vs = getShaderSource(props.platformInfo, props.vs); let fs; if (props.fs) { fs = getShaderSource(props.platformInfo, props.fs); } return { ...props, vs, fs }; } function getShaderSource(platformInfo, shader) { if (typeof shader === "string") { return shader; } switch (platformInfo.type) { case "webgpu": if (shader?.wgsl) { return shader.wgsl; } throw new Error("WebGPU does not support GLSL shaders"); default: if (shader?.glsl) { return shader.glsl; } throw new Error("WebGL does not support WGSL shaders"); } } // ../shadertools/src/lib/shader-assembly/resolve-modules.ts function resolveModules(modules) { const instances = ShaderModuleInstance.instantiateModules(modules); return getShaderDependencies(instances); } function getShaderDependencies(modules) { const moduleMap = {}; const moduleDepth = {}; getDependencyGraph({ modules, level: 0, moduleMap, moduleDepth }); return Object.keys(moduleDepth).sort((a, b) => moduleDepth[b] - moduleDepth[a]).map((name) => moduleMap[name]); } function getDependencyGraph(options) { const { modules, level, moduleMap, moduleDepth } = options; if (level >= 5) { throw new Error("Possible loop in shader dependency graph"); } for (const module of modules) { moduleMap[module.name] = module; if (moduleDepth[module.name] === void 0 || moduleDepth[module.name] < level) { moduleDepth[module.name] = level; } } for (const module of modules) { if (module.dependencies) { getDependencyGraph({ modules: module.dependencies, level: level + 1, moduleMap, moduleDepth }); } } } // ../shadertools/src/lib/shader-assembly/platform-defines.ts function getPlatformShaderDefines(platformInfo) { switch (platformInfo?.gpu.toLowerCase()) { case "apple": return glsl`\ #define APPLE_GPU // Apple optimizes away the calculation necessary for emulated fp64 #define LUMA_FP64_CODE_ELIMINATION_WORKAROUND 1 #define LUMA_FP32_TAN_PRECISION_WORKAROUND 1 // Intel GPU doesn't have full 32 bits precision in same cases, causes overflow #define LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND 1 `; case "nvidia": return glsl`\ #define NVIDIA_GPU // Nvidia optimizes away the calculation necessary for emulated fp64 #define LUMA_FP64_CODE_ELIMINATION_WORKAROUND 1 `; case "intel": return glsl`\ #define INTEL_GPU // Intel optimizes away the calculation necessary for emulated fp64 #define LUMA_FP64_CODE_ELIMINATION_WORKAROUND 1 // Intel's built-in 'tan' function doesn't have acceptable precision #define LUMA_FP32_TAN_PRECISION_WORKAROUND 1 // Intel GPU doesn't have full 32 bits precision in same cases, causes overflow #define LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND 1 `; case "amd": return glsl`\ #define AMD_GPU `; default: return glsl`\ #define DEFAULT_GPU // Prevent driver from optimizing away the calculation necessary for emulated fp64 #define LUMA_FP64_CODE_ELIMINATION_WORKAROUND 1 // Headless Chrome's software shader 'tan' function doesn't have acceptable precision #define LUMA_FP32_TAN_PRECISION_WORKAROUND 1 // If the GPU doesn't have full 32 bits precision, will causes overflow #define LUMA_FP64_HIGH_BITS_OVERFLOW_WORKAROUND 1 `; } } // ../shadertools/src/lib/shader-transpiler/transpile-glsl-shader.ts function transpileGLSLShader(source, stage) { const sourceGLSLVersion = Number(source.match(/^#version[ \t]+(\d+)/m)?.[1] || 100); if (sourceGLSLVersion !== 300) { throw new Error("luma.gl v9 only supports GLSL 3.00 shader sources"); } switch (stage) { case "vertex": source = convertShader(source, ES300_VERTEX_REPLACEMENTS); return source; case "fragment": source = convertShader(source, ES300_FRAGMENT_REPLACEMENTS); return source; default: throw new Error(stage); } } var ES300_REPLACEMENTS = [ // Fix poorly formatted version directive [/^(#version[ \t]+(100|300[ \t]+es))?[ \t]*\n/, "#version 300 es\n"], // The individual `texture...()` functions were replaced with `texture()` overloads [/\btexture(2D|2DProj|Cube)Lod(EXT)?\(/g, "textureLod("], [/\btexture(2D|2DProj|Cube)(EXT)?\(/g, "texture("] ]; var ES300_VERTEX_REPLACEMENTS = [ ...ES300_REPLACEMENTS, // `attribute` keyword replaced with `in` [makeVariableTextRegExp("attribute"), "in $1"], // `varying` keyword replaced with `out` [makeVariableTextRegExp("varying"), "out $1"] ]; var ES300_FRAGMENT_REPLACEMENTS = [ ...ES300_REPLACEMENTS, // `varying` keyword replaced with `in` [makeVariableTextRegExp("varying"), "in $1"] ]; function convertShader(source, replacements) { for (const [pattern, replacement] of replacements) { source = source.replace(pattern, replacement); } return source; } function makeVariableTextRegExp(qualifier) { return new RegExp(`\\b${qualifier}[ \\t]+(\\w+[ \\t]+\\w+(\\[\\w+\\])?;)`, "g"); } // ../shadertools/src/lib/shader-assembly/shader-hooks.ts function getShaderHooks(hookFunctions, hookInjections) { let result = ""; for (const hookName in hookFunctions) { const hookFunction = hookFunctions[hookName]; result += `void ${hookFunction.signature} { `; if (hookFunction.header) { result += ` ${hookFunction.header}`; } if (hookInjections[hookName]) { const injections = hookInjections[hookName]; injections.sort((a, b) => a.order - b.order); for (const injection of injections) { result += ` ${injection.injection} `; } } if (hookFunction.footer) { result += ` ${hookFunction.footer}`; } result += "}\n"; } return result; } function normalizeShaderHooks(hookFunctions) { const result = { vertex: {}, fragment: {} }; for (const hookFunction of hookFunctions) { let opts; let hook; if (typeof hookFunction !== "string") { opts = hookFunction; hook = opts.hook; } else { opts = {}; hook = hookFunction; } hook = hook.trim(); const [shaderStage, signature] = hook.split(":"); const name = hook.replace(/\(.+/, ""); const normalizedHook = Object.assign(opts, { signature }); switch (shaderStage) { case "vs": result.vertex[name] = normalizedHook; break; case "fs": result.fragment[name] = normalizedHook; break; default: throw new Error(shaderStage); } } return result; } // ../shadertools/src/lib/glsl-utils/get-shader-info.ts function getShaderInfo(source, defaultName) { return { name: getShaderName(source, defaultName), language: "glsl", version: getShaderVersion(source) }; } function getShaderName(shader, defaultName = "unnamed") { const SHADER_NAME_REGEXP = /#define[^\S\r\n]*SHADER_NAME[^\S\r\n]*([A-Za-z0-9_-]+)\s*/; const match = SHADER_NAME_REGEXP.exec(shader); return match ? match[1] : defaultName; } function getShaderVersion(source) { let version = 100; const words = source.match(/[^\s]+/g); if (words && words.length >= 2 && words[0] === "#version") { const parsedVersion = parseInt(words[1], 10); if (Number.isFinite(parsedVersion)) { version = parsedVersion; } } if (version !== 100 && version !== 300) { throw new Error(`Invalid GLSL version ${version}`); } return version; } // ../shadertools/src/lib/shader-assembly/assemble-shaders.ts var INJECT_SHADER_DECLARATIONS = ` ${DECLARATION_INJECT_MARKER} `; var FRAGMENT_SHADER_PROLOGUE = glsl`\ precision highp float; `; function assembleShaderWGSL(options) { const modules = resolveModules(options.modules || []); return { source: assembleWGSLShader(options.platformInfo, { ...options, source: options.source, stage: "vertex", modules }), getUniforms: assembleGetUniforms(modules) }; } function assembleShaderPairWGSL(options) { const modules = resolveModules(options.modules || []); return { vs: assembleWGSLShader(options.platformInfo, { ...options, source: options.vs, stage: "vertex", modules }), fs: assembleWGSLShader(options.platformInfo, { ...options, source: options.fs, stage: "fragment", modules }), getUniforms: assembleGetUniforms(modules) }; } function assembleShaderPairGLSL(options) { const { vs, fs } = options; const modules = resolveModules(options.modules || []); return { vs: assembleGLSLShader(options.platformInfo, { ...options, source: vs, stage: "vertex", modules }), fs: assembleGLSLShader(options.platformInfo, { ...options, source: fs, stage: "fragment", modules }), getUniforms: assembleGetUniforms(modules) }; } function assembleWGSLShader(platformInfo, options) { const { // id, source, stage, modules, // defines = {}, hookFunctions = [], inject = {}, log: log6 } = options; assert(typeof source === "string", "shader source must be a string"); const coreSource = source; let assembledSource = ""; const hookFunctionMap = normalizeShaderHooks(hookFunctions); const hookInjections = {}; const declInjections = {}; const mainInjections = {}; for (const key in inject) { const injection = typeof inject[key] === "string" ? { injection: inject[key], order: 0 } : inject[key]; const match = /^(v|f)s:(#)?([\w-]+)$/.exec(key); if (match) { const hash = match[2]; const name = match[3]; if (hash) { if (name === "decl") { declInjections[key] = [injection]; } else { mainInjections[key] = [injection]; } } else { hookInjections[key] = [injection]; } } else { mainInjections[key] = [injection]; } } const modulesToInject = platformInfo.type !== "webgpu" ? modules : []; for (const module of modulesToInject) { if (log6) { module.checkDeprecations(coreSource, log6); } const moduleSource = module.getModuleSource(stage, "wgsl"); assembledSource += moduleSource; const injections = module.injections[stage]; for (const key in injections) { const match = /^(v|f)s:#([\w-]+)$/.exec(key); if (match) { const name = match[2]; const injectionType = name === "decl" ? declInjections : mainInjections; injectionType[key] = injectionType[key] || []; injectionType[key].push(injections[key]); } else { hookInjections[key] = hookInjections[key] || []; hookInjections[key].push(injections[key]); } } } assembledSource += INJECT_SHADER_DECLARATIONS; assembledSource = injectShader(assembledSource, stage, declInjections); assembledSource += getShaderHooks(hookFunctionMap[stage], hookInjections); assembledSource += coreSource; assembledSource = injectShader(assembledSource, stage, mainInjections); return assembledSource; } function assembleGLSLShader(platformInfo, options) { const { id, source, stage, language = "glsl", modules, defines = {}, hookFunctions = [], inject = {}, prologue = true, log: log6 } = options; assert(typeof source === "string", "shader source must be a string"); const sourceVersion = language === "glsl" ? getShaderInfo(source).version : -1; const targetVersion = platformInfo.shaderLanguageVersion; const sourceVersionDirective = sourceVersion === 100 ? "#version 100" : "#version 300 es"; const sourceLines = source.split("\n"); const coreSource = sourceLines.slice(1).join("\n"); const allDefines = {}; modules.forEach((module) => { Object.assign(allDefines, module.getDefines()); }); Object.assign(allDefines, defines); let assembledSource = ""; switch (language) { case "wgsl": break; case "glsl": assembledSource = prologue ? `${sourceVersionDirective} // ----- PROLOGUE ------------------------- ${getShaderNameDefine({ id, source, stage })} ${`#define SHADER_TYPE_${stage.toUpperCase()}`} ${getPlatformShaderDefines(platformInfo)} ${stage === "fragment" ? FRAGMENT_SHADER_PROLOGUE : ""} // ----- APPLICATION DEFINES ------------------------- ${getApplicationDefines(allDefines)} ` : `${sourceVersionDirective} `; break; } const hookFunctionMap = normalizeShaderHooks(hookFunctions); const hookInjections = {}; const declInjections = {}; const mainInjections = {}; for (const key in inject) { const injection = typeof inject[key] === "string" ? { injection: inject[key], order: 0 } : inject[key]; const match = /^(v|f)s:(#)?([\w-]+)$/.exec(key); if (match) { const hash = match[2]; const name = match[3]; if (hash) { if (name === "decl") { declInjections[key] = [injection]; } else { mainInjections[key] = [injection]; } } else { hookInjections[key] = [injection]; } } else { mainInjections[key] = [injection]; } } for (const module of modules) { if (log6) { module.checkDeprecations(coreSource, log6); } const moduleSource = module.getModuleSource(stage); assembledSource += moduleSource; const injections = module.injections[stage]; for (const key in injections) { const match = /^(v|f)s:#([\w-]+)$/.exec(key); if (match) { const name = match[2]; const injectionType = name === "decl" ? declInjections : mainInjections; injectionType[key] = injectionType[key] || []; injectionType[key].push(injections[key]); } else { hookInjections[key] = hookInjections[key] || []; hookInjections[key].push(injections[key]); } } } assembledSource += "// ----- MAIN SHADER SOURCE -------------------------"; assembledSource += INJECT_SHADER_DECLARATIONS; assembledSource = injectShader(assembledSource, stage, declInjections); assembledSource += getShaderHooks(hookFunctionMap[stage], hookInjections); assembledSource += coreSource; assembledSource = injectShader(assembledSource, stage, mainInjections); if (language === "glsl" && sourceVersion !== targetVersion) { assembledSource = transpileGLSLShader(assembledSource, stage); } return assembledSource.trim(); } function assembleGetUniforms(modules) { return function getUniforms(opts) { const uniforms = {}; for (const module of modules) { const moduleUniforms = module.getUniforms(opts, uniforms); Object.assign(uniforms, moduleUniforms); } return uniforms; }; } function getShaderNameDefine(options) { const { id, source, stage } = options; const injectShaderName = id && source.indexOf("SHADER_NAME") === -1; return injectShaderName ? ` #define SHADER_NAME ${id}_${stage} ` : ""; } function getApplicationDefines(defines = {}) { let sourceText = ""; for (const define in defines) { const value = defines[define]; if (value || Number.isFinite(value)) { sourceText += `#define ${define.toUpperCase()} ${defines[define]} `; } } return sourceText; } // ../shadertools/src/lib/shader-assembler.ts var _ShaderAssembler = class { /** Hook functions */ _hookFunctions = []; /** Shader modules */ _defaultModules = []; /** * A default shader assembler instance - the natural place to register default modules and hooks * @returns */ static getDefaultShaderAssembler() { _ShaderAssembler.defaultShaderAssembler = _ShaderAssembler.defaultShaderAssembler || new _ShaderAssembler(); return _ShaderAssembler.defaultShaderAssembler; } /** * Add a default module that does not have to be provided with every call to assembleShaders() */ addDefaultModule(module) { if (!this._defaultModules.find( (m) => m.name === (typeof module === "string" ? module : module.name) )) { this._defaultModules.push(module); } } /** * Remove a default module */ removeDefaultModule(module) { const moduleName = typeof module === "string" ? module : module.name; this._defaultModules = this._defaultModules.filter((m) => m.name !== moduleName); } /** * Register a shader hook * @param hook * @param opts */ addShaderHook(hook, opts) { if (opts) { hook = Object.assign(opts, { hook }); } this._hookFunctions.push(hook); } /** * Assemble a pair of shaders into a single shader program * @param platformInfo * @param props * @returns */ assembleShader(props) { const modules = this._getModuleList(props.modules); const hookFunctions = this._hookFunctions; const options = selectShaders(props); const assembled = assembleShaderWGSL({ platformInfo: props.platformInfo, ...options, modules, hookFunctions }); return { ...assembled, modules }; } /** * Assemble a pair of shaders into a single shader program * @param platformInfo * @param props * @returns */ assembleShaderPair(props) { const options = selectShaders(props); const modules = this._getModuleList(props.modules); const hookFunctions = this._hookFunctions; const { platformInfo } = props; const isWGSL = props.platformInfo.shaderLanguage === "wgsl"; const assembled = isWGSL ? assembleShaderPairWGSL({ platformInfo, ...options, modules, hookFunctions }) : assembleShaderPairGLSL({ platformInfo, ...options, modules, hookFunctions }); return { ...assembled, modules }; } /** * Dedupe and combine with default modules */ _getModuleList(appModules = []) { const modules = new Array( this._defaultModules.length + appModules.length ); const seen = {}; let count = 0; for (let i = 0, len = this._defaultModules.length; i < len; ++i) { const module = this._defaultModules[i]; const name = module.name; modules[count++] = module; seen[name] = true; } for (let i = 0, len = appModules.length; i < len; ++i) { const module = appModules[i]; const name = module.name; if (!seen[name]) { modules[count++] = module; seen[name] = true; } } modules.length = count; return ShaderModuleInstance.instantiateModules(modules); } }; var ShaderAssembler = _ShaderAssembler; /** Default ShaderAssembler instance */ __publicField(ShaderAssembler, "defaultShaderAssembler"); // ../shadertools/src/lib/glsl-utils/shader-utils.ts var FS_GLES = glsl`\ out vec4 transform_output; void main() { transform_output = vec4(0); }`; var FS300 = `#version 300 es ${FS_GLES}`; function getPassthroughFS(options) { const { input, inputChannels, output } = options || {}; if (!input) { return FS300; } if (!inputChannels) { throw new Error("inputChannels"); } const inputType = channelCountToType(inputChannels); const outputValue = convertToVec4(input, inputChannels); return `#version 300 es in ${inputType} ${input}; out vec4 ${output}; void main() { ${output} = ${outputValue}; }`; } function channelCountToType(channels) { switch (channels) { case 1: return "float"; case 2: return "vec2"; case 3: return "vec3"; case 4: return "vec4"; default: throw new Error(`invalid channels: ${channels}`); } } function convertToVec4(variable, channels) { switch (channels) { case 1: return `vec4(${variable}, 0.0, 0.0, 1.0)`; case 2: return `vec4(${variable}, 0.0, 1.0)`; case 3: return `vec4(${variable}, 1.0)`; case 4: return variable; default: throw new Error(`invalid channels: ${channels}`); } } // ../shadertools/src/lib/wgsl/get-shader-layout-wgsl.ts var import_core4 = __toESM(require_core(), 1); // ../../node_modules/wgsl_reflect/wgsl_reflect.module.js var ParseContext = class { constructor() { this.constants = /* @__PURE__ */ new Map(); this.aliases = /* @__PURE__ */ new Map(); this.structs = /* @__PURE__ */ new Map(); } }; var Node = class { constructor() { } get isAstNode() { return true; } get astNodeType() { return ""; } evaluate(context) { throw new Error("Cannot evaluate node"); } evaluateString(context) { return this.evaluate(context).toString(); } search(callback) { } searchBlock(block, callback) { if (block) { callback(_BlockStart.instance); for (const node of block) { if (node instanceof Array) { this.searchBlock(node, callback); } else { node.search(callback); } } callback(_BlockEnd.instance); } } }; var _BlockStart = class extends Node { }; _BlockStart.instance = new _BlockStart(); var _BlockEnd = class extends Node { }; _BlockEnd.instance = new _BlockEnd(); var Statement = class extends Node { constructor() { super(); } }; var Function = class extends Statement { constructor(name, args, returnType, body, startLine, endLine) { super(); this.calls = /* @__PURE__ */ new Set(); this.name = name; this.args = args; this.returnType = returnType; this.body = body; this.startLine = startLine; this.endLine = endLine; } get astNodeType() { return "function"; } search(callback) { this.searchBlock(this.body, callback); } }; var StaticAssert = class extends Statement { constructor(expression) { super(); this.expression = expression; } get astNodeType() { return "staticAssert"; } search(callback) { this.expression.search(callback); } }; var While = class extends Statement { constructor(condition, body) { super(); this.condition = condition; this.body = body; } get astNodeType() { return "while"; } search(callback) { this.condition.search(callback); this.searchBlock(this.body, callback); } }; var Continuing = class extends Statement { constructor(body) { super(); this.body = body; } get astNodeType() { return "continuing"; } search(callback) { this.searchBlock(this.body, callback); } }; var For = class extends Statement { constructor(init, condition, increment, body) { super(); this.init = init; this.condition = condition; this.increment = increment; this.body = body; } get astNodeType() { return "for"; } search(callback) { var _a2, _b, _c; (_a2 = this.init) === null || _a2 === void 0 ? void 0 : _a2.search(callback); (_b = this.condition) === null || _b === void 0 ? void 0 : _b.search(callback); (_c = this.increment) === null || _c === void 0 ? void 0 : _c.search(callback); this.searchBlock(this.body, callback); } }; var Var = class extends Statement { constructor(name, type, storage, access, value) { super(); this.name = name; this.type = type; this.storage = storage; this.access = access; this.value = value; } get astNodeType() { return "var"; } search(callback) { var _a2; callback(this); (_a2 = this.value) === null || _a2 === void 0 ? void 0 : _a2.search(callback); } }; var Override = class extends Statement { constructor(name, type, value) { super(); this.name = name; this.type = type; this.value = value; } get astNodeType() { return "override"; } search(callback) { var _a2; (_a2 = this.value) === null || _a2 === void 0 ? void 0 : _a2.search(callback); } }; var Let = class extends Statement { constructor(name, type, storage, access, value) { super(); this.name = name; this.type = type; this.storage = storage; this.access = access; this.value = value; } get astNodeType() { return "let"; } search(callback) { var _a2; callback(this); (_a2 = this.value) === null || _a2 === void 0 ? void 0 : _a2.search(callback); } }; var Const = class extends Statement { constructor(name, type, storage, access, value) { super(); this.name = name; this.type = type; this.storage = storage; this.access = access; this.value = value; } get astNodeType() { return "const"; } evaluate(context) { return this.value.evaluate(context); } search(callback) { var _a2; callback(this); (_a2 = this.value) === null || _a2 === void 0 ? void 0 : _a2.search(callback); } }; var IncrementOperator; (function(IncrementOperator2) { IncrementOperator2["increment"] = "++"; IncrementOperator2["decrement"] = "--"; })(IncrementOperator || (IncrementOperator = {})); (function(IncrementOperator2) { function parse(val) { const key = val; if (key == "parse") throw new Error("Invalid value for IncrementOperator"); return IncrementOperator2[key]; } IncrementOperator2.parse = parse; })(IncrementOperator || (IncrementOperator = {})); var Increment = class extends Statement { constructor(operator, variable) { super(); this.operator = operator; this.variable = variable; } get astNodeType() { return "increment"; } search(callback) { this.variable.search(callback); } }; var AssignOperator; (function(AssignOperator2) { AssignOperator2["assign"] = "="; AssignOperator2["addAssign"] = "+="; AssignOperator2["subtractAssin"] = "-="; AssignOperator2["multiplyAssign"] = "*="; AssignOperator2["divideAssign"] = "/="; AssignOperator2["moduloAssign"] = "%="; AssignOperator2["andAssign"] = "&="; AssignOperator2["orAssign"] = "|="; AssignOperator2["xorAssign"] = "^="; AssignOperator2["shiftLeftAssign"] = "<<="; AssignOperator2["shiftRightAssign"] = ">>="; })(AssignOperator || (AssignOperator = {})); (function(AssignOperator2) { function parse(val) { const key = val; if (key == "parse") { throw new Error("Invalid value for AssignOperator"); } return key; } AssignOperator2.parse = parse; })(AssignOperator || (AssignOperator = {})); var Assign = class extends Statement { constructor(operator, variable, value) { super(); this.operator = operator; this.variable = variable; this.value = value; } get astNodeType() { return "assign"; } search(callback) { this.variable.search(callback); this.value.search(callback); } }; var Call = class extends Statement { constructor(name, args) { super(); this.name = name; this.args = args; } get astNodeType() { return "call"; } search(callback) { for (const node of this.args) { node.search(callback); } callback(this); } }; var Loop = class extends Statement { constructor(body, continuing) { super(); this.body = body; this.continuing = continuing; } get astNodeType() { return "loop"; } }; var Switch = class extends Statement { constructor(condition, body) { super(); this.condition = condition; this.body = body; } get astNodeType() { return "body"; } }; var If = class extends Statement { constructor(condition, body, elseif, _else) { super(); this.condition = condition; this.body = body; this.elseif = elseif; this.else = _else; } get astNodeType() { return "if"; } search(callback) { this.condition.search(callback); this.searchBlock(this.body, callback); this.searchBlock(this.elseif, callback); this.searchBlock(this.else, callback); } }; var Return = class extends Statement { constructor(value) { super(); this.value = value; } get astNodeType() { return "return"; } search(callback) { var _a2; (_a2 = this.value) === null || _a2 === void 0 ? void 0 : _a2.search(callback); } }; var Enable = class extends Statement { constructor(name) { super(); this.name = name; } get astNodeType() { return "enable"; } }; var Requires = class extends Statement { constructor(extensions) { super(); this.extensions = extensions; } get astNodeType() { return "requires"; } }; var Diagnostic = class extends Statement { constructor(severity, rule) { super(); this.severity = severity; this.rule = rule; } get astNodeType() { return "diagnostic"; } }; var Alias = class extends Statement { constructor(name, type) { super(); this.name = name; this.type = type; } get astNodeType() { return "alias"; } }; var Discard = class extends Statement { constructor() { super(); } get astNodeType() { return "discard"; } }; var Break = class extends Statement { constructor() { super(); } get astNodeType() { return "break"; } }; var Continue = class extends Statement { constructor() { super(); } get astNodeType() { return "continue"; } }; var Type = class extends Statement { constructor(name) { super(); this.name = name; } get astNodeType() { return "type"; } get isStruct() { return false; } get isArray() { return false; } }; var Struct = class extends Type { constructor(name, members, startLine, endLine) { super(name); this.members = members; this.startLine = startLine; this.endLine = endLine; } get astNodeType() { return "struct"; } get isStruct() { return true; } /// Return the index of the member with the given name, or -1 if not found. getMemberIndex(name) { for (let i = 0; i < this.members.length; i++) { if (this.members[i].name == name) return i; } return -1; } }; var TemplateType = class extends Type { constructor(name, format, access) { super(name); this.format = format; this.access = access; } get astNodeType() { return "template"; } }; var PointerType = class extends Type { constructor(name, storage, type, access) { super(name); this.storage = storage; this.type = type; this.access = access; } get astNodeType() { return "pointer"; } }; var ArrayType = class extends Type { constructor(name, attributes, format, count) { super(name); this.attributes = attributes; this.format = format; this.count = count; } get astNodeType() { return "array"; } get isArray() { return true; } }; var SamplerType = class extends Type { constructor(name, format, access) { super(name); this.format = format; this.access = access; } get astNodeType() { return "sampler"; } }; var Expression = class extends Node { constructor() { super(); } }; var StringExpr = class extends Expression { constructor(value) { super(); this.value = value; } get astNodeType() { return "stringExpr"; } toString() { return this.value; } evaluateString() { return this.value; } }; var CreateExpr = class extends Expression { constructor(type, args) { super(); this.type = type; this.args = args; } get astNodeType() { return "createExpr"; } search(callback) { callback(this); for (const node of this.args) { node.search(callback); } } }; var CallExpr = class extends Expression { constructor(name, args) { super(); this.name = name; this.args = args; } get astNodeType() { return "callExpr"; } evaluate(context) { switch (this.name) { case "abs": return Math.abs(this.args[0].evaluate(context)); case "acos": return Math.acos(this.args[0].evaluate(context)); case "acosh": return Math.acosh(this.args[0].evaluate(context)); case "asin": return Math.asin(this.args[0].evaluate(context)); case "asinh": return Math.asinh(this.args[0].evaluate(context)); case "atan": return Math.atan(this.args[0].evaluate(context)); case "atan2": return Math.atan2(this.args[0].evaluate(context), this.args[1].evaluate(context)); case "atanh": return Math.atanh(this.args[0].evaluate(context)); case "ceil": return Math.ceil(this.args[0].evaluate(context)); case "clamp": return Math.min(Math.max(this.args[0].evaluate(context), this.args[1].evaluate(context)), this.args[2].evaluate(context)); case "cos": return Math.cos(this.args[0].evaluate(context)); case "degrees": return this.args[0].evaluate(context) * 180 / Math.PI; case "distance": return Math.sqrt(Math.pow(this.args[0].evaluate(context) - this.args[1].evaluate(context), 2)); case "dot": case "exp": return Math.exp(this.args[0].evaluate(context)); case "exp2": return Math.pow(2, this.args[0].evaluate(context)); case "floor": return Math.floor(this.args[0].evaluate(context)); case "fma": return this.args[0].evaluate(context) * this.args[1].evaluate(context) + this.args[2].evaluate(context); case "fract": return this.args[0].evaluate(context) - Math.floor(this.args[0].evaluate(context)); case "inverseSqrt": return 1 / Math.sqrt(this.args[0].evaluate(context)); case "log": return Math.log(this.args[0].evaluate(context)); case "log2": return Math.log2(this.args[0].evaluate(context)); case "max": return Math.max(this.args[0].evaluate(context), this.args[1].evaluate(context)); case "min": return Math.min(this.args[0].evaluate(context), this.args[1].evaluate(context)); case "mix": return this.args[0].evaluate(context) * (1 - this.args[2].evaluate(context)) + this.args[1].evaluate(context) * this.args[2].evaluate(context); case "modf": return this.args[0].evaluate(context) - Math.floor(this.args[0].evaluate(context)); case "pow": return Math.pow(this.args[0].evaluate(context), this.args[1].evaluate(context)); case "radians": return this.args[0].evaluate(context) * Math.PI / 180; case "round": return Math.round(this.args[0].evaluate(context)); case "sign": return Math.sign(this.args[0].evaluate(context)); case "sin": return Math.sin(this.args[0].evaluate(context)); case "sinh": return Math.sinh(this.args[0].evaluate(context)); case "saturate": return Math.min(Math.max(this.args[0].evaluate(context), 0), 1); case "smoothstep": return this.args[0].evaluate(context) * this.args[0].evaluate(context) * (3 - 2 * this.args[0].evaluate(context)); case "sqrt": return Math.sqrt(this.args[0].evaluate(context)); case "step": return this.args[0].evaluate(context) < this.args[1].evaluate(context) ? 0 : 1; case "tan": return Math.tan(this.args[0].evaluate(context)); case "tanh": return Math.tanh(this.args[0].evaluate(context)); case "trunc": return Math.trunc(this.args[0].evaluate(context)); default: throw new Error("Non const function: " + this.name); } } search(callback) { for (const node of this.args) { node.search(callback); } callback(this); } }; var VariableExpr = class extends Expression { constructor(name) { super(); this.name = name; } get astNodeType() { return "varExpr"; } search(callback) { callback(this); if (this.postfix) { this.postfix.search(callback); } } evaluate(context) { const constant = context.constants.get(this.name); if (!constant) { throw new Error("Cannot evaluate node"); } return constant.evaluate(context); } }; var ConstExpr = class extends Expression { constructor(name, initializer) { super(); this.name = name; this.initializer = initializer; } get astNodeType() { return "constExpr"; } evaluate(context) { var _a2, _b; if (this.initializer instanceof CreateExpr) { const property = (_a2 = this.postfix) === null || _a2 === void 0 ? void 0 : _a2.evaluateString(context); const type = (_b = this.initializer.type) === null || _b === void 0 ? void 0 : _b.name; const struct = context.structs.get(type); const memberIndex = struct === null || struct === void 0 ? void 0 : struct.getMemberIndex(property); if (memberIndex != -1) { const value = this.initializer.args[memberIndex].evaluate(context); return value; } console.log(memberIndex); } return this.initializer.evaluate(context); } search(callback) { this.initializer.search(callback); } }; var LiteralExpr = class extends Expression { constructor(value) { super(); this.value = value; } get astNodeType() { return "literalExpr"; } evaluate() { return this.value; } }; var BitcastExpr = class extends Expression { constructor(type, value) { super(); this.type = type; this.value = value; } get astNodeType() { return "bitcastExpr"; } search(callback) { this.value.search(callback); } }; var TypecastExpr = class extends Expression { constructor(type, args) { super(); this.type = type; this.args = args; } get astNodeType() { return "typecastExpr"; } evaluate(context) { return this.args[0].evaluate(context); } search(callback) { this.searchBlock(this.args, callback); } }; var GroupingExpr = class extends Expression { constructor(contents) { super(); this.contents = contents; } get astNodeType() { return "groupExpr"; } evaluate(context) { return this.contents[0].evaluate(context); } search(callback) { this.searchBlock(this.contents, callback); } }; var ArrayIndex = class extends Expression { constructor(index2) { super(); this.index = index2; } search(callback) { this.index.search(callback); } }; var Operator = class extends Expression { constructor() { super(); } }; var UnaryOperator = class extends Operator { constructor(operator, right) { super(); this.operator = operator; this.right = right; } get astNodeType() { return "unaryOp"; } evaluate(context) { switch (this.operator) { case "+": return this.right.evaluate(context); case "-": return -this.right.evaluate(context); case "!": return this.right.evaluate(context) ? 0 : 1; case "~": return ~this.right.evaluate(context); default: throw new Error("Unknown unary operator: " + this.operator); } } search(callback) { this.right.search(callback); } }; var BinaryOperator = class extends Operator { constructor(operator, left, right) { super(); this.operator = operator; this.left = left; this.right = right; } get astNodeType() { return "binaryOp"; } evaluate(context) { switch (this.operator) { case "+": return this.left.evaluate(context) + this.right.evaluate(context); case "-": return this.left.evaluate(context) - this.right.evaluate(context); case "*": return this.left.evaluate(context) * this.right.evaluate(context); case "/": return this.left.evaluate(context) / this.right.evaluate(context); case "%": return this.left.evaluate(context) % this.right.evaluate(context); case "==": return this.left.evaluate(context) == this.right.evaluate(context) ? 1 : 0; case "!=": return this.left.evaluate(context) != this.right.evaluate(context) ? 1 : 0; case "<": return this.left.evaluate(context) < this.right.evaluate(context) ? 1 : 0; case ">": return this.left.evaluate(context) > this.right.evaluate(context) ? 1 : 0; case "<=": return this.left.evaluate(context) <= this.right.evaluate(context) ? 1 : 0; case ">=": return this.left.evaluate(context) >= this.right.evaluate(context) ? 1 : 0; case "&&": return this.left.evaluate(context) && this.right.evaluate(context) ? 1 : 0; case "||": return this.left.evaluate(context) || this.right.evaluate(context) ? 1 : 0; default: throw new Error(`Unknown operator ${this.operator}`); } } search(callback) { this.left.search(callback); this.right.search(callback); } }; var SwitchCase = class extends Node { constructor() { super(); } }; var Case = class extends SwitchCase { constructor(selector, body) { super(); this.selector = selector; this.body = body; } get astNodeType() { return "case"; } search(callback) { this.searchBlock(this.body, callback); } }; var Default = class extends SwitchCase { constructor(body) { super(); this.body = body; } get astNodeType() { return "default"; } search(callback) { this.searchBlock(this.body, callback); } }; var Argument = class extends Node { constructor(name, type, attributes) { super(); this.name = name; this.type = type; this.attributes = attributes; } get astNodeType() { return "argument"; } }; var ElseIf = class extends Node { constructor(condition, body) { super(); this.condition = condition; this.body = body; } get astNodeType() { return "elseif"; } search(callback) { this.condition.search(callback); this.searchBlock(this.body, callback); } }; var Member = class extends Node { constructor(name, type, attributes) { super(); this.name = name; this.type = type; this.attributes = attributes; } get astNodeType() { return "member"; } }; var Attribute = class extends Node { constructor(name, value) { super(); this.name = name; this.value = value; } get astNodeType() { return "attribute"; } }; var _a; var TokenClass; (function(TokenClass2) { TokenClass2[TokenClass2["token"] = 0] = "token"; TokenClass2[TokenClass2["keyword"] = 1] = "keyword"; TokenClass2[TokenClass2["reserved"] = 2] = "reserved"; })(TokenClass || (TokenClass = {})); var TokenType = class { constructor(name, type, rule) { this.name = name; this.type = type; this.rule = rule; } toString() { return this.name; } }; var TokenTypes = class { }; _a = TokenTypes; TokenTypes.none = new TokenType("", TokenClass.reserved, ""); TokenTypes.eof = new TokenType("EOF", TokenClass.token, ""); TokenTypes.reserved = { asm: new TokenType("asm", TokenClass.reserved, "asm"), bf16: new TokenType("bf16", TokenClass.reserved, "bf16"), do: new TokenType("do", TokenClass.reserved, "do"), enum: new TokenType("enum", TokenClass.reserved, "enum"), f16: new TokenType("f16", TokenClass.reserved, "f16"), f64: new TokenType("f64", TokenClass.reserved, "f64"), handle: new TokenType("handle", TokenClass.reserved, "handle"), i8: new TokenType("i8", TokenClass.reserved, "i8"), i16: new TokenType("i16", TokenClass.reserved, "i16"), i64: new TokenType("i64", TokenClass.reserved, "i64"), mat: new TokenType("mat", TokenClass.reserved, "mat"), premerge: new TokenType("premerge", TokenClass.reserved, "premerge"), regardless: new TokenType("regardless", TokenClass.reserved, "regardless"), typedef: new TokenType("typedef", TokenClass.reserved, "typedef"), u8: new TokenType("u8", TokenClass.reserved, "u8"), u16: new TokenType("u16", TokenClass.reserved, "u16"), u64: new TokenType("u64", TokenClass.reserved, "u64"), unless: new TokenType("unless", TokenClass.reserved, "unless"), using: new TokenType("using", TokenClass.reserved, "using"), vec: new TokenType("vec", TokenClass.reserved, "vec"), void: new TokenType("void", TokenClass.reserved, "void") }; TokenTypes.keywords = { array: new TokenType("array", TokenClass.keyword, "array"), atomic: new TokenType("atomic", TokenClass.keyword, "atomic"), bool: new TokenType("bool", TokenClass.keyword, "bool"), f32: new TokenType("f32", TokenClass.keyword, "f32"), i32: new TokenType("i32", TokenClass.keyword, "i32"), mat2x2: new TokenType("mat2x2", TokenClass.keyword, "mat2x2"), mat2x3: new TokenType("mat2x3", TokenClass.keyword, "mat2x3"), mat2x4: new TokenType("mat2x4", TokenClass.keyword, "mat2x4"), mat3x2: new TokenType("mat3x2", TokenClass.keyword, "mat3x2"), mat3x3: new TokenType("mat3x3", TokenClass.keyword, "mat3x3"), mat3x4: new TokenType("mat3x4", TokenClass.keyword, "mat3x4"), mat4x2: new TokenType("mat4x2", TokenClass.keyword, "mat4x2"), mat4x3: new TokenType("mat4x3", TokenClass.keyword, "mat4x3"), mat4x4: new TokenType("mat4x4", TokenClass.keyword, "mat4x4"), ptr: new TokenType("ptr", TokenClass.keyword, "ptr"), sampler: new TokenType("sampler", TokenClass.keyword, "sampler"), sampler_comparison: new TokenType("sampler_comparison", TokenClass.keyword, "sampler_comparison"), struct: new TokenType("struct", TokenClass.keyword, "struct"), texture_1d: new TokenType("texture_1d", TokenClass.keyword, "texture_1d"), texture_2d: new TokenType("texture_2d", TokenClass.keyword, "texture_2d"), texture_2d_array: new TokenType("texture_2d_array", TokenClass.keyword, "texture_2d_array"), texture_3d: new TokenType("texture_3d", TokenClass.keyword, "texture_3d"), texture_cube: new TokenType("texture_cube", TokenClass.keyword, "texture_cube"), texture_cube_array: new TokenType("texture_cube_array", TokenClass.keyword, "texture_cube_array"), texture_multisampled_2d: new TokenType("texture_multisampled_2d", TokenClass.keyword, "texture_multisampled_2d"), texture_storage_1d: new TokenType("texture_storage_1d", TokenClass.keyword, "texture_storage_1d"), texture_storage_2d: new TokenType("texture_storage_2d", TokenClass.keyword, "texture_storage_2d"), texture_storage_2d_array: new TokenType("texture_storage_2d_array", TokenClass.keyword, "texture_storage_2d_array"), texture_storage_3d: new TokenType("texture_storage_3d", TokenClass.keyword, "texture_storage_3d"), texture_depth_2d: new TokenType("texture_depth_2d", TokenClass.keyword, "texture_depth_2d"), texture_depth_2d_array: new TokenType("texture_depth_2d_array", TokenClass.keyword, "texture_depth_2d_array"), texture_depth_cube: new TokenType("texture_depth_cube", TokenClass.keyword, "texture_depth_cube"), texture_depth_cube_array: new TokenType("texture_depth_cube_array", TokenClass.keyword, "texture_depth_cube_array"), texture_depth_multisampled_2d: new TokenType("texture_depth_multisampled_2d", TokenClass.keyword, "texture_depth_multisampled_2d"), texture_external: new TokenType("texture_external", TokenClass.keyword, "texture_external"), u32: new TokenType("u32", TokenClass.keyword, "u32"), vec2: new TokenType("vec2", TokenClass.keyword, "vec2"), vec3: new TokenType("vec3", TokenClass.keyword, "vec3"), vec4: new TokenType("vec4", TokenClass.keyword, "vec4"), bitcast: new TokenType("bitcast", TokenClass.keyword, "bitcast"), block: new TokenType("block", TokenClass.keyword, "block"), break: new TokenType("break", TokenClass.keyword, "break"), case: new TokenType("case", TokenClass.keyword, "case"), continue: new TokenType("continue", TokenClass.keyword, "continue"), continuing: new TokenType("continuing", TokenClass.keyword, "continuing"), default: new TokenType("default", TokenClass.keyword, "default"), diagnostic: new TokenType("diagnostic", TokenClass.keyword, "diagnostic"), discard: new TokenType("discard", TokenClass.keyword, "discard"), else: new TokenType("else", TokenClass.keyword, "else"), enable: new TokenType("enable", TokenClass.keyword, "enable"), fallthrough: new TokenType("fallthrough", TokenClass.keyword, "fallthrough"), false: new TokenType("false", TokenClass.keyword, "false"), fn: new TokenType("fn", TokenClass.keyword, "fn"), for: new TokenType("for", TokenClass.keyword, "for"), function: new TokenType("function", TokenClass.keyword, "function"), if: new TokenType("if", TokenClass.keyword, "if"), let: new TokenType("let", TokenClass.keyword, "let"), const: new TokenType("const", TokenClass.keyword, "const"), loop: new TokenType("loop", TokenClass.keyword, "loop"), while: new TokenType("while", TokenClass.keyword, "while"), private: new TokenType("private", TokenClass.keyword, "private"), read: new TokenType("read", TokenClass.keyword, "read"), read_write: new TokenType("read_write", TokenClass.keyword, "read_write"), return: new TokenType("return", TokenClass.keyword, "return"), requires: new TokenType("requires", TokenClass.keyword, "requires"), storage: new TokenType("storage", TokenClass.keyword, "storage"), switch: new TokenType("switch", TokenClass.keyword, "switch"), true: new TokenType("true", TokenClass.keyword, "true"), alias: new TokenType("alias", TokenClass.keyword, "alias"), type: new TokenType("type", TokenClass.keyword, "type"), uniform: new TokenType("uniform", TokenClass.keyword, "uniform"), var: new TokenType("var", TokenClass.keyword, "var"), override: new TokenType("override", TokenClass.keyword, "override"), workgroup: new TokenType("workgroup", TokenClass.keyword, "workgroup"), write: new TokenType("write", TokenClass.keyword, "write"), r8unorm: new TokenType("r8unorm", TokenClass.keyword, "r8unorm"), r8snorm: new TokenType("r8snorm", TokenClass.keyword, "r8snorm"), r8uint: new TokenType("r8uint", TokenClass.keyword, "r8uint"), r8sint: new TokenType("r8sint", TokenClass.keyword, "r8sint"), r16uint: new TokenType("r16uint", TokenClass.keyword, "r16uint"), r16sint: new TokenType("r16sint", TokenClass.keyword, "r16sint"), r16float: new TokenType("r16float", TokenClass.keyword, "r16float"), rg8unorm: new TokenType("rg8unorm", TokenClass.keyword, "rg8unorm"), rg8snorm: new TokenType("rg8snorm", TokenClass.keyword, "rg8snorm"), rg8uint: new TokenType("rg8uint", TokenClass.keyword, "rg8uint"), rg8sint: new TokenType("rg8sint", TokenClass.keyword, "rg8sint"), r32uint: new TokenType("r32uint", TokenClass.keyword, "r32uint"), r32sint: new TokenType("r32sint", TokenClass.keyword, "r32sint"), r32float: new TokenType("r32float", TokenClass.keyword, "r32float"), rg16uint: new TokenType("rg16uint", TokenClass.keyword, "rg16uint"), rg16sint: new TokenType("rg16sint", TokenClass.keyword, "rg16sint"), rg16float: new TokenType("rg16float", TokenClass.keyword, "rg16float"), rgba8unorm: new TokenType("rgba8unorm", TokenClass.keyword, "rgba8unorm"), rgba8unorm_srgb: new TokenType("rgba8unorm_srgb", TokenClass.keyword, "rgba8unorm_srgb"), rgba8snorm: new TokenType("rgba8snorm", TokenClass.keyword, "rgba8snorm"), rgba8uint: new TokenType("rgba8uint", TokenClass.keyword, "rgba8uint"), rgba8sint: new TokenType("rgba8sint", TokenClass.keyword, "rgba8sint"), bgra8unorm: new TokenType("bgra8unorm", TokenClass.keyword, "bgra8unorm"), bgra8unorm_srgb: new TokenType("bgra8unorm_srgb", TokenClass.keyword, "bgra8unorm_srgb"), rgb10a2unorm: new TokenType("rgb10a2unorm", TokenClass.keyword, "rgb10a2unorm"), rg11b10float: new TokenType("rg11b10float", TokenClass.keyword, "rg11b10float"), rg32uint: new TokenType("rg32uint", TokenClass.keyword, "rg32uint"), rg32sint: new TokenType("rg32sint", TokenClass.keyword, "rg32sint"), rg32float: new TokenType("rg32float", TokenClass.keyword, "rg32float"), rgba16uint: new TokenType("rgba16uint", TokenClass.keyword, "rgba16uint"), rgba16sint: new TokenType("rgba16sint", TokenClass.keyword, "rgba16sint"), rgba16float: new TokenType("rgba16float", TokenClass.keyword, "rgba16float"), rgba32uint: new TokenType("rgba32uint", TokenClass.keyword, "rgba32uint"), rgba32sint: new TokenType("rgba32sint", TokenClass.keyword, "rgba32sint"), rgba32float: new TokenType("rgba32float", TokenClass.keyword, "rgba32float"), static_assert: new TokenType("static_assert", TokenClass.keyword, "static_assert") // WGSL grammar has a few keywords that have different token names than the strings they // represent. Aliasing them here. /*int32: new TokenType("i32", TokenClass.keyword, "i32"), uint32: new TokenType("u32", TokenClass.keyword, "u32"), float32: new TokenType("f32", TokenClass.keyword, "f32"), pointer: new TokenType("ptr", TokenClass.keyword, "ptr"),*/ }; TokenTypes.tokens = { decimal_float_literal: new TokenType("decimal_float_literal", TokenClass.token, /((-?[0-9]*\.[0-9]+|-?[0-9]+\.[0-9]*)((e|E)(\+|-)?[0-9]+)?f?)|(-?[0-9]+(e|E)(\+|-)?[0-9]+f?)|([0-9]+f)/), hex_float_literal: new TokenType("hex_float_literal", TokenClass.token, /-?0x((([0-9a-fA-F]*\.[0-9a-fA-F]+|[0-9a-fA-F]+\.[0-9a-fA-F]*)((p|P)(\+|-)?[0-9]+f?)?)|([0-9a-fA-F]+(p|P)(\+|-)?[0-9]+f?))/), int_literal: new TokenType("int_literal", TokenClass.token, /-?0x[0-9a-fA-F]+|0i?|-?[1-9][0-9]*i?/), uint_literal: new TokenType("uint_literal", TokenClass.token, /0x[0-9a-fA-F]+u|0u|[1-9][0-9]*u/), ident: new TokenType("ident", TokenClass.token, /[_a-zA-Z][0-9a-zA-Z_]*/), and: new TokenType("and", TokenClass.token, "&"), and_and: new TokenType("and_and", TokenClass.token, "&&"), arrow: new TokenType("arrow ", TokenClass.token, "->"), attr: new TokenType("attr", TokenClass.token, "@"), forward_slash: new TokenType("forward_slash", TokenClass.token, "/"), bang: new TokenType("bang", TokenClass.token, "!"), bracket_left: new TokenType("bracket_left", TokenClass.token, "["), bracket_right: new TokenType("bracket_right", TokenClass.token, "]"), brace_left: new TokenType("brace_left", TokenClass.token, "{"), brace_right: new TokenType("brace_right", TokenClass.token, "}"), colon: new TokenType("colon", TokenClass.token, ":"), comma: new TokenType("comma", TokenClass.token, ","), equal: new TokenType("equal", TokenClass.token, "="), equal_equal: new TokenType("equal_equal", TokenClass.token, "=="), not_equal: new TokenType("not_equal", TokenClass.token, "!="), greater_than: new TokenType("greater_than", TokenClass.token, ">"), greater_than_equal: new TokenType("greater_than_equal", TokenClass.token, ">="), shift_right: new TokenType("shift_right", TokenClass.token, ">>"), less_than: new TokenType("less_than", TokenClass.token, "<"), less_than_equal: new TokenType("less_than_equal", TokenClass.token, "<="), shift_left: new TokenType("shift_left", TokenClass.token, "<<"), modulo: new TokenType("modulo", TokenClass.token, "%"), minus: new TokenType("minus", TokenClass.token, "-"), minus_minus: new TokenType("minus_minus", TokenClass.token, "--"), period: new TokenType("period", TokenClass.token, "."), plus: new TokenType("plus", TokenClass.token, "+"), plus_plus: new TokenType("plus_plus", TokenClass.token, "++"), or: new TokenType("or", TokenClass.token, "|"), or_or: new TokenType("or_or", TokenClass.token, "||"), paren_left: new TokenType("paren_left", TokenClass.token, "("), paren_right: new TokenType("paren_right", TokenClass.token, ")"), semicolon: new TokenType("semicolon", TokenClass.token, ";"), star: new TokenType("star", TokenClass.token, "*"), tilde: new TokenType("tilde", TokenClass.token, "~"), underscore: new TokenType("underscore", TokenClass.token, "_"), xor: new TokenType("xor", TokenClass.token, "^"), plus_equal: new TokenType("plus_equal", TokenClass.token, "+="), minus_equal: new TokenType("minus_equal", TokenClass.token, "-="), times_equal: new TokenType("times_equal", TokenClass.token, "*="), division_equal: new TokenType("division_equal", TokenClass.token, "/="), modulo_equal: new TokenType("modulo_equal", TokenClass.token, "%="), and_equal: new TokenType("and_equal", TokenClass.token, "&="), or_equal: new TokenType("or_equal", TokenClass.token, "|="), xor_equal: new TokenType("xor_equal", TokenClass.token, "^="), shift_right_equal: new TokenType("shift_right_equal", TokenClass.token, ">>="), shift_left_equal: new TokenType("shift_left_equal", TokenClass.token, "<<=") }; TokenTypes.simpleTokens = { "@": _a.tokens.attr, "{": _a.tokens.brace_left, "}": _a.tokens.brace_right, ":": _a.tokens.colon, ",": _a.tokens.comma, "(": _a.tokens.paren_left, ")": _a.tokens.paren_right, ";": _a.tokens.semicolon }; TokenTypes.literalTokens = { "&": _a.tokens.and, "&&": _a.tokens.and_and, "->": _a.tokens.arrow, "/": _a.tokens.forward_slash, "!": _a.tokens.bang, "[": _a.tokens.bracket_left, "]": _a.tokens.bracket_right, "=": _a.tokens.equal, "==": _a.tokens.equal_equal, "!=": _a.tokens.not_equal, ">": _a.tokens.greater_than, ">=": _a.tokens.greater_than_equal, ">>": _a.tokens.shift_right, "<": _a.tokens.less_than, "<=": _a.tokens.less_than_equal, "<<": _a.tokens.shift_left, "%": _a.tokens.modulo, "-": _a.tokens.minus, "--": _a.tokens.minus_minus, ".": _a.tokens.period, "+": _a.tokens.plus, "++": _a.tokens.plus_plus, "|": _a.tokens.or, "||": _a.tokens.or_or, "*": _a.tokens.star, "~": _a.tokens.tilde, "_": _a.tokens.underscore, "^": _a.tokens.xor, "+=": _a.tokens.plus_equal, "-=": _a.tokens.minus_equal, "*=": _a.tokens.times_equal, "/=": _a.tokens.division_equal, "%=": _a.tokens.modulo_equal, "&=": _a.tokens.and_equal, "|=": _a.tokens.or_equal, "^=": _a.tokens.xor_equal, ">>=": _a.tokens.shift_right_equal, "<<=": _a.tokens.shift_left_equal }; TokenTypes.regexTokens = { decimal_float_literal: _a.tokens.decimal_float_literal, hex_float_literal: _a.tokens.hex_float_literal, int_literal: _a.tokens.int_literal, uint_literal: _a.tokens.uint_literal, ident: _a.tokens.ident }; TokenTypes.storage_class = [ _a.keywords.function, _a.keywords.private, _a.keywords.workgroup, _a.keywords.uniform, _a.keywords.storage ]; TokenTypes.access_mode = [ _a.keywords.read, _a.keywords.write, _a.keywords.read_write ]; TokenTypes.sampler_type = [ _a.keywords.sampler, _a.keywords.sampler_comparison ]; TokenTypes.sampled_texture_type = [ _a.keywords.texture_1d, _a.keywords.texture_2d, _a.keywords.texture_2d_array, _a.keywords.texture_3d, _a.keywords.texture_cube, _a.keywords.texture_cube_array ]; TokenTypes.multisampled_texture_type = [ _a.keywords.texture_multisampled_2d ]; TokenTypes.storage_texture_type = [ _a.keywords.texture_storage_1d, _a.keywords.texture_storage_2d, _a.keywords.texture_storage_2d_array, _a.keywords.texture_storage_3d ]; TokenTypes.depth_texture_type = [ _a.keywords.texture_depth_2d, _a.keywords.texture_depth_2d_array, _a.keywords.texture_depth_cube, _a.keywords.texture_depth_cube_array, _a.keywords.texture_depth_multisampled_2d ]; TokenTypes.texture_external_type = [_a.keywords.texture_external]; TokenTypes.any_texture_type = [ ..._a.sampled_texture_type, ..._a.multisampled_texture_type, ..._a.storage_texture_type, ..._a.depth_texture_type, ..._a.texture_external_type ]; TokenTypes.texel_format = [ _a.keywords.r8unorm, _a.keywords.r8snorm, _a.keywords.r8uint, _a.keywords.r8sint, _a.keywords.r16uint, _a.keywords.r16sint, _a.keywords.r16float, _a.keywords.rg8unorm, _a.keywords.rg8snorm, _a.keywords.rg8uint, _a.keywords.rg8sint, _a.keywords.r32uint, _a.keywords.r32sint, _a.keywords.r32float, _a.keywords.rg16uint, _a.keywords.rg16sint, _a.keywords.rg16float, _a.keywords.rgba8unorm, _a.keywords.rgba8unorm_srgb, _a.keywords.rgba8snorm, _a.keywords.rgba8uint, _a.keywords.rgba8sint, _a.keywords.bgra8unorm, _a.keywords.bgra8unorm_srgb, _a.keywords.rgb10a2unorm, _a.keywords.rg11b10float, _a.keywords.rg32uint, _a.keywords.rg32sint, _a.keywords.rg32float, _a.keywords.rgba16uint, _a.keywords.rgba16sint, _a.keywords.rgba16float, _a.keywords.rgba32uint, _a.keywords.rgba32sint, _a.keywords.rgba32float ]; TokenTypes.const_literal = [ _a.tokens.int_literal, _a.tokens.uint_literal, _a.tokens.decimal_float_literal, _a.tokens.hex_float_literal, _a.keywords.true, _a.keywords.false ]; TokenTypes.literal_or_ident = [ _a.tokens.ident, _a.tokens.int_literal, _a.tokens.uint_literal, _a.tokens.decimal_float_literal, _a.tokens.hex_float_literal ]; TokenTypes.element_count_expression = [ _a.tokens.int_literal, _a.tokens.uint_literal, _a.tokens.ident ]; TokenTypes.template_types = [ _a.keywords.vec2, _a.keywords.vec3, _a.keywords.vec4, _a.keywords.mat2x2, _a.keywords.mat2x3, _a.keywords.mat2x4, _a.keywords.mat3x2, _a.keywords.mat3x3, _a.keywords.mat3x4, _a.keywords.mat4x2, _a.keywords.mat4x3, _a.keywords.mat4x4, _a.keywords.atomic, _a.keywords.bitcast, ..._a.any_texture_type ]; TokenTypes.attribute_name = [_a.tokens.ident, _a.keywords.block, _a.keywords.diagnostic]; TokenTypes.assignment_operators = [ _a.tokens.equal, _a.tokens.plus_equal, _a.tokens.minus_equal, _a.tokens.times_equal, _a.tokens.division_equal, _a.tokens.modulo_equal, _a.tokens.and_equal, _a.tokens.or_equal, _a.tokens.xor_equal, _a.tokens.shift_right_equal, _a.tokens.shift_left_equal ]; TokenTypes.increment_operators = [ _a.tokens.plus_plus, _a.tokens.minus_minus ]; var Token = class { constructor(type, lexeme, line) { this.type = type; this.lexeme = lexeme; this.line = line; } toString() { return this.lexeme; } isTemplateType() { return TokenTypes.template_types.indexOf(this.type) != -1; } isArrayType() { return this.type == TokenTypes.keywords.array; } isArrayOrTemplateType() { return this.isArrayType() || this.isTemplateType(); } }; var WgslScanner = class { constructor(source) { this._tokens = []; this._start = 0; this._current = 0; this._line = 1; this._source = source !== null && source !== void 0 ? source : ""; } /// Scan all tokens from the source. scanTokens() { while (!this._isAtEnd()) { this._start = this._current; if (!this.scanToken()) { throw `Invalid syntax at line ${this._line}`; } } this._tokens.push(new Token(TokenTypes.eof, "", this._line)); return this._tokens; } /// Scan a single token from the source. scanToken() { let lexeme = this._advance(); if (lexeme == "\n") { this._line++; return true; } if (this._isWhitespace(lexeme)) { return true; } if (lexeme == "/") { if (this._peekAhead() == "/") { while (lexeme != "\n") { if (this._isAtEnd()) { return true; } lexeme = this._advance(); } this._line++; return true; } else if (this._peekAhead() == "*") { this._advance(); let commentLevel = 1; while (commentLevel > 0) { if (this._isAtEnd()) { return true; } lexeme = this._advance(); if (lexeme == "\n") { this._line++; } else if (lexeme == "*") { if (this._peekAhead() == "/") { this._advance(); commentLevel--; if (commentLevel == 0) { return true; } } } else if (lexeme == "/") { if (this._peekAhead() == "*") { this._advance(); commentLevel++; } } } return true; } } const simpleToken = TokenTypes.simpleTokens[lexeme]; if (simpleToken) { this._addToken(simpleToken); return true; } let matchType = TokenTypes.none; const isAlpha = this._isAlpha(lexeme); const isUnderscore = lexeme === "_"; if (this._isAlphaNumeric(lexeme)) { let nextChar = this._peekAhead(); while (this._isAlphaNumeric(nextChar)) { lexeme += this._advance(); nextChar = this._peekAhead(); } } if (isAlpha) { const matchedType = TokenTypes.keywords[lexeme]; if (matchedType) { this._addToken(matchedType); return true; } } if (isAlpha || isUnderscore) { this._addToken(TokenTypes.tokens.ident); return true; } for (; ; ) { let matchedType = this._findType(lexeme); const nextLexeme = this._peekAhead(); if (lexeme == ">" && (nextLexeme == ">" || nextLexeme == "=")) { let foundLessThan = false; let ti = this._tokens.length - 1; for (let count = 0; count < 5 && ti >= 0; ++count, --ti) { if (this._tokens[ti].type === TokenTypes.tokens.less_than) { if (ti > 0 && this._tokens[ti - 1].isArrayOrTemplateType()) { foundLessThan = true; } break; } } if (foundLessThan) { this._addToken(matchedType); return true; } } if (matchedType === TokenTypes.none) { let lookAheadLexeme = lexeme; let lookAhead = 0; const maxLookAhead = 2; for (let li = 0; li < maxLookAhead; ++li) { lookAheadLexeme += this._peekAhead(li); matchedType = this._findType(lookAheadLexeme); if (matchedType !== TokenTypes.none) { lookAhead = li; break; } } if (matchedType === TokenTypes.none) { if (matchType === TokenTypes.none) { return false; } this._current--; this._addToken(matchType); return true; } lexeme = lookAheadLexeme; this._current += lookAhead + 1; } matchType = matchedType; if (this._isAtEnd()) { break; } lexeme += this._advance(); } if (matchType === TokenTypes.none) { return false; } this._addToken(matchType); return true; } _findType(lexeme) { for (const name in TokenTypes.regexTokens) { const type2 = TokenTypes.regexTokens[name]; if (this._match(lexeme, type2.rule)) { return type2; } } const type = TokenTypes.literalTokens[lexeme]; if (type) { return type; } return TokenTypes.none; } _match(lexeme, rule) { const match = rule.exec(lexeme); return match && match.index == 0 && match[0] == lexeme; } _isAtEnd() { return this._current >= this._source.length; } _isAlpha(c) { return c >= "a" && c <= "z" || c >= "A" && c <= "Z"; } _isAlphaNumeric(c) { return c >= "a" && c <= "z" || c >= "A" && c <= "Z" || c == "_" || c >= "0" && c <= "9"; } _isWhitespace(c) { return c == " " || c == " " || c == "\r"; } _advance(amount = 0) { let c = this._source[this._current]; amount = amount || 0; amount++; this._current += amount; return c; } _peekAhead(offset = 0) { offset = offset || 0; if (this._current + offset >= this._source.length) { return "\0"; } return this._source[this._current + offset]; } _addToken(type) { const text = this._source.substring(this._start, this._current); this._tokens.push(new Token(type, text, this._line)); } }; var WgslParser = class { constructor() { this._tokens = []; this._current = 0; this._currentLine = 0; this._context = new ParseContext(); this._deferArrayCountEval = []; } parse(tokensOrCode) { this._initialize(tokensOrCode); this._deferArrayCountEval.length = 0; const statements = []; while (!this._isAtEnd()) { const statement = this._global_decl_or_directive(); if (!statement) { break; } statements.push(statement); } if (this._deferArrayCountEval.length > 0) { for (const arrayDecl of this._deferArrayCountEval) { const arrayType = arrayDecl["arrayType"]; const countNode = arrayDecl["countNode"]; if (countNode instanceof VariableExpr) { const variable = countNode; const name = variable.name; const constant = this._context.constants.get(name); if (constant) { try { const count = constant.evaluate(this._context); arrayType.count = count; } catch (e) { } } } } this._deferArrayCountEval.length = 0; } return statements; } _initialize(tokensOrCode) { if (tokensOrCode) { if (typeof tokensOrCode == "string") { const scanner = new WgslScanner(tokensOrCode); this._tokens = scanner.scanTokens(); } else { this._tokens = tokensOrCode; } } else { this._tokens = []; } this._current = 0; } _error(token, message) { return { token, message, toString: function() { return `${message}`; } }; } _isAtEnd() { return this._current >= this._tokens.length || this._peek().type == TokenTypes.eof; } _match(types) { if (types instanceof TokenType) { if (this._check(types)) { this._advance(); return true; } return false; } for (let i = 0, l = types.length; i < l; ++i) { const type = types[i]; if (this._check(type)) { this._advance(); return true; } } return false; } _consume(types, message) { if (this._check(types)) { return this._advance(); } throw this._error(this._peek(), message); } _check(types) { if (this._isAtEnd()) { return false; } const tk = this._peek(); if (types instanceof Array) { const t = tk.type; const index2 = types.indexOf(t); return index2 != -1; } return tk.type == types; } _advance() { var _a2, _b; this._currentLine = (_b = (_a2 = this._peek()) === null || _a2 === void 0 ? void 0 : _a2.line) !== null && _b !== void 0 ? _b : -1; if (!this._isAtEnd()) { this._current++; } return this._previous(); } _peek() { return this._tokens[this._current]; } _previous() { return this._tokens[this._current - 1]; } _global_decl_or_directive() { while (this._match(TokenTypes.tokens.semicolon) && !this._isAtEnd()) ; if (this._match(TokenTypes.keywords.alias)) { const type = this._type_alias(); this._consume(TokenTypes.tokens.semicolon, "Expected ';'"); return type; } if (this._match(TokenTypes.keywords.diagnostic)) { const directive = this._diagnostic(); this._consume(TokenTypes.tokens.semicolon, "Expected ';'"); return directive; } if (this._match(TokenTypes.keywords.requires)) { const requires = this._requires_directive(); this._consume(TokenTypes.tokens.semicolon, "Expected ';'"); return requires; } if (this._match(TokenTypes.keywords.enable)) { const enable = this._enable_directive(); this._consume(TokenTypes.tokens.semicolon, "Expected ';'"); return enable; } const attrs = this._attribute(); if (this._check(TokenTypes.keywords.var)) { const _var = this._global_variable_decl(); if (_var != null) { _var.attributes = attrs; } this._consume(TokenTypes.tokens.semicolon, "Expected ';'."); return _var; } if (this._check(TokenTypes.keywords.override)) { const _override = this._override_variable_decl(); if (_override != null) { _override.attributes = attrs; } this._consume(TokenTypes.tokens.semicolon, "Expected ';'."); return _override; } if (this._check(TokenTypes.keywords.let)) { const _let = this._global_let_decl(); if (_let != null) { _let.attributes = attrs; } this._consume(TokenTypes.tokens.semicolon, "Expected ';'."); return _let; } if (this._check(TokenTypes.keywords.const)) { const _const = this._global_const_decl(); if (_const != null) { _const.attributes = attrs; } this._consume(TokenTypes.tokens.semicolon, "Expected ';'."); return _const; } if (this._check(TokenTypes.keywords.struct)) { const _struct = this._struct_decl(); if (_struct != null) { _struct.attributes = attrs; } return _struct; } if (this._check(TokenTypes.keywords.fn)) { const _fn = this._function_decl(); if (_fn != null) { _fn.attributes = attrs; } return _fn; } return null; } _function_decl() { if (!this._match(TokenTypes.keywords.fn)) { return null; } const startLine = this._currentLine; const name = this._consume(TokenTypes.tokens.ident, "Expected function name.").toString(); this._consume(TokenTypes.tokens.paren_left, "Expected '(' for function arguments."); const args = []; if (!this._check(TokenTypes.tokens.paren_right)) { do { if (this._check(TokenTypes.tokens.paren_right)) { break; } const argAttrs = this._attribute(); const name2 = this._consume(TokenTypes.tokens.ident, "Expected argument name.").toString(); this._consume(TokenTypes.tokens.colon, "Expected ':' for argument type."); const typeAttrs = this._attribute(); const type = this._type_decl(); if (type != null) { type.attributes = typeAttrs; args.push(new Argument(name2, type, argAttrs)); } } while (this._match(TokenTypes.tokens.comma)); } this._consume(TokenTypes.tokens.paren_right, "Expected ')' after function arguments."); let _return = null; if (this._match(TokenTypes.tokens.arrow)) { const attrs = this._attribute(); _return = this._type_decl(); if (_return != null) { _return.attributes = attrs; } } const body = this._compound_statement(); const endLine = this._currentLine; return new Function(name, args, _return, body, startLine, endLine); } _compound_statement() { const statements = []; this._consume(TokenTypes.tokens.brace_left, "Expected '{' for block."); while (!this._check(TokenTypes.tokens.brace_right)) { const statement = this._statement(); if (statement !== null) { statements.push(statement); } } this._consume(TokenTypes.tokens.brace_right, "Expected '}' for block."); return statements; } _statement() { while (this._match(TokenTypes.tokens.semicolon) && !this._isAtEnd()) ; if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } if (this._check(TokenTypes.keywords.if)) { return this._if_statement(); } if (this._check(TokenTypes.keywords.switch)) { return this._switch_statement(); } if (this._check(TokenTypes.keywords.loop)) { return this._loop_statement(); } if (this._check(TokenTypes.keywords.for)) { return this._for_statement(); } if (this._check(TokenTypes.keywords.while)) { return this._while_statement(); } if (this._check(TokenTypes.keywords.continuing)) { return this._continuing_statement(); } if (this._check(TokenTypes.keywords.static_assert)) { return this._static_assert_statement(); } if (this._check(TokenTypes.tokens.brace_left)) { return this._compound_statement(); } let result = null; if (this._check(TokenTypes.keywords.return)) { result = this._return_statement(); } else if (this._check([ TokenTypes.keywords.var, TokenTypes.keywords.let, TokenTypes.keywords.const ])) { result = this._variable_statement(); } else if (this._match(TokenTypes.keywords.discard)) { result = new Discard(); } else if (this._match(TokenTypes.keywords.break)) { result = new Break(); } else if (this._match(TokenTypes.keywords.continue)) { result = new Continue(); } else { result = this._increment_decrement_statement() || this._func_call_statement() || this._assignment_statement(); } if (result != null) { this._consume(TokenTypes.tokens.semicolon, "Expected ';' after statement."); } return result; } _static_assert_statement() { if (!this._match(TokenTypes.keywords.static_assert)) { return null; } const expression = this._optional_paren_expression(); return new StaticAssert(expression); } _while_statement() { if (!this._match(TokenTypes.keywords.while)) { return null; } const condition = this._optional_paren_expression(); if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } const block = this._compound_statement(); return new While(condition, block); } _continuing_statement() { if (!this._match(TokenTypes.keywords.continuing)) { return null; } const block = this._compound_statement(); return new Continuing(block); } _for_statement() { if (!this._match(TokenTypes.keywords.for)) { return null; } this._consume(TokenTypes.tokens.paren_left, "Expected '('."); const init = !this._check(TokenTypes.tokens.semicolon) ? this._for_init() : null; this._consume(TokenTypes.tokens.semicolon, "Expected ';'."); const condition = !this._check(TokenTypes.tokens.semicolon) ? this._short_circuit_or_expression() : null; this._consume(TokenTypes.tokens.semicolon, "Expected ';'."); const increment = !this._check(TokenTypes.tokens.paren_right) ? this._for_increment() : null; this._consume(TokenTypes.tokens.paren_right, "Expected ')'."); if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } const body = this._compound_statement(); return new For(init, condition, increment, body); } _for_init() { return this._variable_statement() || this._func_call_statement() || this._assignment_statement(); } _for_increment() { return this._func_call_statement() || this._increment_decrement_statement() || this._assignment_statement(); } _variable_statement() { if (this._check(TokenTypes.keywords.var)) { const _var = this._variable_decl(); if (_var === null) { throw this._error(this._peek(), "Variable declaration expected."); } let value = null; if (this._match(TokenTypes.tokens.equal)) { value = this._short_circuit_or_expression(); } return new Var(_var.name, _var.type, _var.storage, _var.access, value); } if (this._match(TokenTypes.keywords.let)) { const name = this._consume(TokenTypes.tokens.ident, "Expected name for let.").toString(); let type = null; if (this._match(TokenTypes.tokens.colon)) { const typeAttrs = this._attribute(); type = this._type_decl(); if (type != null) { type.attributes = typeAttrs; } } this._consume(TokenTypes.tokens.equal, "Expected '=' for let."); const value = this._short_circuit_or_expression(); return new Let(name, type, null, null, value); } if (this._match(TokenTypes.keywords.const)) { const name = this._consume(TokenTypes.tokens.ident, "Expected name for const.").toString(); let type = null; if (this._match(TokenTypes.tokens.colon)) { const typeAttrs = this._attribute(); type = this._type_decl(); if (type != null) { type.attributes = typeAttrs; } } this._consume(TokenTypes.tokens.equal, "Expected '=' for const."); const value = this._short_circuit_or_expression(); return new Const(name, type, null, null, value); } return null; } _increment_decrement_statement() { const savedPos = this._current; const _var = this._unary_expression(); if (_var == null) { return null; } if (!this._check(TokenTypes.increment_operators)) { this._current = savedPos; return null; } const token = this._consume(TokenTypes.increment_operators, "Expected increment operator"); return new Increment(token.type === TokenTypes.tokens.plus_plus ? IncrementOperator.increment : IncrementOperator.decrement, _var); } _assignment_statement() { let _var = null; if (this._check(TokenTypes.tokens.brace_right)) { return null; } let isUnderscore = this._match(TokenTypes.tokens.underscore); if (!isUnderscore) { _var = this._unary_expression(); } if (!isUnderscore && _var == null) { return null; } const type = this._consume(TokenTypes.assignment_operators, "Expected assignment operator."); const value = this._short_circuit_or_expression(); return new Assign(AssignOperator.parse(type.lexeme), _var, value); } _func_call_statement() { if (!this._check(TokenTypes.tokens.ident)) { return null; } const savedPos = this._current; const name = this._consume(TokenTypes.tokens.ident, "Expected function name."); const args = this._argument_expression_list(); if (args === null) { this._current = savedPos; return null; } return new Call(name.lexeme, args); } _loop_statement() { if (!this._match(TokenTypes.keywords.loop)) { return null; } if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } this._consume(TokenTypes.tokens.brace_left, "Expected '{' for loop."); const statements = []; let statement = this._statement(); while (statement !== null) { if (Array.isArray(statement)) { for (let s of statement) { statements.push(s); } } else { statements.push(statement); } statement = this._statement(); } let continuing = null; if (this._match(TokenTypes.keywords.continuing)) { continuing = this._compound_statement(); } this._consume(TokenTypes.tokens.brace_right, "Expected '}' for loop."); return new Loop(statements, continuing); } _switch_statement() { if (!this._match(TokenTypes.keywords.switch)) { return null; } const condition = this._optional_paren_expression(); if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } this._consume(TokenTypes.tokens.brace_left, "Expected '{' for switch."); const body = this._switch_body(); if (body == null || body.length == 0) { throw this._error(this._previous(), "Expected 'case' or 'default'."); } this._consume(TokenTypes.tokens.brace_right, "Expected '}' for switch."); return new Switch(condition, body); } _switch_body() { const cases = []; if (this._match(TokenTypes.keywords.case)) { const selector = this._case_selectors(); this._match(TokenTypes.tokens.colon); if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } this._consume(TokenTypes.tokens.brace_left, "Exected '{' for switch case."); const body = this._case_body(); this._consume(TokenTypes.tokens.brace_right, "Exected '}' for switch case."); cases.push(new Case(selector, body)); } if (this._match(TokenTypes.keywords.default)) { this._match(TokenTypes.tokens.colon); if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } this._consume(TokenTypes.tokens.brace_left, "Exected '{' for switch default."); const body = this._case_body(); this._consume(TokenTypes.tokens.brace_right, "Exected '}' for switch default."); cases.push(new Default(body)); } if (this._check([TokenTypes.keywords.default, TokenTypes.keywords.case])) { const _cases = this._switch_body(); cases.push(_cases[0]); } return cases; } _case_selectors() { const selectors = [ this._shift_expression() //?.evaluate(this._context).toString() ?? "", ]; while (this._match(TokenTypes.tokens.comma)) { selectors.push(this._shift_expression()); } return selectors; } _case_body() { if (this._match(TokenTypes.keywords.fallthrough)) { this._consume(TokenTypes.tokens.semicolon, "Expected ';'"); return []; } let statement = this._statement(); if (statement == null) { return []; } if (!(statement instanceof Array)) { statement = [statement]; } const nextStatement = this._case_body(); if (nextStatement.length == 0) { return statement; } return [...statement, nextStatement[0]]; } _if_statement() { if (!this._match(TokenTypes.keywords.if)) { return null; } const condition = this._optional_paren_expression(); if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } const block = this._compound_statement(); let elseif = []; if (this._match_elseif()) { if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } elseif = this._elseif_statement(elseif); } let _else = null; if (this._match(TokenTypes.keywords.else)) { if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } _else = this._compound_statement(); } return new If(condition, block, elseif, _else); } _match_elseif() { if (this._tokens[this._current].type === TokenTypes.keywords.else && this._tokens[this._current + 1].type === TokenTypes.keywords.if) { this._advance(); this._advance(); return true; } return false; } _elseif_statement(elseif = []) { const condition = this._optional_paren_expression(); const block = this._compound_statement(); elseif.push(new ElseIf(condition, block)); if (this._match_elseif()) { if (this._check(TokenTypes.tokens.attr)) { this._attribute(); } this._elseif_statement(elseif); } return elseif; } _return_statement() { if (!this._match(TokenTypes.keywords.return)) { return null; } const value = this._short_circuit_or_expression(); return new Return(value); } _short_circuit_or_expression() { let expr = this._short_circuit_and_expr(); while (this._match(TokenTypes.tokens.or_or)) { expr = new BinaryOperator(this._previous().toString(), expr, this._short_circuit_and_expr()); } return expr; } _short_circuit_and_expr() { let expr = this._inclusive_or_expression(); while (this._match(TokenTypes.tokens.and_and)) { expr = new BinaryOperator(this._previous().toString(), expr, this._inclusive_or_expression()); } return expr; } _inclusive_or_expression() { let expr = this._exclusive_or_expression(); while (this._match(TokenTypes.tokens.or)) { expr = new BinaryOperator(this._previous().toString(), expr, this._exclusive_or_expression()); } return expr; } _exclusive_or_expression() { let expr = this._and_expression(); while (this._match(TokenTypes.tokens.xor)) { expr = new BinaryOperator(this._previous().toString(), expr, this._and_expression()); } return expr; } _and_expression() { let expr = this._equality_expression(); while (this._match(TokenTypes.tokens.and)) { expr = new BinaryOperator(this._previous().toString(), expr, this._equality_expression()); } return expr; } _equality_expression() { const expr = this._relational_expression(); if (this._match([TokenTypes.tokens.equal_equal, TokenTypes.tokens.not_equal])) { return new BinaryOperator(this._previous().toString(), expr, this._relational_expression()); } return expr; } _relational_expression() { let expr = this._shift_expression(); while (this._match([ TokenTypes.tokens.less_than, TokenTypes.tokens.greater_than, TokenTypes.tokens.less_than_equal, TokenTypes.tokens.greater_than_equal ])) { expr = new BinaryOperator(this._previous().toString(), expr, this._shift_expression()); } return expr; } _shift_expression() { let expr = this._additive_expression(); while (this._match([TokenTypes.tokens.shift_left, TokenTypes.tokens.shift_right])) { expr = new BinaryOperator(this._previous().toString(), expr, this._additive_expression()); } return expr; } _additive_expression() { let expr = this._multiplicative_expression(); while (this._match([TokenTypes.tokens.plus, TokenTypes.tokens.minus])) { expr = new BinaryOperator(this._previous().toString(), expr, this._multiplicative_expression()); } return expr; } _multiplicative_expression() { let expr = this._unary_expression(); while (this._match([ TokenTypes.tokens.star, TokenTypes.tokens.forward_slash, TokenTypes.tokens.modulo ])) { expr = new BinaryOperator(this._previous().toString(), expr, this._unary_expression()); } return expr; } _unary_expression() { if (this._match([ TokenTypes.tokens.minus, TokenTypes.tokens.bang, TokenTypes.tokens.tilde, TokenTypes.tokens.star, TokenTypes.tokens.and ])) { return new UnaryOperator(this._previous().toString(), this._unary_expression()); } return this._singular_expression(); } _singular_expression() { const expr = this._primary_expression(); const p = this._postfix_expression(); if (p) { expr.postfix = p; } return expr; } _postfix_expression() { if (this._match(TokenTypes.tokens.bracket_left)) { const expr = this._short_circuit_or_expression(); this._consume(TokenTypes.tokens.bracket_right, "Expected ']'."); const arrayIndex = new ArrayIndex(expr); const p = this._postfix_expression(); if (p) { arrayIndex.postfix = p; } return arrayIndex; } if (this._match(TokenTypes.tokens.period)) { const name = this._consume(TokenTypes.tokens.ident, "Expected member name."); const p = this._postfix_expression(); const expr = new StringExpr(name.lexeme); if (p) { expr.postfix = p; } return expr; } return null; } _getStruct(name) { if (this._context.aliases.has(name)) { const alias = this._context.aliases.get(name).type; return alias; } if (this._context.structs.has(name)) { const struct = this._context.structs.get(name); return struct; } return null; } _primary_expression() { if (this._match(TokenTypes.tokens.ident)) { const name = this._previous().toString(); if (this._check(TokenTypes.tokens.paren_left)) { const args2 = this._argument_expression_list(); const struct = this._getStruct(name); if (struct != null) { return new CreateExpr(struct, args2); } return new CallExpr(name, args2); } if (this._context.constants.has(name)) { const c = this._context.constants.get(name); return new ConstExpr(name, c.value); } return new VariableExpr(name); } if (this._match(TokenTypes.const_literal)) { return new LiteralExpr(parseFloat(this._previous().toString())); } if (this._check(TokenTypes.tokens.paren_left)) { return this._paren_expression(); } if (this._match(TokenTypes.keywords.bitcast)) { this._consume(TokenTypes.tokens.less_than, "Expected '<'."); const type2 = this._type_decl(); this._consume(TokenTypes.tokens.greater_than, "Expected '>'."); const value = this._paren_expression(); return new BitcastExpr(type2, value); } const type = this._type_decl(); const args = this._argument_expression_list(); return new TypecastExpr(type, args); } _argument_expression_list() { if (!this._match(TokenTypes.tokens.paren_left)) { return null; } const args = []; do { if (this._check(TokenTypes.tokens.paren_right)) { break; } const arg = this._short_circuit_or_expression(); args.push(arg); } while (this._match(TokenTypes.tokens.comma)); this._consume(TokenTypes.tokens.paren_right, "Expected ')' for agument list"); return args; } _optional_paren_expression() { this._match(TokenTypes.tokens.paren_left); const expr = this._short_circuit_or_expression(); this._match(TokenTypes.tokens.paren_right); return new GroupingExpr([expr]); } _paren_expression() { this._consume(TokenTypes.tokens.paren_left, "Expected '('."); const expr = this._short_circuit_or_expression(); this._consume(TokenTypes.tokens.paren_right, "Expected ')'."); return new GroupingExpr([expr]); } _struct_decl() { if (!this._match(TokenTypes.keywords.struct)) { return null; } const startLine = this._currentLine; const name = this._consume(TokenTypes.tokens.ident, "Expected name for struct.").toString(); this._consume(TokenTypes.tokens.brace_left, "Expected '{' for struct body."); const members = []; while (!this._check(TokenTypes.tokens.brace_right)) { const memberAttrs = this._attribute(); const memberName = this._consume(TokenTypes.tokens.ident, "Expected variable name.").toString(); this._consume(TokenTypes.tokens.colon, "Expected ':' for struct member type."); const typeAttrs = this._attribute(); const memberType = this._type_decl(); if (memberType != null) { memberType.attributes = typeAttrs; } if (!this._check(TokenTypes.tokens.brace_right)) this._consume(TokenTypes.tokens.comma, "Expected ',' for struct member."); else this._match(TokenTypes.tokens.comma); members.push(new Member(memberName, memberType, memberAttrs)); } this._consume(TokenTypes.tokens.brace_right, "Expected '}' after struct body."); const endLine = this._currentLine; const structNode = new Struct(name, members, startLine, endLine); this._context.structs.set(name, structNode); return structNode; } _global_variable_decl() { const _var = this._variable_decl(); if (_var && this._match(TokenTypes.tokens.equal)) { _var.value = this._const_expression(); } return _var; } _override_variable_decl() { const _override = this._override_decl(); if (_override && this._match(TokenTypes.tokens.equal)) { _override.value = this._const_expression(); } return _override; } _global_const_decl() { if (!this._match(TokenTypes.keywords.const)) { return null; } const name = this._consume(TokenTypes.tokens.ident, "Expected variable name"); let type = null; if (this._match(TokenTypes.tokens.colon)) { const attrs = this._attribute(); type = this._type_decl(); if (type != null) { type.attributes = attrs; } } let value = null; if (this._match(TokenTypes.tokens.equal)) { const valueExpr = this._short_circuit_or_expression(); if (valueExpr instanceof CreateExpr) { value = valueExpr; } else if (valueExpr instanceof ConstExpr && valueExpr.initializer instanceof CreateExpr) { value = valueExpr.initializer; } else { try { const constValue = valueExpr.evaluate(this._context); value = new LiteralExpr(constValue); } catch (_a2) { value = valueExpr; } } } const c = new Const(name.toString(), type, "", "", value); this._context.constants.set(c.name, c); return c; } _global_let_decl() { if (!this._match(TokenTypes.keywords.let)) { return null; } const name = this._consume(TokenTypes.tokens.ident, "Expected variable name"); let type = null; if (this._match(TokenTypes.tokens.colon)) { const attrs = this._attribute(); type = this._type_decl(); if (type != null) { type.attributes = attrs; } } let value = null; if (this._match(TokenTypes.tokens.equal)) { value = this._const_expression(); } return new Let(name.toString(), type, "", "", value); } _const_expression() { if (this._match(TokenTypes.const_literal)) { return new StringExpr(this._previous().toString()); } const type = this._type_decl(); this._consume(TokenTypes.tokens.paren_left, "Expected '('."); let args = []; while (!this._check(TokenTypes.tokens.paren_right)) { args.push(this._const_expression()); if (!this._check(TokenTypes.tokens.comma)) { break; } this._advance(); } this._consume(TokenTypes.tokens.paren_right, "Expected ')'."); return new CreateExpr(type, args); } _variable_decl() { if (!this._match(TokenTypes.keywords.var)) { return null; } let storage = ""; let access = ""; if (this._match(TokenTypes.tokens.less_than)) { storage = this._consume(TokenTypes.storage_class, "Expected storage_class.").toString(); if (this._match(TokenTypes.tokens.comma)) access = this._consume(TokenTypes.access_mode, "Expected access_mode.").toString(); this._consume(TokenTypes.tokens.greater_than, "Expected '>'."); } const name = this._consume(TokenTypes.tokens.ident, "Expected variable name"); let type = null; if (this._match(TokenTypes.tokens.colon)) { const attrs = this._attribute(); type = this._type_decl(); if (type != null) { type.attributes = attrs; } } return new Var(name.toString(), type, storage, access, null); } _override_decl() { if (!this._match(TokenTypes.keywords.override)) { return null; } const name = this._consume(TokenTypes.tokens.ident, "Expected variable name"); let type = null; if (this._match(TokenTypes.tokens.colon)) { const attrs = this._attribute(); type = this._type_decl(); if (type != null) { type.attributes = attrs; } } return new Override(name.toString(), type, null); } _diagnostic() { this._consume(TokenTypes.tokens.paren_left, "Expected '('"); const severity = this._consume(TokenTypes.tokens.ident, "Expected severity control name."); this._consume(TokenTypes.tokens.comma, "Expected ','"); const rule = this._consume(TokenTypes.tokens.ident, "Expected diagnostic rule name."); this._consume(TokenTypes.tokens.paren_right, "Expected ')'"); return new Diagnostic(severity.toString(), rule.toString()); } _enable_directive() { const name = this._consume(TokenTypes.tokens.ident, "identity expected."); return new Enable(name.toString()); } _requires_directive() { const extensions = [this._consume(TokenTypes.tokens.ident, "identity expected.").toString()]; while (this._match(TokenTypes.tokens.comma)) { const name = this._consume(TokenTypes.tokens.ident, "identity expected."); extensions.push(name.toString()); } return new Requires(extensions); } _type_alias() { const name = this._consume(TokenTypes.tokens.ident, "identity expected."); this._consume(TokenTypes.tokens.equal, "Expected '=' for type alias."); let aliasType = this._type_decl(); if (aliasType === null) { throw this._error(this._peek(), "Expected Type for Alias."); } if (this._context.aliases.has(aliasType.name)) { aliasType = this._context.aliases.get(aliasType.name).type; } const aliasNode = new Alias(name.toString(), aliasType); this._context.aliases.set(aliasNode.name, aliasNode); return aliasNode; } _type_decl() { if (this._check([ TokenTypes.tokens.ident, ...TokenTypes.texel_format, TokenTypes.keywords.bool, TokenTypes.keywords.f32, TokenTypes.keywords.i32, TokenTypes.keywords.u32 ])) { const type2 = this._advance(); const typeName = type2.toString(); if (this._context.structs.has(typeName)) { return this._context.structs.get(typeName); } if (this._context.aliases.has(typeName)) { return this._context.aliases.get(typeName).type; } return new Type(type2.toString()); } let type = this._texture_sampler_types(); if (type) { return type; } if (this._check(TokenTypes.template_types)) { let type2 = this._advance().toString(); let format = null; let access = null; if (this._match(TokenTypes.tokens.less_than)) { format = this._type_decl(); access = null; if (this._match(TokenTypes.tokens.comma)) { access = this._consume(TokenTypes.access_mode, "Expected access_mode for pointer").toString(); } this._consume(TokenTypes.tokens.greater_than, "Expected '>' for type."); } return new TemplateType(type2, format, access); } if (this._match(TokenTypes.keywords.ptr)) { let pointer = this._previous().toString(); this._consume(TokenTypes.tokens.less_than, "Expected '<' for pointer."); const storage = this._consume(TokenTypes.storage_class, "Expected storage_class for pointer"); this._consume(TokenTypes.tokens.comma, "Expected ',' for pointer."); const decl = this._type_decl(); let access = null; if (this._match(TokenTypes.tokens.comma)) { access = this._consume(TokenTypes.access_mode, "Expected access_mode for pointer").toString(); } this._consume(TokenTypes.tokens.greater_than, "Expected '>' for pointer."); return new PointerType(pointer, storage.toString(), decl, access); } const attrs = this._attribute(); if (this._match(TokenTypes.keywords.array)) { let format = null; let countInt = -1; const array = this._previous(); let countNode = null; if (this._match(TokenTypes.tokens.less_than)) { format = this._type_decl(); if (this._context.aliases.has(format.name)) { format = this._context.aliases.get(format.name).type; } let count = ""; if (this._match(TokenTypes.tokens.comma)) { countNode = this._shift_expression(); try { count = countNode.evaluate(this._context).toString(); countNode = null; } catch (e) { count = "1"; } } this._consume(TokenTypes.tokens.greater_than, "Expected '>' for array."); countInt = count ? parseInt(count) : 0; } const arrayType = new ArrayType(array.toString(), attrs, format, countInt); if (countNode) { this._deferArrayCountEval.push({ arrayType, countNode }); } return arrayType; } return null; } _texture_sampler_types() { if (this._match(TokenTypes.sampler_type)) { return new SamplerType(this._previous().toString(), null, null); } if (this._match(TokenTypes.depth_texture_type)) { return new SamplerType(this._previous().toString(), null, null); } if (this._match(TokenTypes.sampled_texture_type) || this._match(TokenTypes.multisampled_texture_type)) { const sampler = this._previous(); this._consume(TokenTypes.tokens.less_than, "Expected '<' for sampler type."); const format = this._type_decl(); this._consume(TokenTypes.tokens.greater_than, "Expected '>' for sampler type."); return new SamplerType(sampler.toString(), format, null); } if (this._match(TokenTypes.storage_texture_type)) { const sampler = this._previous(); this._consume(TokenTypes.tokens.less_than, "Expected '<' for sampler type."); const format = this._consume(TokenTypes.texel_format, "Invalid texel format.").toString(); this._consume(TokenTypes.tokens.comma, "Expected ',' after texel format."); const access = this._consume(TokenTypes.access_mode, "Expected access mode for storage texture type.").toString(); this._consume(TokenTypes.tokens.greater_than, "Expected '>' for sampler type."); return new SamplerType(sampler.toString(), format, access); } return null; } _attribute() { let attributes = []; while (this._match(TokenTypes.tokens.attr)) { const name = this._consume(TokenTypes.attribute_name, "Expected attribute name"); const attr = new Attribute(name.toString(), null); if (this._match(TokenTypes.tokens.paren_left)) { attr.value = this._consume(TokenTypes.literal_or_ident, "Expected attribute value").toString(); if (this._check(TokenTypes.tokens.comma)) { this._advance(); do { const v = this._consume(TokenTypes.literal_or_ident, "Expected attribute value").toString(); if (!(attr.value instanceof Array)) { attr.value = [attr.value]; } attr.value.push(v); } while (this._match(TokenTypes.tokens.comma)); } this._consume(TokenTypes.tokens.paren_right, "Expected ')'"); } attributes.push(attr); } if (attributes.length == 0) { return null; } return attributes; } }; var TypeInfo = class { constructor(name, attributes) { this.name = name; this.attributes = attributes; this.size = 0; } get isArray() { return false; } get isStruct() { return false; } get isTemplate() { return false; } }; var MemberInfo = class { constructor(name, type, attributes) { this.name = name; this.type = type; this.attributes = attributes; this.offset = 0; this.size = 0; } get isArray() { return this.type.isArray; } get isStruct() { return this.type.isStruct; } get isTemplate() { return this.type.isTemplate; } get align() { return this.type.isStruct ? this.type.align : 0; } get members() { return this.type.isStruct ? this.type.members : null; } get format() { return this.type.isArray ? this.type.format : this.type.isTemplate ? this.type.format : null; } get count() { return this.type.isArray ? this.type.count : 0; } get stride() { return this.type.isArray ? this.type.stride : this.size; } }; var StructInfo = class extends TypeInfo { constructor(name, attributes) { super(name, attributes); this.members = []; this.align = 0; this.startLine = -1; this.endLine = -1; this.inUse = false; } get isStruct() { return true; } }; var ArrayInfo = class extends TypeInfo { constructor(name, attributes) { super(name, attributes); this.count = 0; this.stride = 0; } get isArray() { return true; } }; var TemplateInfo = class extends TypeInfo { constructor(name, format, attributes, access) { super(name, attributes); this.format = format; this.access = access; } get isTemplate() { return true; } }; var ResourceType; (function(ResourceType2) { ResourceType2[ResourceType2["Uniform"] = 0] = "Uniform"; ResourceType2[ResourceType2["Storage"] = 1] = "Storage"; ResourceType2[ResourceType2["Texture"] = 2] = "Texture"; ResourceType2[ResourceType2["Sampler"] = 3] = "Sampler"; ResourceType2[ResourceType2["StorageTexture"] = 4] = "StorageTexture"; })(ResourceType || (ResourceType = {})); var VariableInfo = class { constructor(name, type, group, binding, attributes, resourceType, access) { this.name = name; this.type = type; this.group = group; this.binding = binding; this.attributes = attributes; this.resourceType = resourceType; this.access = access; } get isArray() { return this.type.isArray; } get isStruct() { return this.type.isStruct; } get isTemplate() { return this.type.isTemplate; } get size() { return this.type.size; } get align() { return this.type.isStruct ? this.type.align : 0; } get members() { return this.type.isStruct ? this.type.members : null; } get format() { return this.type.isArray ? this.type.format : this.type.isTemplate ? this.type.format : null; } get count() { return this.type.isArray ? this.type.count : 0; } get stride() { return this.type.isArray ? this.type.stride : this.size; } }; var AliasInfo = class { constructor(name, type) { this.name = name; this.type = type; } }; var _TypeSize = class { constructor(align, size) { this.align = align; this.size = size; } }; var InputInfo = class { constructor(name, type, locationType, location) { this.name = name; this.type = type; this.locationType = locationType; this.location = location; this.interpolation = null; } }; var OutputInfo = class { constructor(name, type, locationType, location) { this.name = name; this.type = type; this.locationType = locationType; this.location = location; } }; var FunctionInfo = class { constructor(name, stage = null) { this.stage = null; this.inputs = []; this.outputs = []; this.resources = []; this.startLine = -1; this.endLine = -1; this.inUse = false; this.calls = /* @__PURE__ */ new Set(); this.name = name; this.stage = stage; } }; var EntryFunctions = class { constructor() { this.vertex = []; this.fragment = []; this.compute = []; } }; var OverrideInfo = class { constructor(name, type, attributes, id) { this.name = name; this.type = type; this.attributes = attributes; this.id = id; } }; var _FunctionResources = class { constructor(node) { this.resources = null; this.inUse = false; this.info = null; this.node = node; } }; var WgslReflect = class { constructor(code) { this.uniforms = []; this.storage = []; this.textures = []; this.samplers = []; this.aliases = []; this.overrides = []; this.structs = []; this.entry = new EntryFunctions(); this.functions = []; this._types = /* @__PURE__ */ new Map(); this._functions = /* @__PURE__ */ new Map(); if (code) { this.update(code); } } _isStorageTexture(type) { return type.name == "texture_storage_1d" || type.name == "texture_storage_2d" || type.name == "texture_storage_2d_array" || type.name == "texture_storage_3d"; } update(code) { const parser = new WgslParser(); const ast = parser.parse(code); for (const node of ast) { if (node instanceof Function) { this._functions.set(node.name, new _FunctionResources(node)); } } for (const node of ast) { if (node instanceof Struct) { const info = this._getTypeInfo(node, null); if (info instanceof StructInfo) { this.structs.push(info); } } } for (const node of ast) { if (node instanceof Alias) { this.aliases.push(this._getAliasInfo(node)); continue; } if (node instanceof Override) { const v = node; const id = this._getAttributeNum(v.attributes, "id", 0); const type = v.type != null ? this._getTypeInfo(v.type, v.attributes) : null; this.overrides.push(new OverrideInfo(v.name, type, v.attributes, id)); continue; } if (this._isUniformVar(node)) { const v = node; const g = this._getAttributeNum(v.attributes, "group", 0); const b = this._getAttributeNum(v.attributes, "binding", 0); const type = this._getTypeInfo(v.type, v.attributes); const varInfo = new VariableInfo(v.name, type, g, b, v.attributes, ResourceType.Uniform, v.access); this.uniforms.push(varInfo); continue; } if (this._isStorageVar(node)) { const v = node; const g = this._getAttributeNum(v.attributes, "group", 0); const b = this._getAttributeNum(v.attributes, "binding", 0); const type = this._getTypeInfo(v.type, v.attributes); const isStorageTexture = this._isStorageTexture(type); const varInfo = new VariableInfo(v.name, type, g, b, v.attributes, isStorageTexture ? ResourceType.StorageTexture : ResourceType.Storage, v.access); this.storage.push(varInfo); continue; } if (this._isTextureVar(node)) { const v = node; const g = this._getAttributeNum(v.attributes, "group", 0); const b = this._getAttributeNum(v.attributes, "binding", 0); const type = this._getTypeInfo(v.type, v.attributes); const isStorageTexture = this._isStorageTexture(type); const varInfo = new VariableInfo(v.name, type, g, b, v.attributes, isStorageTexture ? ResourceType.StorageTexture : ResourceType.Texture, v.access); if (isStorageTexture) { this.storage.push(varInfo); } else { this.textures.push(varInfo); } continue; } if (this._isSamplerVar(node)) { const v = node; const g = this._getAttributeNum(v.attributes, "group", 0); const b = this._getAttributeNum(v.attributes, "binding", 0); const type = this._getTypeInfo(v.type, v.attributes); const varInfo = new VariableInfo(v.name, type, g, b, v.attributes, ResourceType.Sampler, v.access); this.samplers.push(varInfo); continue; } if (node instanceof Function) { const vertexStage = this._getAttribute(node, "vertex"); const fragmentStage = this._getAttribute(node, "fragment"); const computeStage = this._getAttribute(node, "compute"); const stage = vertexStage || fragmentStage || computeStage; const fn = new FunctionInfo(node.name, stage === null || stage === void 0 ? void 0 : stage.name); fn.startLine = node.startLine; fn.endLine = node.endLine; this.functions.push(fn); this._functions.get(node.name).info = fn; if (stage) { this._functions.get(node.name).inUse = true; fn.inUse = true; fn.resources = this._findResources(node, !!stage); fn.inputs = this._getInputs(node.args); fn.outputs = this._getOutputs(node.returnType); this.entry[stage.name].push(fn); } continue; } } for (const fn of this._functions.values()) { if (fn.info) { fn.info.inUse = fn.inUse; this._addCalls(fn.node, fn.info.calls); } } for (const u of this.uniforms) { this._markStructsInUse(u.type); } for (const s of this.storage) { this._markStructsInUse(s.type); } } _markStructsInUse(type) { if (type.isStruct) { type.inUse = true; for (const m of type.members) { this._markStructsInUse(m.type); } } else if (type.isArray) { this._markStructsInUse(type.format); } else if (type.isTemplate) { this._markStructsInUse(type.format); } else { const alias = this._getAlias(type.name); if (alias) { this._markStructsInUse(alias); } } } _addCalls(fn, calls) { var _a2; for (const call of fn.calls) { const info = (_a2 = this._functions.get(call.name)) === null || _a2 === void 0 ? void 0 : _a2.info; if (info) { calls.add(info); } } } /// Find a resource by its group and binding. findResource(group, binding) { for (const u of this.uniforms) { if (u.group == group && u.binding == binding) { return u; } } for (const s of this.storage) { if (s.group == group && s.binding == binding) { return s; } } for (const t of this.textures) { if (t.group == group && t.binding == binding) { return t; } } for (const s of this.samplers) { if (s.group == group && s.binding == binding) { return s; } } return null; } _findResource(name) { for (const u of this.uniforms) { if (u.name == name) { return u; } } for (const s of this.storage) { if (s.name == name) { return s; } } for (const t of this.textures) { if (t.name == name) { return t; } } for (const s of this.samplers) { if (s.name == name) { return s; } } return null; } _markStructsFromAST(type) { const info = this._getTypeInfo(type, null); this._markStructsInUse(info); } _findResources(fn, isEntry) { const resources = []; const self = this; const varStack = []; fn.search((node) => { if (node instanceof _BlockStart) { varStack.push({}); } else if (node instanceof _BlockEnd) { varStack.pop(); } else if (node instanceof Var) { const v = node; if (isEntry && v.type !== null) { this._markStructsFromAST(v.type); } if (varStack.length > 0) { varStack[varStack.length - 1][v.name] = v; } } else if (node instanceof CreateExpr) { const c = node; if (isEntry && c.type !== null) { this._markStructsFromAST(c.type); } } else if (node instanceof Let) { const v = node; if (isEntry && v.type !== null) { this._markStructsFromAST(v.type); } if (varStack.length > 0) { varStack[varStack.length - 1][v.name] = v; } } else if (node instanceof VariableExpr) { const v = node; if (varStack.length > 0) { const varInfo2 = varStack[varStack.length - 1][v.name]; if (varInfo2) { return; } } const varInfo = self._findResource(v.name); if (varInfo) { resources.push(varInfo); } } else if (node instanceof CallExpr) { const c = node; const callFn = self._functions.get(c.name); if (callFn) { if (isEntry) { callFn.inUse = true; } fn.calls.add(callFn.node); if (callFn.resources === null) { callFn.resources = self._findResources(callFn.node, isEntry); } resources.push(...callFn.resources); } } else if (node instanceof Call) { const c = node; const callFn = self._functions.get(c.name); if (callFn) { if (isEntry) { callFn.inUse = true; } fn.calls.add(callFn.node); if (callFn.resources === null) { callFn.resources = self._findResources(callFn.node, isEntry); } resources.push(...callFn.resources); } } }); return [...new Map(resources.map((r) => [r.name, r])).values()]; } getBindGroups() { const groups = []; function _makeRoom(group, binding) { if (group >= groups.length) { groups.length = group + 1; } if (groups[group] === void 0) { groups[group] = []; } if (binding >= groups[group].length) { groups[group].length = binding + 1; } } for (const u of this.uniforms) { _makeRoom(u.group, u.binding); const group = groups[u.group]; group[u.binding] = u; } for (const u of this.storage) { _makeRoom(u.group, u.binding); const group = groups[u.group]; group[u.binding] = u; } for (const t of this.textures) { _makeRoom(t.group, t.binding); const group = groups[t.group]; group[t.binding] = t; } for (const t of this.samplers) { _makeRoom(t.group, t.binding); const group = groups[t.group]; group[t.binding] = t; } return groups; } _getOutputs(type, outputs = void 0) { if (outputs === void 0) { outputs = []; } if (type instanceof Struct) { this._getStructOutputs(type, outputs); } else { const output = this._getOutputInfo(type); if (output !== null) { outputs.push(output); } } return outputs; } _getStructOutputs(struct, outputs) { for (const m of struct.members) { if (m.type instanceof Struct) { this._getStructOutputs(m.type, outputs); } else { const location = this._getAttribute(m, "location") || this._getAttribute(m, "builtin"); if (location !== null) { const typeInfo = this._getTypeInfo(m.type, m.type.attributes); const locationValue = this._parseInt(location.value); const info = new OutputInfo(m.name, typeInfo, location.name, locationValue); outputs.push(info); } } } } _getOutputInfo(type) { const location = this._getAttribute(type, "location") || this._getAttribute(type, "builtin"); if (location !== null) { const typeInfo = this._getTypeInfo(type, type.attributes); const locationValue = this._parseInt(location.value); const info = new OutputInfo("", typeInfo, location.name, locationValue); return info; } return null; } _getInputs(args, inputs = void 0) { if (inputs === void 0) { inputs = []; } for (const arg of args) { if (arg.type instanceof Struct) { this._getStructInputs(arg.type, inputs); } else { const input = this._getInputInfo(arg); if (input !== null) { inputs.push(input); } } } return inputs; } _getStructInputs(struct, inputs) { for (const m of struct.members) { if (m.type instanceof Struct) { this._getStructInputs(m.type, inputs); } else { const input = this._getInputInfo(m); if (input !== null) { inputs.push(input); } } } } _getInputInfo(node) { const location = this._getAttribute(node, "location") || this._getAttribute(node, "builtin"); if (location !== null) { const interpolation = this._getAttribute(node, "interpolation"); const type = this._getTypeInfo(node.type, node.attributes); const locationValue = this._parseInt(location.value); const info = new InputInfo(node.name, type, location.name, locationValue); if (interpolation !== null) { info.interpolation = this._parseString(interpolation.value); } return info; } return null; } _parseString(s) { if (s instanceof Array) { s = s[0]; } return s; } _parseInt(s) { if (s instanceof Array) { s = s[0]; } const n = parseInt(s); return isNaN(n) ? s : n; } _getAlias(name) { for (const a of this.aliases) { if (a.name == name) { return a.type; } } return null; } _getAliasInfo(node) { return new AliasInfo(node.name, this._getTypeInfo(node.type, null)); } _getTypeInfo(type, attributes) { if (this._types.has(type)) { return this._types.get(type); } if (type instanceof ArrayType) { const a = type; const t = this._getTypeInfo(a.format, a.attributes); const info2 = new ArrayInfo(a.name, attributes); info2.format = t; info2.count = a.count; this._types.set(type, info2); this._updateTypeInfo(info2); return info2; } if (type instanceof Struct) { const s = type; const info2 = new StructInfo(s.name, attributes); info2.startLine = s.startLine; info2.endLine = s.endLine; for (const m of s.members) { const t = this._getTypeInfo(m.type, m.attributes); info2.members.push(new MemberInfo(m.name, t, m.attributes)); } this._types.set(type, info2); this._updateTypeInfo(info2); return info2; } if (type instanceof SamplerType) { const s = type; const formatIsType = s.format instanceof Type; const format = s.format ? formatIsType ? this._getTypeInfo(s.format, null) : new TypeInfo(s.format, null) : null; const info2 = new TemplateInfo(s.name, format, attributes, s.access); this._types.set(type, info2); this._updateTypeInfo(info2); return info2; } if (type instanceof TemplateType) { const t = type; const format = t.format ? this._getTypeInfo(t.format, null) : null; const info2 = new TemplateInfo(t.name, format, attributes, t.access); this._types.set(type, info2); this._updateTypeInfo(info2); return info2; } const info = new TypeInfo(type.name, attributes); this._types.set(type, info); this._updateTypeInfo(info); return info; } _updateTypeInfo(type) { var _a2, _b; const typeSize = this._getTypeSize(type); type.size = (_a2 = typeSize === null || typeSize === void 0 ? void 0 : typeSize.size) !== null && _a2 !== void 0 ? _a2 : 0; if (type instanceof ArrayInfo) { const formatInfo = this._getTypeSize(type["format"]); type.stride = (_b = formatInfo === null || formatInfo === void 0 ? void 0 : formatInfo.size) !== null && _b !== void 0 ? _b : 0; this._updateTypeInfo(type["format"]); } if (type instanceof StructInfo) { this._updateStructInfo(type); } } _updateStructInfo(struct) { var _a2; let offset = 0; let lastSize = 0; let lastOffset = 0; let structAlign = 0; for (let mi = 0, ml = struct.members.length; mi < ml; ++mi) { const member = struct.members[mi]; const sizeInfo = this._getTypeSize(member); if (!sizeInfo) { continue; } (_a2 = this._getAlias(member.type.name)) !== null && _a2 !== void 0 ? _a2 : member.type; const align = sizeInfo.align; const size = sizeInfo.size; offset = this._roundUp(align, offset + lastSize); lastSize = size; lastOffset = offset; structAlign = Math.max(structAlign, align); member.offset = offset; member.size = size; this._updateTypeInfo(member.type); } struct.size = this._roundUp(structAlign, lastOffset + lastSize); struct.align = structAlign; } _getTypeSize(type) { var _a2; if (type === null || type === void 0) { return null; } const explicitSize = this._getAttributeNum(type.attributes, "size", 0); const explicitAlign = this._getAttributeNum(type.attributes, "align", 0); if (type instanceof MemberInfo) { type = type.type; } if (type instanceof TypeInfo) { const alias = this._getAlias(type.name); if (alias !== null) { type = alias; } } { const info = WgslReflect._typeInfo[type.name]; if (info !== void 0) { const divisor = type["format"] === "f16" ? 2 : 1; return new _TypeSize(Math.max(explicitAlign, info.align / divisor), Math.max(explicitSize, info.size / divisor)); } } { const info = WgslReflect._typeInfo[type.name.substring(0, type.name.length - 1)]; if (info) { const divisor = type.name[type.name.length - 1] === "h" ? 2 : 1; return new _TypeSize(Math.max(explicitAlign, info.align / divisor), Math.max(explicitSize, info.size / divisor)); } } if (type instanceof ArrayInfo) { let arrayType = type; let align = 8; let size = 8; const E = this._getTypeSize(arrayType.format); if (E !== null) { size = E.size; align = E.align; } const N = arrayType.count; const stride = this._getAttributeNum((_a2 = type === null || type === void 0 ? void 0 : type.attributes) !== null && _a2 !== void 0 ? _a2 : null, "stride", this._roundUp(align, size)); size = N * stride; if (explicitSize) { size = explicitSize; } return new _TypeSize(Math.max(explicitAlign, align), Math.max(explicitSize, size)); } if (type instanceof StructInfo) { let align = 0; let size = 0; let offset = 0; let lastSize = 0; let lastOffset = 0; for (const m of type.members) { const mi = this._getTypeSize(m.type); if (mi !== null) { align = Math.max(mi.align, align); offset = this._roundUp(mi.align, offset + lastSize); lastSize = mi.size; lastOffset = offset; } } size = this._roundUp(align, lastOffset + lastSize); return new _TypeSize(Math.max(explicitAlign, align), Math.max(explicitSize, size)); } return null; } _isUniformVar(node) { return node instanceof Var && node.storage == "uniform"; } _isStorageVar(node) { return node instanceof Var && node.storage == "storage"; } _isTextureVar(node) { return node instanceof Var && node.type !== null && WgslReflect._textureTypes.indexOf(node.type.name) != -1; } _isSamplerVar(node) { return node instanceof Var && node.type !== null && WgslReflect._samplerTypes.indexOf(node.type.name) != -1; } _getAttribute(node, name) { const obj = node; if (!obj || !obj["attributes"]) { return null; } const attrs = obj["attributes"]; for (let a of attrs) { if (a.name == name) { return a; } } return null; } _getAttributeNum(attributes, name, defaultValue) { if (attributes === null) { return defaultValue; } for (let a of attributes) { if (a.name == name) { let v = a !== null && a.value !== null ? a.value : defaultValue; if (v instanceof Array) { v = v[0]; } if (typeof v === "number") { return v; } if (typeof v === "string") { return parseInt(v); } return defaultValue; } } return defaultValue; } _roundUp(k, n) { return Math.ceil(n / k) * k; } }; WgslReflect._typeInfo = { f16: { align: 2, size: 2 }, i32: { align: 4, size: 4 }, u32: { align: 4, size: 4 }, f32: { align: 4, size: 4 }, atomic: { align: 4, size: 4 }, vec2: { align: 8, size: 8 }, vec3: { align: 16, size: 12 }, vec4: { align: 16, size: 16 }, mat2x2: { align: 8, size: 16 }, mat3x2: { align: 8, size: 24 }, mat4x2: { align: 8, size: 32 }, mat2x3: { align: 16, size: 32 }, mat3x3: { align: 16, size: 48 }, mat4x3: { align: 16, size: 64 }, mat2x4: { align: 16, size: 32 }, mat3x4: { align: 16, size: 48 }, mat4x4: { align: 16, size: 64 } }; WgslReflect._textureTypes = TokenTypes.any_texture_type.map((t) => { return t.name; }); WgslReflect._samplerTypes = TokenTypes.sampler_type.map((t) => { return t.name; }); // ../shadertools/src/lib/wgsl/get-shader-layout-wgsl.ts function getShaderLayoutFromWGSL(source) { const shaderLayout = { attributes: [], bindings: [] }; let parsedWGSL; try { parsedWGSL = parseWGSL(source); } catch (error) { import_core4.log.error(error.message)(); return shaderLayout; } for (const uniform of parsedWGSL.uniforms) { const members = []; for (const attribute of uniform.type?.members || []) { members.push({ name: attribute.name, type: getType(attribute.type) }); } shaderLayout.bindings.push({ type: "uniform", name: uniform.name, location: uniform.binding, // @ts-expect-error group: uniform.group, members }); } const vertex = parsedWGSL.entry.vertex[0]; const attributeCount = vertex?.inputs.length || 0; for (let i = 0; i < attributeCount; i++) { const wgslAttribute = vertex.inputs[i]; if (wgslAttribute.locationType === "location") { const type = getType(wgslAttribute.type); shaderLayout.attributes.push({ name: wgslAttribute.name, location: Number(wgslAttribute.location), type }); } } return shaderLayout; } function getType(type) { return type.format ? `${type.name}<${type.format.name}>` : type.name; } function parseWGSL(source) { try { return new WgslReflect(source); } catch (error) { if (error instanceof Error) { throw error; } let message = "WGSL parse error"; if (typeof error === "object" && error?.message) { message += `: ${error.message} `; } if (typeof error === "object" && error?.token) { message += error.token.line || ""; } throw new Error(message, { cause: error }); } } // ../../node_modules/@math.gl/core/dist/lib/common.js var RADIANS_TO_DEGREES = 1 / Math.PI * 180; var DEGREES_TO_RADIANS = 1 / 180 * Math.PI; var DEFAULT_CONFIG = { EPSILON: 1e-12, debug: false, precision: 4, printTypes: false, printDegrees: false, printRowMajor: true, _cartographicRadians: false }; globalThis.mathgl = globalThis.mathgl || { config: { ...DEFAULT_CONFIG } }; var config = globalThis.mathgl.config; function formatValue(value, { precision = config.precision } = {}) { value = round(value); return `${parseFloat(value.toPrecision(precision))}`; } function isArray(value) { return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView); } function equals(a, b, epsilon) { const oldEpsilon = config.EPSILON; if (epsilon) { config.EPSILON = epsilon; } try { if (a === b) { return true; } if (isArray(a) && isArray(b)) { if (a.length !== b.length) { return false; } for (let i = 0; i < a.length; ++i) { if (!equals(a[i], b[i])) { return false; } } return true; } if (a && a.equals) { return a.equals(b); } if (b && b.equals) { return b.equals(a); } if (typeof a === "number" && typeof b === "number") { return Math.abs(a - b) <= config.EPSILON * Math.max(1, Math.abs(a), Math.abs(b)); } return false; } finally { config.EPSILON = oldEpsilon; } } function round(value) { return Math.round(value / config.EPSILON) * config.EPSILON; } // ../../node_modules/@math.gl/core/dist/classes/base/math-array.js var MathArray = class extends Array { // Common methods /** * Clone the current object * @returns a new copy of this object */ clone() { return new this.constructor().copy(this); } fromArray(array, offset = 0) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] = array[i + offset]; } return this.check(); } toArray(targetArray = [], offset = 0) { for (let i = 0; i < this.ELEMENTS; ++i) { targetArray[offset + i] = this[i]; } return targetArray; } toObject(targetObject) { return targetObject; } from(arrayOrObject) { return Array.isArray(arrayOrObject) ? this.copy(arrayOrObject) : ( // @ts-ignore this.fromObject(arrayOrObject) ); } to(arrayOrObject) { if (arrayOrObject === this) { return this; } return isArray(arrayOrObject) ? this.toArray(arrayOrObject) : this.toObject(arrayOrObject); } toTarget(target) { return target ? this.to(target) : this; } /** @deprecated */ toFloat32Array() { return new Float32Array(this); } toString() { return this.formatString(config); } /** Formats string according to options */ formatString(opts) { let string = ""; for (let i = 0; i < this.ELEMENTS; ++i) { string += (i > 0 ? ", " : "") + formatValue(this[i], opts); } return `${opts.printTypes ? this.constructor.name : ""}[${string}]`; } equals(array) { if (!array || this.length !== array.length) { return false; } for (let i = 0; i < this.ELEMENTS; ++i) { if (!equals(this[i], array[i])) { return false; } } return true; } exactEquals(array) { if (!array || this.length !== array.length) { return false; } for (let i = 0; i < this.ELEMENTS; ++i) { if (this[i] !== array[i]) { return false; } } return true; } // Modifiers /** Negates all values in this object */ negate() { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] = -this[i]; } return this.check(); } lerp(a, b, t) { if (t === void 0) { return this.lerp(this, a, b); } for (let i = 0; i < this.ELEMENTS; ++i) { const ai = a[i]; const endValue = typeof b === "number" ? b : b[i]; this[i] = ai + t * (endValue - ai); } return this.check(); } /** Minimal */ min(vector) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] = Math.min(vector[i], this[i]); } return this.check(); } /** Maximal */ max(vector) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] = Math.max(vector[i], this[i]); } return this.check(); } clamp(minVector, maxVector) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] = Math.min(Math.max(this[i], minVector[i]), maxVector[i]); } return this.check(); } add(...vectors) { for (const vector of vectors) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] += vector[i]; } } return this.check(); } subtract(...vectors) { for (const vector of vectors) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] -= vector[i]; } } return this.check(); } scale(scale2) { if (typeof scale2 === "number") { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] *= scale2; } } else { for (let i = 0; i < this.ELEMENTS && i < scale2.length; ++i) { this[i] *= scale2[i]; } } return this.check(); } /** * Multiplies all elements by `scale` * Note: `Matrix4.multiplyByScalar` only scales its 3x3 "minor" */ multiplyByScalar(scalar) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] *= scalar; } return this.check(); } // Debug checks /** Throws an error if array length is incorrect or contains illegal values */ check() { if (config.debug && !this.validate()) { throw new Error(`math.gl: ${this.constructor.name} some fields set to invalid numbers'`); } return this; } /** Returns false if the array length is incorrect or contains illegal values */ validate() { let valid = this.length === this.ELEMENTS; for (let i = 0; i < this.ELEMENTS; ++i) { valid = valid && Number.isFinite(this[i]); } return valid; } // three.js compatibility /** @deprecated */ sub(a) { return this.subtract(a); } /** @deprecated */ setScalar(a) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] = a; } return this.check(); } /** @deprecated */ addScalar(a) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] += a; } return this.check(); } /** @deprecated */ subScalar(a) { return this.addScalar(-a); } /** @deprecated */ multiplyScalar(scalar) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] *= scalar; } return this.check(); } /** @deprecated */ divideScalar(a) { return this.multiplyByScalar(1 / a); } /** @deprecated */ clampScalar(min, max) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] = Math.min(Math.max(this[i], min), max); } return this.check(); } /** @deprecated */ get elements() { return this; } }; // ../../node_modules/@math.gl/core/dist/lib/validators.js function validateVector(v, length) { if (v.length !== length) { return false; } for (let i = 0; i < v.length; ++i) { if (!Number.isFinite(v[i])) { return false; } } return true; } function checkNumber(value) { if (!Number.isFinite(value)) { throw new Error(`Invalid number ${JSON.stringify(value)}`); } return value; } function checkVector(v, length, callerName = "") { if (config.debug && !validateVector(v, length)) { throw new Error(`math.gl: ${callerName} some fields set to invalid numbers'`); } return v; } // ../../node_modules/@math.gl/core/dist/lib/assert.js function assert2(condition, message) { if (!condition) { throw new Error(`math.gl assertion ${message}`); } } // ../../node_modules/@math.gl/core/dist/classes/base/vector.js var Vector = class extends MathArray { // ACCESSORS get x() { return this[0]; } set x(value) { this[0] = checkNumber(value); } get y() { return this[1]; } set y(value) { this[1] = checkNumber(value); } /** * Returns the length of the vector from the origin to the point described by this vector * * @note `length` is a reserved word for Arrays, so `v.length()` will return number of elements * Instead we provide `len` and `magnitude` */ len() { return Math.sqrt(this.lengthSquared()); } /** * Returns the length of the vector from the origin to the point described by this vector */ magnitude() { return this.len(); } /** * Returns the squared length of the vector from the origin to the point described by this vector */ lengthSquared() { let length = 0; for (let i = 0; i < this.ELEMENTS; ++i) { length += this[i] * this[i]; } return length; } /** * Returns the squared length of the vector from the origin to the point described by this vector */ magnitudeSquared() { return this.lengthSquared(); } distance(mathArray) { return Math.sqrt(this.distanceSquared(mathArray)); } distanceSquared(mathArray) { let length = 0; for (let i = 0; i < this.ELEMENTS; ++i) { const dist = this[i] - mathArray[i]; length += dist * dist; } return checkNumber(length); } dot(mathArray) { let product = 0; for (let i = 0; i < this.ELEMENTS; ++i) { product += this[i] * mathArray[i]; } return checkNumber(product); } // MODIFIERS normalize() { const length = this.magnitude(); if (length !== 0) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] /= length; } } return this.check(); } multiply(...vectors) { for (const vector of vectors) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] *= vector[i]; } } return this.check(); } divide(...vectors) { for (const vector of vectors) { for (let i = 0; i < this.ELEMENTS; ++i) { this[i] /= vector[i]; } } return this.check(); } // THREE.js compatibility lengthSq() { return this.lengthSquared(); } distanceTo(vector) { return this.distance(vector); } distanceToSquared(vector) { return this.distanceSquared(vector); } getComponent(i) { assert2(i >= 0 && i < this.ELEMENTS, "index is out of range"); return checkNumber(this[i]); } setComponent(i, value) { assert2(i >= 0 && i < this.ELEMENTS, "index is out of range"); this[i] = value; return this.check(); } addVectors(a, b) { return this.copy(a).add(b); } subVectors(a, b) { return this.copy(a).subtract(b); } multiplyVectors(a, b) { return this.copy(a).multiply(b); } addScaledVector(a, b) { return this.add(new this.constructor(a).multiplyScalar(b)); } }; // ../../node_modules/@math.gl/core/dist/gl-matrix/common.js var EPSILON = 1e-6; var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array; var degree = Math.PI / 180; // ../../node_modules/@math.gl/core/dist/gl-matrix/vec2.js function create() { const out = new ARRAY_TYPE(2); if (ARRAY_TYPE != Float32Array) { out[0] = 0; out[1] = 0; } return out; } function transformMat4(out, a, m) { const x = a[0]; const y = a[1]; out[0] = m[0] * x + m[4] * y + m[12]; out[1] = m[1] * x + m[5] * y + m[13]; return out; } var forEach = function() { const vec = create(); return function(a, stride, offset, count, fn, arg) { let i; let l; if (!stride) { stride = 2; } if (!offset) { offset = 0; } if (count) { l = Math.min(count * stride + offset, a.length); } else { l = a.length; } for (i = offset; i < l; i += stride) { vec[0] = a[i]; vec[1] = a[i + 1]; fn(vec, vec, arg); a[i] = vec[0]; a[i + 1] = vec[1]; } return a; }; }(); // ../../node_modules/@math.gl/core/dist/lib/gl-matrix-extras.js function vec2_transformMat4AsVector(out, a, m) { const x = a[0]; const y = a[1]; const w = m[3] * x + m[7] * y || 1; out[0] = (m[0] * x + m[4] * y) / w; out[1] = (m[1] * x + m[5] * y) / w; return out; } function vec3_transformMat4AsVector(out, a, m) { const x = a[0]; const y = a[1]; const z = a[2]; const w = m[3] * x + m[7] * y + m[11] * z || 1; out[0] = (m[0] * x + m[4] * y + m[8] * z) / w; out[1] = (m[1] * x + m[5] * y + m[9] * z) / w; out[2] = (m[2] * x + m[6] * y + m[10] * z) / w; return out; } function vec3_transformMat2(out, a, m) { const x = a[0]; const y = a[1]; out[0] = m[0] * x + m[2] * y; out[1] = m[1] * x + m[3] * y; out[2] = a[2]; return out; } // ../../node_modules/@math.gl/core/dist/gl-matrix/vec3.js function create2() { const out = new ARRAY_TYPE(3); if (ARRAY_TYPE != Float32Array) { out[0] = 0; out[1] = 0; out[2] = 0; } return out; } function dot(a, b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } function cross(out, a, b) { const ax = a[0]; const ay = a[1]; const az = a[2]; const bx = b[0]; const by = b[1]; const bz = b[2]; out[0] = ay * bz - az * by; out[1] = az * bx - ax * bz; out[2] = ax * by - ay * bx; return out; } function transformMat42(out, a, m) { const x = a[0]; const y = a[1]; const z = a[2]; let w = m[3] * x + m[7] * y + m[11] * z + m[15]; w = w || 1; out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; return out; } function transformMat3(out, a, m) { const x = a[0]; const y = a[1]; const z = a[2]; out[0] = x * m[0] + y * m[3] + z * m[6]; out[1] = x * m[1] + y * m[4] + z * m[7]; out[2] = x * m[2] + y * m[5] + z * m[8]; return out; } function transformQuat(out, a, q) { const qx = q[0]; const qy = q[1]; const qz = q[2]; const qw = q[3]; const x = a[0]; const y = a[1]; const z = a[2]; let uvx = qy * z - qz * y; let uvy = qz * x - qx * z; let uvz = qx * y - qy * x; let uuvx = qy * uvz - qz * uvy; let uuvy = qz * uvx - qx * uvz; let uuvz = qx * uvy - qy * uvx; const w2 = qw * 2; uvx *= w2; uvy *= w2; uvz *= w2; uuvx *= 2; uuvy *= 2; uuvz *= 2; out[0] = x + uvx + uuvx; out[1] = y + uvy + uuvy; out[2] = z + uvz + uuvz; return out; } function rotateX(out, a, b, rad) { const p = []; const r = []; p[0] = a[0] - b[0]; p[1] = a[1] - b[1]; p[2] = a[2] - b[2]; r[0] = p[0]; r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad); r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); out[0] = r[0] + b[0]; out[1] = r[1] + b[1]; out[2] = r[2] + b[2]; return out; } function rotateY(out, a, b, rad) { const p = []; const r = []; p[0] = a[0] - b[0]; p[1] = a[1] - b[1]; p[2] = a[2] - b[2]; r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad); r[1] = p[1]; r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); out[0] = r[0] + b[0]; out[1] = r[1] + b[1]; out[2] = r[2] + b[2]; return out; } function rotateZ(out, a, b, rad) { const p = []; const r = []; p[0] = a[0] - b[0]; p[1] = a[1] - b[1]; p[2] = a[2] - b[2]; r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad); r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad); r[2] = p[2]; out[0] = r[0] + b[0]; out[1] = r[1] + b[1]; out[2] = r[2] + b[2]; return out; } function angle(a, b) { const ax = a[0]; const ay = a[1]; const az = a[2]; const bx = b[0]; const by = b[1]; const bz = b[2]; const mag = Math.sqrt((ax * ax + ay * ay + az * az) * (bx * bx + by * by + bz * bz)); const cosine = mag && dot(a, b) / mag; return Math.acos(Math.min(Math.max(cosine, -1), 1)); } var forEach2 = function() { const vec = create2(); return function(a, stride, offset, count, fn, arg) { let i; let l; if (!stride) { stride = 3; } if (!offset) { offset = 0; } if (count) { l = Math.min(count * stride + offset, a.length); } else { l = a.length; } for (i = offset; i < l; i += stride) { vec[0] = a[i]; vec[1] = a[i + 1]; vec[2] = a[i + 2]; fn(vec, vec, arg); a[i] = vec[0]; a[i + 1] = vec[1]; a[i + 2] = vec[2]; } return a; }; }(); // ../../node_modules/@math.gl/core/dist/classes/vector3.js var ORIGIN = [0, 0, 0]; var ZERO; var Vector3 = class extends Vector { static get ZERO() { if (!ZERO) { ZERO = new Vector3(0, 0, 0); Object.freeze(ZERO); } return ZERO; } /** * @class * @param x * @param y * @param z */ constructor(x = 0, y = 0, z = 0) { super(-0, -0, -0); if (arguments.length === 1 && isArray(x)) { this.copy(x); } else { if (config.debug) { checkNumber(x); checkNumber(y); checkNumber(z); } this[0] = x; this[1] = y; this[2] = z; } } set(x, y, z) { this[0] = x; this[1] = y; this[2] = z; return this.check(); } copy(array) { this[0] = array[0]; this[1] = array[1]; this[2] = array[2]; return this.check(); } fromObject(object) { if (config.debug) { checkNumber(object.x); checkNumber(object.y); checkNumber(object.z); } this[0] = object.x; this[1] = object.y; this[2] = object.z; return this.check(); } toObject(object) { object.x = this[0]; object.y = this[1]; object.z = this[2]; return object; } // Getters/setters get ELEMENTS() { return 3; } get z() { return this[2]; } set z(value) { this[2] = checkNumber(value); } // ACCESSORS angle(vector) { return angle(this, vector); } // MODIFIERS cross(vector) { cross(this, this, vector); return this.check(); } rotateX({ radians, origin = ORIGIN }) { rotateX(this, this, origin, radians); return this.check(); } rotateY({ radians, origin = ORIGIN }) { rotateY(this, this, origin, radians); return this.check(); } rotateZ({ radians, origin = ORIGIN }) { rotateZ(this, this, origin, radians); return this.check(); } // Transforms // transforms as point (4th component is implicitly 1) transform(matrix4) { return this.transformAsPoint(matrix4); } // transforms as point (4th component is implicitly 1) transformAsPoint(matrix4) { transformMat42(this, this, matrix4); return this.check(); } // transforms as vector (4th component is implicitly 0, ignores translation. slightly faster) transformAsVector(matrix4) { vec3_transformMat4AsVector(this, this, matrix4); return this.check(); } transformByMatrix3(matrix3) { transformMat3(this, this, matrix3); return this.check(); } transformByMatrix2(matrix2) { vec3_transformMat2(this, this, matrix2); return this.check(); } transformByQuaternion(quaternion) { transformQuat(this, this, quaternion); return this.check(); } }; // ../../node_modules/@math.gl/core/dist/classes/base/matrix.js var Matrix = class extends MathArray { // fromObject(object) { // const array = object.elements; // return this.fromRowMajor(array); // } // toObject(object) { // const array = object.elements; // this.toRowMajor(array); // return object; // } // TODO better override formatString? toString() { let string = "["; if (config.printRowMajor) { string += "row-major:"; for (let row = 0; row < this.RANK; ++row) { for (let col = 0; col < this.RANK; ++col) { string += ` ${this[col * this.RANK + row]}`; } } } else { string += "column-major:"; for (let i = 0; i < this.ELEMENTS; ++i) { string += ` ${this[i]}`; } } string += "]"; return string; } getElementIndex(row, col) { return col * this.RANK + row; } // By default assumes row major indices getElement(row, col) { return this[col * this.RANK + row]; } // By default assumes row major indices setElement(row, col, value) { this[col * this.RANK + row] = checkNumber(value); return this; } getColumn(columnIndex, result = new Array(this.RANK).fill(-0)) { const firstIndex = columnIndex * this.RANK; for (let i = 0; i < this.RANK; ++i) { result[i] = this[firstIndex + i]; } return result; } setColumn(columnIndex, columnVector) { const firstIndex = columnIndex * this.RANK; for (let i = 0; i < this.RANK; ++i) { this[firstIndex + i] = columnVector[i]; } return this; } }; // ../../node_modules/@math.gl/core/dist/gl-matrix/mat4.js function identity(out) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = 1; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[10] = 1; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } function transpose(out, a) { if (out === a) { const a01 = a[1]; const a02 = a[2]; const a03 = a[3]; const a12 = a[6]; const a13 = a[7]; const a23 = a[11]; out[1] = a[4]; out[2] = a[8]; out[3] = a[12]; out[4] = a01; out[6] = a[9]; out[7] = a[13]; out[8] = a02; out[9] = a12; out[11] = a[14]; out[12] = a03; out[13] = a13; out[14] = a23; } else { out[0] = a[0]; out[1] = a[4]; out[2] = a[8]; out[3] = a[12]; out[4] = a[1]; out[5] = a[5]; out[6] = a[9]; out[7] = a[13]; out[8] = a[2]; out[9] = a[6]; out[10] = a[10]; out[11] = a[14]; out[12] = a[3]; out[13] = a[7]; out[14] = a[11]; out[15] = a[15]; } return out; } function invert(out, a) { const a00 = a[0]; const a01 = a[1]; const a02 = a[2]; const a03 = a[3]; const a10 = a[4]; const a11 = a[5]; const a12 = a[6]; const a13 = a[7]; const a20 = a[8]; const a21 = a[9]; const a22 = a[10]; const a23 = a[11]; const a30 = a[12]; const a31 = a[13]; const a32 = a[14]; const a33 = a[15]; const b00 = a00 * a11 - a01 * a10; const b01 = a00 * a12 - a02 * a10; const b02 = a00 * a13 - a03 * a10; const b03 = a01 * a12 - a02 * a11; const b04 = a01 * a13 - a03 * a11; const b05 = a02 * a13 - a03 * a12; const b06 = a20 * a31 - a21 * a30; const b07 = a20 * a32 - a22 * a30; const b08 = a20 * a33 - a23 * a30; const b09 = a21 * a32 - a22 * a31; const b10 = a21 * a33 - a23 * a31; const b11 = a22 * a33 - a23 * a32; let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; if (!det) { return null; } det = 1 / det; out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; return out; } function determinant(a) { const a00 = a[0]; const a01 = a[1]; const a02 = a[2]; const a03 = a[3]; const a10 = a[4]; const a11 = a[5]; const a12 = a[6]; const a13 = a[7]; const a20 = a[8]; const a21 = a[9]; const a22 = a[10]; const a23 = a[11]; const a30 = a[12]; const a31 = a[13]; const a32 = a[14]; const a33 = a[15]; const b0 = a00 * a11 - a01 * a10; const b1 = a00 * a12 - a02 * a10; const b2 = a01 * a12 - a02 * a11; const b3 = a20 * a31 - a21 * a30; const b4 = a20 * a32 - a22 * a30; const b5 = a21 * a32 - a22 * a31; const b6 = a00 * b5 - a01 * b4 + a02 * b3; const b7 = a10 * b5 - a11 * b4 + a12 * b3; const b8 = a20 * b2 - a21 * b1 + a22 * b0; const b9 = a30 * b2 - a31 * b1 + a32 * b0; return a13 * b6 - a03 * b7 + a33 * b8 - a23 * b9; } function multiply(out, a, b) { const a00 = a[0]; const a01 = a[1]; const a02 = a[2]; const a03 = a[3]; const a10 = a[4]; const a11 = a[5]; const a12 = a[6]; const a13 = a[7]; const a20 = a[8]; const a21 = a[9]; const a22 = a[10]; const a23 = a[11]; const a30 = a[12]; const a31 = a[13]; const a32 = a[14]; const a33 = a[15]; let b0 = b[0]; let b1 = b[1]; let b2 = b[2]; let b3 = b[3]; out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; return out; } function translate(out, a, v) { const x = v[0]; const y = v[1]; const z = v[2]; let a00; let a01; let a02; let a03; let a10; let a11; let a12; let a13; let a20; let a21; let a22; let a23; if (a === out) { out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; } else { a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; out[12] = a00 * x + a10 * y + a20 * z + a[12]; out[13] = a01 * x + a11 * y + a21 * z + a[13]; out[14] = a02 * x + a12 * y + a22 * z + a[14]; out[15] = a03 * x + a13 * y + a23 * z + a[15]; } return out; } function scale(out, a, v) { const x = v[0]; const y = v[1]; const z = v[2]; out[0] = a[0] * x; out[1] = a[1] * x; out[2] = a[2] * x; out[3] = a[3] * x; out[4] = a[4] * y; out[5] = a[5] * y; out[6] = a[6] * y; out[7] = a[7] * y; out[8] = a[8] * z; out[9] = a[9] * z; out[10] = a[10] * z; out[11] = a[11] * z; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; return out; } function rotate(out, a, rad, axis) { let x = axis[0]; let y = axis[1]; let z = axis[2]; let len = Math.sqrt(x * x + y * y + z * z); let c; let s; let t; let a00; let a01; let a02; let a03; let a10; let a11; let a12; let a13; let a20; let a21; let a22; let a23; let b00; let b01; let b02; let b10; let b11; let b12; let b20; let b21; let b22; if (len < EPSILON) { return null; } len = 1 / len; x *= len; y *= len; z *= len; s = Math.sin(rad); c = Math.cos(rad); t = 1 - c; a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; out[0] = a00 * b00 + a10 * b01 + a20 * b02; out[1] = a01 * b00 + a11 * b01 + a21 * b02; out[2] = a02 * b00 + a12 * b01 + a22 * b02; out[3] = a03 * b00 + a13 * b01 + a23 * b02; out[4] = a00 * b10 + a10 * b11 + a20 * b12; out[5] = a01 * b10 + a11 * b11 + a21 * b12; out[6] = a02 * b10 + a12 * b11 + a22 * b12; out[7] = a03 * b10 + a13 * b11 + a23 * b12; out[8] = a00 * b20 + a10 * b21 + a20 * b22; out[9] = a01 * b20 + a11 * b21 + a21 * b22; out[10] = a02 * b20 + a12 * b21 + a22 * b22; out[11] = a03 * b20 + a13 * b21 + a23 * b22; if (a !== out) { out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; } return out; } function rotateX2(out, a, rad) { const s = Math.sin(rad); const c = Math.cos(rad); const a10 = a[4]; const a11 = a[5]; const a12 = a[6]; const a13 = a[7]; const a20 = a[8]; const a21 = a[9]; const a22 = a[10]; const a23 = a[11]; if (a !== out) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; } out[4] = a10 * c + a20 * s; out[5] = a11 * c + a21 * s; out[6] = a12 * c + a22 * s; out[7] = a13 * c + a23 * s; out[8] = a20 * c - a10 * s; out[9] = a21 * c - a11 * s; out[10] = a22 * c - a12 * s; out[11] = a23 * c - a13 * s; return out; } function rotateY2(out, a, rad) { const s = Math.sin(rad); const c = Math.cos(rad); const a00 = a[0]; const a01 = a[1]; const a02 = a[2]; const a03 = a[3]; const a20 = a[8]; const a21 = a[9]; const a22 = a[10]; const a23 = a[11]; if (a !== out) { out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; } out[0] = a00 * c - a20 * s; out[1] = a01 * c - a21 * s; out[2] = a02 * c - a22 * s; out[3] = a03 * c - a23 * s; out[8] = a00 * s + a20 * c; out[9] = a01 * s + a21 * c; out[10] = a02 * s + a22 * c; out[11] = a03 * s + a23 * c; return out; } function rotateZ2(out, a, rad) { const s = Math.sin(rad); const c = Math.cos(rad); const a00 = a[0]; const a01 = a[1]; const a02 = a[2]; const a03 = a[3]; const a10 = a[4]; const a11 = a[5]; const a12 = a[6]; const a13 = a[7]; if (a !== out) { out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; } out[0] = a00 * c + a10 * s; out[1] = a01 * c + a11 * s; out[2] = a02 * c + a12 * s; out[3] = a03 * c + a13 * s; out[4] = a10 * c - a00 * s; out[5] = a11 * c - a01 * s; out[6] = a12 * c - a02 * s; out[7] = a13 * c - a03 * s; return out; } function fromQuat(out, q) { const x = q[0]; const y = q[1]; const z = q[2]; const w = q[3]; const x2 = x + x; const y2 = y + y; const z2 = z + z; const xx = x * x2; const yx = y * x2; const yy = y * y2; const zx = z * x2; const zy = z * y2; const zz = z * z2; const wx = w * x2; const wy = w * y2; const wz = w * z2; out[0] = 1 - yy - zz; out[1] = yx + wz; out[2] = zx - wy; out[3] = 0; out[4] = yx - wz; out[5] = 1 - xx - zz; out[6] = zy + wx; out[7] = 0; out[8] = zx + wy; out[9] = zy - wx; out[10] = 1 - xx - yy; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } function frustum(out, left, right, bottom, top, near, far) { const rl = 1 / (right - left); const tb = 1 / (top - bottom); const nf = 1 / (near - far); out[0] = near * 2 * rl; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = near * 2 * tb; out[6] = 0; out[7] = 0; out[8] = (right + left) * rl; out[9] = (top + bottom) * tb; out[10] = (far + near) * nf; out[11] = -1; out[12] = 0; out[13] = 0; out[14] = far * near * 2 * nf; out[15] = 0; return out; } function perspectiveNO(out, fovy, aspect, near, far) { const f = 1 / Math.tan(fovy / 2); out[0] = f / aspect; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = f; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[11] = -1; out[12] = 0; out[13] = 0; out[15] = 0; if (far != null && far !== Infinity) { const nf = 1 / (near - far); out[10] = (far + near) * nf; out[14] = 2 * far * near * nf; } else { out[10] = -1; out[14] = -2 * near; } return out; } var perspective = perspectiveNO; function orthoNO(out, left, right, bottom, top, near, far) { const lr = 1 / (left - right); const bt = 1 / (bottom - top); const nf = 1 / (near - far); out[0] = -2 * lr; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = -2 * bt; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[10] = 2 * nf; out[11] = 0; out[12] = (left + right) * lr; out[13] = (top + bottom) * bt; out[14] = (far + near) * nf; out[15] = 1; return out; } var ortho = orthoNO; function lookAt(out, eye, center, up) { let len; let x0; let x1; let x2; let y0; let y1; let y2; let z0; let z1; let z2; const eyex = eye[0]; const eyey = eye[1]; const eyez = eye[2]; const upx = up[0]; const upy = up[1]; const upz = up[2]; const centerx = center[0]; const centery = center[1]; const centerz = center[2]; if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) { return identity(out); } z0 = eyex - centerx; z1 = eyey - centery; z2 = eyez - centerz; len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); z0 *= len; z1 *= len; z2 *= len; x0 = upy * z2 - upz * z1; x1 = upz * z0 - upx * z2; x2 = upx * z1 - upy * z0; len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); if (!len) { x0 = 0; x1 = 0; x2 = 0; } else { len = 1 / len; x0 *= len; x1 *= len; x2 *= len; } y0 = z1 * x2 - z2 * x1; y1 = z2 * x0 - z0 * x2; y2 = z0 * x1 - z1 * x0; len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); if (!len) { y0 = 0; y1 = 0; y2 = 0; } else { len = 1 / len; y0 *= len; y1 *= len; y2 *= len; } out[0] = x0; out[1] = y0; out[2] = z0; out[3] = 0; out[4] = x1; out[5] = y1; out[6] = z1; out[7] = 0; out[8] = x2; out[9] = y2; out[10] = z2; out[11] = 0; out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); out[15] = 1; return out; } // ../../node_modules/@math.gl/core/dist/gl-matrix/vec4.js function create3() { const out = new ARRAY_TYPE(4); if (ARRAY_TYPE != Float32Array) { out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 0; } return out; } function transformMat43(out, a, m) { const x = a[0]; const y = a[1]; const z = a[2]; const w = a[3]; out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; return out; } var forEach3 = function() { const vec = create3(); return function(a, stride, offset, count, fn, arg) { let i; let l; if (!stride) { stride = 4; } if (!offset) { offset = 0; } if (count) { l = Math.min(count * stride + offset, a.length); } else { l = a.length; } for (i = offset; i < l; i += stride) { vec[0] = a[i]; vec[1] = a[i + 1]; vec[2] = a[i + 2]; vec[3] = a[i + 3]; fn(vec, vec, arg); a[i] = vec[0]; a[i + 1] = vec[1]; a[i + 2] = vec[2]; a[i + 3] = vec[3]; } return a; }; }(); // ../../node_modules/@math.gl/core/dist/classes/matrix4.js var INDICES; (function(INDICES2) { INDICES2[INDICES2["COL0ROW0"] = 0] = "COL0ROW0"; INDICES2[INDICES2["COL0ROW1"] = 1] = "COL0ROW1"; INDICES2[INDICES2["COL0ROW2"] = 2] = "COL0ROW2"; INDICES2[INDICES2["COL0ROW3"] = 3] = "COL0ROW3"; INDICES2[INDICES2["COL1ROW0"] = 4] = "COL1ROW0"; INDICES2[INDICES2["COL1ROW1"] = 5] = "COL1ROW1"; INDICES2[INDICES2["COL1ROW2"] = 6] = "COL1ROW2"; INDICES2[INDICES2["COL1ROW3"] = 7] = "COL1ROW3"; INDICES2[INDICES2["COL2ROW0"] = 8] = "COL2ROW0"; INDICES2[INDICES2["COL2ROW1"] = 9] = "COL2ROW1"; INDICES2[INDICES2["COL2ROW2"] = 10] = "COL2ROW2"; INDICES2[INDICES2["COL2ROW3"] = 11] = "COL2ROW3"; INDICES2[INDICES2["COL3ROW0"] = 12] = "COL3ROW0"; INDICES2[INDICES2["COL3ROW1"] = 13] = "COL3ROW1"; INDICES2[INDICES2["COL3ROW2"] = 14] = "COL3ROW2"; INDICES2[INDICES2["COL3ROW3"] = 15] = "COL3ROW3"; })(INDICES || (INDICES = {})); var DEFAULT_FOVY = 45 * Math.PI / 180; var DEFAULT_ASPECT = 1; var DEFAULT_NEAR = 0.1; var DEFAULT_FAR = 500; var IDENTITY_MATRIX = Object.freeze([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); var Matrix4 = class extends Matrix { static get IDENTITY() { return getIdentityMatrix(); } static get ZERO() { return getZeroMatrix(); } get ELEMENTS() { return 16; } get RANK() { return 4; } get INDICES() { return INDICES; } constructor(array) { super(-0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0); if (arguments.length === 1 && Array.isArray(array)) { this.copy(array); } else { this.identity(); } } copy(array) { this[0] = array[0]; this[1] = array[1]; this[2] = array[2]; this[3] = array[3]; this[4] = array[4]; this[5] = array[5]; this[6] = array[6]; this[7] = array[7]; this[8] = array[8]; this[9] = array[9]; this[10] = array[10]; this[11] = array[11]; this[12] = array[12]; this[13] = array[13]; this[14] = array[14]; this[15] = array[15]; return this.check(); } // eslint-disable-next-line max-params set(m00, m10, m20, m30, m01, m11, m21, m31, m02, m12, m22, m32, m03, m13, m23, m33) { this[0] = m00; this[1] = m10; this[2] = m20; this[3] = m30; this[4] = m01; this[5] = m11; this[6] = m21; this[7] = m31; this[8] = m02; this[9] = m12; this[10] = m22; this[11] = m32; this[12] = m03; this[13] = m13; this[14] = m23; this[15] = m33; return this.check(); } // accepts row major order, stores as column major // eslint-disable-next-line max-params setRowMajor(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { this[0] = m00; this[1] = m10; this[2] = m20; this[3] = m30; this[4] = m01; this[5] = m11; this[6] = m21; this[7] = m31; this[8] = m02; this[9] = m12; this[10] = m22; this[11] = m32; this[12] = m03; this[13] = m13; this[14] = m23; this[15] = m33; return this.check(); } toRowMajor(result) { result[0] = this[0]; result[1] = this[4]; result[2] = this[8]; result[3] = this[12]; result[4] = this[1]; result[5] = this[5]; result[6] = this[9]; result[7] = this[13]; result[8] = this[2]; result[9] = this[6]; result[10] = this[10]; result[11] = this[14]; result[12] = this[3]; result[13] = this[7]; result[14] = this[11]; result[15] = this[15]; return result; } // Constructors /** Set to identity matrix */ identity() { return this.copy(IDENTITY_MATRIX); } /** * * @param object * @returns self */ // eslint-disable-next-line @typescript-eslint/no-unused-vars fromObject(object) { return this.check(); } /** * Calculates a 4x4 matrix from the given quaternion * @param quaternion Quaternion to create matrix from * @returns self */ fromQuaternion(quaternion) { fromQuat(this, quaternion); return this.check(); } /** * Generates a frustum matrix with the given bounds * @param view.left - Left bound of the frustum * @param view.right - Right bound of the frustum * @param view.bottom - Bottom bound of the frustum * @param view.top - Top bound of the frustum * @param view.near - Near bound of the frustum * @param view.far - Far bound of the frustum. Can be set to Infinity. * @returns self */ frustum(view) { const { left, right, bottom, top, near = DEFAULT_NEAR, far = DEFAULT_FAR } = view; if (far === Infinity) { computeInfinitePerspectiveOffCenter(this, left, right, bottom, top, near); } else { frustum(this, left, right, bottom, top, near, far); } return this.check(); } /** * Generates a look-at matrix with the given eye position, focal point, * and up axis * @param view.eye - (vector) Position of the viewer * @param view.center - (vector) Point the viewer is looking at * @param view.up - (vector) Up axis * @returns self */ lookAt(view) { const { eye, center = [0, 0, 0], up = [0, 1, 0] } = view; lookAt(this, eye, center, up); return this.check(); } /** * Generates a orthogonal projection matrix with the given bounds * from "traditional" view space parameters * @param view.left - Left bound of the frustum * @param view.right number Right bound of the frustum * @param view.bottom - Bottom bound of the frustum * @param view.top number Top bound of the frustum * @param view.near - Near bound of the frustum * @param view.far number Far bound of the frustum * @returns self */ ortho(view) { const { left, right, bottom, top, near = DEFAULT_NEAR, far = DEFAULT_FAR } = view; ortho(this, left, right, bottom, top, near, far); return this.check(); } /** * Generates an orthogonal projection matrix with the same parameters * as a perspective matrix (plus focalDistance) * @param view.fovy Vertical field of view in radians * @param view.aspect Aspect ratio. Typically viewport width / viewport height * @param view.focalDistance Distance in the view frustum used for extent calculations * @param view.near Near bound of the frustum * @param view.far Far bound of the frustum * @returns self */ orthographic(view) { const { fovy = DEFAULT_FOVY, aspect = DEFAULT_ASPECT, focalDistance = 1, near = DEFAULT_NEAR, far = DEFAULT_FAR } = view; checkRadians(fovy); const halfY = fovy / 2; const top = focalDistance * Math.tan(halfY); const right = top * aspect; return this.ortho({ left: -right, right, bottom: -top, top, near, far }); } /** * Generates a perspective projection matrix with the given bounds * @param view.fovy Vertical field of view in radians * @param view.aspect Aspect ratio. typically viewport width/height * @param view.near Near bound of the frustum * @param view.far Far bound of the frustum * @returns self */ perspective(view) { const { fovy = 45 * Math.PI / 180, aspect = 1, near = 0.1, far = 500 } = view; checkRadians(fovy); perspective(this, fovy, aspect, near, far); return this.check(); } // Accessors determinant() { return determinant(this); } /** * Extracts the non-uniform scale assuming the matrix is an affine transformation. * The scales are the "lengths" of the column vectors in the upper-left 3x3 matrix. * @param result * @returns self */ getScale(result = [-0, -0, -0]) { result[0] = Math.sqrt(this[0] * this[0] + this[1] * this[1] + this[2] * this[2]); result[1] = Math.sqrt(this[4] * this[4] + this[5] * this[5] + this[6] * this[6]); result[2] = Math.sqrt(this[8] * this[8] + this[9] * this[9] + this[10] * this[10]); return result; } /** * Gets the translation portion, assuming the matrix is a affine transformation matrix. * @param result * @returns self */ getTranslation(result = [-0, -0, -0]) { result[0] = this[12]; result[1] = this[13]; result[2] = this[14]; return result; } /** * Gets upper left 3x3 pure rotation matrix (non-scaling), assume affine transformation matrix * @param result * @param scaleResult * @returns self */ getRotation(result, scaleResult) { result = result || [-0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0]; scaleResult = scaleResult || [-0, -0, -0]; const scale2 = this.getScale(scaleResult); const inverseScale0 = 1 / scale2[0]; const inverseScale1 = 1 / scale2[1]; const inverseScale2 = 1 / scale2[2]; result[0] = this[0] * inverseScale0; result[1] = this[1] * inverseScale1; result[2] = this[2] * inverseScale2; result[3] = 0; result[4] = this[4] * inverseScale0; result[5] = this[5] * inverseScale1; result[6] = this[6] * inverseScale2; result[7] = 0; result[8] = this[8] * inverseScale0; result[9] = this[9] * inverseScale1; result[10] = this[10] * inverseScale2; result[11] = 0; result[12] = 0; result[13] = 0; result[14] = 0; result[15] = 1; return result; } /** * * @param result * @param scaleResult * @returns self */ getRotationMatrix3(result, scaleResult) { result = result || [-0, -0, -0, -0, -0, -0, -0, -0, -0]; scaleResult = scaleResult || [-0, -0, -0]; const scale2 = this.getScale(scaleResult); const inverseScale0 = 1 / scale2[0]; const inverseScale1 = 1 / scale2[1]; const inverseScale2 = 1 / scale2[2]; result[0] = this[0] * inverseScale0; result[1] = this[1] * inverseScale1; result[2] = this[2] * inverseScale2; result[3] = this[4] * inverseScale0; result[4] = this[5] * inverseScale1; result[5] = this[6] * inverseScale2; result[6] = this[8] * inverseScale0; result[7] = this[9] * inverseScale1; result[8] = this[10] * inverseScale2; return result; } // Modifiers transpose() { transpose(this, this); return this.check(); } invert() { invert(this, this); return this.check(); } // Operations multiplyLeft(a) { multiply(this, a, this); return this.check(); } multiplyRight(a) { multiply(this, this, a); return this.check(); } // Rotates a matrix by the given angle around the X axis rotateX(radians) { rotateX2(this, this, radians); return this.check(); } // Rotates a matrix by the given angle around the Y axis. rotateY(radians) { rotateY2(this, this, radians); return this.check(); } /** * Rotates a matrix by the given angle around the Z axis. * @param radians * @returns self */ rotateZ(radians) { rotateZ2(this, this, radians); return this.check(); } /** * * @param param0 * @returns self */ rotateXYZ(angleXYZ) { return this.rotateX(angleXYZ[0]).rotateY(angleXYZ[1]).rotateZ(angleXYZ[2]); } /** * * @param radians * @param axis * @returns self */ rotateAxis(radians, axis) { rotate(this, this, radians, axis); return this.check(); } /** * * @param factor * @returns self */ scale(factor) { scale(this, this, Array.isArray(factor) ? factor : [factor, factor, factor]); return this.check(); } /** * * @param vec * @returns self */ translate(vector) { translate(this, this, vector); return this.check(); } // Transforms /** * Transforms any 2, 3 or 4 element vector. 2 and 3 elements are treated as points * @param vector * @param result * @returns self */ transform(vector, result) { if (vector.length === 4) { result = transformMat43(result || [-0, -0, -0, -0], vector, this); checkVector(result, 4); return result; } return this.transformAsPoint(vector, result); } /** * Transforms any 2 or 3 element array as point (w implicitly 1) * @param vector * @param result * @returns self */ transformAsPoint(vector, result) { const { length } = vector; let out; switch (length) { case 2: out = transformMat4(result || [-0, -0], vector, this); break; case 3: out = transformMat42(result || [-0, -0, -0], vector, this); break; default: throw new Error("Illegal vector"); } checkVector(out, vector.length); return out; } /** * Transforms any 2 or 3 element array as vector (w implicitly 0) * @param vector * @param result * @returns self */ transformAsVector(vector, result) { let out; switch (vector.length) { case 2: out = vec2_transformMat4AsVector(result || [-0, -0], vector, this); break; case 3: out = vec3_transformMat4AsVector(result || [-0, -0, -0], vector, this); break; default: throw new Error("Illegal vector"); } checkVector(out, vector.length); return out; } /** @deprecated */ transformPoint(vector, result) { return this.transformAsPoint(vector, result); } /** @deprecated */ transformVector(vector, result) { return this.transformAsPoint(vector, result); } /** @deprecated */ transformDirection(vector, result) { return this.transformAsVector(vector, result); } // three.js math API compatibility makeRotationX(radians) { return this.identity().rotateX(radians); } makeTranslation(x, y, z) { return this.identity().translate([x, y, z]); } }; var ZERO2; var IDENTITY; function getZeroMatrix() { if (!ZERO2) { ZERO2 = new Matrix4([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); Object.freeze(ZERO2); } return ZERO2; } function getIdentityMatrix() { if (!IDENTITY) { IDENTITY = new Matrix4(); Object.freeze(IDENTITY); } return IDENTITY; } function checkRadians(possiblyDegrees) { if (possiblyDegrees > Math.PI * 2) { throw Error("expected radians"); } } function computeInfinitePerspectiveOffCenter(result, left, right, bottom, top, near) { const column0Row0 = 2 * near / (right - left); const column1Row1 = 2 * near / (top - bottom); const column2Row0 = (right + left) / (right - left); const column2Row1 = (top + bottom) / (top - bottom); const column2Row2 = -1; const column2Row3 = -1; const column3Row2 = -2 * near; result[0] = column0Row0; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = 0; result[5] = column1Row1; result[6] = 0; result[7] = 0; result[8] = column2Row0; result[9] = column2Row1; result[10] = column2Row2; result[11] = column2Row3; result[12] = 0; result[13] = 0; result[14] = column3Row2; result[15] = 0; return result; } // src/geometry/gpu-geometry.ts var import_core5 = __toESM(require_core(), 1); var GPUGeometry = class { id; userData = {}; /** Determines how vertices are read from the 'vertex' attributes */ topology; bufferLayout = []; vertexCount; indices; attributes; constructor(props) { this.id = props.id || (0, import_core5.uid)("geometry"); this.topology = props.topology; this.indices = props.indices || null; this.attributes = props.attributes; this.vertexCount = props.vertexCount; this.bufferLayout = props.bufferLayout || []; if (this.indices) { (0, import_core5.assert)(this.indices.usage === import_core5.Buffer.INDEX); } } destroy() { this.indices?.destroy(); for (const attribute of Object.values(this.attributes)) { attribute.destroy(); } } getVertexCount() { return this.vertexCount; } getAttributes() { return this.attributes; } getIndexes() { return this.indices; } _calculateVertexCount(positions) { const vertexCount = positions.byteLength / 12; return vertexCount; } }; function makeGPUGeometry(device, geometry) { if (geometry instanceof GPUGeometry) { return geometry; } const indices = getIndexBufferFromGeometry(device, geometry); const { attributes, bufferLayout } = getAttributeBuffersFromGeometry(device, geometry); return new GPUGeometry({ topology: geometry.topology || "triangle-list", bufferLayout, vertexCount: geometry.vertexCount, indices, attributes }); } function getIndexBufferFromGeometry(device, geometry) { if (!geometry.indices) { return void 0; } const data = geometry.indices.value; return device.createBuffer({ usage: import_core5.Buffer.INDEX, data }); } function getAttributeBuffersFromGeometry(device, geometry) { const bufferLayout = []; const attributes = {}; for (const [attributeName, attribute] of Object.entries(geometry.attributes)) { let name = attributeName; switch (attributeName) { case "POSITION": name = "positions"; break; case "NORMAL": name = "normals"; break; case "TEXCOORD_0": name = "texCoords"; break; case "COLOR_0": name = "colors"; break; } attributes[name] = device.createBuffer({ data: attribute.value, id: `${attributeName}-buffer` }); const { value, size, normalized } = attribute; bufferLayout.push({ name, format: (0, import_core5.getVertexFormatFromAttribute)(value, size, normalized) }); } const vertexCount = geometry._calculateVertexCount(geometry.attributes, geometry.indices); return { attributes, bufferLayout, vertexCount }; } // src/shader-inputs.ts var import_core6 = __toESM(require_core(), 1); var ShaderInputs = class { /** * The map of modules * @todo should should this include the resolved dependencies? */ modules; /** Stores the uniform values for each module */ moduleUniforms; /** Stores the uniform bindings for each module */ moduleBindings; /** Tracks if uniforms have changed */ moduleUniformsChanged; /** * Create a new UniformStore instance * @param modules */ constructor(modules) { const resolvedModules = resolveModules( Object.values(modules).filter((module) => module.dependencies) ); for (const resolvedModule of resolvedModules) { modules[resolvedModule.name] = resolvedModule; } import_core6.log.log(1, "Creating ShaderInputs with modules", Object.keys(modules))(); this.modules = modules; this.moduleUniforms = {}; this.moduleBindings = {}; for (const [name, module] of Object.entries(modules)) { const moduleName = name; this.moduleUniforms[moduleName] = module.defaultUniforms || {}; this.moduleBindings[moduleName] = {}; } } /** Destroy */ destroy() { } /** * Set module props */ setProps(props) { for (const name of Object.keys(props)) { const moduleName = name; const moduleProps = props[moduleName]; const module = this.modules[moduleName]; if (!module) { import_core6.log.warn(`Module ${name} not found`)(); continue; } const oldUniforms = this.moduleUniforms[moduleName]; const oldBindings = this.moduleBindings[moduleName]; const uniformsAndBindings = module.getUniforms?.(moduleProps, oldUniforms) || moduleProps; const { uniforms, bindings } = (0, import_core6.splitUniformsAndBindings)(uniformsAndBindings); this.moduleUniforms[moduleName] = { ...oldUniforms, ...uniforms }; this.moduleBindings[moduleName] = { ...oldBindings, ...bindings }; } } /** Merges all bindings for the shader (from the various modules) */ // getUniformBlocks(): Record { // return this.moduleUniforms; // } /** * Return the map of modules * @todo should should this include the resolved dependencies? */ getModules() { return Object.values(this.modules); } /** Get all uniform values for all modules */ getUniformValues() { return this.moduleUniforms; } /** Merges all bindings for the shader (from the various modules) */ getBindings() { const bindings = {}; for (const moduleBindings of Object.values(this.moduleBindings)) { Object.assign(bindings, moduleBindings); } return bindings; } getDebugTable() { const table = {}; for (const [moduleName, module] of Object.entries(this.moduleUniforms)) { for (const [key, value] of Object.entries(module)) { table[`${moduleName}.${key}`] = { type: this.modules[moduleName].uniformTypes?.[key], value: String(value) }; } } return table; } }; // src/lib/pipeline-factory.ts var import_core7 = __toESM(require_core(), 1); var _PipelineFactory = class { device; _hashCounter = 0; _hashes = {}; _renderPipelineCache = {}; _computePipelineCache = {}; /** Get the singleton default pipeline factory for the specified device */ static getDefaultPipelineFactory(device) { device._lumaData.defaultPipelineFactory = device._lumaData.defaultPipelineFactory || new _PipelineFactory(device); return device._lumaData.defaultPipelineFactory; } constructor(device) { this.device = device; } /** Return a RenderPipeline matching props. Reuses a similar pipeline if already created. */ createRenderPipeline(props) { const allProps = { ...import_core7.RenderPipeline.defaultProps, ...props }; const hash = this._hashRenderPipeline(allProps); if (!this._renderPipelineCache[hash]) { const pipeline = this.device.createRenderPipeline({ ...allProps, id: allProps.id ? `${allProps.id}-cached` : void 0 }); pipeline.hash = hash; this._renderPipelineCache[hash] = { pipeline, useCount: 0 }; } this._renderPipelineCache[hash].useCount++; return this._renderPipelineCache[hash].pipeline; } createComputePipeline(props) { const allProps = { ...import_core7.ComputePipeline.defaultProps, ...props }; const hash = this._hashComputePipeline(allProps); if (!this._computePipelineCache[hash]) { const pipeline = this.device.createComputePipeline({ ...allProps, id: allProps.id ? `${allProps.id}-cached` : void 0 }); pipeline.hash = hash; this._computePipelineCache[hash] = { pipeline, useCount: 0 }; } this._computePipelineCache[hash].useCount++; return this._computePipelineCache[hash].pipeline; } release(pipeline) { const hash = pipeline.hash; const cache = pipeline instanceof import_core7.ComputePipeline ? this._computePipelineCache : this._renderPipelineCache; cache[hash].useCount--; if (cache[hash].useCount === 0) { cache[hash].pipeline.destroy(); delete cache[hash]; } } // PRIVATE _hashComputePipeline(props) { const shaderHash = this._getHash(props.shader.source); return `${shaderHash}`; } /** Calculate a hash based on all the inputs for a render pipeline */ _hashRenderPipeline(props) { const vsHash = this._getHash(props.vs.source); const fsHash = props.fs ? this._getHash(props.fs.source) : 0; const varyingHash = "-"; const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout)); switch (this.device.type) { case "webgl": return `${vsHash}/${fsHash}V${varyingHash}BL${bufferLayoutHash}`; default: const parameterHash = this._getHash(JSON.stringify(props.parameters)); return `${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`; } } _getHash(key) { if (this._hashes[key] === void 0) { this._hashes[key] = this._hashCounter++; } return this._hashes[key]; } }; var PipelineFactory = _PipelineFactory; __publicField(PipelineFactory, "defaultProps", { ...import_core7.RenderPipeline.defaultProps }); // src/lib/shader-factory.ts var import_core8 = __toESM(require_core(), 1); var _ShaderFactory = class { device; _cache = {}; /** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */ static getDefaultShaderFactory(device) { device._lumaData.defaultShaderFactory ||= new _ShaderFactory(device); return device._lumaData.defaultShaderFactory; } /** @internal */ constructor(device) { this.device = device; } /** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */ createShader(props) { const key = this._hashShader(props); let cacheEntry = this._cache[key]; if (!cacheEntry) { const shader = this.device.createShader({ ...props, id: props.id ? `${props.id}-cached` : void 0 }); this._cache[key] = cacheEntry = { shader, useCount: 0 }; } cacheEntry.useCount++; return cacheEntry.shader; } /** Releases a previously-requested {@link Shader}, destroying it if no users remain. */ release(shader) { const key = this._hashShader(shader); const cacheEntry = this._cache[key]; if (cacheEntry) { cacheEntry.useCount--; if (cacheEntry.useCount === 0) { delete this._cache[key]; cacheEntry.shader.destroy(); } } } // PRIVATE _hashShader(value) { return `${value.stage}:${value.source}`; } }; var ShaderFactory = _ShaderFactory; __publicField(ShaderFactory, "defaultProps", { ...import_core8.Shader.defaultProps }); // src/debug/debug-shader-layout.ts function getDebugTableForShaderLayout(layout, name) { const table = {}; const header = "Values"; if (layout.attributes.length === 0 && !layout.varyings?.length) { return { "No attributes or varyings": { [header]: "N/A" } }; } for (const attributeDeclaration of layout.attributes) { if (attributeDeclaration) { const glslDeclaration = `${attributeDeclaration.location} ${attributeDeclaration.name}: ${attributeDeclaration.type}`; table[`in ${glslDeclaration}`] = { [header]: attributeDeclaration.stepMode || "vertex" }; } } for (const varyingDeclaration of layout.varyings || []) { const glslDeclaration = `${varyingDeclaration.location} ${varyingDeclaration.name}`; table[`out ${glslDeclaration}`] = { [header]: JSON.stringify(varyingDeclaration.accessor) }; } return table; } // src/debug/debug-framebuffer.ts var canvas = null; var ctx = null; function debugFramebuffer(fbo, { id, minimap, opaque, top = "0", left = "0", rgbaScale = 1 }) { if (!canvas) { canvas = document.createElement("canvas"); canvas.id = id; canvas.title = id; canvas.style.zIndex = "100"; canvas.style.position = "absolute"; canvas.style.top = top; canvas.style.left = left; canvas.style.border = "blue 1px solid"; canvas.style.transform = "scaleY(-1)"; document.body.appendChild(canvas); ctx = canvas.getContext("2d"); } if (canvas.width !== fbo.width || canvas.height !== fbo.height) { canvas.width = fbo.width / 2; canvas.height = fbo.height / 2; canvas.style.width = "400px"; canvas.style.height = "400px"; } const color = fbo.device.readPixelsToArrayWebGL(fbo); const imageData = ctx.createImageData(fbo.width, fbo.height); const offset = 0; for (let i = 0; i < color.length; i += 4) { imageData.data[offset + i + 0] = color[i + 0] * rgbaScale; imageData.data[offset + i + 1] = color[i + 1] * rgbaScale; imageData.data[offset + i + 2] = color[i + 2] * rgbaScale; imageData.data[offset + i + 3] = opaque ? 255 : color[i + 3] * rgbaScale; } ctx.putImageData(imageData, 0, 0); } // src/model/model.ts var LOG_DRAW_PRIORITY = 2; var LOG_DRAW_TIMEOUT = 1e4; var _Model = class { device; id; source; vs; fs; pipelineFactory; shaderFactory; userData = {}; // Fixed properties (change can trigger pipeline rebuild) /** The render pipeline GPU parameters, depth testing etc */ parameters; /** The primitive topology */ topology; /** Buffer layout */ bufferLayout; // Dynamic properties /** Use instanced rendering */ isInstanced = void 0; /** instance count. `undefined` means not instanced */ instanceCount = 0; /** Vertex count */ vertexCount; /** Index buffer */ indexBuffer = null; /** Buffer-valued attributes */ bufferAttributes = {}; /** Constant-valued attributes */ constantAttributes = {}; /** Bindings (textures, samplers, uniform buffers) */ bindings = {}; /** Sets uniforms @deprecated Use uniform buffers and setBindings() for portability*/ uniforms = {}; /** * VertexArray * @note not implemented: if bufferLayout is updated, vertex array has to be rebuilt! * @todo - allow application to define multiple vertex arrays? * */ vertexArray; /** TransformFeedback, WebGL 2 only. */ transformFeedback = null; /** The underlying GPU "program". @note May be recreated if parameters change */ pipeline; /** ShaderInputs instance */ shaderInputs; _uniformStore; _attributeInfos = {}; _gpuGeometry = null; _getModuleUniforms; props; _pipelineNeedsUpdate = "newly created"; _needsRedraw = "initializing"; _destroyed = false; /** "Time" of last draw. Monotonically increasing timestamp */ _lastDrawTimestamp = -1; constructor(device, props) { this.props = { ..._Model.defaultProps, ...props }; props = this.props; this.id = props.id || (0, import_core11.uid)("model"); this.device = device; Object.assign(this.userData, props.userData); const moduleMap = Object.fromEntries( this.props.modules?.map((module) => [module.name, module]) || [] ); this.setShaderInputs(props.shaderInputs || new ShaderInputs(moduleMap)); const platformInfo = getPlatformInfo(device); const modules = (this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || []; const isWebGPU = this.device.type === "webgpu"; if (isWebGPU && this.props.source) { this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.source); const { source, getUniforms } = this.props.shaderAssembler.assembleShader({ platformInfo, ...this.props, modules }); this.source = source; this._getModuleUniforms = getUniforms; } else { const { vs, fs, getUniforms } = this.props.shaderAssembler.assembleShaderPair({ platformInfo, ...this.props, modules }); this.vs = vs; this.fs = fs; this._getModuleUniforms = getUniforms; } this.vertexCount = this.props.vertexCount; this.instanceCount = this.props.instanceCount; this.topology = this.props.topology; this.bufferLayout = this.props.bufferLayout; this.parameters = this.props.parameters; if (props.geometry) { this.setGeometry(props.geometry); } this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device); this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device); this.pipeline = this._updatePipeline(); this.vertexArray = device.createVertexArray({ renderPipeline: this.pipeline }); if (this._gpuGeometry) { this._setGeometryAttributes(this._gpuGeometry); } if ("isInstanced" in props) { this.isInstanced = props.isInstanced; } if (props.instanceCount) { this.setInstanceCount(props.instanceCount); } if (props.vertexCount) { this.setVertexCount(props.vertexCount); } if (props.indexBuffer) { this.setIndexBuffer(props.indexBuffer); } if (props.attributes) { this.setAttributes(props.attributes); } if (props.constantAttributes) { this.setConstantAttributes(props.constantAttributes); } if (props.bindings) { this.setBindings(props.bindings); } if (props.uniforms) { this.setUniforms(props.uniforms); } if (props.moduleSettings) { this.updateModuleSettings(props.moduleSettings); } if (props.transformFeedback) { this.transformFeedback = props.transformFeedback; } Object.seal(this); } destroy() { if (this._destroyed) return; this.pipelineFactory.release(this.pipeline); this.shaderFactory.release(this.pipeline.vs); if (this.pipeline.fs) { this.shaderFactory.release(this.pipeline.fs); } this._uniformStore.destroy(); this._gpuGeometry?.destroy(); this._destroyed = true; } // Draw call /** Query redraw status. Clears the status. */ needsRedraw() { if (this._getBindingsUpdateTimestamp() > this._lastDrawTimestamp) { this.setNeedsRedraw("contents of bound textures or buffers updated"); } const needsRedraw = this._needsRedraw; this._needsRedraw = false; return needsRedraw; } /** Mark the model as needing a redraw */ setNeedsRedraw(reason) { this._needsRedraw ||= reason; } predraw() { this.updateShaderInputs(); this.pipeline = this._updatePipeline(); } draw(renderPass) { this.predraw(); let drawSuccess; try { this._logDrawCallStart(); this.pipeline = this._updatePipeline(); this.pipeline.setBindings(this.bindings, { disableWarnings: this.props.disableWarnings }); if (!(0, import_core11.isObjectEmpty)(this.uniforms)) { this.pipeline.setUniformsWebGL(this.uniforms); } const { indexBuffer } = this.vertexArray; const indexCount = indexBuffer ? indexBuffer.byteLength / (indexBuffer.indexType === "uint32" ? 4 : 2) : void 0; drawSuccess = this.pipeline.draw({ renderPass, vertexArray: this.vertexArray, isInstanced: this.isInstanced, vertexCount: this.vertexCount, instanceCount: this.instanceCount, indexCount, transformFeedback: this.transformFeedback || void 0, // WebGL shares underlying cached pipelines even for models that have different parameters and topology, // so we must provide our unique parameters to each draw // (In WebGPU most parameters are encoded in the pipeline and cannot be changed per draw call) parameters: this.parameters, topology: this.topology }); } finally { this._logDrawCallEnd(); } this._logFramebuffer(renderPass); if (drawSuccess) { this._lastDrawTimestamp = this.device.timestamp; this._needsRedraw = false; } else { this._needsRedraw = "waiting for resource initialization"; } return drawSuccess; } // Update fixed fields (can trigger pipeline rebuild) /** * Updates the optional geometry * Geometry, set topology and bufferLayout * @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU */ setGeometry(geometry) { this._gpuGeometry?.destroy(); const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry); if (gpuGeometry) { this.setTopology(gpuGeometry.topology || "triangle-list"); this.bufferLayout = mergeBufferLayouts(gpuGeometry.bufferLayout, this.bufferLayout); if (this.vertexArray) { this._setGeometryAttributes(gpuGeometry); } } this._gpuGeometry = gpuGeometry; } /** * Updates the primitive topology ('triangle-list', 'triangle-strip' etc). * @note Triggers a pipeline rebuild / pipeline cache fetch on WebGPU */ setTopology(topology) { if (topology !== this.topology) { this.topology = topology; this._setPipelineNeedsUpdate("topology"); } } /** * Updates the buffer layout. * @note Triggers a pipeline rebuild / pipeline cache fetch */ setBufferLayout(bufferLayout) { this.bufferLayout = this._gpuGeometry ? mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout) : bufferLayout; this._setPipelineNeedsUpdate("bufferLayout"); this.pipeline = this._updatePipeline(); this.vertexArray = this.device.createVertexArray({ renderPipeline: this.pipeline }); if (this._gpuGeometry) { this._setGeometryAttributes(this._gpuGeometry); } } /** * Set GPU parameters. * @note Can trigger a pipeline rebuild / pipeline cache fetch. * @param parameters */ setParameters(parameters) { if (!(0, import_core11.deepEqual)(parameters, this.parameters, 2)) { this.parameters = parameters; this._setPipelineNeedsUpdate("parameters"); } } // Update dynamic fields /** * Updates the instance count (used in draw calls) * @note Any attributes with stepMode=instance need to be at least this big */ setInstanceCount(instanceCount) { this.instanceCount = instanceCount; if (this.isInstanced === void 0 && instanceCount > 0) { this.isInstanced = true; } this.setNeedsRedraw("instanceCount"); } /** * Updates the vertex count (used in draw calls) * @note Any attributes with stepMode=vertex need to be at least this big */ setVertexCount(vertexCount) { this.vertexCount = vertexCount; this.setNeedsRedraw("vertexCount"); } /** Set the shader inputs */ setShaderInputs(shaderInputs) { this.shaderInputs = shaderInputs; this._uniformStore = new import_core10.UniformStore(this.shaderInputs.modules); for (const moduleName of Object.keys(this.shaderInputs.modules)) { const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName); this.bindings[`${moduleName}Uniforms`] = uniformBuffer; } this.setNeedsRedraw("shaderInputs"); } /** Update uniform buffers from the model's shader inputs */ updateShaderInputs() { this._uniformStore.setUniforms(this.shaderInputs.getUniformValues()); this.setBindings(this.shaderInputs.getBindings()); this.setNeedsRedraw("shaderInputs"); } /** * Sets bindings (textures, samplers, uniform buffers) */ setBindings(bindings) { Object.assign(this.bindings, bindings); this.setNeedsRedraw("bindings"); } /** * Updates optional transform feedback. WebGL only. */ setTransformFeedback(transformFeedback) { this.transformFeedback = transformFeedback; this.setNeedsRedraw("transformFeedback"); } /** * Sets the index buffer * @todo - how to unset it if we change geometry? */ setIndexBuffer(indexBuffer) { this.vertexArray.setIndexBuffer(indexBuffer); this.setNeedsRedraw("indexBuffer"); } /** * Sets attributes (buffers) * @note Overrides any attributes previously set with the same name */ setAttributes(buffers, options) { if (buffers.indices) { import_core11.log.warn( `Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()` )(); } for (const [bufferName, buffer] of Object.entries(buffers)) { const bufferLayout = this.bufferLayout.find( (layout) => getAttributeNames(layout).includes(bufferName) ); if (!bufferLayout) { import_core11.log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)(); continue; } const attributeNames = getAttributeNames(bufferLayout); let set = false; for (const attributeName of attributeNames) { const attributeInfo = this._attributeInfos[attributeName]; if (attributeInfo) { this.vertexArray.setBuffer(attributeInfo.location, buffer); set = true; } } if (!set && !(options?.disableWarnings ?? this.props.disableWarnings)) { import_core11.log.warn( `Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"` )(); } } this.setNeedsRedraw("attributes"); } /** * Sets constant attributes * @note Overrides any attributes previously set with the same name * Constant attributes are only supported in WebGL, not in WebGPU * Any attribute that is disabled in the current vertex array object * is read from the context's global constant value for that attribute location. * @param constantAttributes */ setConstantAttributes(attributes, options) { for (const [attributeName, value] of Object.entries(attributes)) { const attributeInfo = this._attributeInfos[attributeName]; if (attributeInfo) { this.vertexArray.setConstantWebGL(attributeInfo.location, value); } else if (!(options?.disableWarnings ?? this.props.disableWarnings)) { import_core11.log.warn( `Model "${this.id}: Ignoring constant supplied for unknown attribute "${attributeName}"` )(); } } this.setNeedsRedraw("constants"); } // DEPRECATED METHODS /** * Sets individual uniforms * @deprecated WebGL only, use uniform buffers for portability * @param uniforms */ setUniforms(uniforms) { if (!(0, import_core11.isObjectEmpty)(uniforms)) { this.pipeline.setUniformsWebGL(uniforms); Object.assign(this.uniforms, uniforms); } this.setNeedsRedraw("uniforms"); } /** * @deprecated Updates shader module settings (which results in uniforms being set) */ updateModuleSettings(props) { const { bindings, uniforms } = (0, import_core11.splitUniformsAndBindings)(this._getModuleUniforms(props)); Object.assign(this.bindings, bindings); Object.assign(this.uniforms, uniforms); this.setNeedsRedraw("moduleSettings"); } // Internal methods /** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */ _getBindingsUpdateTimestamp() { let timestamp = 0; for (const binding of Object.values(this.bindings)) { if (binding instanceof import_core9.TextureView) { timestamp = Math.max(timestamp, binding.texture.updateTimestamp); } else if (binding instanceof import_core9.Buffer || binding instanceof import_core9.Texture) { timestamp = Math.max(timestamp, binding.updateTimestamp); } else if (!(binding instanceof import_core9.Sampler)) { timestamp = Math.max(timestamp, binding.buffer.updateTimestamp); } } return timestamp; } /** * Updates the optional geometry attributes * Geometry, sets several attributes, indexBuffer, and also vertex count * @note Can trigger a pipeline rebuild / pipeline cache fetch on WebGPU */ _setGeometryAttributes(gpuGeometry) { const attributes = { ...gpuGeometry.attributes }; for (const [attributeName] of Object.entries(attributes)) { if (!this.pipeline.shaderLayout.attributes.find((layout) => layout.name === attributeName) && attributeName !== "positions") { delete attributes[attributeName]; } } this.vertexCount = gpuGeometry.vertexCount; this.setIndexBuffer(gpuGeometry.indices || null); this.setAttributes(gpuGeometry.attributes, { disableWarnings: true }); this.setAttributes(attributes, { disableWarnings: this.props.disableWarnings }); this.setNeedsRedraw("geometry attributes"); } /** Mark pipeline as needing update */ _setPipelineNeedsUpdate(reason) { this._pipelineNeedsUpdate ||= reason; this.setNeedsRedraw(reason); } /** Update pipeline if needed */ _updatePipeline() { if (this._pipelineNeedsUpdate) { let prevShaderVs = null; let prevShaderFs = null; if (this.pipeline) { import_core11.log.log( 1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".` )(); prevShaderVs = this.pipeline.vs; prevShaderFs = this.pipeline.fs; } this._pipelineNeedsUpdate = false; const vs = this.shaderFactory.createShader({ id: `${this.id}-vertex`, stage: "vertex", source: this.source || this.vs, debug: this.props.debugShaders }); let fs = null; if (this.source) { fs = vs; } else if (this.fs) { fs = this.shaderFactory.createShader({ id: `${this.id}-fragment`, stage: "fragment", source: this.source || this.fs, debug: this.props.debugShaders }); } this.pipeline = this.pipelineFactory.createRenderPipeline({ ...this.props, bufferLayout: this.bufferLayout, topology: this.topology, parameters: this.parameters, vs, fs }); this._attributeInfos = (0, import_core12.getAttributeInfosFromLayouts)( this.pipeline.shaderLayout, this.bufferLayout ); if (prevShaderVs) this.shaderFactory.release(prevShaderVs); if (prevShaderFs) this.shaderFactory.release(prevShaderFs); } return this.pipeline; } /** Throttle draw call logging */ _lastLogTime = 0; _logOpen = false; _logDrawCallStart() { const logDrawTimeout = import_core11.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT; if (import_core11.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) { return; } this._lastLogTime = Date.now(); this._logOpen = true; import_core11.log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core11.log.level <= 2 })(); } _logDrawCallEnd() { if (this._logOpen) { const shaderLayoutTable = getDebugTableForShaderLayout(this.pipeline.shaderLayout, this.id); import_core11.log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)(); const uniformTable = this.shaderInputs.getDebugTable(); for (const [name, value] of Object.entries(this.uniforms)) { uniformTable[name] = { value }; } import_core11.log.table(LOG_DRAW_PRIORITY, uniformTable)(); const attributeTable = this._getAttributeDebugTable(); import_core11.log.table(LOG_DRAW_PRIORITY, this._attributeInfos)(); import_core11.log.table(LOG_DRAW_PRIORITY, attributeTable)(); import_core11.log.groupEnd(LOG_DRAW_PRIORITY)(); this._logOpen = false; } } _drawCount = 0; _logFramebuffer(renderPass) { const debugFramebuffers = import_core11.log.get("framebuffer"); this._drawCount++; if (!debugFramebuffers || this._drawCount++ > 3 && this._drawCount % 60) { return; } const framebuffer = renderPass.props.framebuffer; if (framebuffer) { debugFramebuffer(framebuffer, { id: framebuffer.id, minimap: true }); } } _getAttributeDebugTable() { const table = {}; for (const [name, attributeInfo] of Object.entries(this._attributeInfos)) { table[attributeInfo.location] = { name, type: attributeInfo.shaderType, values: this._getBufferOrConstantValues( this.vertexArray.attributes[attributeInfo.location], attributeInfo.bufferDataType ) }; } if (this.vertexArray.indexBuffer) { const { indexBuffer } = this.vertexArray; const values = indexBuffer.indexType === "uint32" ? new Uint32Array(indexBuffer.debugData) : new Uint16Array(indexBuffer.debugData); table.indices = { name: "indices", type: indexBuffer.indexType, values: values.toString() }; } return table; } // TODO - fix typing of luma data types _getBufferOrConstantValues(attribute, dataType) { const TypedArrayConstructor = (0, import_core12.getTypedArrayFromDataType)(dataType); const typedArray = attribute instanceof import_core9.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute; return typedArray.toString(); } }; var Model = _Model; __publicField(Model, "defaultProps", { ...import_core10.RenderPipeline.defaultProps, source: null, vs: null, fs: null, id: "unnamed", handle: void 0, userData: {}, defines: {}, modules: [], moduleSettings: void 0, geometry: null, indexBuffer: null, attributes: {}, constantAttributes: {}, varyings: [], isInstanced: void 0, instanceCount: 0, vertexCount: 0, shaderInputs: void 0, pipelineFactory: void 0, shaderFactory: void 0, transformFeedback: void 0, shaderAssembler: ShaderAssembler.getDefaultShaderAssembler(), debugShaders: void 0, disableWarnings: void 0 }); function mergeBufferLayouts(layouts1, layouts2) { const layouts = [...layouts1]; for (const attribute of layouts2) { const index2 = layouts.findIndex((attribute2) => attribute2.name === attribute.name); if (index2 < 0) { layouts.push(attribute); } else { layouts[index2] = attribute; } } return layouts; } function getPlatformInfo(device) { return { type: device.type, shaderLanguage: device.info.shadingLanguage, shaderLanguageVersion: device.info.shadingLanguageVersion, gpu: device.info.gpu, // HACK - we pretend that the DeviceFeatures is a Set, it has a similar API features: device.features }; } function getAttributeNames(bufferLayout) { return bufferLayout.attributes ? bufferLayout.attributes?.map((layout) => layout.attribute) : [bufferLayout.name]; } // src/transform/buffer-transform.ts var import_core13 = __toESM(require_core(), 1); var BufferTransform = class { device; model; transformFeedback; /** @deprecated Use device feature test. */ static isSupported(device) { return device?.info?.type === "webgl"; } constructor(device, props = Model.defaultProps) { (0, import_core13.assert)(BufferTransform.isSupported(device), "BufferTransform not yet implemented on WebGPU"); this.device = device; this.model = new Model(this.device, { id: props.id || "buffer-transform-model", fs: props.fs || getPassthroughFS(), topology: props.topology || "point-list", ...props }); this.transformFeedback = this.device.createTransformFeedback({ layout: this.model.pipeline.shaderLayout, buffers: props.feedbackBuffers }); this.model.setTransformFeedback(this.transformFeedback); Object.seal(this); } /** Destroy owned resources. */ destroy() { if (this.model) { this.model.destroy(); } } /** @deprecated Use {@link destroy}. */ delete() { this.destroy(); } /** Run one transform loop. */ run(options) { const renderPass = this.device.beginRenderPass(options); this.model.draw(renderPass); renderPass.end(); } /** @deprecated */ update(...args) { console.warn("TextureTransform#update() not implemented"); } /** Returns the {@link Buffer} or {@link BufferRange} for given varying name. */ getBuffer(varyingName) { return this.transformFeedback.getBuffer(varyingName); } readAsync(varyingName) { const result = this.getBuffer(varyingName); if (result instanceof import_core13.Buffer) { return result.readAsync(); } const { buffer, byteOffset = 0, byteLength = buffer.byteLength } = result; return buffer.readAsync(byteOffset, byteLength); } }; // src/transform/texture-transform.ts var FS_OUTPUT_VARIABLE = "transform_output"; var TextureTransform = class { device; model; sampler; currentIndex = 0; samplerTextureMap = null; bindings = []; // each element is an object : {sourceTextures, targetTexture, framebuffer} resources = {}; // resources to be deleted constructor(device, props) { this.device = device; this.sampler = device.createSampler({ addressModeU: "clamp-to-edge", addressModeV: "clamp-to-edge", minFilter: "nearest", magFilter: "nearest", mipmapFilter: "nearest" }); this.model = new Model(this.device, { id: props.id || "texture-transform-model", fs: props.fs || getPassthroughFS({ input: props.targetTextureVarying, inputChannels: props.targetTextureChannels, output: FS_OUTPUT_VARIABLE }), vertexCount: props.vertexCount, // TODO(donmccurdy): Naming? ...props }); this._initialize(props); Object.seal(this); } // Delete owned resources. destroy() { } /** @deprecated Use {@link destroy}. */ delete() { this.destroy(); } run(options) { const { framebuffer } = this.bindings[this.currentIndex]; const renderPass = this.device.beginRenderPass({ framebuffer, ...options }); this.model.draw(renderPass); renderPass.end(); } /** @deprecated */ update(...args) { console.warn("TextureTransform#update() not implemented"); } getData({ packed = false } = {}) { throw new Error("getData() not implemented"); } getTargetTexture() { const { targetTexture } = this.bindings[this.currentIndex]; return targetTexture; } getFramebuffer() { const currentResources = this.bindings[this.currentIndex]; return currentResources.framebuffer; } // Private _initialize(props) { this._updateBindings(props); } _updateBindings(props) { this.bindings[this.currentIndex] = this._updateBinding(this.bindings[this.currentIndex], props); } _updateBinding(binding, { sourceBuffers, sourceTextures, targetTexture }) { if (!binding) { binding = { sourceBuffers: {}, sourceTextures: {}, targetTexture: null }; } Object.assign(binding.sourceTextures, sourceTextures); Object.assign(binding.sourceBuffers, sourceBuffers); if (targetTexture) { binding.targetTexture = targetTexture; const { width, height } = targetTexture; if (binding.framebuffer) { binding.framebuffer.destroy(); } binding.framebuffer = this.device.createFramebuffer({ id: "transform-framebuffer", width, height, colorAttachments: [targetTexture] }); binding.framebuffer.resize({ width, height }); } return binding; } // set texture filtering parameters on source textures. _setSourceTextureParameters() { const index2 = this.currentIndex; const { sourceTextures } = this.bindings[index2]; for (const name in sourceTextures) { sourceTextures[name].sampler = this.sampler; } } }; // src/lib/clip-space.ts var import_core15 = __toESM(require_core(), 1); // src/geometry/geometry.ts var import_core14 = __toESM(require_core(), 1); var Geometry = class { id; /** Determines how vertices are read from the 'vertex' attributes */ topology; vertexCount; indices; attributes; userData = {}; constructor(props) { const { attributes = {}, indices = null, vertexCount = null } = props; this.id = props.id || (0, import_core14.uid)("geometry"); this.topology = props.topology; if (indices) { this.indices = ArrayBuffer.isView(indices) ? { value: indices, size: 1 } : indices; } this.attributes = {}; for (const [attributeName, attributeValue] of Object.entries(attributes)) { const attribute = ArrayBuffer.isView(attributeValue) ? { value: attributeValue } : attributeValue; (0, import_core14.assert)( ArrayBuffer.isView(attribute.value), `${this._print(attributeName)}: must be typed array or object with value as typed array` ); if ((attributeName === "POSITION" || attributeName === "positions") && !attribute.size) { attribute.size = 3; } if (attributeName === "indices") { (0, import_core14.assert)(!this.indices); this.indices = attribute; } else { this.attributes[attributeName] = attribute; } } if (this.indices && this.indices.isIndexed !== void 0) { this.indices = Object.assign({}, this.indices); delete this.indices.isIndexed; } this.vertexCount = vertexCount || this._calculateVertexCount(this.attributes, this.indices); } getVertexCount() { return this.vertexCount; } /** * Return an object with all attributes plus indices added as a field. * TODO Geometry types are a mess */ getAttributes() { return this.indices ? { indices: this.indices, ...this.attributes } : this.attributes; } // PRIVATE _print(attributeName) { return `Geometry ${this.id} attribute ${attributeName}`; } /** * GeometryAttribute * value: typed array * type: indices, vertices, uvs * size: elements per vertex * target: WebGL buffer type (string or constant) * * @param attributes * @param indices * @returns */ _setAttributes(attributes, indices) { return this; } _calculateVertexCount(attributes, indices) { if (indices) { return indices.value.length; } let vertexCount = Infinity; for (const attribute of Object.values(attributes)) { const { value, size, constant } = attribute; if (!constant && value && size >= 1) { vertexCount = Math.min(vertexCount, value.length / size); } } (0, import_core14.assert)(Number.isFinite(vertexCount)); return vertexCount; } }; // src/lib/clip-space.ts var CLIPSPACE_VERTEX_SHADER = import_core15.glsl`\ #version 300 es in vec2 aClipSpacePosition; in vec2 aTexCoord; in vec2 aCoordinate; out vec2 position; out vec2 coordinate; out vec2 uv; void main(void) { gl_Position = vec4(aClipSpacePosition, 0., 1.); position = aClipSpacePosition; coordinate = aCoordinate; uv = aTexCoord; } `; var POSITIONS = [-1, -1, 1, -1, -1, 1, 1, 1]; var ClipSpace = class extends Model { constructor(device, opts) { const TEX_COORDS = POSITIONS.map((coord) => coord === -1 ? 0 : coord); super(device, { ...opts, vs: CLIPSPACE_VERTEX_SHADER, vertexCount: 4, geometry: new Geometry({ topology: "triangle-strip", vertexCount: 4, attributes: { aClipSpacePosition: { size: 2, value: new Float32Array(POSITIONS) }, aTexCoord: { size: 2, value: new Float32Array(TEX_COORDS) }, aCoordinate: { size: 2, value: new Float32Array(TEX_COORDS) } } }) }); } }; // src/scenegraph/scenegraph-node.ts var import_core16 = __toESM(require_core(), 1); var ScenegraphNode = class { id; matrix = new Matrix4(); display = true; position = new Vector3(); rotation = new Vector3(); scale = new Vector3(1, 1, 1); userData = {}; props = {}; constructor(props = {}) { const { id } = props; this.id = id || (0, import_core16.uid)(this.constructor.name); this._setScenegraphNodeProps(props); } getBounds() { return null; } destroy() { } /** @deprecated use .destroy() */ delete() { this.destroy(); } setProps(props) { this._setScenegraphNodeProps(props); return this; } toString() { return `{type: ScenegraphNode, id: ${this.id})}`; } setPosition(position) { (0, import_core16.assert)(position.length === 3, "setPosition requires vector argument"); this.position = position; return this; } setRotation(rotation) { (0, import_core16.assert)(rotation.length === 3, "setRotation requires vector argument"); this.rotation = rotation; return this; } setScale(scale2) { (0, import_core16.assert)(scale2.length === 3, "setScale requires vector argument"); this.scale = scale2; return this; } setMatrix(matrix, copyMatrix = true) { if (copyMatrix) { this.matrix.copy(matrix); } else { this.matrix = matrix; } } setMatrixComponents(components) { const { position, rotation, scale: scale2, update = true } = components; if (position) { this.setPosition(position); } if (rotation) { this.setRotation(rotation); } if (scale2) { this.setScale(scale2); } if (update) { this.updateMatrix(); } return this; } updateMatrix() { const pos = this.position; const rot = this.rotation; const scale2 = this.scale; this.matrix.identity(); this.matrix.translate(pos); this.matrix.rotateXYZ(rot); this.matrix.scale(scale2); return this; } update(options = {}) { const { position, rotation, scale: scale2 } = options; if (position) { this.setPosition(position); } if (rotation) { this.setRotation(rotation); } if (scale2) { this.setScale(scale2); } this.updateMatrix(); return this; } getCoordinateUniforms(viewMatrix, modelMatrix) { (0, import_core16.assert)(viewMatrix); modelMatrix = modelMatrix || this.matrix; const worldMatrix = new Matrix4(viewMatrix).multiplyRight(modelMatrix); const worldInverse = worldMatrix.invert(); const worldInverseTranspose = worldInverse.transpose(); return { viewMatrix, modelMatrix, objectMatrix: modelMatrix, worldMatrix, worldInverseMatrix: worldInverse, worldInverseTransposeMatrix: worldInverseTranspose }; } // TODO - copied code, not yet vetted /* transform() { if (!this.parent) { this.endPosition.set(this.position); this.endRotation.set(this.rotation); this.endScale.set(this.scale); } else { const parent = this.parent; this.endPosition.set(this.position.add(parent.endPosition)); this.endRotation.set(this.rotation.add(parent.endRotation)); this.endScale.set(this.scale.add(parent.endScale)); } const ch = this.children; for (let i = 0; i < ch.length; ++i) { ch[i].transform(); } return this; } */ _setScenegraphNodeProps(props) { if ("display" in props) { this.display = props.display; } if ("position" in props) { this.setPosition(props.position); } if ("rotation" in props) { this.setRotation(props.rotation); } if ("scale" in props) { this.setScale(props.scale); } if ("matrix" in props) { this.setMatrix(props.matrix); } Object.assign(this.props, props); } }; // src/scenegraph/group-node.ts var import_core19 = __toESM(require_core(), 1); var GroupNode = class extends ScenegraphNode { children; constructor(props = {}) { props = Array.isArray(props) ? { children: props } : props; const { children = [] } = props; import_core19.log.assert( children.every((child) => child instanceof ScenegraphNode), "every child must an instance of ScenegraphNode" ); super(props); this.children = children; } getBounds() { const result = [ [Infinity, Infinity, Infinity], [-Infinity, -Infinity, -Infinity] ]; this.traverse((node, { worldMatrix }) => { const bounds = node.getBounds(); if (!bounds) { return; } const [min, max] = bounds; const center = new Vector3(min).add(max).divide([2, 2, 2]); worldMatrix.transformAsPoint(center, center); const halfSize = new Vector3(max).subtract(min).divide([2, 2, 2]); worldMatrix.transformAsVector(halfSize, halfSize); for (let v = 0; v < 8; v++) { const position = new Vector3(v & 1 ? -1 : 1, v & 2 ? -1 : 1, v & 4 ? -1 : 1).multiply(halfSize).add(center); for (let i = 0; i < 3; i++) { result[0][i] = Math.min(result[0][i], position[i]); result[1][i] = Math.max(result[1][i], position[i]); } } }); if (!Number.isFinite(result[0][0])) { return null; } return result; } destroy() { this.children.forEach((child) => child.destroy()); this.removeAll(); super.destroy(); } // Unpacks arrays and nested arrays of children add(...children) { for (const child of children) { if (Array.isArray(child)) { this.add(...child); } else { this.children.push(child); } } return this; } remove(child) { const children = this.children; const indexOf = children.indexOf(child); if (indexOf > -1) { children.splice(indexOf, 1); } return this; } removeAll() { this.children = []; return this; } traverse(visitor, { worldMatrix = new Matrix4() } = {}) { const modelMatrix = new Matrix4(worldMatrix).multiplyRight(this.matrix); for (const child of this.children) { if (child instanceof GroupNode) { child.traverse(visitor, { worldMatrix: modelMatrix }); } else { visitor(child, { worldMatrix: modelMatrix }); } } } }; // src/scenegraph/model-node.ts var ModelNode = class extends ScenegraphNode { model; bounds = null; managedResources; // TODO - is this used? override callbacks to make sure we call them with this // onBeforeRender = null; // onAfterRender = null; // AfterRender = null; constructor(props) { super(props); this.model = props.model; this.managedResources = props.managedResources || []; this.bounds = props.bounds || null; this.setProps(props); } getBounds() { return this.bounds; } destroy() { if (this.model) { this.model.destroy(); this.model = null; } this.managedResources.forEach((resource) => resource.destroy()); this.managedResources = []; } // Expose model methods draw(renderPass) { return this.model.draw(renderPass); } }; // src/geometries/cone-geometry.ts var import_core21 = __toESM(require_core(), 1); // src/geometries/truncated-cone-geometry.ts var import_core20 = __toESM(require_core(), 1); var INDEX_OFFSETS = { x: [2, 0, 1], y: [0, 1, 2], z: [1, 2, 0] }; var TruncatedConeGeometry = class extends Geometry { constructor(props = {}) { const { id = (0, import_core20.uid)("truncated-code-geometry") } = props; const { indices, attributes } = tesselateTruncatedCone(props); super({ ...props, id, topology: "triangle-list", indices, attributes: { POSITION: { size: 3, value: attributes.POSITION }, NORMAL: { size: 3, value: attributes.NORMAL }, TEXCOORD_0: { size: 2, value: attributes.TEXCOORD_0 }, ...props.attributes } }); } }; function tesselateTruncatedCone(props = {}) { const { bottomRadius = 0, topRadius = 0, height = 1, nradial = 10, nvertical = 10, verticalAxis = "y", topCap = false, bottomCap = false } = props; const extra = (topCap ? 2 : 0) + (bottomCap ? 2 : 0); const numVertices = (nradial + 1) * (nvertical + 1 + extra); const slant = Math.atan2(bottomRadius - topRadius, height); const msin = Math.sin; const mcos = Math.cos; const mpi = Math.PI; const cosSlant = mcos(slant); const sinSlant = msin(slant); const start = topCap ? -2 : 0; const end = nvertical + (bottomCap ? 2 : 0); const vertsAroundEdge = nradial + 1; const indices = new Uint16Array(nradial * (nvertical + extra) * 6); const indexOffset = INDEX_OFFSETS[verticalAxis]; const positions = new Float32Array(numVertices * 3); const normals = new Float32Array(numVertices * 3); const texCoords = new Float32Array(numVertices * 2); let i3 = 0; let i2 = 0; for (let i = start; i <= end; i++) { let v = i / nvertical; let y = height * v; let ringRadius; if (i < 0) { y = 0; v = 1; ringRadius = bottomRadius; } else if (i > nvertical) { y = height; v = 1; ringRadius = topRadius; } else { ringRadius = bottomRadius + (topRadius - bottomRadius) * (i / nvertical); } if (i === -2 || i === nvertical + 2) { ringRadius = 0; v = 0; } y -= height / 2; for (let j = 0; j < vertsAroundEdge; j++) { const sin = msin(j * mpi * 2 / nradial); const cos = mcos(j * mpi * 2 / nradial); positions[i3 + indexOffset[0]] = sin * ringRadius; positions[i3 + indexOffset[1]] = y; positions[i3 + indexOffset[2]] = cos * ringRadius; normals[i3 + indexOffset[0]] = i < 0 || i > nvertical ? 0 : sin * cosSlant; normals[i3 + indexOffset[1]] = i < 0 ? -1 : i > nvertical ? 1 : sinSlant; normals[i3 + indexOffset[2]] = i < 0 || i > nvertical ? 0 : cos * cosSlant; texCoords[i2 + 0] = j / nradial; texCoords[i2 + 1] = v; i2 += 2; i3 += 3; } } for (let i = 0; i < nvertical + extra; i++) { for (let j = 0; j < nradial; j++) { const index2 = (i * nradial + j) * 6; indices[index2 + 0] = vertsAroundEdge * (i + 0) + 0 + j; indices[index2 + 1] = vertsAroundEdge * (i + 0) + 1 + j; indices[index2 + 2] = vertsAroundEdge * (i + 1) + 1 + j; indices[index2 + 3] = vertsAroundEdge * (i + 0) + 0 + j; indices[index2 + 4] = vertsAroundEdge * (i + 1) + 1 + j; indices[index2 + 5] = vertsAroundEdge * (i + 1) + 0 + j; } } return { indices, attributes: { POSITION: positions, NORMAL: normals, TEXCOORD_0: texCoords } }; } // src/geometries/cone-geometry.ts var ConeGeometry = class extends TruncatedConeGeometry { constructor(props = {}) { const { id = (0, import_core21.uid)("cone-geometry"), radius = 1, cap = true } = props; super({ ...props, id, topRadius: 0, topCap: Boolean(cap), bottomCap: Boolean(cap), bottomRadius: radius }); } }; // src/geometries/cube-geometry.ts var import_core22 = __toESM(require_core(), 1); var CubeGeometry = class extends Geometry { constructor(props = {}) { const { id = (0, import_core22.uid)("cube-geometry"), indices = true } = props; super( indices ? { ...props, id, topology: "triangle-list", indices: { size: 1, value: CUBE_INDICES }, attributes: { ...ATTRIBUTES, ...props.attributes } } : { ...props, id, topology: "triangle-list", indices: void 0, attributes: { ...NON_INDEXED_ATTRIBUTES, ...props.attributes } } ); } }; var CUBE_INDICES = new Uint16Array([ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23 ]); var CUBE_POSITIONS = new Float32Array([ -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1 ]); var CUBE_NORMALS = new Float32Array([ // Front face 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Back face 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, // Top face 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Bottom face 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, // Right face 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Left face -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0 ]); var CUBE_TEX_COORDS = new Float32Array([ // Front face 0, 0, 1, 0, 1, 1, 0, 1, // Back face 1, 0, 1, 1, 0, 1, 0, 0, // Top face 0, 1, 0, 0, 1, 0, 1, 1, // Bottom face 1, 1, 0, 1, 0, 0, 1, 0, // Right face 1, 0, 1, 1, 0, 1, 0, 0, // Left face 0, 0, 1, 0, 1, 1, 0, 1 ]); var CUBE_NON_INDEXED_POSITIONS = new Float32Array([ 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1 ]); var CUBE_NON_INDEXED_TEX_COORDS = new Float32Array([ 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0 ]); var CUBE_NON_INDEXED_COLORS = new Float32Array([ 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1 ]); var ATTRIBUTES = { POSITION: { size: 3, value: CUBE_POSITIONS }, NORMAL: { size: 3, value: CUBE_NORMALS }, TEXCOORD_0: { size: 2, value: CUBE_TEX_COORDS } }; var NON_INDEXED_ATTRIBUTES = { POSITION: { size: 3, value: CUBE_NON_INDEXED_POSITIONS }, // NORMAL: {size: 3, value: CUBE_NON_INDEXED_NORMALS}, TEXCOORD_0: { size: 2, value: CUBE_NON_INDEXED_TEX_COORDS }, COLOR_0: { size: 3, value: CUBE_NON_INDEXED_COLORS } }; // src/geometries/cylinder-geometry.ts var import_core23 = __toESM(require_core(), 1); var CylinderGeometry = class extends TruncatedConeGeometry { constructor(props = {}) { const { id = (0, import_core23.uid)("cylinder-geometry"), radius = 1 } = props; super({ ...props, id, bottomRadius: radius, topRadius: radius }); } }; // src/geometries/ico-sphere-geometry.ts var import_core24 = __toESM(require_core(), 1); var ICO_POSITIONS = [-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 1, 0, -1, 0, 1, 0, 0]; var ICO_INDICES = [3, 4, 5, 3, 5, 1, 3, 1, 0, 3, 0, 4, 4, 0, 2, 4, 2, 5, 2, 0, 1, 5, 2, 1]; var IcoSphereGeometry = class extends Geometry { constructor(props = {}) { const { id = (0, import_core24.uid)("ico-sphere-geometry") } = props; const { indices, attributes } = tesselateIcosaHedron(props); super({ ...props, id, topology: "triangle-list", indices, attributes: { ...attributes, ...props.attributes } }); } }; function tesselateIcosaHedron(props) { const { iterations = 0 } = props; const PI = Math.PI; const PI2 = PI * 2; const positions = [...ICO_POSITIONS]; let indices = [...ICO_INDICES]; positions.push(); indices.push(); const getMiddlePoint = (() => { const pointMemo = {}; return (i1, i2) => { i1 *= 3; i2 *= 3; const mini = i1 < i2 ? i1 : i2; const maxi = i1 > i2 ? i1 : i2; const key = `${mini}|${maxi}`; if (key in pointMemo) { return pointMemo[key]; } const x1 = positions[i1]; const y1 = positions[i1 + 1]; const z1 = positions[i1 + 2]; const x2 = positions[i2]; const y2 = positions[i2 + 1]; const z2 = positions[i2 + 2]; let xm = (x1 + x2) / 2; let ym = (y1 + y2) / 2; let zm = (z1 + z2) / 2; const len = Math.sqrt(xm * xm + ym * ym + zm * zm); xm /= len; ym /= len; zm /= len; positions.push(xm, ym, zm); return pointMemo[key] = positions.length / 3 - 1; }; })(); for (let i = 0; i < iterations; i++) { const indices2 = []; for (let j = 0; j < indices.length; j += 3) { const a = getMiddlePoint(indices[j + 0], indices[j + 1]); const b = getMiddlePoint(indices[j + 1], indices[j + 2]); const c = getMiddlePoint(indices[j + 2], indices[j + 0]); indices2.push(c, indices[j + 0], a, a, indices[j + 1], b, b, indices[j + 2], c, a, b, c); } indices = indices2; } const normals = new Array(positions.length); const texCoords = new Array(positions.length / 3 * 2); const l = indices.length; for (let i = l - 3; i >= 0; i -= 3) { const i1 = indices[i + 0]; const i2 = indices[i + 1]; const i3 = indices[i + 2]; const in1 = i1 * 3; const in2 = i2 * 3; const in3 = i3 * 3; const iu1 = i1 * 2; const iu2 = i2 * 2; const iu3 = i3 * 2; const x1 = positions[in1 + 0]; const y1 = positions[in1 + 1]; const z1 = positions[in1 + 2]; const theta1 = Math.acos(z1 / Math.sqrt(x1 * x1 + y1 * y1 + z1 * z1)); const phi1 = Math.atan2(y1, x1) + PI; const v1 = theta1 / PI; const u1 = 1 - phi1 / PI2; const x2 = positions[in2 + 0]; const y2 = positions[in2 + 1]; const z2 = positions[in2 + 2]; const theta2 = Math.acos(z2 / Math.sqrt(x2 * x2 + y2 * y2 + z2 * z2)); const phi2 = Math.atan2(y2, x2) + PI; const v2 = theta2 / PI; const u2 = 1 - phi2 / PI2; const x3 = positions[in3 + 0]; const y3 = positions[in3 + 1]; const z3 = positions[in3 + 2]; const theta3 = Math.acos(z3 / Math.sqrt(x3 * x3 + y3 * y3 + z3 * z3)); const phi3 = Math.atan2(y3, x3) + PI; const v3 = theta3 / PI; const u3 = 1 - phi3 / PI2; const vec1 = [x3 - x2, y3 - y2, z3 - z2]; const vec2 = [x1 - x2, y1 - y2, z1 - z2]; const normal = new Vector3(vec1).cross(vec2).normalize(); let newIndex; if ((u1 === 0 || u2 === 0 || u3 === 0) && (u1 === 0 || u1 > 0.5) && (u2 === 0 || u2 > 0.5) && (u3 === 0 || u3 > 0.5)) { positions.push(positions[in1 + 0], positions[in1 + 1], positions[in1 + 2]); newIndex = positions.length / 3 - 1; indices.push(newIndex); texCoords[newIndex * 2 + 0] = 1; texCoords[newIndex * 2 + 1] = v1; normals[newIndex * 3 + 0] = normal.x; normals[newIndex * 3 + 1] = normal.y; normals[newIndex * 3 + 2] = normal.z; positions.push(positions[in2 + 0], positions[in2 + 1], positions[in2 + 2]); newIndex = positions.length / 3 - 1; indices.push(newIndex); texCoords[newIndex * 2 + 0] = 1; texCoords[newIndex * 2 + 1] = v2; normals[newIndex * 3 + 0] = normal.x; normals[newIndex * 3 + 1] = normal.y; normals[newIndex * 3 + 2] = normal.z; positions.push(positions[in3 + 0], positions[in3 + 1], positions[in3 + 2]); newIndex = positions.length / 3 - 1; indices.push(newIndex); texCoords[newIndex * 2 + 0] = 1; texCoords[newIndex * 2 + 1] = v3; normals[newIndex * 3 + 0] = normal.x; normals[newIndex * 3 + 1] = normal.y; normals[newIndex * 3 + 2] = normal.z; } normals[in1 + 0] = normals[in2 + 0] = normals[in3 + 0] = normal.x; normals[in1 + 1] = normals[in2 + 1] = normals[in3 + 1] = normal.y; normals[in1 + 2] = normals[in2 + 2] = normals[in3 + 2] = normal.z; texCoords[iu1 + 0] = u1; texCoords[iu1 + 1] = v1; texCoords[iu2 + 0] = u2; texCoords[iu2 + 1] = v2; texCoords[iu3 + 0] = u3; texCoords[iu3 + 1] = v3; } return { indices: { size: 1, value: new Uint16Array(indices) }, attributes: { POSITION: { size: 3, value: new Float32Array(positions) }, NORMAL: { size: 3, value: new Float32Array(normals) }, TEXCOORD_0: { size: 2, value: new Float32Array(texCoords) } } }; } // src/geometries/plane-geometry.ts var import_core26 = __toESM(require_core(), 1); // src/geometry/geometry-utils.ts function unpackIndexedGeometry(geometry) { const { indices, attributes } = geometry; if (!indices) { return geometry; } const vertexCount = indices.value.length; const unpackedAttributes = {}; for (const attributeName in attributes) { const attribute = attributes[attributeName]; const { constant, value, size } = attribute; if (constant || !size) { continue; } const unpackedValue = new value.constructor(vertexCount * size); for (let x = 0; x < vertexCount; ++x) { const index2 = indices.value[x]; for (let i = 0; i < size; i++) { unpackedValue[x * size + i] = value[index2 * size + i]; } } unpackedAttributes[attributeName] = { size, value: unpackedValue }; } return { attributes: Object.assign({}, attributes, unpackedAttributes) }; } // src/geometries/plane-geometry.ts var PlaneGeometry = class extends Geometry { constructor(props = {}) { const { id = (0, import_core26.uid)("plane-geometry") } = props; const { indices, attributes } = tesselatePlane(props); super({ ...props, id, topology: "triangle-list", indices, attributes: { ...attributes, ...props.attributes } }); } }; function tesselatePlane(props) { const { type = "x,y", offset = 0, flipCull = false, unpack = false } = props; const coords = type.split(","); let c1len = props[`${coords[0]}len`] || 1; const c2len = props[`${coords[1]}len`] || 1; const subdivisions1 = props[`n${coords[0]}`] || 1; const subdivisions2 = props[`n${coords[1]}`] || 1; const numVertices = (subdivisions1 + 1) * (subdivisions2 + 1); const positions = new Float32Array(numVertices * 3); const normals = new Float32Array(numVertices * 3); const texCoords = new Float32Array(numVertices * 2); if (flipCull) { c1len = -c1len; } let i2 = 0; let i3 = 0; for (let z = 0; z <= subdivisions2; z++) { for (let x = 0; x <= subdivisions1; x++) { const u = x / subdivisions1; const v = z / subdivisions2; texCoords[i2 + 0] = flipCull ? 1 - u : u; texCoords[i2 + 1] = v; switch (type) { case "x,y": positions[i3 + 0] = c1len * u - c1len * 0.5; positions[i3 + 1] = c2len * v - c2len * 0.5; positions[i3 + 2] = offset; normals[i3 + 0] = 0; normals[i3 + 1] = 0; normals[i3 + 2] = flipCull ? 1 : -1; break; case "x,z": positions[i3 + 0] = c1len * u - c1len * 0.5; positions[i3 + 1] = offset; positions[i3 + 2] = c2len * v - c2len * 0.5; normals[i3 + 0] = 0; normals[i3 + 1] = flipCull ? 1 : -1; normals[i3 + 2] = 0; break; case "y,z": positions[i3 + 0] = offset; positions[i3 + 1] = c1len * u - c1len * 0.5; positions[i3 + 2] = c2len * v - c2len * 0.5; normals[i3 + 0] = flipCull ? 1 : -1; normals[i3 + 1] = 0; normals[i3 + 2] = 0; break; default: throw new Error("PlaneGeometry: unknown type"); } i2 += 2; i3 += 3; } } const numVertsAcross = subdivisions1 + 1; const indices = new Uint16Array(subdivisions1 * subdivisions2 * 6); for (let z = 0; z < subdivisions2; z++) { for (let x = 0; x < subdivisions1; x++) { const index2 = (z * subdivisions1 + x) * 6; indices[index2 + 0] = (z + 0) * numVertsAcross + x; indices[index2 + 1] = (z + 1) * numVertsAcross + x; indices[index2 + 2] = (z + 0) * numVertsAcross + x + 1; indices[index2 + 3] = (z + 1) * numVertsAcross + x; indices[index2 + 4] = (z + 1) * numVertsAcross + x + 1; indices[index2 + 5] = (z + 0) * numVertsAcross + x + 1; } } const geometry = { indices: { size: 1, value: indices }, attributes: { POSITION: { size: 3, value: positions }, NORMAL: { size: 3, value: normals }, TEXCOORD_0: { size: 2, value: texCoords } } }; return unpack ? unpackIndexedGeometry(geometry) : geometry; } // src/geometries/sphere-geometry.ts var import_core27 = __toESM(require_core(), 1); var SphereGeometry = class extends Geometry { constructor(props = {}) { const { id = (0, import_core27.uid)("sphere-geometry") } = props; const { indices, attributes } = tesselateSphere(props); super({ ...props, id, topology: "triangle-list", indices, attributes: { ...attributes, ...props.attributes } }); } }; function tesselateSphere(props) { const { nlat = 10, nlong = 10 } = props; const startLat = 0; const endLat = Math.PI; const latRange = endLat - startLat; const startLong = 0; const endLong = 2 * Math.PI; const longRange = endLong - startLong; const numVertices = (nlat + 1) * (nlong + 1); const radius = (n1, n2, n3, u, v) => props.radius || 1; const positions = new Float32Array(numVertices * 3); const normals = new Float32Array(numVertices * 3); const texCoords = new Float32Array(numVertices * 2); const IndexType = numVertices > 65535 ? Uint32Array : Uint16Array; const indices = new IndexType(nlat * nlong * 6); for (let y = 0; y <= nlat; y++) { for (let x = 0; x <= nlong; x++) { const u = x / nlong; const v = y / nlat; const index2 = x + y * (nlong + 1); const i2 = index2 * 2; const i3 = index2 * 3; const theta = longRange * u; const phi = latRange * v; const sinTheta = Math.sin(theta); const cosTheta = Math.cos(theta); const sinPhi = Math.sin(phi); const cosPhi = Math.cos(phi); const ux = cosTheta * sinPhi; const uy = cosPhi; const uz = sinTheta * sinPhi; const r = radius(ux, uy, uz, u, v); positions[i3 + 0] = r * ux; positions[i3 + 1] = r * uy; positions[i3 + 2] = r * uz; normals[i3 + 0] = ux; normals[i3 + 1] = uy; normals[i3 + 2] = uz; texCoords[i2 + 0] = u; texCoords[i2 + 1] = 1 - v; } } const numVertsAround = nlong + 1; for (let x = 0; x < nlong; x++) { for (let y = 0; y < nlat; y++) { const index2 = (x * nlat + y) * 6; indices[index2 + 0] = y * numVertsAround + x; indices[index2 + 1] = y * numVertsAround + x + 1; indices[index2 + 2] = (y + 1) * numVertsAround + x; indices[index2 + 3] = (y + 1) * numVertsAround + x; indices[index2 + 4] = y * numVertsAround + x + 1; indices[index2 + 5] = (y + 1) * numVertsAround + x + 1; } } return { indices: { size: 1, value: indices }, attributes: { POSITION: { size: 3, value: positions }, NORMAL: { size: 3, value: normals }, TEXCOORD_0: { size: 2, value: texCoords } } }; } // src/computation.ts var import_core28 = __toESM(require_core(), 1); var import_core29 = __toESM(require_core(), 1); var import_core30 = __toESM(require_core(), 1); var LOG_DRAW_PRIORITY2 = 2; var LOG_DRAW_TIMEOUT2 = 1e4; var _Computation = class { device; id; pipelineFactory; shaderFactory; userData = {}; /** Bindings (textures, samplers, uniform buffers) */ bindings = {}; /** The underlying GPU "program". @note May be recreated if parameters change */ pipeline; /** the underlying compiled compute shader */ shader; source; /** ShaderInputs instance */ shaderInputs; _uniformStore; _pipelineNeedsUpdate = "newly created"; _getModuleUniforms; props; _destroyed = false; constructor(device, props) { if (device.type !== "webgpu") { throw new Error("Computation is only supported in WebGPU"); } this.props = { ..._Computation.defaultProps, ...props }; props = this.props; this.id = props.id || (0, import_core29.uid)("model"); this.device = device; Object.assign(this.userData, props.userData); const moduleMap = Object.fromEntries( this.props.modules?.map((module) => [module.name, module]) || [] ); this.setShaderInputs(props.shaderInputs || new ShaderInputs(moduleMap)); this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.source); const platformInfo = getPlatformInfo2(device); const modules = (this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || []; this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device); this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device); const { source, getUniforms } = this.props.shaderAssembler.assembleShader({ platformInfo, ...this.props, modules }); this.source = source; this._getModuleUniforms = getUniforms; this.pipeline = this._updatePipeline(); if (props.bindings) { this.setBindings(props.bindings); } Object.seal(this); } destroy() { if (this._destroyed) return; this.pipelineFactory.release(this.pipeline); this.shaderFactory.release(this.shader); this._uniformStore.destroy(); this._destroyed = true; } // Draw call predraw() { this.updateShaderInputs(); } dispatch(computePass, x, y, z) { try { this._logDrawCallStart(); this.pipeline = this._updatePipeline(); this.pipeline.setBindings(this.bindings); computePass.setPipeline(this.pipeline); computePass.setBindings([]); computePass.dispatch(x, y, z); } finally { this._logDrawCallEnd(); } } // Update fixed fields (can trigger pipeline rebuild) // Update dynamic fields /** * Updates the vertex count (used in draw calls) * @note Any attributes with stepMode=vertex need to be at least this big */ setVertexCount(vertexCount) { } /** * Updates the instance count (used in draw calls) * @note Any attributes with stepMode=instance need to be at least this big */ setInstanceCount(instanceCount) { } setShaderInputs(shaderInputs) { this.shaderInputs = shaderInputs; this._uniformStore = new import_core28.UniformStore(this.shaderInputs.modules); for (const moduleName of Object.keys(this.shaderInputs.modules)) { const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName); this.bindings[`${moduleName}Uniforms`] = uniformBuffer; } } /** * Updates shader module settings (which results in uniforms being set) */ setShaderModuleProps(props) { const uniforms = this._getModuleUniforms(props); const keys = Object.keys(uniforms).filter((k) => { const uniform = uniforms[k]; return !(0, import_core29.isNumberArray)(uniform) && typeof uniform !== "number" && typeof uniform !== "boolean"; }); const bindings = {}; for (const k of keys) { bindings[k] = uniforms[k]; delete uniforms[k]; } } updateShaderInputs() { this._uniformStore.setUniforms(this.shaderInputs.getUniformValues()); } /** * Sets bindings (textures, samplers, uniform buffers) */ setBindings(bindings) { Object.assign(this.bindings, bindings); } _setPipelineNeedsUpdate(reason) { this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason; } _updatePipeline() { if (this._pipelineNeedsUpdate) { let prevShader = null; if (this.pipeline) { import_core29.log.log( 1, `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".` )(); prevShader = this.shader; } this._pipelineNeedsUpdate = false; this.shader = this.shaderFactory.createShader({ id: `${this.id}-fragment`, stage: "compute", source: this.source, debug: this.props.debugShaders }); this.pipeline = this.pipelineFactory.createComputePipeline({ ...this.props, shader: this.shader }); if (prevShader) { this.shaderFactory.release(prevShader); } } return this.pipeline; } /** Throttle draw call logging */ _lastLogTime = 0; _logOpen = false; _logDrawCallStart() { const logDrawTimeout = import_core29.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT2; if (import_core29.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) { return; } this._lastLogTime = Date.now(); this._logOpen = true; import_core29.log.group(LOG_DRAW_PRIORITY2, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core29.log.level <= 2 })(); } _logDrawCallEnd() { if (this._logOpen) { const uniformTable = this.shaderInputs.getDebugTable(); import_core29.log.table(LOG_DRAW_PRIORITY2, uniformTable)(); import_core29.log.groupEnd(LOG_DRAW_PRIORITY2)(); this._logOpen = false; } } _drawCount = 0; // TODO - fix typing of luma data types _getBufferOrConstantValues(attribute, dataType) { const TypedArrayConstructor = (0, import_core30.getTypedArrayFromDataType)(dataType); const typedArray = attribute instanceof import_core28.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute; return typedArray.toString(); } }; var Computation = _Computation; __publicField(Computation, "defaultProps", { ...import_core28.ComputePipeline.defaultProps, id: "unnamed", handle: void 0, userData: {}, source: "", modules: [], defines: {}, bindings: void 0, shaderInputs: void 0, pipelineFactory: void 0, shaderFactory: void 0, shaderAssembler: ShaderAssembler.getDefaultShaderAssembler(), debugShaders: void 0 }); function getPlatformInfo2(device) { return { type: device.type, shaderLanguage: device.info.shadingLanguage, shaderLanguageVersion: device.info.shadingLanguageVersion, gpu: device.info.gpu, // HACK - we pretend that the DeviceFeatures is a Set, it has a similar API features: device.features }; } return __toCommonJS(bundle_exports); })(); return __exports__; });